@iveri/contracts 0.7.0 → 0.9.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 (114) hide show
  1. package/README.md +24 -4
  2. package/dist/cjs/api/unibox/canned-reply.type.d.ts +49 -0
  3. package/dist/cjs/api/unibox/canned-reply.type.d.ts.map +1 -0
  4. package/dist/cjs/api/unibox/canned-reply.type.js +3 -0
  5. package/dist/cjs/api/unibox/canned-reply.type.js.map +1 -0
  6. package/dist/cjs/api/unibox/channel-platform.enum.d.ts +32 -0
  7. package/dist/cjs/api/unibox/channel-platform.enum.d.ts.map +1 -0
  8. package/dist/cjs/api/unibox/channel-platform.enum.js +36 -0
  9. package/dist/cjs/api/unibox/channel-platform.enum.js.map +1 -0
  10. package/dist/cjs/api/unibox/channel.type.d.ts +110 -0
  11. package/dist/cjs/api/unibox/channel.type.d.ts.map +1 -0
  12. package/dist/cjs/api/unibox/channel.type.js +3 -0
  13. package/dist/cjs/api/unibox/channel.type.js.map +1 -0
  14. package/dist/cjs/api/unibox/contact.type.d.ts +102 -0
  15. package/dist/cjs/api/unibox/contact.type.d.ts.map +1 -0
  16. package/dist/cjs/api/unibox/contact.type.js +3 -0
  17. package/dist/cjs/api/unibox/contact.type.js.map +1 -0
  18. package/dist/cjs/api/unibox/conversation-status.enum.d.ts +39 -0
  19. package/dist/cjs/api/unibox/conversation-status.enum.d.ts.map +1 -0
  20. package/dist/cjs/api/unibox/conversation-status.enum.js +43 -0
  21. package/dist/cjs/api/unibox/conversation-status.enum.js.map +1 -0
  22. package/dist/cjs/api/unibox/conversation.type.d.ts +134 -0
  23. package/dist/cjs/api/unibox/conversation.type.d.ts.map +1 -0
  24. package/dist/cjs/api/unibox/conversation.type.js +3 -0
  25. package/dist/cjs/api/unibox/conversation.type.js.map +1 -0
  26. package/dist/cjs/api/unibox/index.d.ts +13 -0
  27. package/dist/cjs/api/unibox/index.d.ts.map +1 -0
  28. package/dist/cjs/api/unibox/index.js +29 -0
  29. package/dist/cjs/api/unibox/index.js.map +1 -0
  30. package/dist/cjs/api/unibox/message-author-type.enum.d.ts +26 -0
  31. package/dist/cjs/api/unibox/message-author-type.enum.d.ts.map +1 -0
  32. package/dist/cjs/api/unibox/message-author-type.enum.js +30 -0
  33. package/dist/cjs/api/unibox/message-author-type.enum.js.map +1 -0
  34. package/dist/cjs/api/unibox/message-content-type.enum.d.ts +29 -0
  35. package/dist/cjs/api/unibox/message-content-type.enum.d.ts.map +1 -0
  36. package/dist/cjs/api/unibox/message-content-type.enum.js +33 -0
  37. package/dist/cjs/api/unibox/message-content-type.enum.js.map +1 -0
  38. package/dist/cjs/api/unibox/message-direction.enum.d.ts +23 -0
  39. package/dist/cjs/api/unibox/message-direction.enum.d.ts.map +1 -0
  40. package/dist/cjs/api/unibox/message-direction.enum.js +27 -0
  41. package/dist/cjs/api/unibox/message-direction.enum.js.map +1 -0
  42. package/dist/cjs/api/unibox/message-status.enum.d.ts +40 -0
  43. package/dist/cjs/api/unibox/message-status.enum.d.ts.map +1 -0
  44. package/dist/cjs/api/unibox/message-status.enum.js +44 -0
  45. package/dist/cjs/api/unibox/message-status.enum.js.map +1 -0
  46. package/dist/cjs/api/unibox/message.type.d.ts +120 -0
  47. package/dist/cjs/api/unibox/message.type.d.ts.map +1 -0
  48. package/dist/cjs/api/unibox/message.type.js +3 -0
  49. package/dist/cjs/api/unibox/message.type.js.map +1 -0
  50. package/dist/cjs/api/unibox/team.type.d.ts +50 -0
  51. package/dist/cjs/api/unibox/team.type.d.ts.map +1 -0
  52. package/dist/cjs/api/unibox/team.type.js +3 -0
  53. package/dist/cjs/api/unibox/team.type.js.map +1 -0
  54. package/dist/cjs/enum/user-permission.enum.d.ts +52 -1
  55. package/dist/cjs/enum/user-permission.enum.d.ts.map +1 -1
  56. package/dist/cjs/enum/user-permission.enum.js +60 -0
  57. package/dist/cjs/enum/user-permission.enum.js.map +1 -1
  58. package/dist/esm/api/unibox/canned-reply.type.d.ts +49 -0
  59. package/dist/esm/api/unibox/canned-reply.type.d.ts.map +1 -0
  60. package/dist/esm/api/unibox/canned-reply.type.js +2 -0
  61. package/dist/esm/api/unibox/canned-reply.type.js.map +1 -0
  62. package/dist/esm/api/unibox/channel-platform.enum.d.ts +32 -0
  63. package/dist/esm/api/unibox/channel-platform.enum.d.ts.map +1 -0
  64. package/dist/esm/api/unibox/channel-platform.enum.js +33 -0
  65. package/dist/esm/api/unibox/channel-platform.enum.js.map +1 -0
  66. package/dist/esm/api/unibox/channel.type.d.ts +110 -0
  67. package/dist/esm/api/unibox/channel.type.d.ts.map +1 -0
  68. package/dist/esm/api/unibox/channel.type.js +2 -0
  69. package/dist/esm/api/unibox/channel.type.js.map +1 -0
  70. package/dist/esm/api/unibox/contact.type.d.ts +102 -0
  71. package/dist/esm/api/unibox/contact.type.d.ts.map +1 -0
  72. package/dist/esm/api/unibox/contact.type.js +2 -0
  73. package/dist/esm/api/unibox/contact.type.js.map +1 -0
  74. package/dist/esm/api/unibox/conversation-status.enum.d.ts +39 -0
  75. package/dist/esm/api/unibox/conversation-status.enum.d.ts.map +1 -0
  76. package/dist/esm/api/unibox/conversation-status.enum.js +40 -0
  77. package/dist/esm/api/unibox/conversation-status.enum.js.map +1 -0
  78. package/dist/esm/api/unibox/conversation.type.d.ts +134 -0
  79. package/dist/esm/api/unibox/conversation.type.d.ts.map +1 -0
  80. package/dist/esm/api/unibox/conversation.type.js +2 -0
  81. package/dist/esm/api/unibox/conversation.type.js.map +1 -0
  82. package/dist/esm/api/unibox/index.d.ts +13 -0
  83. package/dist/esm/api/unibox/index.d.ts.map +1 -0
  84. package/dist/esm/api/unibox/index.js +13 -0
  85. package/dist/esm/api/unibox/index.js.map +1 -0
  86. package/dist/esm/api/unibox/message-author-type.enum.d.ts +26 -0
  87. package/dist/esm/api/unibox/message-author-type.enum.d.ts.map +1 -0
  88. package/dist/esm/api/unibox/message-author-type.enum.js +27 -0
  89. package/dist/esm/api/unibox/message-author-type.enum.js.map +1 -0
  90. package/dist/esm/api/unibox/message-content-type.enum.d.ts +29 -0
  91. package/dist/esm/api/unibox/message-content-type.enum.d.ts.map +1 -0
  92. package/dist/esm/api/unibox/message-content-type.enum.js +30 -0
  93. package/dist/esm/api/unibox/message-content-type.enum.js.map +1 -0
  94. package/dist/esm/api/unibox/message-direction.enum.d.ts +23 -0
  95. package/dist/esm/api/unibox/message-direction.enum.d.ts.map +1 -0
  96. package/dist/esm/api/unibox/message-direction.enum.js +24 -0
  97. package/dist/esm/api/unibox/message-direction.enum.js.map +1 -0
  98. package/dist/esm/api/unibox/message-status.enum.d.ts +40 -0
  99. package/dist/esm/api/unibox/message-status.enum.d.ts.map +1 -0
  100. package/dist/esm/api/unibox/message-status.enum.js +41 -0
  101. package/dist/esm/api/unibox/message-status.enum.js.map +1 -0
  102. package/dist/esm/api/unibox/message.type.d.ts +120 -0
  103. package/dist/esm/api/unibox/message.type.d.ts.map +1 -0
  104. package/dist/esm/api/unibox/message.type.js +2 -0
  105. package/dist/esm/api/unibox/message.type.js.map +1 -0
  106. package/dist/esm/api/unibox/team.type.d.ts +50 -0
  107. package/dist/esm/api/unibox/team.type.d.ts.map +1 -0
  108. package/dist/esm/api/unibox/team.type.js +2 -0
  109. package/dist/esm/api/unibox/team.type.js.map +1 -0
  110. package/dist/esm/enum/user-permission.enum.d.ts +52 -1
  111. package/dist/esm/enum/user-permission.enum.d.ts.map +1 -1
  112. package/dist/esm/enum/user-permission.enum.js +60 -0
  113. package/dist/esm/enum/user-permission.enum.js.map +1 -1
  114. package/package.json +9 -1
