@aglyn/plugins-outreach 1.0.0-beta.143

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 (282) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +93 -0
  3. package/package.json +52 -0
  4. package/src/index.d.ts +22 -0
  5. package/src/index.js +29 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/compliance-section.d.ts +20 -0
  8. package/src/lib/components/compliance-section.js +291 -0
  9. package/src/lib/components/compliance-section.js.map +1 -0
  10. package/src/lib/components/enroll-dialog.d.ts +36 -0
  11. package/src/lib/components/enroll-dialog.js +656 -0
  12. package/src/lib/components/enroll-dialog.js.map +1 -0
  13. package/src/lib/components/enrollments-table.d.ts +28 -0
  14. package/src/lib/components/enrollments-table.js +375 -0
  15. package/src/lib/components/enrollments-table.js.map +1 -0
  16. package/src/lib/components/mailbox-card.d.ts +46 -0
  17. package/src/lib/components/mailbox-card.js +517 -0
  18. package/src/lib/components/mailbox-card.js.map +1 -0
  19. package/src/lib/components/mailboxes-section.d.ts +24 -0
  20. package/src/lib/components/mailboxes-section.js +258 -0
  21. package/src/lib/components/mailboxes-section.js.map +1 -0
  22. package/src/lib/components/outreach-console-page.d.ts +17 -0
  23. package/src/lib/components/outreach-console-page.js +81 -0
  24. package/src/lib/components/outreach-console-page.js.map +1 -0
  25. package/src/lib/components/outreach-console-sections.d.ts +43 -0
  26. package/src/lib/components/outreach-console-sections.js +55 -0
  27. package/src/lib/components/outreach-console-sections.js.map +1 -0
  28. package/src/lib/components/outreach-ui.d.ts +51 -0
  29. package/src/lib/components/outreach-ui.js +171 -0
  30. package/src/lib/components/outreach-ui.js.map +1 -0
  31. package/src/lib/components/send-window-fields.d.ts +25 -0
  32. package/src/lib/components/send-window-fields.js +178 -0
  33. package/src/lib/components/send-window-fields.js.map +1 -0
  34. package/src/lib/components/sequence-detail.d.ts +54 -0
  35. package/src/lib/components/sequence-detail.js +435 -0
  36. package/src/lib/components/sequence-detail.js.map +1 -0
  37. package/src/lib/components/sequence-editor.d.ts +37 -0
  38. package/src/lib/components/sequence-editor.js +485 -0
  39. package/src/lib/components/sequence-editor.js.map +1 -0
  40. package/src/lib/components/sequence-mailbox-picker.d.ts +44 -0
  41. package/src/lib/components/sequence-mailbox-picker.js +137 -0
  42. package/src/lib/components/sequence-mailbox-picker.js.map +1 -0
  43. package/src/lib/components/sequence-preview.d.ts +27 -0
  44. package/src/lib/components/sequence-preview.js +146 -0
  45. package/src/lib/components/sequence-preview.js.map +1 -0
  46. package/src/lib/components/sequence-step-card.d.ts +31 -0
  47. package/src/lib/components/sequence-step-card.js +326 -0
  48. package/src/lib/components/sequence-step-card.js.map +1 -0
  49. package/src/lib/components/sequences-section.d.ts +40 -0
  50. package/src/lib/components/sequences-section.js +310 -0
  51. package/src/lib/components/sequences-section.js.map +1 -0
  52. package/src/lib/components/use-outreach-api.d.ts +38 -0
  53. package/src/lib/components/use-outreach-api.js +139 -0
  54. package/src/lib/components/use-outreach-api.js.map +1 -0
  55. package/src/lib/components/use-outreach-crm.d.ts +50 -0
  56. package/src/lib/components/use-outreach-crm.js +200 -0
  57. package/src/lib/components/use-outreach-crm.js.map +1 -0
  58. package/src/lib/components/use-outreach-data.d.ts +55 -0
  59. package/src/lib/components/use-outreach-data.js +199 -0
  60. package/src/lib/components/use-outreach-data.js.map +1 -0
  61. package/src/lib/components/use-outreach-mailbox-api.d.ts +30 -0
  62. package/src/lib/components/use-outreach-mailbox-api.js +101 -0
  63. package/src/lib/components/use-outreach-mailbox-api.js.map +1 -0
  64. package/src/lib/components/use-outreach-mailboxes.d.ts +22 -0
  65. package/src/lib/components/use-outreach-mailboxes.js +68 -0
  66. package/src/lib/components/use-outreach-mailboxes.js.map +1 -0
  67. package/src/lib/components/use-outreach-settings.d.ts +17 -0
  68. package/src/lib/components/use-outreach-settings.js +64 -0
  69. package/src/lib/components/use-outreach-settings.js.map +1 -0
  70. package/src/lib/constants/api-routes.d.ts +68 -0
  71. package/src/lib/constants/api-routes.js +57 -0
  72. package/src/lib/constants/api-routes.js.map +1 -0
  73. package/src/lib/constants/bundle-common.d.ts +46 -0
  74. package/src/lib/constants/bundle-common.js +55 -0
  75. package/src/lib/constants/bundle-common.js.map +1 -0
  76. package/src/lib/constants/runtime-jobs.d.ts +24 -0
  77. package/src/lib/constants/runtime-jobs.js +24 -0
  78. package/src/lib/constants/runtime-jobs.js.map +1 -0
  79. package/src/lib/declarations.console-server.d.ts +38 -0
  80. package/src/lib/declarations.console-server.js +99 -0
  81. package/src/lib/declarations.console-server.js.map +1 -0
  82. package/src/lib/engine/compose.d.ts +86 -0
  83. package/src/lib/engine/compose.js +212 -0
  84. package/src/lib/engine/compose.js.map +1 -0
  85. package/src/lib/engine/delivery-status.d.ts +53 -0
  86. package/src/lib/engine/delivery-status.js +184 -0
  87. package/src/lib/engine/delivery-status.js.map +1 -0
  88. package/src/lib/engine/do-not-contact.d.ts +18 -0
  89. package/src/lib/engine/do-not-contact.js +34 -0
  90. package/src/lib/engine/do-not-contact.js.map +1 -0
  91. package/src/lib/engine/enrollment-state.d.ts +156 -0
  92. package/src/lib/engine/enrollment-state.js +303 -0
  93. package/src/lib/engine/enrollment-state.js.map +1 -0
  94. package/src/lib/engine/gates.d.ts +125 -0
  95. package/src/lib/engine/gates.js +232 -0
  96. package/src/lib/engine/gates.js.map +1 -0
  97. package/src/lib/engine/index.d.ts +28 -0
  98. package/src/lib/engine/index.js +33 -0
  99. package/src/lib/engine/index.js.map +1 -0
  100. package/src/lib/engine/mailbox-health.d.ts +49 -0
  101. package/src/lib/engine/mailbox-health.js +83 -0
  102. package/src/lib/engine/mailbox-health.js.map +1 -0
  103. package/src/lib/engine/opt-out-intent.d.ts +41 -0
  104. package/src/lib/engine/opt-out-intent.js +220 -0
  105. package/src/lib/engine/opt-out-intent.js.map +1 -0
  106. package/src/lib/engine/recipient-country.d.ts +41 -0
  107. package/src/lib/engine/recipient-country.js +171 -0
  108. package/src/lib/engine/recipient-country.js.map +1 -0
  109. package/src/lib/engine/schedule.d.ts +70 -0
  110. package/src/lib/engine/schedule.js +115 -0
  111. package/src/lib/engine/schedule.js.map +1 -0
  112. package/src/lib/engine/sending-capacity.d.ts +96 -0
  113. package/src/lib/engine/sending-capacity.js +172 -0
  114. package/src/lib/engine/sending-capacity.js.map +1 -0
  115. package/src/lib/engine/sequence-validation.d.ts +90 -0
  116. package/src/lib/engine/sequence-validation.js +291 -0
  117. package/src/lib/engine/sequence-validation.js.map +1 -0
  118. package/src/lib/engine/thread-classification.d.ts +78 -0
  119. package/src/lib/engine/thread-classification.js +224 -0
  120. package/src/lib/engine/thread-classification.js.map +1 -0
  121. package/src/lib/engine/thread-message.d.ts +80 -0
  122. package/src/lib/engine/thread-message.js +143 -0
  123. package/src/lib/engine/thread-message.js.map +1 -0
  124. package/src/lib/enrollment/enroll-people.d.ts +81 -0
  125. package/src/lib/enrollment/enroll-people.js +250 -0
  126. package/src/lib/enrollment/enroll-people.js.map +1 -0
  127. package/src/lib/enrollment/gate-lookups.d.ts +32 -0
  128. package/src/lib/enrollment/gate-lookups.js +154 -0
  129. package/src/lib/enrollment/gate-lookups.js.map +1 -0
  130. package/src/lib/mailboxes/mailbox-api.d.ts +126 -0
  131. package/src/lib/mailboxes/mailbox-api.js +66 -0
  132. package/src/lib/mailboxes/mailbox-api.js.map +1 -0
  133. package/src/lib/mailboxes/mailbox-credentials.d.ts +95 -0
  134. package/src/lib/mailboxes/mailbox-credentials.js +102 -0
  135. package/src/lib/mailboxes/mailbox-credentials.js.map +1 -0
  136. package/src/lib/mailboxes/mailbox-erasure.d.ts +69 -0
  137. package/src/lib/mailboxes/mailbox-erasure.js +148 -0
  138. package/src/lib/mailboxes/mailbox-erasure.js.map +1 -0
  139. package/src/lib/mailboxes/mailbox-gate.d.ts +75 -0
  140. package/src/lib/mailboxes/mailbox-gate.js +98 -0
  141. package/src/lib/mailboxes/mailbox-gate.js.map +1 -0
  142. package/src/lib/mailboxes/mailbox-revoke.d.ts +59 -0
  143. package/src/lib/mailboxes/mailbox-revoke.js +41 -0
  144. package/src/lib/mailboxes/mailbox-revoke.js.map +1 -0
  145. package/src/lib/mailboxes/mailbox-routes.d.ts +119 -0
  146. package/src/lib/mailboxes/mailbox-routes.js +605 -0
  147. package/src/lib/mailboxes/mailbox-routes.js.map +1 -0
  148. package/src/lib/mailboxes/mailbox-settings.d.ts +110 -0
  149. package/src/lib/mailboxes/mailbox-settings.js +212 -0
  150. package/src/lib/mailboxes/mailbox-settings.js.map +1 -0
  151. package/src/lib/mailboxes/mailbox-transport.d.ts +64 -0
  152. package/src/lib/mailboxes/mailbox-transport.js +94 -0
  153. package/src/lib/mailboxes/mailbox-transport.js.map +1 -0
  154. package/src/lib/mailboxes/oauth-redirect.d.ts +41 -0
  155. package/src/lib/mailboxes/oauth-redirect.js +63 -0
  156. package/src/lib/mailboxes/oauth-redirect.js.map +1 -0
  157. package/src/lib/mailboxes/oauth-state.d.ts +152 -0
  158. package/src/lib/mailboxes/oauth-state.js +212 -0
  159. package/src/lib/mailboxes/oauth-state.js.map +1 -0
  160. package/src/lib/mailboxes/outreach-config.d.ts +64 -0
  161. package/src/lib/mailboxes/outreach-config.js +77 -0
  162. package/src/lib/mailboxes/outreach-config.js.map +1 -0
  163. package/src/lib/mailboxes/register-mailbox-routes.d.ts +47 -0
  164. package/src/lib/mailboxes/register-mailbox-routes.js +135 -0
  165. package/src/lib/mailboxes/register-mailbox-routes.js.map +1 -0
  166. package/src/lib/model/compliance-settings.d.ts +78 -0
  167. package/src/lib/model/compliance-settings.js +155 -0
  168. package/src/lib/model/compliance-settings.js.map +1 -0
  169. package/src/lib/model/outreach-api.d.ts +210 -0
  170. package/src/lib/model/outreach-api.js +28 -0
  171. package/src/lib/model/outreach-api.js.map +1 -0
  172. package/src/lib/model/outreach.types.d.ts +563 -0
  173. package/src/lib/model/outreach.types.js +225 -0
  174. package/src/lib/model/outreach.types.js.map +1 -0
  175. package/src/lib/model/sequence-draft.d.ts +84 -0
  176. package/src/lib/model/sequence-draft.js +239 -0
  177. package/src/lib/model/sequence-draft.js.map +1 -0
  178. package/src/lib/model/step-preview.d.ts +45 -0
  179. package/src/lib/model/step-preview.js +98 -0
  180. package/src/lib/model/step-preview.js.map +1 -0
  181. package/src/lib/model/stored-records.d.ts +23 -0
  182. package/src/lib/model/stored-records.js +84 -0
  183. package/src/lib/model/stored-records.js.map +1 -0
  184. package/src/lib/plugin.d.ts +46 -0
  185. package/src/lib/plugin.js +86 -0
  186. package/src/lib/plugin.js.map +1 -0
  187. package/src/lib/routes/enroll-routes.d.ts +64 -0
  188. package/src/lib/routes/enroll-routes.js +350 -0
  189. package/src/lib/routes/enroll-routes.js.map +1 -0
  190. package/src/lib/routes/enrollment-routes.d.ts +19 -0
  191. package/src/lib/routes/enrollment-routes.js +171 -0
  192. package/src/lib/routes/enrollment-routes.js.map +1 -0
  193. package/src/lib/routes/platform-deps.d.ts +51 -0
  194. package/src/lib/routes/platform-deps.js +66 -0
  195. package/src/lib/routes/platform-deps.js.map +1 -0
  196. package/src/lib/routes/preview-routes.d.ts +33 -0
  197. package/src/lib/routes/preview-routes.js +117 -0
  198. package/src/lib/routes/preview-routes.js.map +1 -0
  199. package/src/lib/routes/register-routes.d.ts +22 -0
  200. package/src/lib/routes/register-routes.js +92 -0
  201. package/src/lib/routes/register-routes.js.map +1 -0
  202. package/src/lib/routes/route-deps.d.ts +49 -0
  203. package/src/lib/routes/route-deps.js +27 -0
  204. package/src/lib/routes/route-deps.js.map +1 -0
  205. package/src/lib/routes/route-gate.d.ts +94 -0
  206. package/src/lib/routes/route-gate.js +87 -0
  207. package/src/lib/routes/route-gate.js.map +1 -0
  208. package/src/lib/routes/route-http.d.ts +32 -0
  209. package/src/lib/routes/route-http.js +62 -0
  210. package/src/lib/routes/route-http.js.map +1 -0
  211. package/src/lib/routes/sequence-routes.d.ts +32 -0
  212. package/src/lib/routes/sequence-routes.js +359 -0
  213. package/src/lib/routes/sequence-routes.js.map +1 -0
  214. package/src/lib/routes/settings-routes.d.ts +30 -0
  215. package/src/lib/routes/settings-routes.js +73 -0
  216. package/src/lib/routes/settings-routes.js.map +1 -0
  217. package/src/lib/runtime/enrollment-events.d.ts +86 -0
  218. package/src/lib/runtime/enrollment-events.js +141 -0
  219. package/src/lib/runtime/enrollment-events.js.map +1 -0
  220. package/src/lib/runtime/fixtures/fake-gmail.d.ts +121 -0
  221. package/src/lib/runtime/fixtures/fake-gmail.js +312 -0
  222. package/src/lib/runtime/fixtures/fake-gmail.js.map +1 -0
  223. package/src/lib/runtime/mailbox-health-store.d.ts +47 -0
  224. package/src/lib/runtime/mailbox-health-store.js +168 -0
  225. package/src/lib/runtime/mailbox-health-store.js.map +1 -0
  226. package/src/lib/runtime/person-erasure.d.ts +39 -0
  227. package/src/lib/runtime/person-erasure.js +57 -0
  228. package/src/lib/runtime/person-erasure.js.map +1 -0
  229. package/src/lib/runtime/platform-runtime-deps.d.ts +29 -0
  230. package/src/lib/runtime/platform-runtime-deps.js +98 -0
  231. package/src/lib/runtime/platform-runtime-deps.js.map +1 -0
  232. package/src/lib/runtime/runtime-deps.d.ts +77 -0
  233. package/src/lib/runtime/runtime-deps.js +18 -0
  234. package/src/lib/runtime/runtime-deps.js.map +1 -0
  235. package/src/lib/runtime/send-job.d.ts +42 -0
  236. package/src/lib/runtime/send-job.js +780 -0
  237. package/src/lib/runtime/send-job.js.map +1 -0
  238. package/src/lib/runtime/sync-job.d.ts +41 -0
  239. package/src/lib/runtime/sync-job.js +480 -0
  240. package/src/lib/runtime/sync-job.js.map +1 -0
  241. package/src/lib/runtime/timeline.d.ts +67 -0
  242. package/src/lib/runtime/timeline.js +93 -0
  243. package/src/lib/runtime/timeline.js.map +1 -0
  244. package/src/lib/runtime/unsubscribe-link.d.ts +75 -0
  245. package/src/lib/runtime/unsubscribe-link.js +121 -0
  246. package/src/lib/runtime/unsubscribe-link.js.map +1 -0
  247. package/src/lib/runtime/unsubscribe-route.d.ts +24 -0
  248. package/src/lib/runtime/unsubscribe-route.js +103 -0
  249. package/src/lib/runtime/unsubscribe-route.js.map +1 -0
  250. package/src/lib/server.d.ts +53 -0
  251. package/src/lib/server.js +94 -0
  252. package/src/lib/server.js.map +1 -0
  253. package/src/lib/storage/compliance-settings-store.d.ts +44 -0
  254. package/src/lib/storage/compliance-settings-store.js +78 -0
  255. package/src/lib/storage/compliance-settings-store.js.map +1 -0
  256. package/src/lib/storage/do-not-contact-store.d.ts +60 -0
  257. package/src/lib/storage/do-not-contact-store.js +168 -0
  258. package/src/lib/storage/do-not-contact-store.js.map +1 -0
  259. package/src/lib/storage/outreach-records.d.ts +33 -0
  260. package/src/lib/storage/outreach-records.js +35 -0
  261. package/src/lib/storage/outreach-records.js.map +1 -0
  262. package/src/lib/subprocessors.d.ts +48 -0
  263. package/src/lib/subprocessors.js +70 -0
  264. package/src/lib/subprocessors.js.map +1 -0
  265. package/src/lib/transport/gmail-client.d.ts +145 -0
  266. package/src/lib/transport/gmail-client.js +229 -0
  267. package/src/lib/transport/gmail-client.js.map +1 -0
  268. package/src/lib/transport/gmail-errors.d.ts +84 -0
  269. package/src/lib/transport/gmail-errors.js +138 -0
  270. package/src/lib/transport/gmail-errors.js.map +1 -0
  271. package/src/lib/transport/google-oauth.d.ts +138 -0
  272. package/src/lib/transport/google-oauth.js +247 -0
  273. package/src/lib/transport/google-oauth.js.map +1 -0
  274. package/src/lib/transport/http.d.ts +53 -0
  275. package/src/lib/transport/http.js +79 -0
  276. package/src/lib/transport/http.js.map +1 -0
  277. package/src/lib/transport/rfc5322.d.ts +116 -0
  278. package/src/lib/transport/rfc5322.js +330 -0
  279. package/src/lib/transport/rfc5322.js.map +1 -0
  280. package/src/lib/transport/send-message.d.ts +69 -0
  281. package/src/lib/transport/send-message.js +77 -0
  282. package/src/lib/transport/send-message.js.map +1 -0
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { SecretBoxError } from "@aglyn/shared-util-tools/secret-box";
17
+ import { GmailTransportError } from "../transport/gmail-errors.js";
18
+ import { revokeGoogleToken } from "../transport/google-oauth.js";
19
+ import { countOtherCredentialsForAccount, openMailboxRefreshToken } from "./mailbox-credentials.js";
20
+ /** Revokes one stored grant at Google, unless it is still shared. Never throws. */ export async function revokeMailboxGrant(firestore, credential, deps, options = {}) {
21
+ try {
22
+ const others = await countOtherCredentialsForAccount(firestore, {
23
+ providerAccountId: credential.providerAccountId,
24
+ mailboxId: credential.mailboxId,
25
+ excludeOrgId: options.excludeOrgId,
26
+ excludeMailboxIds: options.excludeMailboxIds
27
+ });
28
+ if (others > 0) return 'kept-for-other-mailbox';
29
+ const config = deps.readConfig();
30
+ if (!config.configured) return 'failed';
31
+ const { refreshToken } = openMailboxRefreshToken(credential, config.config.keyring);
32
+ return await revokeGoogleToken(refreshToken, deps.transport);
33
+ } catch (error) {
34
+ if (!(error instanceof GmailTransportError) && !(error instanceof SecretBoxError)) {
35
+ console.error('[outreach] revoking a mailbox grant failed', error);
36
+ }
37
+ return 'failed';
38
+ }
39
+ }
40
+
41
+ //# sourceMappingURL=mailbox-revoke.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/mailboxes/mailbox-revoke.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SecretBoxError } from '@aglyn/shared-util-tools/secret-box'\nimport { GmailTransportError } from '../transport/gmail-errors'\nimport { revokeGoogleToken } from '../transport/google-oauth'\nimport type { TransportDeps } from '../transport/http'\nimport type { OutreachMailboxDisconnectResponse } from './mailbox-api'\nimport {\n countOtherCredentialsForAccount,\n openMailboxRefreshToken,\n type OutreachGoogleMailboxCredentials,\n} from './mailbox-credentials'\nimport type { OutreachGoogleConfigResult } from './outreach-config'\n\n/**\n * TELLING GOOGLE A STORED GRANT IS OVER (AGL-2978).\n *\n * A disconnect, a workspace erasure and an account erasure all end a\n * mailbox's grant the same way: open its sealed refresh token with this\n * deployment's key and revoke it at Google — unless another stored\n * credential still uses the same Google account, because Google's\n * revocation ends the whole grant this client holds for the account, and\n * revoking it would silently break that other mailbox.\n *\n * Never throws. A grant that cannot be revoked is still deleted by whoever\n * called this; the outcome says which happened.\n */\n\n/**\n * What became of a grant at Google: `revoked`, `already-invalid`,\n * `kept-for-other-mailbox` while another credential still uses the account,\n * or `failed` when Google could not be told — the token would not open, the\n * deployment is not configured, or Google did not answer.\n */\nexport type OutreachGrantRevocation = OutreachMailboxDisconnectResponse['revocation']\n\nexport interface OutreachRevokeDeps {\n readConfig(): OutreachGoogleConfigResult\n /** The network and retry policy the revocation call uses. */\n transport: TransportDeps\n}\n\nexport interface RevokeMailboxGrantOptions {\n /**\n * Credentials of this organization do not count as another use of the\n * account: the workspace erasure is ending all of them.\n */\n excludeOrgId?: string\n /**\n * These credentials do not count as another use of the account either:\n * the account erasure is ending every one of the person's grants.\n */\n excludeMailboxIds?: ReadonlySet<string>\n}\n\n/** Revokes one stored grant at Google, unless it is still shared. Never throws. */\nexport async function revokeMailboxGrant(\n firestore: FirebaseFirestore.Firestore,\n credential: OutreachGoogleMailboxCredentials,\n deps: OutreachRevokeDeps,\n options: RevokeMailboxGrantOptions = {},\n): Promise<OutreachGrantRevocation> {\n try {\n const others = await countOtherCredentialsForAccount(firestore, {\n providerAccountId: credential.providerAccountId,\n mailboxId: credential.mailboxId,\n excludeOrgId: options.excludeOrgId,\n excludeMailboxIds: options.excludeMailboxIds,\n })\n if (others > 0) return 'kept-for-other-mailbox'\n const config = deps.readConfig()\n if (!config.configured) return 'failed'\n const { refreshToken } = openMailboxRefreshToken(credential, config.config.keyring)\n return await revokeGoogleToken(refreshToken, deps.transport)\n } catch (error) {\n if (!(error instanceof GmailTransportError) && !(error instanceof SecretBoxError)) {\n console.error('[outreach] revoking a mailbox grant failed', error)\n }\n return 'failed'\n }\n}\n"],"names":["SecretBoxError","GmailTransportError","revokeGoogleToken","countOtherCredentialsForAccount","openMailboxRefreshToken","revokeMailboxGrant","firestore","credential","deps","options","others","providerAccountId","mailboxId","excludeOrgId","excludeMailboxIds","config","readConfig","configured","refreshToken","keyring","transport","error","console"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,cAAc,QAAQ,sCAAqC;AACpE,SAASC,mBAAmB,QAAQ,+BAA2B;AAC/D,SAASC,iBAAiB,QAAQ,+BAA2B;AAG7D,SACEC,+BAA+B,EAC/BC,uBAAuB,QAElB,2BAAuB;AA4C9B,iFAAiF,GACjF,OAAO,eAAeC,mBACpBC,SAAsC,EACtCC,UAA4C,EAC5CC,IAAwB,EACxBC,UAAqC,CAAC,CAAC;IAEvC,IAAI;QACF,MAAMC,SAAS,MAAMP,gCAAgCG,WAAW;YAC9DK,mBAAmBJ,WAAWI,iBAAiB;YAC/CC,WAAWL,WAAWK,SAAS;YAC/BC,cAAcJ,QAAQI,YAAY;YAClCC,mBAAmBL,QAAQK,iBAAiB;QAC9C;QACA,IAAIJ,SAAS,GAAG,OAAO;QACvB,MAAMK,SAASP,KAAKQ,UAAU;QAC9B,IAAI,CAACD,OAAOE,UAAU,EAAE,OAAO;QAC/B,MAAM,EAAEC,YAAY,EAAE,GAAGd,wBAAwBG,YAAYQ,OAAOA,MAAM,CAACI,OAAO;QAClF,OAAO,MAAMjB,kBAAkBgB,cAAcV,KAAKY,SAAS;IAC7D,EAAE,OAAOC,OAAO;QACd,IAAI,CAAEA,CAAAA,iBAAiBpB,mBAAkB,KAAM,CAAEoB,CAAAA,iBAAiBrB,cAAa,GAAI;YACjFsB,QAAQD,KAAK,CAAC,8CAA8CA;QAC9D;QACA,OAAO;IACT;AACF"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import type { PluginWebApiHandler } from '@aglyn/aglyn/server';
18
+ import type { TransportDeps } from '../transport/http';
19
+ import { type OutreachGateDeps } from './mailbox-gate';
20
+ import { type OutreachGoogleConfigResult } from './outreach-config';
21
+ /**
22
+ * THE MAILBOX ROUTES (AGL-2978): connect a rep's Google mailbox, keep its
23
+ * settings, pause it, test it, and disconnect it.
24
+ *
25
+ * ## The connect, end to end
26
+ *
27
+ * 1. `connect` (the member's session) mints a signed, single-use state bound
28
+ * to the member and the organization, records its pending entry, and
29
+ * answers Google's consent address — offline access, the consent prompt,
30
+ * a PKCE challenge and an OpenID nonce, both derived from the state.
31
+ * 2. Google redirects the browser to `oauth/callback`. That request carries
32
+ * no bearer token, so it DOES nothing: it verifies the state's signature,
33
+ * finds the organization's console path, and redirects to the Mailboxes
34
+ * page with the code in the URL FRAGMENT, where no server and no `Referer`
35
+ * sees it. Its release gate was asked about the organization and the
36
+ * member the state names (the route's declared subject).
37
+ * 3. The page takes the code out of the address bar and posts it to
38
+ * `connect/complete` with the member's own session. That is where the
39
+ * state is consumed, where it is refused if it was minted for anyone else,
40
+ * and where the code is exchanged. So a consent screen someone else was
41
+ * tricked into completing cannot connect THEIR mailbox to the member who
42
+ * started it: the code arrives in the wrong browser, whose session is not
43
+ * the state's member.
44
+ *
45
+ * ## Refusals, in order, on `connect/complete`
46
+ *
47
+ * A state that is invalid, minted for another member or organization,
48
+ * expired, already used or superseded; a code Google refuses; a grant with no
49
+ * refresh token; a grant missing `gmail.send` or `gmail.readonly` (the consent
50
+ * screen lets a person untick them); an ID token that is not about this
51
+ * exchange or whose address Google has not verified; a Gmail profile whose
52
+ * address is not the ID token's; and a member at their mailbox limit.
53
+ *
54
+ * A grant refused after the code exchange is dropped, not revoked. Google's
55
+ * revocation ends the whole grant this client holds for the account, and the
56
+ * same account may already be connected — by this member in another
57
+ * organization, or by a teammate — so revoking a token this route merely
58
+ * declines to keep could disconnect a mailbox that is working.
59
+ *
60
+ * ## Who may do what
61
+ *
62
+ * Every route but the callback climbs `outreachMemberGate`. The member who
63
+ * connected a mailbox manages it; an organization owner or admin may also
64
+ * change its settings, pause it and disconnect it — a departing rep's mailbox
65
+ * has to be stoppable by somebody. Only its own member can send a test from
66
+ * it, since the test lands in their inbox.
67
+ */
68
+ export interface OutreachMailboxRouteDeps {
69
+ firestore(): FirebaseFirestore.Firestore;
70
+ gate: OutreachGateDeps;
71
+ readConfig(): OutreachGoogleConfigResult;
72
+ /** Whether the signing secret the OAuth state needs is configured. */
73
+ stateSigningConfigured(): boolean;
74
+ redirectUri(requestUrl: string): string | null;
75
+ now(): number;
76
+ /** The network and retry policy every Google call uses. */
77
+ transport: TransportDeps;
78
+ consumeRateLimit(key: string, options: {
79
+ limit: number;
80
+ windowMs: number;
81
+ }): Promise<{
82
+ allowed: boolean;
83
+ }>;
84
+ logOrgActivity(orgId: string, actor: {
85
+ uid: string;
86
+ email?: string | null;
87
+ }, action: string, target: {
88
+ type: typeof OUTREACH_MAILBOX_ACTIVITY_TARGET;
89
+ id: string;
90
+ name: string;
91
+ }): Promise<void>;
92
+ confirmAliasesByProvider(firestore: FirebaseFirestore.Firestore, input: {
93
+ orgId: string;
94
+ uid: string;
95
+ addresses: readonly string[];
96
+ nowMs: number;
97
+ }): Promise<{
98
+ ok: boolean;
99
+ confirmed?: string[];
100
+ }>;
101
+ }
102
+ export interface OutreachMailboxRoutes {
103
+ availability: PluginWebApiHandler;
104
+ connect: PluginWebApiHandler;
105
+ oauthCallback: PluginWebApiHandler;
106
+ connectComplete: PluginWebApiHandler;
107
+ settings: PluginWebApiHandler;
108
+ status: PluginWebApiHandler;
109
+ test: PluginWebApiHandler;
110
+ disconnect: PluginWebApiHandler;
111
+ }
112
+ /** Test sends one mailbox may make in an hour. */
113
+ export declare const OUTREACH_TEST_SENDS_PER_HOUR = 5;
114
+ /**
115
+ * The org activity target a mailbox's rows are filed under: Outreach's own
116
+ * namespaced resource, which the feed reads as "Mailbox".
117
+ */
118
+ export declare const OUTREACH_MAILBOX_ACTIVITY_TARGET = "outreach:mailbox";
119
+ export declare function createOutreachMailboxRoutes(deps: OutreachMailboxRouteDeps): OutreachMailboxRoutes;