@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.
- package/LICENSE +201 -0
- package/README.md +93 -0
- package/package.json +52 -0
- package/src/index.d.ts +22 -0
- package/src/index.js +29 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/compliance-section.d.ts +20 -0
- package/src/lib/components/compliance-section.js +291 -0
- package/src/lib/components/compliance-section.js.map +1 -0
- package/src/lib/components/enroll-dialog.d.ts +36 -0
- package/src/lib/components/enroll-dialog.js +656 -0
- package/src/lib/components/enroll-dialog.js.map +1 -0
- package/src/lib/components/enrollments-table.d.ts +28 -0
- package/src/lib/components/enrollments-table.js +375 -0
- package/src/lib/components/enrollments-table.js.map +1 -0
- package/src/lib/components/mailbox-card.d.ts +46 -0
- package/src/lib/components/mailbox-card.js +517 -0
- package/src/lib/components/mailbox-card.js.map +1 -0
- package/src/lib/components/mailboxes-section.d.ts +24 -0
- package/src/lib/components/mailboxes-section.js +258 -0
- package/src/lib/components/mailboxes-section.js.map +1 -0
- package/src/lib/components/outreach-console-page.d.ts +17 -0
- package/src/lib/components/outreach-console-page.js +81 -0
- package/src/lib/components/outreach-console-page.js.map +1 -0
- package/src/lib/components/outreach-console-sections.d.ts +43 -0
- package/src/lib/components/outreach-console-sections.js +55 -0
- package/src/lib/components/outreach-console-sections.js.map +1 -0
- package/src/lib/components/outreach-ui.d.ts +51 -0
- package/src/lib/components/outreach-ui.js +171 -0
- package/src/lib/components/outreach-ui.js.map +1 -0
- package/src/lib/components/send-window-fields.d.ts +25 -0
- package/src/lib/components/send-window-fields.js +178 -0
- package/src/lib/components/send-window-fields.js.map +1 -0
- package/src/lib/components/sequence-detail.d.ts +54 -0
- package/src/lib/components/sequence-detail.js +435 -0
- package/src/lib/components/sequence-detail.js.map +1 -0
- package/src/lib/components/sequence-editor.d.ts +37 -0
- package/src/lib/components/sequence-editor.js +485 -0
- package/src/lib/components/sequence-editor.js.map +1 -0
- package/src/lib/components/sequence-mailbox-picker.d.ts +44 -0
- package/src/lib/components/sequence-mailbox-picker.js +137 -0
- package/src/lib/components/sequence-mailbox-picker.js.map +1 -0
- package/src/lib/components/sequence-preview.d.ts +27 -0
- package/src/lib/components/sequence-preview.js +146 -0
- package/src/lib/components/sequence-preview.js.map +1 -0
- package/src/lib/components/sequence-step-card.d.ts +31 -0
- package/src/lib/components/sequence-step-card.js +326 -0
- package/src/lib/components/sequence-step-card.js.map +1 -0
- package/src/lib/components/sequences-section.d.ts +40 -0
- package/src/lib/components/sequences-section.js +310 -0
- package/src/lib/components/sequences-section.js.map +1 -0
- package/src/lib/components/use-outreach-api.d.ts +38 -0
- package/src/lib/components/use-outreach-api.js +139 -0
- package/src/lib/components/use-outreach-api.js.map +1 -0
- package/src/lib/components/use-outreach-crm.d.ts +50 -0
- package/src/lib/components/use-outreach-crm.js +200 -0
- package/src/lib/components/use-outreach-crm.js.map +1 -0
- package/src/lib/components/use-outreach-data.d.ts +55 -0
- package/src/lib/components/use-outreach-data.js +199 -0
- package/src/lib/components/use-outreach-data.js.map +1 -0
- package/src/lib/components/use-outreach-mailbox-api.d.ts +30 -0
- package/src/lib/components/use-outreach-mailbox-api.js +101 -0
- package/src/lib/components/use-outreach-mailbox-api.js.map +1 -0
- package/src/lib/components/use-outreach-mailboxes.d.ts +22 -0
- package/src/lib/components/use-outreach-mailboxes.js +68 -0
- package/src/lib/components/use-outreach-mailboxes.js.map +1 -0
- package/src/lib/components/use-outreach-settings.d.ts +17 -0
- package/src/lib/components/use-outreach-settings.js +64 -0
- package/src/lib/components/use-outreach-settings.js.map +1 -0
- package/src/lib/constants/api-routes.d.ts +68 -0
- package/src/lib/constants/api-routes.js +57 -0
- package/src/lib/constants/api-routes.js.map +1 -0
- package/src/lib/constants/bundle-common.d.ts +46 -0
- package/src/lib/constants/bundle-common.js +55 -0
- package/src/lib/constants/bundle-common.js.map +1 -0
- package/src/lib/constants/runtime-jobs.d.ts +24 -0
- package/src/lib/constants/runtime-jobs.js +24 -0
- package/src/lib/constants/runtime-jobs.js.map +1 -0
- package/src/lib/declarations.console-server.d.ts +38 -0
- package/src/lib/declarations.console-server.js +99 -0
- package/src/lib/declarations.console-server.js.map +1 -0
- package/src/lib/engine/compose.d.ts +86 -0
- package/src/lib/engine/compose.js +212 -0
- package/src/lib/engine/compose.js.map +1 -0
- package/src/lib/engine/delivery-status.d.ts +53 -0
- package/src/lib/engine/delivery-status.js +184 -0
- package/src/lib/engine/delivery-status.js.map +1 -0
- package/src/lib/engine/do-not-contact.d.ts +18 -0
- package/src/lib/engine/do-not-contact.js +34 -0
- package/src/lib/engine/do-not-contact.js.map +1 -0
- package/src/lib/engine/enrollment-state.d.ts +156 -0
- package/src/lib/engine/enrollment-state.js +303 -0
- package/src/lib/engine/enrollment-state.js.map +1 -0
- package/src/lib/engine/gates.d.ts +125 -0
- package/src/lib/engine/gates.js +232 -0
- package/src/lib/engine/gates.js.map +1 -0
- package/src/lib/engine/index.d.ts +28 -0
- package/src/lib/engine/index.js +33 -0
- package/src/lib/engine/index.js.map +1 -0
- package/src/lib/engine/mailbox-health.d.ts +49 -0
- package/src/lib/engine/mailbox-health.js +83 -0
- package/src/lib/engine/mailbox-health.js.map +1 -0
- package/src/lib/engine/opt-out-intent.d.ts +41 -0
- package/src/lib/engine/opt-out-intent.js +220 -0
- package/src/lib/engine/opt-out-intent.js.map +1 -0
- package/src/lib/engine/recipient-country.d.ts +41 -0
- package/src/lib/engine/recipient-country.js +171 -0
- package/src/lib/engine/recipient-country.js.map +1 -0
- package/src/lib/engine/schedule.d.ts +70 -0
- package/src/lib/engine/schedule.js +115 -0
- package/src/lib/engine/schedule.js.map +1 -0
- package/src/lib/engine/sending-capacity.d.ts +96 -0
- package/src/lib/engine/sending-capacity.js +172 -0
- package/src/lib/engine/sending-capacity.js.map +1 -0
- package/src/lib/engine/sequence-validation.d.ts +90 -0
- package/src/lib/engine/sequence-validation.js +291 -0
- package/src/lib/engine/sequence-validation.js.map +1 -0
- package/src/lib/engine/thread-classification.d.ts +78 -0
- package/src/lib/engine/thread-classification.js +224 -0
- package/src/lib/engine/thread-classification.js.map +1 -0
- package/src/lib/engine/thread-message.d.ts +80 -0
- package/src/lib/engine/thread-message.js +143 -0
- package/src/lib/engine/thread-message.js.map +1 -0
- package/src/lib/enrollment/enroll-people.d.ts +81 -0
- package/src/lib/enrollment/enroll-people.js +250 -0
- package/src/lib/enrollment/enroll-people.js.map +1 -0
- package/src/lib/enrollment/gate-lookups.d.ts +32 -0
- package/src/lib/enrollment/gate-lookups.js +154 -0
- package/src/lib/enrollment/gate-lookups.js.map +1 -0
- package/src/lib/mailboxes/mailbox-api.d.ts +126 -0
- package/src/lib/mailboxes/mailbox-api.js +66 -0
- package/src/lib/mailboxes/mailbox-api.js.map +1 -0
- package/src/lib/mailboxes/mailbox-credentials.d.ts +95 -0
- package/src/lib/mailboxes/mailbox-credentials.js +102 -0
- package/src/lib/mailboxes/mailbox-credentials.js.map +1 -0
- package/src/lib/mailboxes/mailbox-erasure.d.ts +69 -0
- package/src/lib/mailboxes/mailbox-erasure.js +148 -0
- package/src/lib/mailboxes/mailbox-erasure.js.map +1 -0
- package/src/lib/mailboxes/mailbox-gate.d.ts +75 -0
- package/src/lib/mailboxes/mailbox-gate.js +98 -0
- package/src/lib/mailboxes/mailbox-gate.js.map +1 -0
- package/src/lib/mailboxes/mailbox-revoke.d.ts +59 -0
- package/src/lib/mailboxes/mailbox-revoke.js +41 -0
- package/src/lib/mailboxes/mailbox-revoke.js.map +1 -0
- package/src/lib/mailboxes/mailbox-routes.d.ts +119 -0
- package/src/lib/mailboxes/mailbox-routes.js +605 -0
- package/src/lib/mailboxes/mailbox-routes.js.map +1 -0
- package/src/lib/mailboxes/mailbox-settings.d.ts +110 -0
- package/src/lib/mailboxes/mailbox-settings.js +212 -0
- package/src/lib/mailboxes/mailbox-settings.js.map +1 -0
- package/src/lib/mailboxes/mailbox-transport.d.ts +64 -0
- package/src/lib/mailboxes/mailbox-transport.js +94 -0
- package/src/lib/mailboxes/mailbox-transport.js.map +1 -0
- package/src/lib/mailboxes/oauth-redirect.d.ts +41 -0
- package/src/lib/mailboxes/oauth-redirect.js +63 -0
- package/src/lib/mailboxes/oauth-redirect.js.map +1 -0
- package/src/lib/mailboxes/oauth-state.d.ts +152 -0
- package/src/lib/mailboxes/oauth-state.js +212 -0
- package/src/lib/mailboxes/oauth-state.js.map +1 -0
- package/src/lib/mailboxes/outreach-config.d.ts +64 -0
- package/src/lib/mailboxes/outreach-config.js +77 -0
- package/src/lib/mailboxes/outreach-config.js.map +1 -0
- package/src/lib/mailboxes/register-mailbox-routes.d.ts +47 -0
- package/src/lib/mailboxes/register-mailbox-routes.js +135 -0
- package/src/lib/mailboxes/register-mailbox-routes.js.map +1 -0
- package/src/lib/model/compliance-settings.d.ts +78 -0
- package/src/lib/model/compliance-settings.js +155 -0
- package/src/lib/model/compliance-settings.js.map +1 -0
- package/src/lib/model/outreach-api.d.ts +210 -0
- package/src/lib/model/outreach-api.js +28 -0
- package/src/lib/model/outreach-api.js.map +1 -0
- package/src/lib/model/outreach.types.d.ts +563 -0
- package/src/lib/model/outreach.types.js +225 -0
- package/src/lib/model/outreach.types.js.map +1 -0
- package/src/lib/model/sequence-draft.d.ts +84 -0
- package/src/lib/model/sequence-draft.js +239 -0
- package/src/lib/model/sequence-draft.js.map +1 -0
- package/src/lib/model/step-preview.d.ts +45 -0
- package/src/lib/model/step-preview.js +98 -0
- package/src/lib/model/step-preview.js.map +1 -0
- package/src/lib/model/stored-records.d.ts +23 -0
- package/src/lib/model/stored-records.js +84 -0
- package/src/lib/model/stored-records.js.map +1 -0
- package/src/lib/plugin.d.ts +46 -0
- package/src/lib/plugin.js +86 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/routes/enroll-routes.d.ts +64 -0
- package/src/lib/routes/enroll-routes.js +350 -0
- package/src/lib/routes/enroll-routes.js.map +1 -0
- package/src/lib/routes/enrollment-routes.d.ts +19 -0
- package/src/lib/routes/enrollment-routes.js +171 -0
- package/src/lib/routes/enrollment-routes.js.map +1 -0
- package/src/lib/routes/platform-deps.d.ts +51 -0
- package/src/lib/routes/platform-deps.js +66 -0
- package/src/lib/routes/platform-deps.js.map +1 -0
- package/src/lib/routes/preview-routes.d.ts +33 -0
- package/src/lib/routes/preview-routes.js +117 -0
- package/src/lib/routes/preview-routes.js.map +1 -0
- package/src/lib/routes/register-routes.d.ts +22 -0
- package/src/lib/routes/register-routes.js +92 -0
- package/src/lib/routes/register-routes.js.map +1 -0
- package/src/lib/routes/route-deps.d.ts +49 -0
- package/src/lib/routes/route-deps.js +27 -0
- package/src/lib/routes/route-deps.js.map +1 -0
- package/src/lib/routes/route-gate.d.ts +94 -0
- package/src/lib/routes/route-gate.js +87 -0
- package/src/lib/routes/route-gate.js.map +1 -0
- package/src/lib/routes/route-http.d.ts +32 -0
- package/src/lib/routes/route-http.js +62 -0
- package/src/lib/routes/route-http.js.map +1 -0
- package/src/lib/routes/sequence-routes.d.ts +32 -0
- package/src/lib/routes/sequence-routes.js +359 -0
- package/src/lib/routes/sequence-routes.js.map +1 -0
- package/src/lib/routes/settings-routes.d.ts +30 -0
- package/src/lib/routes/settings-routes.js +73 -0
- package/src/lib/routes/settings-routes.js.map +1 -0
- package/src/lib/runtime/enrollment-events.d.ts +86 -0
- package/src/lib/runtime/enrollment-events.js +141 -0
- package/src/lib/runtime/enrollment-events.js.map +1 -0
- package/src/lib/runtime/fixtures/fake-gmail.d.ts +121 -0
- package/src/lib/runtime/fixtures/fake-gmail.js +312 -0
- package/src/lib/runtime/fixtures/fake-gmail.js.map +1 -0
- package/src/lib/runtime/mailbox-health-store.d.ts +47 -0
- package/src/lib/runtime/mailbox-health-store.js +168 -0
- package/src/lib/runtime/mailbox-health-store.js.map +1 -0
- package/src/lib/runtime/person-erasure.d.ts +39 -0
- package/src/lib/runtime/person-erasure.js +57 -0
- package/src/lib/runtime/person-erasure.js.map +1 -0
- package/src/lib/runtime/platform-runtime-deps.d.ts +29 -0
- package/src/lib/runtime/platform-runtime-deps.js +98 -0
- package/src/lib/runtime/platform-runtime-deps.js.map +1 -0
- package/src/lib/runtime/runtime-deps.d.ts +77 -0
- package/src/lib/runtime/runtime-deps.js +18 -0
- package/src/lib/runtime/runtime-deps.js.map +1 -0
- package/src/lib/runtime/send-job.d.ts +42 -0
- package/src/lib/runtime/send-job.js +780 -0
- package/src/lib/runtime/send-job.js.map +1 -0
- package/src/lib/runtime/sync-job.d.ts +41 -0
- package/src/lib/runtime/sync-job.js +480 -0
- package/src/lib/runtime/sync-job.js.map +1 -0
- package/src/lib/runtime/timeline.d.ts +67 -0
- package/src/lib/runtime/timeline.js +93 -0
- package/src/lib/runtime/timeline.js.map +1 -0
- package/src/lib/runtime/unsubscribe-link.d.ts +75 -0
- package/src/lib/runtime/unsubscribe-link.js +121 -0
- package/src/lib/runtime/unsubscribe-link.js.map +1 -0
- package/src/lib/runtime/unsubscribe-route.d.ts +24 -0
- package/src/lib/runtime/unsubscribe-route.js +103 -0
- package/src/lib/runtime/unsubscribe-route.js.map +1 -0
- package/src/lib/server.d.ts +53 -0
- package/src/lib/server.js +94 -0
- package/src/lib/server.js.map +1 -0
- package/src/lib/storage/compliance-settings-store.d.ts +44 -0
- package/src/lib/storage/compliance-settings-store.js +78 -0
- package/src/lib/storage/compliance-settings-store.js.map +1 -0
- package/src/lib/storage/do-not-contact-store.d.ts +60 -0
- package/src/lib/storage/do-not-contact-store.js +168 -0
- package/src/lib/storage/do-not-contact-store.js.map +1 -0
- package/src/lib/storage/outreach-records.d.ts +33 -0
- package/src/lib/storage/outreach-records.js +35 -0
- package/src/lib/storage/outreach-records.js.map +1 -0
- package/src/lib/subprocessors.d.ts +48 -0
- package/src/lib/subprocessors.js +70 -0
- package/src/lib/subprocessors.js.map +1 -0
- package/src/lib/transport/gmail-client.d.ts +145 -0
- package/src/lib/transport/gmail-client.js +229 -0
- package/src/lib/transport/gmail-client.js.map +1 -0
- package/src/lib/transport/gmail-errors.d.ts +84 -0
- package/src/lib/transport/gmail-errors.js +138 -0
- package/src/lib/transport/gmail-errors.js.map +1 -0
- package/src/lib/transport/google-oauth.d.ts +138 -0
- package/src/lib/transport/google-oauth.js +247 -0
- package/src/lib/transport/google-oauth.js.map +1 -0
- package/src/lib/transport/http.d.ts +53 -0
- package/src/lib/transport/http.js +79 -0
- package/src/lib/transport/http.js.map +1 -0
- package/src/lib/transport/rfc5322.d.ts +116 -0
- package/src/lib/transport/rfc5322.js +330 -0
- package/src/lib/transport/rfc5322.js.map +1 -0
- package/src/lib/transport/send-message.d.ts +69 -0
- package/src/lib/transport/send-message.js +77 -0
- package/src/lib/transport/send-message.js.map +1 -0
|
@@ -0,0 +1,51 @@
|
|
|
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 { lockdownRefusal } from '@aglyn/tenant-data-admin/server/lockdown';
|
|
18
|
+
import { logOrgActivity } from '@aglyn/tenant-data-admin/server/organizations';
|
|
19
|
+
import { resolveOrgPermissions } from '@aglyn/tenant-runtime/org-permissions';
|
|
20
|
+
/**
|
|
21
|
+
* The platform's heavier server modules the Outreach routes reach
|
|
22
|
+
* (AGL-2980): the permission resolver, the lockdown verdict, the activity
|
|
23
|
+
* log and the saved-view sweep.
|
|
24
|
+
*
|
|
25
|
+
* Imported here statically, and this module is loaded by
|
|
26
|
+
* `register-routes.ts` the first time a request needs one of them: the
|
|
27
|
+
* manifest loads Outreach's server bundle into every console API process
|
|
28
|
+
* whether or not an Outreach route is ever called, and `org-permissions`
|
|
29
|
+
* alone reaches the whole tenant data barrel. Loading them through one
|
|
30
|
+
* module of this plugin keeps every import of the platform's libraries a
|
|
31
|
+
* static one.
|
|
32
|
+
*/
|
|
33
|
+
export { lockdownRefusal, logOrgActivity, resolveOrgPermissions };
|
|
34
|
+
/**
|
|
35
|
+
* Whether the member holds a CATALOG permission (`data.manage`) as the
|
|
36
|
+
* org's roles resolve it — custom role and per-member overrides included.
|
|
37
|
+
* A lookup that failed has not shown the member holds it.
|
|
38
|
+
*/
|
|
39
|
+
export declare function holdsOrgCatalogPermission(uid: string, orgId: string, key: string): Promise<boolean>;
|
|
40
|
+
/**
|
|
41
|
+
* The addresses a saved Contacts view selects among one site's contacts,
|
|
42
|
+
* read by the dynamic-list sweep's own scan, and whether it reached the
|
|
43
|
+
* whole view.
|
|
44
|
+
*/
|
|
45
|
+
export declare function crmViewEmails(input: {
|
|
46
|
+
hostId: string;
|
|
47
|
+
viewId: string;
|
|
48
|
+
}): Promise<{
|
|
49
|
+
emails: string[];
|
|
50
|
+
complete: boolean;
|
|
51
|
+
}>;
|
|
@@ -0,0 +1,66 @@
|
|
|
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 { collectDynamicListCandidates } from "@aglyn/tenant-data-admin/server/dynamic-list-materialize";
|
|
17
|
+
import { lockdownRefusal } from "@aglyn/tenant-data-admin/server/lockdown";
|
|
18
|
+
import { logOrgActivity, memberHasOrgPermission, resolveOrgMembership } from "@aglyn/tenant-data-admin/server/organizations";
|
|
19
|
+
import { resolveOrgPermissions } from "@aglyn/tenant-runtime/org-permissions";
|
|
20
|
+
/**
|
|
21
|
+
* The platform's heavier server modules the Outreach routes reach
|
|
22
|
+
* (AGL-2980): the permission resolver, the lockdown verdict, the activity
|
|
23
|
+
* log and the saved-view sweep.
|
|
24
|
+
*
|
|
25
|
+
* Imported here statically, and this module is loaded by
|
|
26
|
+
* `register-routes.ts` the first time a request needs one of them: the
|
|
27
|
+
* manifest loads Outreach's server bundle into every console API process
|
|
28
|
+
* whether or not an Outreach route is ever called, and `org-permissions`
|
|
29
|
+
* alone reaches the whole tenant data barrel. Loading them through one
|
|
30
|
+
* module of this plugin keeps every import of the platform's libraries a
|
|
31
|
+
* static one.
|
|
32
|
+
*/ export { lockdownRefusal, logOrgActivity, resolveOrgPermissions };
|
|
33
|
+
/**
|
|
34
|
+
* Whether the member holds a CATALOG permission (`data.manage`) as the
|
|
35
|
+
* org's roles resolve it — custom role and per-member overrides included.
|
|
36
|
+
* A lookup that failed has not shown the member holds it.
|
|
37
|
+
*/ export async function holdsOrgCatalogPermission(uid, orgId, key) {
|
|
38
|
+
try {
|
|
39
|
+
const membership = await resolveOrgMembership(uid, orgId);
|
|
40
|
+
if (!(membership == null ? void 0 : membership.member)) return false;
|
|
41
|
+
return await memberHasOrgPermission(orgId, membership.member, key) === true;
|
|
42
|
+
} catch (unused) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The addresses a saved Contacts view selects among one site's contacts,
|
|
48
|
+
* read by the dynamic-list sweep's own scan, and whether it reached the
|
|
49
|
+
* whole view.
|
|
50
|
+
*/ export async function crmViewEmails(input) {
|
|
51
|
+
const scan = await collectDynamicListCandidates({
|
|
52
|
+
hostId: input.hostId,
|
|
53
|
+
rule: {
|
|
54
|
+
sources: [
|
|
55
|
+
'contacts'
|
|
56
|
+
],
|
|
57
|
+
viewId: input.viewId
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
return {
|
|
61
|
+
emails: scan.candidates.map((candidate)=>candidate.email),
|
|
62
|
+
complete: scan.complete
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=platform-deps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/routes/platform-deps.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 { collectDynamicListCandidates } from '@aglyn/tenant-data-admin/server/dynamic-list-materialize'\nimport { lockdownRefusal } from '@aglyn/tenant-data-admin/server/lockdown'\nimport {\n logOrgActivity,\n memberHasOrgPermission,\n resolveOrgMembership,\n} from '@aglyn/tenant-data-admin/server/organizations'\nimport { resolveOrgPermissions } from '@aglyn/tenant-runtime/org-permissions'\n\n/**\n * The platform's heavier server modules the Outreach routes reach\n * (AGL-2980): the permission resolver, the lockdown verdict, the activity\n * log and the saved-view sweep.\n *\n * Imported here statically, and this module is loaded by\n * `register-routes.ts` the first time a request needs one of them: the\n * manifest loads Outreach's server bundle into every console API process\n * whether or not an Outreach route is ever called, and `org-permissions`\n * alone reaches the whole tenant data barrel. Loading them through one\n * module of this plugin keeps every import of the platform's libraries a\n * static one.\n */\n\nexport { lockdownRefusal, logOrgActivity, resolveOrgPermissions }\n\n/**\n * Whether the member holds a CATALOG permission (`data.manage`) as the\n * org's roles resolve it — custom role and per-member overrides included.\n * A lookup that failed has not shown the member holds it.\n */\nexport async function holdsOrgCatalogPermission(uid: string, orgId: string, key: string): Promise<boolean> {\n try {\n const membership = await resolveOrgMembership(uid, orgId)\n if (!membership?.member) return false\n return (\n (await memberHasOrgPermission(\n orgId,\n membership.member,\n key as Parameters<typeof memberHasOrgPermission>[2],\n )) === true\n )\n } catch {\n return false\n }\n}\n\n/**\n * The addresses a saved Contacts view selects among one site's contacts,\n * read by the dynamic-list sweep's own scan, and whether it reached the\n * whole view.\n */\nexport async function crmViewEmails(input: {\n hostId: string\n viewId: string\n}): Promise<{ emails: string[]; complete: boolean }> {\n const scan = await collectDynamicListCandidates({\n hostId: input.hostId,\n rule: { sources: ['contacts'], viewId: input.viewId },\n })\n return { emails: scan.candidates.map((candidate) => candidate.email), complete: scan.complete }\n}\n"],"names":["collectDynamicListCandidates","lockdownRefusal","logOrgActivity","memberHasOrgPermission","resolveOrgMembership","resolveOrgPermissions","holdsOrgCatalogPermission","uid","orgId","key","membership","member","crmViewEmails","input","scan","hostId","rule","sources","viewId","emails","candidates","map","candidate","email","complete"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,4BAA4B,QAAQ,2DAA0D;AACvG,SAASC,eAAe,QAAQ,2CAA0C;AAC1E,SACEC,cAAc,EACdC,sBAAsB,EACtBC,oBAAoB,QACf,gDAA+C;AACtD,SAASC,qBAAqB,QAAQ,wCAAuC;AAE7E;;;;;;;;;;;;CAYC,GAED,SAASJ,eAAe,EAAEC,cAAc,EAAEG,qBAAqB,GAAE;AAEjE;;;;CAIC,GACD,OAAO,eAAeC,0BAA0BC,GAAW,EAAEC,KAAa,EAAEC,GAAW;IACrF,IAAI;QACF,MAAMC,aAAa,MAAMN,qBAAqBG,KAAKC;QACnD,IAAI,EAACE,8BAAAA,WAAYC,MAAM,GAAE,OAAO;QAChC,OACE,AAAC,MAAMR,uBACLK,OACAE,WAAWC,MAAM,EACjBF,SACK;IAEX,EAAE,eAAM;QACN,OAAO;IACT;AACF;AAEA;;;;CAIC,GACD,OAAO,eAAeG,cAAcC,KAGnC;IACC,MAAMC,OAAO,MAAMd,6BAA6B;QAC9Ce,QAAQF,MAAME,MAAM;QACpBC,MAAM;YAAEC,SAAS;gBAAC;aAAW;YAAEC,QAAQL,MAAMK,MAAM;QAAC;IACtD;IACA,OAAO;QAAEC,QAAQL,KAAKM,UAAU,CAACC,GAAG,CAAC,CAACC,YAAcA,UAAUC,KAAK;QAAGC,UAAUV,KAAKU,QAAQ;IAAC;AAChG"}
|
|
@@ -0,0 +1,33 @@
|
|
|
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 { OutreachRouteDeps } from './route-deps';
|
|
19
|
+
/**
|
|
20
|
+
* ONE EMAIL OF A SAVED SEQUENCE, AS A PERSON WOULD GET IT (AGL-2980):
|
|
21
|
+
* `outreach/preview`.
|
|
22
|
+
*
|
|
23
|
+
* Written from what is stored — the sequence, the CRM template a step names,
|
|
24
|
+
* the mailbox it sends as, the organization's footer — by the engine's own
|
|
25
|
+
* composer (`previewOutreachStep`), for a real contact with the personal
|
|
26
|
+
* line the rep is writing, or for a sample person. The enroll dialog shows
|
|
27
|
+
* it beside each person before Confirm, so the rep reads the sentence they
|
|
28
|
+
* wrote in the email it goes into.
|
|
29
|
+
*
|
|
30
|
+
* A real contact is read from the CRM, so naming one asks for `data.manage`
|
|
31
|
+
* as enrolling does; the sample person asks for nothing more.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createOutreachPreviewRoute(deps: OutreachRouteDeps): PluginWebApiHandler;
|
|
@@ -0,0 +1,117 @@
|
|
|
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 { consentGroupForHost } from "@aglyn/aglyn/app-utils/consent-groups";
|
|
17
|
+
import { normalizeContactEmail } from "@aglyn/aglyn/app-utils/contacts";
|
|
18
|
+
import { CRM_COLLECTIONS } from "@aglyn/aglyn/app-utils/crm";
|
|
19
|
+
import { normalizeCrmEmailTemplate } from "@aglyn/aglyn/app-utils/crm-email-templates";
|
|
20
|
+
import { visibleToHost } from "@aglyn/aglyn/app-utils/scope-tokens";
|
|
21
|
+
import { firstEmailStepIndex } from "../engine/sequence-validation.js";
|
|
22
|
+
import { OUTREACH_SAMPLE_PERSON, outreachSampleMergeContext, previewOutreachStep } from "../model/step-preview.js";
|
|
23
|
+
import { readOutreachComplianceSettingsDoc } from "../storage/compliance-settings-store.js";
|
|
24
|
+
import { outreachOrgCollection, readStoredOutreachMailbox, readStoredOutreachSequence } from "../storage/outreach-records.js";
|
|
25
|
+
import { OUTREACH_READS_PEOPLE } from "./enroll-routes.js";
|
|
26
|
+
import { outreachRouteGate } from "./route-gate.js";
|
|
27
|
+
import { outreachMethodNotAllowed, outreachOk, outreachRefusal, readOutreachDocumentId, readOutreachJsonBody } from "./route-http.js";
|
|
28
|
+
/**
|
|
29
|
+
* ONE EMAIL OF A SAVED SEQUENCE, AS A PERSON WOULD GET IT (AGL-2980):
|
|
30
|
+
* `outreach/preview`.
|
|
31
|
+
*
|
|
32
|
+
* Written from what is stored — the sequence, the CRM template a step names,
|
|
33
|
+
* the mailbox it sends as, the organization's footer — by the engine's own
|
|
34
|
+
* composer (`previewOutreachStep`), for a real contact with the personal
|
|
35
|
+
* line the rep is writing, or for a sample person. The enroll dialog shows
|
|
36
|
+
* it beside each person before Confirm, so the rep reads the sentence they
|
|
37
|
+
* wrote in the email it goes into.
|
|
38
|
+
*
|
|
39
|
+
* A real contact is read from the CRM, so naming one asks for `data.manage`
|
|
40
|
+
* as enrolling does; the sample person asks for nothing more.
|
|
41
|
+
*/ export function createOutreachPreviewRoute(deps) {
|
|
42
|
+
return async (request)=>{
|
|
43
|
+
var _host_get, _normalizeContactEmail, _ref, _ref1;
|
|
44
|
+
var _result_email, _result_email1;
|
|
45
|
+
if (request.method !== 'POST') return outreachMethodNotAllowed('POST');
|
|
46
|
+
const body = await readOutreachJsonBody(request);
|
|
47
|
+
const contactId = body['contactId'] === undefined ? null : readOutreachDocumentId(body['contactId']);
|
|
48
|
+
if (body['contactId'] !== undefined && !contactId) {
|
|
49
|
+
return outreachRefusal(400, 'invalid-request', 'Name the contact to preview for.');
|
|
50
|
+
}
|
|
51
|
+
const caller = await outreachRouteGate(request, body['orgId'], deps.gate, contactId ? [
|
|
52
|
+
OUTREACH_READS_PEOPLE
|
|
53
|
+
] : []);
|
|
54
|
+
if (caller instanceof Response) return caller;
|
|
55
|
+
const sequenceId = readOutreachDocumentId(body['sequenceId']);
|
|
56
|
+
if (!sequenceId) return outreachRefusal(400, 'invalid-request', 'Name the sequence to preview.');
|
|
57
|
+
const firestore = deps.firestore();
|
|
58
|
+
const org = firestore.collection('orgs').doc(caller.orgId);
|
|
59
|
+
const snapshot = await outreachOrgCollection(firestore, caller.orgId, 'sequences').doc(sequenceId).get();
|
|
60
|
+
const sequence = readStoredOutreachSequence(sequenceId, snapshot.exists ? snapshot.data() : undefined);
|
|
61
|
+
if (!sequence) return outreachRefusal(404, 'sequence-not-found', 'That sequence no longer exists.');
|
|
62
|
+
const requested = body['stepIndex'];
|
|
63
|
+
const stepIndex = typeof requested === 'number' ? requested : firstEmailStepIndex(sequence.steps);
|
|
64
|
+
const step = sequence.steps[stepIndex];
|
|
65
|
+
if ((step == null ? void 0 : step.kind) !== 'email') {
|
|
66
|
+
return outreachRefusal(400, 'invalid-request', 'That step does not send an email.');
|
|
67
|
+
}
|
|
68
|
+
const [orgSettings, mailboxSnapshot, host, template, contact] = await Promise.all([
|
|
69
|
+
readOutreachComplianceSettingsDoc(firestore, caller.orgId),
|
|
70
|
+
sequence.mailboxId ? outreachOrgCollection(firestore, caller.orgId, 'mailboxes').doc(sequence.mailboxId).get() : null,
|
|
71
|
+
sequence.hostId ? firestore.collection('hosts').doc(sequence.hostId).get() : null,
|
|
72
|
+
step.templateId ? org.collection(CRM_COLLECTIONS.emailTemplates).doc(step.templateId).get() : null,
|
|
73
|
+
contactId ? org.collection('contacts').doc(contactId).get() : null
|
|
74
|
+
]);
|
|
75
|
+
const contactData = (contact == null ? void 0 : contact.exists) ? contact.data() : null;
|
|
76
|
+
if (contactId && (!contactData || !visibleToHost(contactData['visibleTo'], sequence.hostId))) {
|
|
77
|
+
return outreachRefusal(404, 'contact-not-found', "That contact isn't in this sequence's site's CRM.");
|
|
78
|
+
}
|
|
79
|
+
const mailbox = readStoredOutreachMailbox(sequence.mailboxId, (mailboxSnapshot == null ? void 0 : mailboxSnapshot.exists) ? mailboxSnapshot.data() : undefined);
|
|
80
|
+
const sender = mailbox ? {
|
|
81
|
+
name: mailbox.displayName,
|
|
82
|
+
email: mailbox.sendAs || mailbox.email
|
|
83
|
+
} : null;
|
|
84
|
+
const siteName = (host == null ? void 0 : host.exists) ? String((_host_get = host.get('name')) != null ? _host_get : '') : '';
|
|
85
|
+
const merge = contactData ? {
|
|
86
|
+
contact: contactData,
|
|
87
|
+
contactGroupId: consentGroupForHost(caller.org, sequence.hostId).groupId,
|
|
88
|
+
sender,
|
|
89
|
+
site: {
|
|
90
|
+
name: siteName
|
|
91
|
+
}
|
|
92
|
+
} : outreachSampleMergeContext({
|
|
93
|
+
sender,
|
|
94
|
+
siteName
|
|
95
|
+
});
|
|
96
|
+
const personalLine = typeof body['personalLine'] === 'string' ? body['personalLine'] : contactData ? '' : OUTREACH_SAMPLE_PERSON.personalLine;
|
|
97
|
+
const result = previewOutreachStep({
|
|
98
|
+
steps: sequence.steps,
|
|
99
|
+
stepIndex,
|
|
100
|
+
orgSettings,
|
|
101
|
+
merge,
|
|
102
|
+
email: contactData ? (_normalizeContactEmail = normalizeContactEmail(contactData['email'])) != null ? _normalizeContactEmail : '' : OUTREACH_SAMPLE_PERSON.email,
|
|
103
|
+
personalLine,
|
|
104
|
+
templateBody: (template == null ? void 0 : template.exists) ? normalizeCrmEmailTemplate(template.data()).body : null
|
|
105
|
+
});
|
|
106
|
+
return outreachOk({
|
|
107
|
+
ok: true,
|
|
108
|
+
stepIndex,
|
|
109
|
+
subject: (_ref = (_result_email = result.email) == null ? void 0 : _result_email.subject) != null ? _ref : '',
|
|
110
|
+
text: (_ref1 = (_result_email1 = result.email) == null ? void 0 : _result_email1.text) != null ? _ref1 : '',
|
|
111
|
+
unresolvedFields: result.unresolvedFields,
|
|
112
|
+
error: result.error
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
//# sourceMappingURL=preview-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/routes/preview-routes.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 { consentGroupForHost } from '@aglyn/aglyn/app-utils/consent-groups'\nimport { normalizeContactEmail } from '@aglyn/aglyn/app-utils/contacts'\nimport { CRM_COLLECTIONS } from '@aglyn/aglyn/app-utils/crm'\nimport { normalizeCrmEmailTemplate } from '@aglyn/aglyn/app-utils/crm-email-templates'\nimport { visibleToHost } from '@aglyn/aglyn/app-utils/scope-tokens'\nimport type { PluginWebApiHandler } from '@aglyn/aglyn/server'\nimport { firstEmailStepIndex } from '../engine/sequence-validation'\nimport type { OutreachPreviewResponse } from '../model/outreach-api'\nimport {\n OUTREACH_SAMPLE_PERSON,\n outreachSampleMergeContext,\n previewOutreachStep,\n} from '../model/step-preview'\nimport { readOutreachComplianceSettingsDoc } from '../storage/compliance-settings-store'\nimport {\n outreachOrgCollection,\n readStoredOutreachMailbox,\n readStoredOutreachSequence,\n} from '../storage/outreach-records'\nimport { OUTREACH_READS_PEOPLE } from './enroll-routes'\nimport type { OutreachRouteDeps } from './route-deps'\nimport { outreachRouteGate } from './route-gate'\nimport {\n outreachMethodNotAllowed,\n outreachOk,\n outreachRefusal,\n readOutreachDocumentId,\n readOutreachJsonBody,\n} from './route-http'\n\n/**\n * ONE EMAIL OF A SAVED SEQUENCE, AS A PERSON WOULD GET IT (AGL-2980):\n * `outreach/preview`.\n *\n * Written from what is stored — the sequence, the CRM template a step names,\n * the mailbox it sends as, the organization's footer — by the engine's own\n * composer (`previewOutreachStep`), for a real contact with the personal\n * line the rep is writing, or for a sample person. The enroll dialog shows\n * it beside each person before Confirm, so the rep reads the sentence they\n * wrote in the email it goes into.\n *\n * A real contact is read from the CRM, so naming one asks for `data.manage`\n * as enrolling does; the sample person asks for nothing more.\n */\n\nexport function createOutreachPreviewRoute(deps: OutreachRouteDeps): PluginWebApiHandler {\n return async (request) => {\n if (request.method !== 'POST') return outreachMethodNotAllowed('POST')\n const body = await readOutreachJsonBody(request)\n const contactId = body['contactId'] === undefined ? null : readOutreachDocumentId(body['contactId'])\n if (body['contactId'] !== undefined && !contactId) {\n return outreachRefusal(400, 'invalid-request', 'Name the contact to preview for.')\n }\n const caller = await outreachRouteGate(\n request,\n body['orgId'],\n deps.gate,\n contactId ? [OUTREACH_READS_PEOPLE] : [],\n )\n if (caller instanceof Response) return caller\n const sequenceId = readOutreachDocumentId(body['sequenceId'])\n if (!sequenceId) return outreachRefusal(400, 'invalid-request', 'Name the sequence to preview.')\n const firestore = deps.firestore()\n const org = firestore.collection('orgs').doc(caller.orgId)\n const snapshot = await outreachOrgCollection(firestore, caller.orgId, 'sequences').doc(sequenceId).get()\n const sequence = readStoredOutreachSequence(sequenceId, snapshot.exists ? snapshot.data() : undefined)\n if (!sequence) return outreachRefusal(404, 'sequence-not-found', 'That sequence no longer exists.')\n\n const requested = body['stepIndex']\n const stepIndex = typeof requested === 'number' ? requested : firstEmailStepIndex(sequence.steps)\n const step = sequence.steps[stepIndex]\n if (step?.kind !== 'email') {\n return outreachRefusal(400, 'invalid-request', 'That step does not send an email.')\n }\n\n const [orgSettings, mailboxSnapshot, host, template, contact] = await Promise.all([\n readOutreachComplianceSettingsDoc(firestore, caller.orgId),\n sequence.mailboxId ? outreachOrgCollection(firestore, caller.orgId, 'mailboxes').doc(sequence.mailboxId).get() : null,\n sequence.hostId ? firestore.collection('hosts').doc(sequence.hostId).get() : null,\n step.templateId ? org.collection(CRM_COLLECTIONS.emailTemplates).doc(step.templateId).get() : null,\n contactId ? org.collection('contacts').doc(contactId).get() : null,\n ])\n const contactData = contact?.exists ? (contact.data() as Record<string, unknown>) : null\n if (\n contactId &&\n (!contactData || !visibleToHost(contactData['visibleTo'] as string[] | undefined, sequence.hostId))\n ) {\n return outreachRefusal(404, 'contact-not-found', \"That contact isn't in this sequence's site's CRM.\")\n }\n const mailbox = readStoredOutreachMailbox(\n sequence.mailboxId,\n mailboxSnapshot?.exists ? mailboxSnapshot.data() : undefined,\n )\n const sender = mailbox ? { name: mailbox.displayName, email: mailbox.sendAs || mailbox.email } : null\n const siteName = host?.exists ? String(host.get('name') ?? '') : ''\n const merge = contactData\n ? {\n contact: contactData,\n contactGroupId: consentGroupForHost(caller.org, sequence.hostId).groupId,\n sender,\n site: { name: siteName },\n }\n : outreachSampleMergeContext({ sender, siteName })\n const personalLine =\n typeof body['personalLine'] === 'string'\n ? body['personalLine']\n : contactData\n ? ''\n : OUTREACH_SAMPLE_PERSON.personalLine\n const result = previewOutreachStep({\n steps: sequence.steps,\n stepIndex,\n orgSettings,\n merge,\n email: contactData ? (normalizeContactEmail(contactData['email']) ?? '') : OUTREACH_SAMPLE_PERSON.email,\n personalLine,\n templateBody: template?.exists\n ? normalizeCrmEmailTemplate(template.data() as Record<string, unknown>).body\n : null,\n })\n return outreachOk({\n ok: true,\n stepIndex,\n subject: result.email?.subject ?? '',\n text: result.email?.text ?? '',\n unresolvedFields: result.unresolvedFields,\n error: result.error,\n } satisfies OutreachPreviewResponse)\n }\n}\n"],"names":["consentGroupForHost","normalizeContactEmail","CRM_COLLECTIONS","normalizeCrmEmailTemplate","visibleToHost","firstEmailStepIndex","OUTREACH_SAMPLE_PERSON","outreachSampleMergeContext","previewOutreachStep","readOutreachComplianceSettingsDoc","outreachOrgCollection","readStoredOutreachMailbox","readStoredOutreachSequence","OUTREACH_READS_PEOPLE","outreachRouteGate","outreachMethodNotAllowed","outreachOk","outreachRefusal","readOutreachDocumentId","readOutreachJsonBody","createOutreachPreviewRoute","deps","request","host","result","method","body","contactId","undefined","caller","gate","Response","sequenceId","firestore","org","collection","doc","orgId","snapshot","get","sequence","exists","data","requested","stepIndex","steps","step","kind","orgSettings","mailboxSnapshot","template","contact","Promise","all","mailboxId","hostId","templateId","emailTemplates","contactData","mailbox","sender","name","displayName","email","sendAs","siteName","String","merge","contactGroupId","groupId","site","personalLine","templateBody","ok","subject","text","unresolvedFields","error"],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
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 OutreachEnrollRouteDeps } from './enroll-routes';
|
|
18
|
+
import type { OutreachRouteGateDeps } from './route-gate';
|
|
19
|
+
/** The gate's reach into the platform. */
|
|
20
|
+
export declare function defaultOutreachRouteGateDeps(): OutreachRouteGateDeps;
|
|
21
|
+
export declare function defaultOutreachRouteDeps(): OutreachEnrollRouteDeps;
|
|
22
|
+
export declare function registerOutreachRoutes(deps?: OutreachEnrollRouteDeps): void;
|
|
@@ -0,0 +1,92 @@
|
|
|
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 { registerPluginApiRoute } from "@aglyn/aglyn/server";
|
|
17
|
+
import { firebaseAdmin } from "@aglyn/tenant-data-admin/server/firebase-admin";
|
|
18
|
+
import { OUTREACH_API_ROUTES } from "../constants/api-routes.js";
|
|
19
|
+
import { outreachOrgSubject } from "../mailboxes/register-mailbox-routes.js";
|
|
20
|
+
import { createOutreachEnrollRoutes } from "./enroll-routes.js";
|
|
21
|
+
import { createOutreachEnrollmentActionRoute } from "./enrollment-routes.js";
|
|
22
|
+
import { createOutreachPreviewRoute } from "./preview-routes.js";
|
|
23
|
+
import { createOutreachSequenceRoutes } from "./sequence-routes.js";
|
|
24
|
+
import { createOutreachSettingsRoute } from "./settings-routes.js";
|
|
25
|
+
/**
|
|
26
|
+
* Wires the settings, sequence and enrollment routes into the console
|
|
27
|
+
* dispatcher (AGL-2980) with the platform's own dependencies. Specs build
|
|
28
|
+
* their own.
|
|
29
|
+
*
|
|
30
|
+
* Every one names its organization (`orgId`, in the query or the JSON body)
|
|
31
|
+
* and none names a site, so each declares the mailbox routes' subject reader:
|
|
32
|
+
* the dispatcher's release gate then asks about that organization, and a
|
|
33
|
+
* `release_outreach` override for one organization reaches these routes as it
|
|
34
|
+
* reaches Mailboxes. Without it the gate reads the request as anonymous, which
|
|
35
|
+
* only a fully enabled flag or a staff session passes.
|
|
36
|
+
*/ /** The platform's heavier modules, loaded the first time a request needs one. */ const platform = ()=>import("./platform-deps.js");
|
|
37
|
+
/** The gate's reach into the platform. */ export function defaultOutreachRouteGateDeps() {
|
|
38
|
+
return {
|
|
39
|
+
verifyIdToken: (idToken)=>firebaseAdmin.app().auth().verifyIdToken(idToken),
|
|
40
|
+
resolveOrgPermissions: async (uid, context)=>(await platform()).resolveOrgPermissions(uid, context),
|
|
41
|
+
holdsOrgCatalogPermission: async (uid, orgId, key)=>(await platform()).holdsOrgCatalogPermission(uid, orgId, key),
|
|
42
|
+
readOrg: async (orgId)=>{
|
|
43
|
+
var _snapshot_data;
|
|
44
|
+
const snapshot = await firebaseAdmin.app().firestore().collection('orgs').doc(orgId).get();
|
|
45
|
+
return snapshot.exists ? (_snapshot_data = snapshot.data()) != null ? _snapshot_data : {} : null;
|
|
46
|
+
},
|
|
47
|
+
lockdownRefusal: async (options)=>(await platform()).lockdownRefusal(options)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function defaultOutreachRouteDeps() {
|
|
51
|
+
return {
|
|
52
|
+
firestore: ()=>firebaseAdmin.app().firestore(),
|
|
53
|
+
gate: defaultOutreachRouteGateDeps(),
|
|
54
|
+
now: Date.now,
|
|
55
|
+
random: Math.random,
|
|
56
|
+
logOrgActivity: async (orgId, actor, action, target)=>(await platform()).logOrgActivity(orgId, actor, action, target),
|
|
57
|
+
crmViewEmails: async (input)=>(await platform()).crmViewEmails(input)
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function registerOutreachRoutes(deps = defaultOutreachRouteDeps()) {
|
|
61
|
+
const sequences = createOutreachSequenceRoutes(deps);
|
|
62
|
+
const enroll = createOutreachEnrollRoutes(deps);
|
|
63
|
+
const orgSubject = {
|
|
64
|
+
subject: outreachOrgSubject
|
|
65
|
+
};
|
|
66
|
+
registerPluginApiRoute(OUTREACH_API_ROUTES.settings, {
|
|
67
|
+
web: createOutreachSettingsRoute(deps)
|
|
68
|
+
}, orgSubject);
|
|
69
|
+
registerPluginApiRoute(OUTREACH_API_ROUTES.sequencesSave, {
|
|
70
|
+
web: sequences.save
|
|
71
|
+
}, orgSubject);
|
|
72
|
+
registerPluginApiRoute(OUTREACH_API_ROUTES.sequencesStatus, {
|
|
73
|
+
web: sequences.status
|
|
74
|
+
}, orgSubject);
|
|
75
|
+
registerPluginApiRoute(OUTREACH_API_ROUTES.sequencesDelete, {
|
|
76
|
+
web: sequences.remove
|
|
77
|
+
}, orgSubject);
|
|
78
|
+
registerPluginApiRoute(OUTREACH_API_ROUTES.enrollPreview, {
|
|
79
|
+
web: enroll.preview
|
|
80
|
+
}, orgSubject);
|
|
81
|
+
registerPluginApiRoute(OUTREACH_API_ROUTES.enroll, {
|
|
82
|
+
web: enroll.confirm
|
|
83
|
+
}, orgSubject);
|
|
84
|
+
registerPluginApiRoute(OUTREACH_API_ROUTES.enrollmentsAction, {
|
|
85
|
+
web: createOutreachEnrollmentActionRoute(deps)
|
|
86
|
+
}, orgSubject);
|
|
87
|
+
registerPluginApiRoute(OUTREACH_API_ROUTES.preview, {
|
|
88
|
+
web: createOutreachPreviewRoute(deps)
|
|
89
|
+
}, orgSubject);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//# sourceMappingURL=register-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/routes/register-routes.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 { registerPluginApiRoute } from '@aglyn/aglyn/server'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin/server/firebase-admin'\nimport { OUTREACH_API_ROUTES } from '../constants/api-routes'\nimport { outreachOrgSubject } from '../mailboxes/register-mailbox-routes'\nimport { createOutreachEnrollRoutes, type OutreachEnrollRouteDeps } from './enroll-routes'\nimport { createOutreachEnrollmentActionRoute } from './enrollment-routes'\nimport { createOutreachPreviewRoute } from './preview-routes'\nimport type { OutreachRouteGateDeps } from './route-gate'\nimport { createOutreachSequenceRoutes } from './sequence-routes'\nimport { createOutreachSettingsRoute } from './settings-routes'\n\n/**\n * Wires the settings, sequence and enrollment routes into the console\n * dispatcher (AGL-2980) with the platform's own dependencies. Specs build\n * their own.\n *\n * Every one names its organization (`orgId`, in the query or the JSON body)\n * and none names a site, so each declares the mailbox routes' subject reader:\n * the dispatcher's release gate then asks about that organization, and a\n * `release_outreach` override for one organization reaches these routes as it\n * reaches Mailboxes. Without it the gate reads the request as anonymous, which\n * only a fully enabled flag or a staff session passes.\n */\n\n/** The platform's heavier modules, loaded the first time a request needs one. */\nconst platform = () => import('./platform-deps')\n\n/** The gate's reach into the platform. */\nexport function defaultOutreachRouteGateDeps(): OutreachRouteGateDeps {\n return {\n verifyIdToken: (idToken) => firebaseAdmin.app().auth().verifyIdToken(idToken),\n resolveOrgPermissions: async (uid, context) => (await platform()).resolveOrgPermissions(uid, context),\n holdsOrgCatalogPermission: async (uid, orgId, key) =>\n (await platform()).holdsOrgCatalogPermission(uid, orgId, key),\n readOrg: async (orgId) => {\n const snapshot = await firebaseAdmin.app().firestore().collection('orgs').doc(orgId).get()\n return snapshot.exists ? (snapshot.data() ?? {}) : null\n },\n lockdownRefusal: async (options) => (await platform()).lockdownRefusal(options),\n }\n}\n\nexport function defaultOutreachRouteDeps(): OutreachEnrollRouteDeps {\n return {\n firestore: () => firebaseAdmin.app().firestore(),\n gate: defaultOutreachRouteGateDeps(),\n now: Date.now,\n random: Math.random,\n logOrgActivity: async (orgId, actor, action, target) =>\n (await platform()).logOrgActivity(orgId, actor, action, target),\n crmViewEmails: async (input) => (await platform()).crmViewEmails(input),\n }\n}\n\nexport function registerOutreachRoutes(\n deps: OutreachEnrollRouteDeps = defaultOutreachRouteDeps(),\n): void {\n const sequences = createOutreachSequenceRoutes(deps)\n const enroll = createOutreachEnrollRoutes(deps)\n const orgSubject = { subject: outreachOrgSubject }\n registerPluginApiRoute(OUTREACH_API_ROUTES.settings, { web: createOutreachSettingsRoute(deps) }, orgSubject)\n registerPluginApiRoute(OUTREACH_API_ROUTES.sequencesSave, { web: sequences.save }, orgSubject)\n registerPluginApiRoute(OUTREACH_API_ROUTES.sequencesStatus, { web: sequences.status }, orgSubject)\n registerPluginApiRoute(OUTREACH_API_ROUTES.sequencesDelete, { web: sequences.remove }, orgSubject)\n registerPluginApiRoute(OUTREACH_API_ROUTES.enrollPreview, { web: enroll.preview }, orgSubject)\n registerPluginApiRoute(OUTREACH_API_ROUTES.enroll, { web: enroll.confirm }, orgSubject)\n registerPluginApiRoute(\n OUTREACH_API_ROUTES.enrollmentsAction,\n { web: createOutreachEnrollmentActionRoute(deps) },\n orgSubject,\n )\n registerPluginApiRoute(OUTREACH_API_ROUTES.preview, { web: createOutreachPreviewRoute(deps) }, orgSubject)\n}\n"],"names":["registerPluginApiRoute","firebaseAdmin","OUTREACH_API_ROUTES","outreachOrgSubject","createOutreachEnrollRoutes","createOutreachEnrollmentActionRoute","createOutreachPreviewRoute","createOutreachSequenceRoutes","createOutreachSettingsRoute","platform","defaultOutreachRouteGateDeps","verifyIdToken","idToken","app","auth","resolveOrgPermissions","uid","context","holdsOrgCatalogPermission","orgId","key","readOrg","snapshot","firestore","collection","doc","get","exists","data","lockdownRefusal","options","defaultOutreachRouteDeps","gate","now","Date","random","Math","logOrgActivity","actor","action","target","crmViewEmails","input","registerOutreachRoutes","deps","sequences","enroll","orgSubject","subject","settings","web","sequencesSave","save","sequencesStatus","status","sequencesDelete","remove","enrollPreview","preview","confirm","enrollmentsAction"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,sBAAsB,QAAQ,sBAAqB;AAC5D,SAASC,aAAa,QAAQ,iDAAgD;AAC9E,SAASC,mBAAmB,QAAQ,6BAAyB;AAC7D,SAASC,kBAAkB,QAAQ,0CAAsC;AACzE,SAASC,0BAA0B,QAAsC,qBAAiB;AAC1F,SAASC,mCAAmC,QAAQ,yBAAqB;AACzE,SAASC,0BAA0B,QAAQ,sBAAkB;AAE7D,SAASC,4BAA4B,QAAQ,uBAAmB;AAChE,SAASC,2BAA2B,QAAQ,uBAAmB;AAE/D;;;;;;;;;;;CAWC,GAED,+EAA+E,GAC/E,MAAMC,WAAW,IAAM,MAAM,CAAC;AAE9B,wCAAwC,GACxC,OAAO,SAASC;IACd,OAAO;QACLC,eAAe,CAACC,UAAYX,cAAcY,GAAG,GAAGC,IAAI,GAAGH,aAAa,CAACC;QACrEG,uBAAuB,OAAOC,KAAKC,UAAY,AAAC,CAAA,MAAMR,UAAS,EAAGM,qBAAqB,CAACC,KAAKC;QAC7FC,2BAA2B,OAAOF,KAAKG,OAAOC,MAC5C,AAAC,CAAA,MAAMX,UAAS,EAAGS,yBAAyB,CAACF,KAAKG,OAAOC;QAC3DC,SAAS,OAAOF;gBAEYG;YAD1B,MAAMA,WAAW,MAAMrB,cAAcY,GAAG,GAAGU,SAAS,GAAGC,UAAU,CAAC,QAAQC,GAAG,CAACN,OAAOO,GAAG;YACxF,OAAOJ,SAASK,MAAM,IAAIL,iBAAAA,SAASM,IAAI,cAAbN,iBAAmB,CAAC,IAAK;QACrD;QACAO,iBAAiB,OAAOC,UAAY,AAAC,CAAA,MAAMrB,UAAS,EAAGoB,eAAe,CAACC;IACzE;AACF;AAEA,OAAO,SAASC;IACd,OAAO;QACLR,WAAW,IAAMtB,cAAcY,GAAG,GAAGU,SAAS;QAC9CS,MAAMtB;QACNuB,KAAKC,KAAKD,GAAG;QACbE,QAAQC,KAAKD,MAAM;QACnBE,gBAAgB,OAAOlB,OAAOmB,OAAOC,QAAQC,SAC3C,AAAC,CAAA,MAAM/B,UAAS,EAAG4B,cAAc,CAAClB,OAAOmB,OAAOC,QAAQC;QAC1DC,eAAe,OAAOC,QAAU,AAAC,CAAA,MAAMjC,UAAS,EAAGgC,aAAa,CAACC;IACnE;AACF;AAEA,OAAO,SAASC,uBACdC,OAAgCb,0BAA0B;IAE1D,MAAMc,YAAYtC,6BAA6BqC;IAC/C,MAAME,SAAS1C,2BAA2BwC;IAC1C,MAAMG,aAAa;QAAEC,SAAS7C;IAAmB;IACjDH,uBAAuBE,oBAAoB+C,QAAQ,EAAE;QAAEC,KAAK1C,4BAA4BoC;IAAM,GAAGG;IACjG/C,uBAAuBE,oBAAoBiD,aAAa,EAAE;QAAED,KAAKL,UAAUO,IAAI;IAAC,GAAGL;IACnF/C,uBAAuBE,oBAAoBmD,eAAe,EAAE;QAAEH,KAAKL,UAAUS,MAAM;IAAC,GAAGP;IACvF/C,uBAAuBE,oBAAoBqD,eAAe,EAAE;QAAEL,KAAKL,UAAUW,MAAM;IAAC,GAAGT;IACvF/C,uBAAuBE,oBAAoBuD,aAAa,EAAE;QAAEP,KAAKJ,OAAOY,OAAO;IAAC,GAAGX;IACnF/C,uBAAuBE,oBAAoB4C,MAAM,EAAE;QAAEI,KAAKJ,OAAOa,OAAO;IAAC,GAAGZ;IAC5E/C,uBACEE,oBAAoB0D,iBAAiB,EACrC;QAAEV,KAAK7C,oCAAoCuC;IAAM,GACjDG;IAEF/C,uBAAuBE,oBAAoBwD,OAAO,EAAE;QAAER,KAAK5C,2BAA2BsC;IAAM,GAAGG;AACjG"}
|
|
@@ -0,0 +1,49 @@
|
|
|
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 { OutreachRouteGateDeps } from './route-gate';
|
|
18
|
+
/**
|
|
19
|
+
* What the settings, sequence and enrollment routes reach outside this
|
|
20
|
+
* plugin (AGL-2980). The platform's own are `register-routes.ts`; specs
|
|
21
|
+
* build their own.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* The org activity target a sequence's rows are filed under: Outreach's own
|
|
25
|
+
* namespaced resource (`pluginId:noun`), which the feed reads as "Sequence".
|
|
26
|
+
* Core's target list names only core's resources, so a plugin's never joins
|
|
27
|
+
* it.
|
|
28
|
+
*/
|
|
29
|
+
export declare const OUTREACH_SEQUENCE_ACTIVITY_TARGET = "outreach:sequence";
|
|
30
|
+
/** What an org activity line written by these routes points at. */
|
|
31
|
+
export type OutreachActivityTarget = {
|
|
32
|
+
type: 'org';
|
|
33
|
+
id: string;
|
|
34
|
+
} | {
|
|
35
|
+
type: typeof OUTREACH_SEQUENCE_ACTIVITY_TARGET;
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
};
|
|
39
|
+
export interface OutreachRouteDeps {
|
|
40
|
+
firestore(): FirebaseFirestore.Firestore;
|
|
41
|
+
gate: OutreachRouteGateDeps;
|
|
42
|
+
now(): number;
|
|
43
|
+
/** A source of numbers in `[0, 1)` — the scheduler's jitter. */
|
|
44
|
+
random(): number;
|
|
45
|
+
logOrgActivity(orgId: string, actor: {
|
|
46
|
+
uid: string;
|
|
47
|
+
email?: string | null;
|
|
48
|
+
}, action: string, target: OutreachActivityTarget): Promise<void>;
|
|
49
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
* What the settings, sequence and enrollment routes reach outside this
|
|
18
|
+
* plugin (AGL-2980). The platform's own are `register-routes.ts`; specs
|
|
19
|
+
* build their own.
|
|
20
|
+
*/ /**
|
|
21
|
+
* The org activity target a sequence's rows are filed under: Outreach's own
|
|
22
|
+
* namespaced resource (`pluginId:noun`), which the feed reads as "Sequence".
|
|
23
|
+
* Core's target list names only core's resources, so a plugin's never joins
|
|
24
|
+
* it.
|
|
25
|
+
*/ export const OUTREACH_SEQUENCE_ACTIVITY_TARGET = 'outreach:sequence';
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=route-deps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/routes/route-deps.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 type { OutreachRouteGateDeps } from './route-gate'\n\n/**\n * What the settings, sequence and enrollment routes reach outside this\n * plugin (AGL-2980). The platform's own are `register-routes.ts`; specs\n * build their own.\n */\n\n/**\n * The org activity target a sequence's rows are filed under: Outreach's own\n * namespaced resource (`pluginId:noun`), which the feed reads as \"Sequence\".\n * Core's target list names only core's resources, so a plugin's never joins\n * it.\n */\nexport const OUTREACH_SEQUENCE_ACTIVITY_TARGET = 'outreach:sequence'\n\n/** What an org activity line written by these routes points at. */\nexport type OutreachActivityTarget =\n | { type: 'org'; id: string }\n | { type: typeof OUTREACH_SEQUENCE_ACTIVITY_TARGET; id: string; name: string }\n\nexport interface OutreachRouteDeps {\n firestore(): FirebaseFirestore.Firestore\n gate: OutreachRouteGateDeps\n now(): number\n /** A source of numbers in `[0, 1)` — the scheduler's jitter. */\n random(): number\n logOrgActivity(\n orgId: string,\n actor: { uid: string; email?: string | null },\n action: string,\n target: OutreachActivityTarget,\n ): Promise<void>\n}\n"],"names":["OUTREACH_SEQUENCE_ACTIVITY_TARGET"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAID;;;;CAIC,GAED;;;;;CAKC,GACD,OAAO,MAAMA,oCAAoC,oBAAmB"}
|
|
@@ -0,0 +1,94 @@
|
|
|
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 { DecodedIdToken } from 'firebase-admin/auth';
|
|
18
|
+
/**
|
|
19
|
+
* THE GATE EVERY SETTINGS, SEQUENCE AND ENROLLMENT ROUTE CLIMBS (AGL-2980).
|
|
20
|
+
*
|
|
21
|
+
* The console dispatcher has already refused a request while
|
|
22
|
+
* `release_outreach` is off for it, an unverified account's token, a
|
|
23
|
+
* lockdown with no org in scope, and a caller over the console rate limit —
|
|
24
|
+
* every route here is registered under the `outreach/` prefix, which is what
|
|
25
|
+
* puts it behind those. What the dispatcher cannot know is anything about
|
|
26
|
+
* the member, so each rung below is this plugin's:
|
|
27
|
+
*
|
|
28
|
+
* 401 no bearer token, or one the verifier refused
|
|
29
|
+
* 403 the account's address is unverified (an impersonation session is exempt)
|
|
30
|
+
* 400 the request did not name an organization
|
|
31
|
+
* 403 not a member of it, a site collaborator without org-wide reach, or
|
|
32
|
+
* without `outreach.use` — or without a permission the route adds
|
|
33
|
+
* 403 the organization does not hold the `outreach` entitlement
|
|
34
|
+
* 423 lockdown, now with the organization and the account in scope
|
|
35
|
+
*
|
|
36
|
+
* The reach is org-wide for the reason the rules give: a sequence enrolls
|
|
37
|
+
* people from every site of the organization, so none of it is a fact
|
|
38
|
+
* about the one site a collaborator was invited to.
|
|
39
|
+
*
|
|
40
|
+
* `resolveOrgPermissions` is always given the concrete org id. Called
|
|
41
|
+
* without one it resolves a caller with no org at all as that future org's
|
|
42
|
+
* owner, which is right for a fresh signup and wrong for every question
|
|
43
|
+
* asked here.
|
|
44
|
+
*/
|
|
45
|
+
export interface OutreachRouteGateDeps {
|
|
46
|
+
verifyIdToken(idToken: string): Promise<DecodedIdToken>;
|
|
47
|
+
resolveOrgPermissions(uid: string, context: {
|
|
48
|
+
orgId: string;
|
|
49
|
+
}): Promise<{
|
|
50
|
+
orgId: string | null;
|
|
51
|
+
/** `null` when the account is not on the organization's roster. */
|
|
52
|
+
role: string | null;
|
|
53
|
+
isOwner: boolean;
|
|
54
|
+
orgWide: boolean;
|
|
55
|
+
permissions: Partial<Record<string, boolean | undefined>>;
|
|
56
|
+
}>;
|
|
57
|
+
/**
|
|
58
|
+
* Whether the member holds a CATALOG permission (`data.manage`) as the
|
|
59
|
+
* org's roles resolve it. Asked separately because the map
|
|
60
|
+
* `resolveOrgPermissions` answers carries the legacy keys and the plugins'
|
|
61
|
+
* own, never a catalog key: read there, a catalog key refuses everyone.
|
|
62
|
+
*/
|
|
63
|
+
holdsOrgCatalogPermission(uid: string, orgId: string, key: string): Promise<boolean>;
|
|
64
|
+
readOrg(orgId: string): Promise<Record<string, unknown> | null>;
|
|
65
|
+
lockdownRefusal(options: {
|
|
66
|
+
request: Request;
|
|
67
|
+
staff: boolean;
|
|
68
|
+
uid: string;
|
|
69
|
+
org: Record<string, unknown>;
|
|
70
|
+
}): Promise<Response | null>;
|
|
71
|
+
}
|
|
72
|
+
/** Who is asking, once the gate let them through. */
|
|
73
|
+
export interface OutreachRouteCaller {
|
|
74
|
+
uid: string;
|
|
75
|
+
/** The account's sign-in address, lower-cased, when the token carries one. */
|
|
76
|
+
email: string | null;
|
|
77
|
+
staff: boolean;
|
|
78
|
+
orgId: string;
|
|
79
|
+
/** The organization document the entitlement was read from. */
|
|
80
|
+
org: Record<string, unknown>;
|
|
81
|
+
/** An owner or admin of the organization, who may send from any member's mailbox. */
|
|
82
|
+
isOrgAdmin: boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* A catalog permission a route asks for beyond `outreach.use`, with its
|
|
86
|
+
* refusal — `data.manage` for a route that reads the CRM's people, which
|
|
87
|
+
* the contacts' own rules gate on.
|
|
88
|
+
*/
|
|
89
|
+
export interface OutreachRouteExtraPermission {
|
|
90
|
+
key: string;
|
|
91
|
+
/** Why the route needs it, as the refusal says it. */
|
|
92
|
+
refusal: string;
|
|
93
|
+
}
|
|
94
|
+
export declare function outreachRouteGate(request: Request, rawOrgId: unknown, deps: OutreachRouteGateDeps, extra?: readonly OutreachRouteExtraPermission[]): Promise<Response | OutreachRouteCaller>;
|