@@ -0,0 +1,50 @@
1
+ import type { IsoDateTime } from '../../type/iso-date-time.type.js';
2
+ import type { Nullable } from '../../type/nil.type.js';
3
+ import type { Paginated } from '../../type/paginated.type.js';
4
+ import type { UUID } from '../../type/uuid.type.js';
5
+ /**
6
+ * A group of agents work is routed to — Support, Sales, Billing.
7
+ *
8
+ * **A team is not a role and not a membership.** Identity owns who exists and what they may do;
9
+ * this owns who is expected to answer what. Keeping them apart is what lets an agent be moved
10
+ * between teams without touching their permissions, which is the operation that actually happens
11
+ * weekly.
12
+ *
13
+ * `memberUserIds` names users in `iveri-identity-api`, so it is a loose reference with no foreign
14
+ * key. A user removed there leaves a stale id here; Unibox filters those out when resolving a
15
+ * team rather than pretending it can prevent them.
16
+ */
17
+ export interface Team {
18
+ id: UUID;
19
+ name: string;
20
+ description: Nullable<string>;
21
+ /** Identity user ids. Order is not meaningful. */
22
+ memberUserIds: UUID[];
23
+ /**
24
+ * Conversations on these channels are routed to this team when nothing else claims them.
25
+ *
26
+ * Empty means the team takes no automatic routing and is assignment-only. Deliberately a list
27
+ * on the team rather than a team id on the channel: a channel routed to two teams during a
28
+ * handover period is a real thing customers ask for, and the other direction cannot express it.
29
+ */
30
+ channelIds: UUID[];
31
+ createdAt: IsoDateTime;
32
+ updatedAt: IsoDateTime;
33
+ }
34
+ /** `GET /api/v1/teams`. Offset-paged; a tenant has a handful. */
35
+ export type TeamsPage = Paginated<Team>;
36
+ /** `POST /api/v1/teams`. */
37
+ export interface CreateTeamBody {
38
+ name: string;
39
+ description?: Nullable<string>;
40
+ memberUserIds?: Nullable<UUID[]>;
41
+ channelIds?: Nullable<UUID[]>;
42
+ }
43
+ /** `PATCH /api/v1/teams/:id`. Both id lists replace wholesale; omit to leave alone, `[]` clears. */
44
+ export interface UpdateTeamBody {
45
+ name?: string;
46
+ description?: Nullable<string>;
47
+ memberUserIds?: Nullable<UUID[]>;
48
+ channelIds?: Nullable<UUID[]>;
49
+ }
50
+ //# sourceMappingURL=team.type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.type.d.ts","sourceRoot":"","sources":["../../../../src/api/unibox/team.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,IAAI;IACjB,EAAE,EAAE,IAAI,CAAC;IAET,IAAI,EAAE,MAAM,CAAC;IAEb,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE9B,kDAAkD;IAClD,aAAa,EAAE,IAAI,EAAE,CAAC;IAEtB;;;;;;OAMG;IACH,UAAU,EAAE,IAAI,EAAE,CAAC;IAEnB,SAAS,EAAE,WAAW,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;CAC1B;AAED,iEAAiE;AACjE,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAExC,4BAA4B;AAC5B,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,aAAa,CAAC,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;CACjC;AAED,oGAAoG;AACpG,MAAM,WAAW,cAAc;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,aAAa,CAAC,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;CACjC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=team.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.type.js","sourceRoot":"","sources":["../../../../src/api/unibox/team.type.ts"],"names":[],"mappings":""}
@@ -128,7 +128,58 @@ export declare enum UserPermission {
128
128
  */
129
129
  CONDUIT_DISPATCH_SEND = "conduit:dispatch:send",
130
130
  /** Redrive a dead-lettered dispatch, or cancel one still pending. */
131
- CONDUIT_DISPATCH_OPERATE = "conduit:dispatch:operate"
131
+ CONDUIT_DISPATCH_OPERATE = "conduit:dispatch:operate",
132
+ /** Read the tenant's product catalog, including prices and availability. */
133
+ COMMERCE_CATALOG_READ = "commerce:catalog:read",
134
+ /** Create, edit, archive or restore products in the tenant's catalog. */
135
+ COMMERCE_CATALOG_MANAGE = "commerce:catalog:manage",
136
+ /** Read connected messaging accounts. Never exposes a channel's ingest secret. */
137
+ UNIBOX_CHANNEL_READ = "unibox:channel:read",
138
+ /**
139
+ * Connect, amend or disconnect a messaging account, and rotate its ingest secret.
140
+ *
141
+ * A single manage permission for the same reason as `CONDUIT_CONNECTION_MANAGE`: the
142
+ * dangerous act is holding the credential that lets anything post messages into a tenant's
143
+ * inbox, and create/update/delete carry that identically.
144
+ */
145
+ UNIBOX_CHANNEL_MANAGE = "unibox:channel:manage",
146
+ /** Read contacts. Personal data — closer to a data-export permission than a config one. */
147
+ UNIBOX_CONTACT_READ = "unibox:contact:read",
148
+ /** Create, amend or delete a contact record. */
149
+ UNIBOX_CONTACT_MANAGE = "unibox:contact:manage",
150
+ /**
151
+ * Read the inbox and every message in it.
152
+ *
153
+ * **There is deliberately no separate `unibox:message:read`.** A conversation with its
154
+ * messages hidden is an empty row, so a permission that granted one without the other would
155
+ * describe a screen nobody can use — and the reverse would be a way to read a customer's
156
+ * messages while appearing to have no access to the inbox.
157
+ */
158
+ UNIBOX_CONVERSATION_READ = "unibox:conversation:read",
159
+ /** Change a conversation's status — close, snooze, reopen — and write internal notes. */
160
+ UNIBOX_CONVERSATION_MANAGE = "unibox:conversation:manage",
161
+ /**
162
+ * Assign a conversation to an agent or a team, and take over from the AI.
163
+ *
164
+ * Separate from `UNIBOX_CONVERSATION_MANAGE` because assignment decides whose work this is.
165
+ * A supervisor routing a queue and an agent closing their own conversations are different
166
+ * jobs, and a tenant that wants only the first to reassign should be able to say so.
167
+ */
168
+ UNIBOX_CONVERSATION_ASSIGN = "unibox:conversation:assign",
169
+ /**
170
+ * Send a message to a contact.
171
+ *
172
+ * The sharpest permission in this service, and the reason there is no `unibox:message:*`
173
+ * read counterpart. Everything else here moves rows around inside our own database; this one
174
+ * reaches a real person on their phone, through a paid channel, and cannot be taken back.
175
+ */
176
+ UNIBOX_MESSAGE_SEND = "unibox:message:send",
177
+ UNIBOX_TEAM_READ = "unibox:team:read",
178
+ /** Create teams and change who is in them. Routing, not permissions — identity owns those. */
179
+ UNIBOX_TEAM_MANAGE = "unibox:team:manage",
180
+ UNIBOX_CANNED_REPLY_READ = "unibox:canned-reply:read",
181
+ /** Author the saved replies every agent in the tenant will send. */
182
+ UNIBOX_CANNED_REPLY_MANAGE = "unibox:canned-reply:manage"
132
183
  }
133
184
  /**
134
185
  * Every member, for seeding the owner role and validating custom-role input.
@@ -1 +1 @@
1
- {"version":3,"file":"user-permission.enum.d.ts","sourceRoot":"","sources":["../../../src/enum/user-permission.enum.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,oBAAY,cAAc;IAItB,WAAW,gBAAgB;IAC3B,aAAa,kBAAkB;IAC/B,sFAAsF;IACtF,aAAa,kBAAkB;IAG/B,SAAS,cAAc;IACvB,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAG3B,eAAe,oBAAoB;IACnC,6EAA6E;IAC7E,iBAAiB,sBAAsB;IACvC;;;OAGG;IACH,sBAAsB,2BAA2B;IAGjD,SAAS,cAAc;IACvB,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAG3B,YAAY,iBAAiB;IAC7B,aAAa,kBAAkB;IAC/B,cAAc,mBAAmB;IAKjC,qEAAqE;IACrE,qBAAqB,0BAA0B;IAC/C,uBAAuB,4BAA4B;IACnD,uBAAuB,4BAA4B;IACnD,uBAAuB,4BAA4B;IAGnD;;;;OAIG;IACH,oBAAoB,yBAAyB;IAC7C,sBAAsB,2BAA2B;IAGjD;;;;OAIG;IACH,sBAAsB,2BAA2B;IAGjD,qBAAqB,0BAA0B;IAC/C,yFAAyF;IACzF,uBAAuB,4BAA4B;IAGnD,mEAAmE;IACnE,wBAAwB,6BAA6B;IACrD;;;;;;;OAOG;IACH,0BAA0B,+BAA+B;IAGzD,kBAAkB,uBAAuB;IACzC,2DAA2D;IAC3D,oBAAoB,yBAAyB;IAG7C;;;;;OAKG;IACH,qBAAqB,0BAA0B;IAC/C;;;;;;OAMG;IACH,wBAAwB,6BAA6B;IAGrD,wFAAwF;IACxF,sBAAsB,2BAA2B;IACjD;;;;;;;;OAQG;IACH,wBAAwB,6BAA6B;IAGrD,sEAAsE;IACtE,uBAAuB,4BAA4B;IACnD;;;;;OAKG;IACH,yBAAyB,8BAA8B;IAGvD;;;;;OAKG;IACH,qBAAqB,0BAA0B;IAC/C;;;;;;;OAOG;IACH,qBAAqB,0BAA0B;IAC/C,qEAAqE;IACrE,wBAAwB,6BAA6B;CACxD;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,cAAc,EAAiD,CAAC"}
1
+ {"version":3,"file":"user-permission.enum.d.ts","sourceRoot":"","sources":["../../../src/enum/user-permission.enum.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,oBAAY,cAAc;IAItB,WAAW,gBAAgB;IAC3B,aAAa,kBAAkB;IAC/B,sFAAsF;IACtF,aAAa,kBAAkB;IAG/B,SAAS,cAAc;IACvB,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAG3B,eAAe,oBAAoB;IACnC,6EAA6E;IAC7E,iBAAiB,sBAAsB;IACvC;;;OAGG;IACH,sBAAsB,2BAA2B;IAGjD,SAAS,cAAc;IACvB,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAG3B,YAAY,iBAAiB;IAC7B,aAAa,kBAAkB;IAC/B,cAAc,mBAAmB;IAKjC,qEAAqE;IACrE,qBAAqB,0BAA0B;IAC/C,uBAAuB,4BAA4B;IACnD,uBAAuB,4BAA4B;IACnD,uBAAuB,4BAA4B;IAGnD;;;;OAIG;IACH,oBAAoB,yBAAyB;IAC7C,sBAAsB,2BAA2B;IAGjD;;;;OAIG;IACH,sBAAsB,2BAA2B;IAGjD,qBAAqB,0BAA0B;IAC/C,yFAAyF;IACzF,uBAAuB,4BAA4B;IAGnD,mEAAmE;IACnE,wBAAwB,6BAA6B;IACrD;;;;;;;OAOG;IACH,0BAA0B,+BAA+B;IAGzD,kBAAkB,uBAAuB;IACzC,2DAA2D;IAC3D,oBAAoB,yBAAyB;IAG7C;;;;;OAKG;IACH,qBAAqB,0BAA0B;IAC/C;;;;;;OAMG;IACH,wBAAwB,6BAA6B;IAGrD,wFAAwF;IACxF,sBAAsB,2BAA2B;IACjD;;;;;;;;OAQG;IACH,wBAAwB,6BAA6B;IAGrD,sEAAsE;IACtE,uBAAuB,4BAA4B;IACnD;;;;;OAKG;IACH,yBAAyB,8BAA8B;IAGvD;;;;;OAKG;IACH,qBAAqB,0BAA0B;IAC/C;;;;;;;OAOG;IACH,qBAAqB,0BAA0B;IAC/C,qEAAqE;IACrE,wBAAwB,6BAA6B;IAKrD,4EAA4E;IAC5E,qBAAqB,0BAA0B;IAC/C,yEAAyE;IACzE,uBAAuB,4BAA4B;IAKnD,kFAAkF;IAClF,mBAAmB,wBAAwB;IAC3C;;;;;;OAMG;IACH,qBAAqB,0BAA0B;IAG/C,2FAA2F;IAC3F,mBAAmB,wBAAwB;IAC3C,gDAAgD;IAChD,qBAAqB,0BAA0B;IAG/C;;;;;;;OAOG;IACH,wBAAwB,6BAA6B;IACrD,yFAAyF;IACzF,0BAA0B,+BAA+B;IACzD;;;;;;OAMG;IACH,0BAA0B,+BAA+B;IAGzD;;;;;;OAMG;IACH,mBAAmB,wBAAwB;IAG3C,gBAAgB,qBAAqB;IACrC,8FAA8F;IAC9F,kBAAkB,uBAAuB;IAGzC,wBAAwB,6BAA6B;IACrD,oEAAoE;IACpE,0BAA0B,+BAA+B;CAC5D;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,cAAc,EAAiD,CAAC"}
@@ -150,6 +150,66 @@ var UserPermission;
150
150
  UserPermission["CONDUIT_DISPATCH_SEND"] = "conduit:dispatch:send";
151
151
  /** Redrive a dead-lettered dispatch, or cancel one still pending. */
152
152
  UserPermission["CONDUIT_DISPATCH_OPERATE"] = "conduit:dispatch:operate";
153
+ // ══ commerce-api ═════════════════════════════════════════════════════════
154
+ // ── Catalog ─────────────────────────────────────────────────────────────
155
+ /** Read the tenant's product catalog, including prices and availability. */
156
+ UserPermission["COMMERCE_CATALOG_READ"] = "commerce:catalog:read";
157
+ /** Create, edit, archive or restore products in the tenant's catalog. */
158
+ UserPermission["COMMERCE_CATALOG_MANAGE"] = "commerce:catalog:manage";
159
+ // ══ unibox-api ═══════════════════════════════════════════════════════════
160
+ // ── Channel ─────────────────────────────────────────────────────────────
161
+ /** Read connected messaging accounts. Never exposes a channel's ingest secret. */
162
+ UserPermission["UNIBOX_CHANNEL_READ"] = "unibox:channel:read";
163
+ /**
164
+ * Connect, amend or disconnect a messaging account, and rotate its ingest secret.
165
+ *
166
+ * A single manage permission for the same reason as `CONDUIT_CONNECTION_MANAGE`: the
167
+ * dangerous act is holding the credential that lets anything post messages into a tenant's
168
+ * inbox, and create/update/delete carry that identically.
169
+ */
170
+ UserPermission["UNIBOX_CHANNEL_MANAGE"] = "unibox:channel:manage";
171
+ // ── Contact ─────────────────────────────────────────────────────────────
172
+ /** Read contacts. Personal data — closer to a data-export permission than a config one. */
173
+ UserPermission["UNIBOX_CONTACT_READ"] = "unibox:contact:read";
174
+ /** Create, amend or delete a contact record. */
175
+ UserPermission["UNIBOX_CONTACT_MANAGE"] = "unibox:contact:manage";
176
+ // ── Conversation ────────────────────────────────────────────────────────
177
+ /**
178
+ * Read the inbox and every message in it.
179
+ *
180
+ * **There is deliberately no separate `unibox:message:read`.** A conversation with its
181
+ * messages hidden is an empty row, so a permission that granted one without the other would
182
+ * describe a screen nobody can use — and the reverse would be a way to read a customer's
183
+ * messages while appearing to have no access to the inbox.
184
+ */
185
+ UserPermission["UNIBOX_CONVERSATION_READ"] = "unibox:conversation:read";
186
+ /** Change a conversation's status — close, snooze, reopen — and write internal notes. */
187
+ UserPermission["UNIBOX_CONVERSATION_MANAGE"] = "unibox:conversation:manage";
188
+ /**
189
+ * Assign a conversation to an agent or a team, and take over from the AI.
190
+ *
191
+ * Separate from `UNIBOX_CONVERSATION_MANAGE` because assignment decides whose work this is.
192
+ * A supervisor routing a queue and an agent closing their own conversations are different
193
+ * jobs, and a tenant that wants only the first to reassign should be able to say so.
194
+ */
195
+ UserPermission["UNIBOX_CONVERSATION_ASSIGN"] = "unibox:conversation:assign";
196
+ // ── Message ─────────────────────────────────────────────────────────────
197
+ /**
198
+ * Send a message to a contact.
199
+ *
200
+ * The sharpest permission in this service, and the reason there is no `unibox:message:*`
201
+ * read counterpart. Everything else here moves rows around inside our own database; this one
202
+ * reaches a real person on their phone, through a paid channel, and cannot be taken back.
203
+ */
204
+ UserPermission["UNIBOX_MESSAGE_SEND"] = "unibox:message:send";
205
+ // ── Team ────────────────────────────────────────────────────────────────
206
+ UserPermission["UNIBOX_TEAM_READ"] = "unibox:team:read";
207
+ /** Create teams and change who is in them. Routing, not permissions — identity owns those. */
208
+ UserPermission["UNIBOX_TEAM_MANAGE"] = "unibox:team:manage";
209
+ // ── Canned reply ────────────────────────────────────────────────────────
210
+ UserPermission["UNIBOX_CANNED_REPLY_READ"] = "unibox:canned-reply:read";
211
+ /** Author the saved replies every agent in the tenant will send. */
212
+ UserPermission["UNIBOX_CANNED_REPLY_MANAGE"] = "unibox:canned-reply:manage";
153
213
  })(UserPermission || (exports.UserPermission = UserPermission = {}));
154
214
  /**
155
215
  * Every member, for seeding the owner role and validating custom-role input.
@@ -1 +1 @@
1
- {"version":3,"file":"user-permission.enum.js","sourceRoot":"","sources":["../../../src/enum/user-permission.enum.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,IAAY,cAkJX;AAlJD,WAAY,cAAc;IACtB,4EAA4E;IAE5E,2EAA2E;IAC3E,6CAA2B,CAAA;IAC3B,iDAA+B,CAAA;IAC/B,sFAAsF;IACtF,iDAA+B,CAAA;IAE/B,2EAA2E;IAC3E,yCAAuB,CAAA;IACvB,6CAA2B,CAAA;IAC3B,6CAA2B,CAAA;IAC3B,6CAA2B,CAAA;IAE3B,2EAA2E;IAC3E,qDAAmC,CAAA;IACnC,6EAA6E;IAC7E,yDAAuC,CAAA;IACvC;;;OAGG;IACH,mEAAiD,CAAA;IAEjD,2EAA2E;IAC3E,yCAAuB,CAAA;IACvB,6CAA2B,CAAA;IAC3B,6CAA2B,CAAA;IAC3B,6CAA2B,CAAA;IAE3B,2EAA2E;IAC3E,+CAA6B,CAAA;IAC7B,iDAA+B,CAAA;IAC/B,mDAAiC,CAAA;IAEjC,4EAA4E;IAE5E,2EAA2E;IAC3E,qEAAqE;IACrE,iEAA+C,CAAA;IAC/C,qEAAmD,CAAA;IACnD,qEAAmD,CAAA;IACnD,qEAAmD,CAAA;IAEnD,2EAA2E;IAC3E;;;;OAIG;IACH,+DAA6C,CAAA;IAC7C,mEAAiD,CAAA;IAEjD,2EAA2E;IAC3E;;;;OAIG;IACH,mEAAiD,CAAA;IAEjD,2EAA2E;IAC3E,iEAA+C,CAAA;IAC/C,yFAAyF;IACzF,qEAAmD,CAAA;IAEnD,2EAA2E;IAC3E,mEAAmE;IACnE,uEAAqD,CAAA;IACrD;;;;;;;OAOG;IACH,2EAAyD,CAAA;IAEzD,2EAA2E;IAC3E,2DAAyC,CAAA;IACzC,2DAA2D;IAC3D,+DAA6C,CAAA;IAE7C,2EAA2E;IAC3E;;;;;OAKG;IACH,iEAA+C,CAAA;IAC/C;;;;;;OAMG;IACH,uEAAqD,CAAA;IAErD,2EAA2E;IAC3E,wFAAwF;IACxF,mEAAiD,CAAA;IACjD;;;;;;;;OAQG;IACH,uEAAqD,CAAA;IAErD,2EAA2E;IAC3E,sEAAsE;IACtE,qEAAmD,CAAA;IACnD;;;;;OAKG;IACH,yEAAuD,CAAA;IAEvD,2EAA2E;IAC3E;;;;;OAKG;IACH,iEAA+C,CAAA;IAC/C;;;;;;;OAOG;IACH,iEAA+C,CAAA;IAC/C,qEAAqE;IACrE,uEAAqD,CAAA;AACzD,CAAC,EAlJW,cAAc,8BAAd,cAAc,QAkJzB;AAED;;;;;GAKG;AACU,QAAA,oBAAoB,GAA8B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"user-permission.enum.js","sourceRoot":"","sources":["../../../src/enum/user-permission.enum.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,IAAY,cAuNX;AAvND,WAAY,cAAc;IACtB,4EAA4E;IAE5E,2EAA2E;IAC3E,6CAA2B,CAAA;IAC3B,iDAA+B,CAAA;IAC/B,sFAAsF;IACtF,iDAA+B,CAAA;IAE/B,2EAA2E;IAC3E,yCAAuB,CAAA;IACvB,6CAA2B,CAAA;IAC3B,6CAA2B,CAAA;IAC3B,6CAA2B,CAAA;IAE3B,2EAA2E;IAC3E,qDAAmC,CAAA;IACnC,6EAA6E;IAC7E,yDAAuC,CAAA;IACvC;;;OAGG;IACH,mEAAiD,CAAA;IAEjD,2EAA2E;IAC3E,yCAAuB,CAAA;IACvB,6CAA2B,CAAA;IAC3B,6CAA2B,CAAA;IAC3B,6CAA2B,CAAA;IAE3B,2EAA2E;IAC3E,+CAA6B,CAAA;IAC7B,iDAA+B,CAAA;IAC/B,mDAAiC,CAAA;IAEjC,4EAA4E;IAE5E,2EAA2E;IAC3E,qEAAqE;IACrE,iEAA+C,CAAA;IAC/C,qEAAmD,CAAA;IACnD,qEAAmD,CAAA;IACnD,qEAAmD,CAAA;IAEnD,2EAA2E;IAC3E;;;;OAIG;IACH,+DAA6C,CAAA;IAC7C,mEAAiD,CAAA;IAEjD,2EAA2E;IAC3E;;;;OAIG;IACH,mEAAiD,CAAA;IAEjD,2EAA2E;IAC3E,iEAA+C,CAAA;IAC/C,yFAAyF;IACzF,qEAAmD,CAAA;IAEnD,2EAA2E;IAC3E,mEAAmE;IACnE,uEAAqD,CAAA;IACrD;;;;;;;OAOG;IACH,2EAAyD,CAAA;IAEzD,2EAA2E;IAC3E,2DAAyC,CAAA;IACzC,2DAA2D;IAC3D,+DAA6C,CAAA;IAE7C,2EAA2E;IAC3E;;;;;OAKG;IACH,iEAA+C,CAAA;IAC/C;;;;;;OAMG;IACH,uEAAqD,CAAA;IAErD,2EAA2E;IAC3E,wFAAwF;IACxF,mEAAiD,CAAA;IACjD;;;;;;;;OAQG;IACH,uEAAqD,CAAA;IAErD,2EAA2E;IAC3E,sEAAsE;IACtE,qEAAmD,CAAA;IACnD;;;;;OAKG;IACH,yEAAuD,CAAA;IAEvD,2EAA2E;IAC3E;;;;;OAKG;IACH,iEAA+C,CAAA;IAC/C;;;;;;;OAOG;IACH,iEAA+C,CAAA;IAC/C,qEAAqE;IACrE,uEAAqD,CAAA;IAErD,4EAA4E;IAE5E,2EAA2E;IAC3E,4EAA4E;IAC5E,iEAA+C,CAAA;IAC/C,yEAAyE;IACzE,qEAAmD,CAAA;IAEnD,4EAA4E;IAE5E,2EAA2E;IAC3E,kFAAkF;IAClF,6DAA2C,CAAA;IAC3C;;;;;;OAMG;IACH,iEAA+C,CAAA;IAE/C,2EAA2E;IAC3E,2FAA2F;IAC3F,6DAA2C,CAAA;IAC3C,gDAAgD;IAChD,iEAA+C,CAAA;IAE/C,2EAA2E;IAC3E;;;;;;;OAOG;IACH,uEAAqD,CAAA;IACrD,yFAAyF;IACzF,2EAAyD,CAAA;IACzD;;;;;;OAMG;IACH,2EAAyD,CAAA;IAEzD,2EAA2E;IAC3E;;;;;;OAMG;IACH,6DAA2C,CAAA;IAE3C,2EAA2E;IAC3E,uDAAqC,CAAA;IACrC,8FAA8F;IAC9F,2DAAyC,CAAA;IAEzC,2EAA2E;IAC3E,uEAAqD,CAAA;IACrD,oEAAoE;IACpE,2EAAyD,CAAA;AAC7D,CAAC,EAvNW,cAAc,8BAAd,cAAc,QAuNzB;AAED;;;;;GAKG;AACU,QAAA,oBAAoB,GAA8B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC"}
@@ -0,0 +1,49 @@
1
+ import type { IsoDateTime } from '../../type/iso-date-time.type.js';
2
+ import type { Nullable } from '../../type/nil.type.js';
3
+ import type { Paginated } from '../../type/paginated.type.js';
4
+ import type { UUID } from '../../type/uuid.type.js';
5
+ /**
6
+ * A saved reply an agent can insert into a message.
7
+ *
8
+ * **Inserted into the composer, never sent by itself.** A canned reply is text an agent chooses
9
+ * and can edit before sending — it is not an automation, and there is no endpoint that sends one
10
+ * directly. That line is what keeps this out of §14's no-scripting territory: the moment a saved
11
+ * reply can fire on a condition, we have built a rules engine in a chat product.
12
+ */
13
+ export interface CannedReply {
14
+ id: UUID;
15
+ /** What an agent types to find it, e.g. `/hours`. Unique within the tenant. */
16
+ shortcut: string;
17
+ title: string;
18
+ /**
19
+ * The text, with `{{placeholders}}` substituted client-side at insert time.
20
+ *
21
+ * Substitution is the client's job on purpose. The server would have to resolve them at send
22
+ * time, which means an agent could send a message whose final text they never saw — and the
23
+ * one thing an agent must always be able to do is read what they are about to send.
24
+ */
25
+ body: string;
26
+ /** For grouping in the picker. Null is the ungrouped bucket. */
27
+ category: Nullable<string>;
28
+ createdByUserId: Nullable<UUID>;
29
+ createdAt: IsoDateTime;
30
+ updatedAt: IsoDateTime;
31
+ }
32
+ /** `GET /api/v1/canned-replies`. Offset-paged. */
33
+ export type CannedRepliesPage = Paginated<CannedReply>;
34
+ /** `POST /api/v1/canned-replies`. */
35
+ export interface CreateCannedReplyBody {
36
+ /** Lowercase, `[a-z0-9-]`, no leading slash — the UI supplies that. */
37
+ shortcut: string;
38
+ title: string;
39
+ body: string;
40
+ category?: Nullable<string>;
41
+ }
42
+ /** `PATCH /api/v1/canned-replies/:id`. */
43
+ export interface UpdateCannedReplyBody {
44
+ shortcut?: string;
45
+ title?: string;
46
+ body?: string;
47
+ category?: Nullable<string>;
48
+ }
49
+ //# sourceMappingURL=canned-reply.type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canned-reply.type.d.ts","sourceRoot":"","sources":["../../../../src/api/unibox/canned-reply.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,IAAI,CAAC;IAET,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;IAEjB,KAAK,EAAE,MAAM,CAAC;IAEd;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb,gEAAgE;IAChE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE3B,eAAe,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEhC,SAAS,EAAE,WAAW,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;CAC1B;AAED,kDAAkD;AAClD,MAAM,MAAM,iBAAiB,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;AAEvD,qCAAqC;AACrC,MAAM,WAAW,qBAAqB;IAClC,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED,0CAA0C;AAC1C,MAAM,WAAW,qBAAqB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC/B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=canned-reply.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canned-reply.type.js","sourceRoot":"","sources":["../../../../src/api/unibox/canned-reply.type.ts"],"names":[],"mappings":""}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The messaging network a channel is connected to.
3
+ *
4
+ * This is Unibox's vocabulary, not Conduit's. Conduit knows about *connectors* — a set of hosts
5
+ * and operations someone wrote down — and has no idea that any of them carry conversations.
6
+ * Unibox knows that a WhatsApp message and an Instagram message are the same kind of thing and
7
+ * belong in one inbox, which is the whole product.
8
+ *
9
+ * The members are the platforms Unibox can **normalize**, which is a stricter bar than the ones
10
+ * Conduit can talk to: normalizing means we can read a provider's webhook into a contact, a
11
+ * conversation and a message, and write a reply back. Adding one is a normalizer plus a
12
+ * connector manifest, and is a minor version here.
13
+ */
14
+ export declare enum ChannelPlatform {
15
+ /** WhatsApp Cloud API. The first real platform, and the one `conduit-api` ships a manifest for. */
16
+ WHATSAPP = "whatsapp",
17
+ /** Instagram Direct, via the Messenger Platform. */
18
+ INSTAGRAM = "instagram",
19
+ /** Facebook Messenger. */
20
+ MESSENGER = "messenger",
21
+ /**
22
+ * A loopback platform for local development and tests, matching Conduit's `local-echo`
23
+ * connector.
24
+ *
25
+ * It exists for the same reason that connector does: the entire pipeline — receive,
26
+ * normalize, thread, reply, dispatch — is provable without a Meta app, and a real Meta app
27
+ * would only prove we can talk to Meta. It is a first-class member rather than a test double
28
+ * so the normalizer registry has no branch that only exists under Jest.
29
+ */
30
+ ECHO = "echo"
31
+ }
32
+ //# sourceMappingURL=channel-platform.enum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-platform.enum.d.ts","sourceRoot":"","sources":["../../../../src/api/unibox/channel-platform.enum.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,oBAAY,eAAe;IACvB,mGAAmG;IACnG,QAAQ,aAAa;IAErB,oDAAoD;IACpD,SAAS,cAAc;IAEvB,0BAA0B;IAC1B,SAAS,cAAc;IAEvB;;;;;;;;OAQG;IACH,IAAI,SAAS;CAChB"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The messaging network a channel is connected to.
3
+ *
4
+ * This is Unibox's vocabulary, not Conduit's. Conduit knows about *connectors* — a set of hosts
5
+ * and operations someone wrote down — and has no idea that any of them carry conversations.
6
+ * Unibox knows that a WhatsApp message and an Instagram message are the same kind of thing and
7
+ * belong in one inbox, which is the whole product.
8
+ *
9
+ * The members are the platforms Unibox can **normalize**, which is a stricter bar than the ones
10
+ * Conduit can talk to: normalizing means we can read a provider's webhook into a contact, a
11
+ * conversation and a message, and write a reply back. Adding one is a normalizer plus a
12
+ * connector manifest, and is a minor version here.
13
+ */
14
+ export var ChannelPlatform;
15
+ (function (ChannelPlatform) {
16
+ /** WhatsApp Cloud API. The first real platform, and the one `conduit-api` ships a manifest for. */
17
+ ChannelPlatform["WHATSAPP"] = "whatsapp";
18
+ /** Instagram Direct, via the Messenger Platform. */
19
+ ChannelPlatform["INSTAGRAM"] = "instagram";
20
+ /** Facebook Messenger. */
21
+ ChannelPlatform["MESSENGER"] = "messenger";
22
+ /**
23
+ * A loopback platform for local development and tests, matching Conduit's `local-echo`
24
+ * connector.
25
+ *
26
+ * It exists for the same reason that connector does: the entire pipeline — receive,
27
+ * normalize, thread, reply, dispatch — is provable without a Meta app, and a real Meta app
28
+ * would only prove we can talk to Meta. It is a first-class member rather than a test double
29
+ * so the normalizer registry has no branch that only exists under Jest.
30
+ */
31
+ ChannelPlatform["ECHO"] = "echo";
32
+ })(ChannelPlatform || (ChannelPlatform = {}));
33
+ //# sourceMappingURL=channel-platform.enum.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-platform.enum.js","sourceRoot":"","sources":["../../../../src/api/unibox/channel-platform.enum.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAN,IAAY,eAoBX;AApBD,WAAY,eAAe;IACvB,mGAAmG;IACnG,wCAAqB,CAAA;IAErB,oDAAoD;IACpD,0CAAuB,CAAA;IAEvB,0BAA0B;IAC1B,0CAAuB,CAAA;IAEvB;;;;;;;;OAQG;IACH,gCAAa,CAAA;AACjB,CAAC,EApBW,eAAe,KAAf,eAAe,QAoB1B"}
@@ -0,0 +1,110 @@
1
+ import type { IsoDateTime } from '../../type/iso-date-time.type.js';
2
+ import type { Nullable } from '../../type/nil.type.js';
3
+ import type { Paginated } from '../../type/paginated.type.js';
4
+ import type { UUID } from '../../type/uuid.type.js';
5
+ import type { ChannelPlatform } from './channel-platform.enum.js';
6
+ /**
7
+ * One messaging account a tenant has connected — a WhatsApp number, an Instagram business
8
+ * account, a Facebook page.
9
+ *
10
+ * A channel is the seam between Unibox and Conduit, and it points at Conduit twice, in opposite
11
+ * directions:
12
+ *
13
+ * - **Inbound**, Conduit forwards a provider's raw webhook to Unibox and presents this channel's
14
+ * ingest secret. Conduit does not parse it — it cannot, because §11 forbids it knowing what a
15
+ * chat is — so normalizing the bytes into a message is Unibox's job.
16
+ * - **Outbound**, a reply is submitted to Conduit naming `connectionKey` and `sendOperation`.
17
+ * Unibox never calls the Graph API itself (§12).
18
+ *
19
+ * Neither reference is a foreign key, because they name rows in another service's database. A
20
+ * `connectionKey` that no longer resolves is a misconfiguration Unibox reports; it is not
21
+ * something Unibox can prevent, and pretending otherwise would mean Unibox reading Conduit's
22
+ * tables, which is exactly what §2 forbids.
23
+ */
24
+ export interface Channel {
25
+ id: UUID;
26
+ /** Tenant-scoped, stable, and how a normalizer is chosen for inbound traffic. */
27
+ key: string;
28
+ name: string;
29
+ platform: ChannelPlatform;
30
+ /**
31
+ * The account's own identifier at the provider — a WhatsApp phone-number id, an Instagram
32
+ * account id.
33
+ *
34
+ * Stored because a provider's webhook names the *recipient* account, and a tenant may have
35
+ * several channels on one platform. Without it there is no way to tell which of two WhatsApp
36
+ * numbers a message arrived at, and both would look equally plausible.
37
+ */
38
+ externalAccountId: string;
39
+ /** Conduit connection a reply is dispatched through. Loose reference into another service. */
40
+ connectionKey: string;
41
+ /** Which of that connector's operations sends a message. */
42
+ sendOperation: string;
43
+ /**
44
+ * Whether this channel accepts inbound traffic and sends replies.
45
+ *
46
+ * Turning it off stops new conversations and refuses sends. It does **not** delete anything
47
+ * already received: a channel a customer disconnected still has a history someone needs to
48
+ * read.
49
+ */
50
+ isActive: boolean;
51
+ /**
52
+ * Whether an ingest secret is currently set.
53
+ *
54
+ * A boolean, never the value. The secret is what authenticates Conduit to Unibox, so it is
55
+ * envelope-encrypted, returned by no endpoint, and shown to the operator exactly once — at
56
+ * the moment it is generated, when it also has to be pasted into Conduit's destination
57
+ * headers. Same control as an endpoint's signing secret in Conduit.
58
+ */
59
+ hasIngestSecret: boolean;
60
+ /** When a message was last received or sent here. Null until the first one. */
61
+ lastActivityAt: Nullable<IsoDateTime>;
62
+ createdAt: IsoDateTime;
63
+ updatedAt: IsoDateTime;
64
+ }
65
+ /** `GET /api/v1/channels`. Offset-paged: a tenant has a handful of channels, not a stream of them. */
66
+ export type ChannelsPage = Paginated<Channel>;
67
+ /** `POST /api/v1/channels`. */
68
+ export interface CreateChannelBody {
69
+ /** Lowercase, `[a-z0-9-]`. Unique within the tenant and immutable once created. */
70
+ key: string;
71
+ name: string;
72
+ platform: ChannelPlatform;
73
+ externalAccountId: string;
74
+ connectionKey: string;
75
+ /** Defaults to the platform's conventional send operation when omitted. */
76
+ sendOperation?: Nullable<string>;
77
+ }
78
+ /**
79
+ * `PATCH /api/v1/channels/:id`.
80
+ *
81
+ * `key` and `platform` are absent on purpose. The key is what an ingest request resolves and what
82
+ * an operator wrote into Conduit's configuration; the platform decides which normalizer reads the
83
+ * history already stored against this channel. Changing either would silently reinterpret rows
84
+ * that are already there, so both are create-only — delete and recreate is the honest path.
85
+ */
86
+ export interface UpdateChannelBody {
87
+ name?: string;
88
+ externalAccountId?: string;
89
+ connectionKey?: string;
90
+ sendOperation?: string;
91
+ isActive?: boolean;
92
+ }
93
+ /**
94
+ * `POST /api/v1/channels/:id/ingest-secret` — the **only** response that ever carries the secret.
95
+ *
96
+ * Rotating replaces the stored value immediately, so the previous secret stops working the moment
97
+ * this returns. That is deliberate and it is a brief outage by design: an ingest secret that
98
+ * overlapped with its replacement would mean a leaked one keeps working for as long as the
99
+ * overlap, which is the thing rotation exists to end.
100
+ */
101
+ export interface ChannelIngestSecretResponse {
102
+ channelId: UUID;
103
+ /** Shown once. Not stored in retrievable form, and no endpoint returns it again. */
104
+ ingestSecret: string;
105
+ /** The URL to configure as the destination in Conduit, for convenience. */
106
+ ingestUrl: string;
107
+ /** The header Conduit must carry the secret in. */
108
+ ingestHeaderName: string;
109
+ }
110
+ //# sourceMappingURL=channel.type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.type.d.ts","sourceRoot":"","sources":["../../../../src/api/unibox/channel.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAElE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,OAAO;IACpB,EAAE,EAAE,IAAI,CAAC;IAET,iFAAiF;IACjF,GAAG,EAAE,MAAM,CAAC;IAEZ,IAAI,EAAE,MAAM,CAAC;IAEb,QAAQ,EAAE,eAAe,CAAC;IAE1B;;;;;;;OAOG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAE1B,8FAA8F;IAC9F,aAAa,EAAE,MAAM,CAAC;IAEtB,4DAA4D;IAC5D,aAAa,EAAE,MAAM,CAAC;IAEtB;;;;;;OAMG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;;;;;;OAOG;IACH,eAAe,EAAE,OAAO,CAAC;IAEzB,+EAA+E;IAC/E,cAAc,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IAEtC,SAAS,EAAE,WAAW,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;CAC1B;AAED,sGAAsG;AACtG,MAAM,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;AAE9C,+BAA+B;AAC/B,MAAM,WAAW,iBAAiB;IAC9B,mFAAmF;IACnF,GAAG,EAAE,MAAM,CAAC;IAEZ,IAAI,EAAE,MAAM,CAAC;IAEb,QAAQ,EAAE,eAAe,CAAC;IAE1B,iBAAiB,EAAE,MAAM,CAAC;IAE1B,aAAa,EAAE,MAAM,CAAC;IAEtB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,2BAA2B;IACxC,SAAS,EAAE,IAAI,CAAC;IAEhB,oFAAoF;IACpF,YAAY,EAAE,MAAM,CAAC;IAErB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC;IAElB,mDAAmD;IACnD,gBAAgB,EAAE,MAAM,CAAC;CAC5B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=channel.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.type.js","sourceRoot":"","sources":["../../../../src/api/unibox/channel.type.ts"],"names":[],"mappings":""}
@@ -0,0 +1,102 @@
1
+ import type { CursorPage } from '../../type/cursor-page.type.js';
2
+ import type { IsoDateTime } from '../../type/iso-date-time.type.js';
3
+ import type { Nullable } from '../../type/nil.type.js';
4
+ import type { UUID } from '../../type/uuid.type.js';
5
+ import type { ChannelPlatform } from './channel-platform.enum.js';
6
+ /**
7
+ * One way of reaching a contact on one platform.
8
+ *
9
+ * A person is not a phone number. The same human messages a business from WhatsApp on Monday and
10
+ * from Instagram on Thursday, and an inbox that treats those as two strangers is an inbox that
11
+ * loses the thread — so identities are a child collection rather than columns on the contact.
12
+ *
13
+ * That shape is what makes merging possible later without a migration. Merging is **not built**;
14
+ * the modelling for it is, which is the part that is expensive to retrofit.
15
+ */
16
+ export interface ContactIdentity {
17
+ id: UUID;
18
+ platform: ChannelPlatform;
19
+ /**
20
+ * The provider's own identifier for this person — a WhatsApp `wa_id`, an Instagram-scoped
21
+ * user id.
22
+ *
23
+ * Unique per `(tenant, platform)`. **Scoped ids are not portable across platforms**: the same
24
+ * person has an entirely different id on Instagram and on Messenger, and treating one as the
25
+ * other merges two strangers. That is why the platform is part of the key rather than the id
26
+ * being assumed globally unique.
27
+ */
28
+ externalId: string;
29
+ /** The name the provider supplied, when it supplied one. Not authoritative and often absent. */
30
+ displayName: Nullable<string>;
31
+ createdAt: IsoDateTime;
32
+ }
33
+ /**
34
+ * A person the tenant talks to.
35
+ *
36
+ * Personal data, deliberately minimal: Unibox stores what it needs to thread a conversation and
37
+ * address someone by name. A CRM's worth of fields belongs in the vertical that needs them, and
38
+ * §17's GDPR line is materially cheaper to honour on a small table.
39
+ */
40
+ export interface Contact {
41
+ id: UUID;
42
+ /**
43
+ * The name shown in the inbox.
44
+ *
45
+ * Editable by an agent, because a provider's display name is frequently a handle or absent,
46
+ * and correcting it is the first thing anyone does. Falls back to the first identity's
47
+ * `displayName`, then to its `externalId`.
48
+ */
49
+ displayName: string;
50
+ email: Nullable<string>;
51
+ /** E.164 where known. Not the same as a WhatsApp identity's `externalId`, which is scoped. */
52
+ phone: Nullable<string>;
53
+ /** Free-form agent notes. Not shown to the contact and never sent anywhere. */
54
+ notes: Nullable<string>;
55
+ /** Lowercased, deduplicated. For filtering the inbox, not for automation. */
56
+ tags: string[];
57
+ identities: ContactIdentity[];
58
+ /** When this contact last sent or received a message. Null until the first one. */
59
+ lastActivityAt: Nullable<IsoDateTime>;
60
+ createdAt: IsoDateTime;
61
+ updatedAt: IsoDateTime;
62
+ }
63
+ /** `GET /api/v1/contacts`. Cursor-paged: inbound traffic appends to it while it is being read. */
64
+ export type ContactsPage = CursorPage<Contact>;
65
+ /** Query for `GET /api/v1/contacts`. */
66
+ export interface GetContactsQuery {
67
+ limit?: number;
68
+ /** Opaque cursor from the previous page's `nextCursor`. Never parse it. */
69
+ after?: Nullable<string>;
70
+ /** Case-insensitive substring of the display name, email or phone. */
71
+ search?: Nullable<string>;
72
+ tag?: Nullable<string>;
73
+ }
74
+ /**
75
+ * `POST /api/v1/contacts`.
76
+ *
77
+ * Creating a contact by hand is the uncommon path — almost every contact arrives because someone
78
+ * messaged in, and inbound creates them. This exists so an agent can prepare a record before a
79
+ * conversation starts, and so a vertical can seed one.
80
+ */
81
+ export interface CreateContactBody {
82
+ displayName: string;
83
+ email?: Nullable<string>;
84
+ phone?: Nullable<string>;
85
+ notes?: Nullable<string>;
86
+ tags?: Nullable<string[]>;
87
+ }
88
+ /**
89
+ * `PATCH /api/v1/contacts/:id`.
90
+ *
91
+ * `identities` is absent: an identity is asserted by a provider, not chosen by an agent. Adding
92
+ * one by hand is how two strangers get merged into one record, and there is no undo for that.
93
+ */
94
+ export interface UpdateContactBody {
95
+ displayName?: string;
96
+ email?: Nullable<string>;
97
+ phone?: Nullable<string>;
98
+ notes?: Nullable<string>;
99
+ /** Replaces the whole set. Omit to leave it alone; `[]` clears it. */
100
+ tags?: Nullable<string[]>;
101
+ }
102
+ //# sourceMappingURL=contact.type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contact.type.d.ts","sourceRoot":"","sources":["../../../../src/api/unibox/contact.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAElE;;;;;;;;;GASG;AACH,MAAM,WAAW,eAAe;IAC5B,EAAE,EAAE,IAAI,CAAC;IAET,QAAQ,EAAE,eAAe,CAAC;IAE1B;;;;;;;;OAQG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB,gGAAgG;IAChG,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE9B,SAAS,EAAE,WAAW,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,OAAO;IACpB,EAAE,EAAE,IAAI,CAAC;IAET;;;;;;OAMG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAExB,8FAA8F;IAC9F,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAExB,+EAA+E;IAC/E,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAExB,6EAA6E;IAC7E,IAAI,EAAE,MAAM,EAAE,CAAC;IAEf,UAAU,EAAE,eAAe,EAAE,CAAC;IAE9B,mFAAmF;IACnF,cAAc,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IAEtC,SAAS,EAAE,WAAW,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;CAC1B;AAED,kGAAkG;AAClG,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;AAE/C,wCAAwC;AACxC,MAAM,WAAW,gBAAgB;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,2EAA2E;IAC3E,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEzB,sEAAsE;IACtE,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE1B,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEzB,sEAAsE;IACtE,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;CAC7B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=contact.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contact.type.js","sourceRoot":"","sources":["../../../../src/api/unibox/contact.type.ts"],"names":[],"mappings":""}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Where one conversation is in an agent's working day.
3
+ *
4
+ * These are **workflow** states, not delivery states — nothing here says whether a message
5
+ * reached anyone. `MessageStatus` answers that, and conflating the two is how an inbox ends up
6
+ * showing a conversation as "failed".
7
+ *
8
+ * There is deliberately no `ARCHIVED`. Closing is already the "I am done with this" state, and a
9
+ * second one just moves the question of which list a conversation belongs in from the filter to
10
+ * the operator.
11
+ */
12
+ export declare enum ConversationStatus {
13
+ /** Needs a human. The default for anything with an unanswered inbound message. */
14
+ OPEN = "open",
15
+ /**
16
+ * Answered, waiting on the contact.
17
+ *
18
+ * Distinct from `OPEN` because an inbox sorted only by "has unread" hides the conversations
19
+ * an agent is actually running. A new inbound message moves this back to `OPEN`.
20
+ */
21
+ PENDING = "pending",
22
+ /**
23
+ * Deliberately out of sight until `snoozedUntil`.
24
+ *
25
+ * The only status carrying a time. It exists because "I will deal with this on Monday" is
26
+ * otherwise expressed by closing something that is not finished, and a closed conversation is
27
+ * one nobody looks at again.
28
+ */
29
+ SNOOZED = "snoozed",
30
+ /**
31
+ * Finished. Reopened automatically by a new inbound message.
32
+ *
33
+ * That automatic reopen is the important half: a contact replying to a closed conversation is
34
+ * continuing it, and starting a second thread would split one person's history across two
35
+ * rows for no reason a customer would recognise.
36
+ */
37
+ CLOSED = "closed"
38
+ }
39
+ //# sourceMappingURL=conversation-status.enum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-status.enum.d.ts","sourceRoot":"","sources":["../../../../src/api/unibox/conversation-status.enum.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,oBAAY,kBAAkB;IAC1B,kFAAkF;IAClF,IAAI,SAAS;IAEb;;;;;OAKG;IACH,OAAO,YAAY;IAEnB;;;;;;OAMG;IACH,OAAO,YAAY;IAEnB;;;;;;OAMG;IACH,MAAM,WAAW;CACpB"}