@aglyn/plugins-outreach 1.0.0-beta.220 → 1.0.0-beta.222
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/package.json +14 -14
- package/src/lib/components/do-not-contact-domains.d.ts +6 -2
- package/src/lib/components/do-not-contact-domains.js +73 -11
- package/src/lib/components/do-not-contact-domains.js.map +1 -1
- package/src/lib/components/enrollments-table.d.ts +6 -0
- package/src/lib/components/enrollments-table.js +77 -4
- package/src/lib/components/enrollments-table.js.map +1 -1
- package/src/lib/components/sequence-detail.js +3 -1
- package/src/lib/components/sequence-detail.js.map +1 -1
- package/src/lib/components/sequence-report-card.js +7 -3
- package/src/lib/components/sequence-report-card.js.map +1 -1
- package/src/lib/components/use-outreach-crm.d.ts +18 -15
- package/src/lib/components/use-outreach-crm.js +118 -87
- package/src/lib/components/use-outreach-crm.js.map +1 -1
- package/src/lib/components/use-outreach-data.d.ts +2 -2
- package/src/lib/components/use-outreach-data.js.map +1 -1
- package/src/lib/constants/transfer-resources.d.ts +33 -0
- package/src/lib/constants/transfer-resources.js +38 -0
- package/src/lib/constants/transfer-resources.js.map +1 -0
- package/src/lib/declarations.console-server.d.ts +7 -1
- package/src/lib/declarations.console-server.js +66 -1
- package/src/lib/declarations.console-server.js.map +1 -1
- package/src/lib/engine/click-tracking.js +1 -1
- package/src/lib/engine/click-tracking.js.map +1 -1
- package/src/lib/engine/ip-range.d.ts +26 -0
- package/src/lib/engine/ip-range.js +78 -0
- package/src/lib/engine/ip-range.js.map +1 -0
- package/src/lib/engine/open-source.d.ts +24 -0
- package/src/lib/engine/open-source.js +130 -0
- package/src/lib/engine/open-source.js.map +1 -0
- package/src/lib/engine/open-tracking.d.ts +15 -2
- package/src/lib/engine/open-tracking.js +59 -16
- package/src/lib/engine/open-tracking.js.map +1 -1
- package/src/lib/engine/outreach-access.d.ts +47 -0
- package/src/lib/engine/outreach-access.js +56 -0
- package/src/lib/engine/outreach-access.js.map +1 -0
- package/src/lib/enrollment/enroll-people.d.ts +10 -10
- package/src/lib/enrollment/enroll-people.js +30 -25
- package/src/lib/enrollment/enroll-people.js.map +1 -1
- package/src/lib/enrollment/gate-lookups.js +30 -15
- package/src/lib/enrollment/gate-lookups.js.map +1 -1
- package/src/lib/enrollment/message-templates.d.ts +24 -0
- package/src/lib/enrollment/message-templates.js +35 -0
- package/src/lib/enrollment/message-templates.js.map +1 -0
- package/src/lib/model/enrollment-engagement.d.ts +16 -0
- package/src/lib/model/enrollment-engagement.js +16 -0
- package/src/lib/model/enrollment-engagement.js.map +1 -1
- package/src/lib/model/enrollment-history.d.ts +8 -1
- package/src/lib/model/enrollment-history.js +17 -5
- package/src/lib/model/enrollment-history.js.map +1 -1
- package/src/lib/model/enrollment-timeline.d.ts +3 -0
- package/src/lib/model/enrollment-timeline.js +15 -4
- package/src/lib/model/enrollment-timeline.js.map +1 -1
- package/src/lib/model/outreach.types.d.ts +12 -3
- package/src/lib/model/outreach.types.js +12 -1
- package/src/lib/model/outreach.types.js.map +1 -1
- package/src/lib/model/sequence-report.d.ts +14 -7
- package/src/lib/model/sequence-report.js +12 -8
- package/src/lib/model/sequence-report.js.map +1 -1
- package/src/lib/plugin.js +18 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/routes/curate-routes.js +4 -6
- package/src/lib/routes/curate-routes.js.map +1 -1
- package/src/lib/routes/enroll-routes.d.ts +0 -12
- package/src/lib/routes/enroll-routes.js +52 -92
- package/src/lib/routes/enroll-routes.js.map +1 -1
- package/src/lib/routes/platform-deps.d.ts +4 -16
- package/src/lib/routes/platform-deps.js +5 -25
- package/src/lib/routes/platform-deps.js.map +1 -1
- package/src/lib/routes/preview-routes.js +25 -13
- package/src/lib/routes/preview-routes.js.map +1 -1
- package/src/lib/routes/register-routes.js +7 -5
- package/src/lib/routes/register-routes.js.map +1 -1
- package/src/lib/routes/route-gate.js +6 -17
- package/src/lib/routes/route-gate.js.map +1 -1
- package/src/lib/routes/sequence-routes.d.ts +46 -0
- package/src/lib/routes/sequence-routes.js +155 -63
- package/src/lib/routes/sequence-routes.js.map +1 -1
- package/src/lib/runtime/click-events.js +8 -8
- package/src/lib/runtime/click-events.js.map +1 -1
- package/src/lib/runtime/click-route.js +5 -2
- package/src/lib/runtime/click-route.js.map +1 -1
- package/src/lib/runtime/lead-records.d.ts +18 -10
- package/src/lib/runtime/lead-records.js +14 -60
- package/src/lib/runtime/lead-records.js.map +1 -1
- package/src/lib/runtime/open-events.d.ts +8 -0
- package/src/lib/runtime/open-events.js +10 -3
- package/src/lib/runtime/open-events.js.map +1 -1
- package/src/lib/runtime/platform-runtime-deps.d.ts +9 -5
- package/src/lib/runtime/platform-runtime-deps.js +31 -24
- package/src/lib/runtime/platform-runtime-deps.js.map +1 -1
- package/src/lib/runtime/send-job.js +20 -17
- package/src/lib/runtime/send-job.js.map +1 -1
- package/src/lib/runtime/sync-job.js +10 -5
- package/src/lib/runtime/sync-job.js.map +1 -1
- package/src/lib/storage/do-not-contact-store.d.ts +8 -0
- package/src/lib/storage/do-not-contact-store.js +13 -0
- package/src/lib/storage/do-not-contact-store.js.map +1 -1
- package/src/lib/testing/stand-in-record-system.d.ts +54 -0
- package/src/lib/testing/stand-in-record-system.js +243 -0
- package/src/lib/testing/stand-in-record-system.js.map +1 -0
- package/src/lib/transfer/do-not-contact-transfer.d.ts +129 -0
- package/src/lib/transfer/do-not-contact-transfer.js +801 -0
- package/src/lib/transfer/do-not-contact-transfer.js.map +1 -0
- package/src/lib/transfer/plan-gate.d.ts +25 -0
- package/src/lib/transfer/plan-gate.js +35 -0
- package/src/lib/transfer/plan-gate.js.map +1 -0
- package/src/lib/transfer/platform-transfer-deps.d.ts +24 -0
- package/src/lib/transfer/platform-transfer-deps.js +39 -0
- package/src/lib/transfer/platform-transfer-deps.js.map +1 -0
- package/src/lib/transfer/sequences-package.d.ts +48 -0
- package/src/lib/transfer/sequences-package.js +93 -0
- package/src/lib/transfer/sequences-package.js.map +1 -0
- package/src/lib/transfer/sequences-package.server.d.ts +31 -0
- package/src/lib/transfer/sequences-package.server.js +207 -0
- package/src/lib/transfer/sequences-package.server.js.map +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/transfer/do-not-contact-transfer.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 { normalizeContactEmail } from '@aglyn/aglyn/app-utils/contacts'\nimport { isPublicMailboxDomain } from '@aglyn/aglyn/app-utils/crm'\nimport { nameSearchNormalizers } from '@aglyn/aglyn/app-utils/name-search'\nimport {\n buildTransferPlan,\n matchLookupKey,\n planTransferUndo,\n TRANSFER_ID_FIELD,\n transferIdField,\n withTransferResourceFindings,\n type BuildTransferPlanInput,\n type MatchLookupRequest,\n type PlannedTransferRow,\n type RowMatchOutcome,\n type TransferCatalogInput,\n type TransferField,\n type TransferLockedRule,\n type TransferPlan,\n type TransferPolicy,\n type TransferResourceFinding,\n type TransferRowResult,\n type TransferUndoEntry,\n type TransferUndoStep,\n} from '@aglyn/aglyn/data-transfer'\nimport type {\n PluginTransferResource,\n TransferReadOptions,\n TransferRecordsHooks,\n TransferResourceContext,\n} from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources'\nimport {\n LIST_QUERY_ID_PATH,\n planListQuery,\n type ListQueryPlan,\n type ListQueryRequest,\n} from '@aglyn/shared-ui-jsx/const/list-query-plan'\nimport { applyListQuery } from '@aglyn/tenant-data-admin/server/list-query'\nimport { FieldPath } from 'firebase-admin/firestore'\nimport { OUTREACH_DNC_MATCH_KEYS } from '../constants/transfer-resources'\nimport { outreachDoNotContactKey } from '../engine/do-not-contact'\nimport { normalizeOutreachDomain, outreachEmailDomain } from '../engine/do-not-contact-domain'\nimport {\n outreachEntitlementRefusal,\n outreachMembershipRefusal,\n type OutreachMembership,\n} from '../engine/outreach-access'\nimport { OUTREACH_DO_NOT_CONTACT_DOMAIN_LIST_QUERY } from '../model/do-not-contact-domain-list-query'\nimport {\n OUTREACH_DO_NOT_CONTACT_REASON_LABELS,\n OUTREACH_DO_NOT_CONTACT_SOURCE_LABELS,\n type OutreachDoNotContactEntry,\n} from '../model/outreach.types'\nimport {\n addOutreachDoNotContact,\n addOutreachDoNotContactDomain,\n lookupOutreachDoNotContactDomains,\n outreachDoNotContactCollection,\n outreachDoNotContactDomainCollection,\n readOutreachDoNotContactDomainEntry,\n readOutreachDoNotContactEntry,\n removeOutreachDoNotContactDomain,\n removeOutreachDoNotContactEntry,\n} from '../storage/do-not-contact-store'\n\n/**\n * THE DO-NOT-CONTACT LIST AS A FILE: `outreach.do-not-contact`, an\n * organization's addresses and domains that no sequence emails.\n *\n * ## One file, two collections\n *\n * A row is one entry, and its Entry cell says which kind: an email address\n * goes to `orgs/{orgId}/outreachDoNotContact/{key}`, anything else that reads\n * as a domain to `orgs/{orgId}/outreachDoNotContactDomains/{domain}`. The\n * Aglyn ID names the kind too — `domain:<domain>` or `address:<key>` — so a\n * re-imported export finds its entries by id.\n *\n * ## Only ever added to\n *\n * Every entry is written once and never edited (the store's `create()`), and\n * the first reason an entry was added is the record of why it is there. An\n * import keeps that: a row that finds an entry already on the list is\n * skipped whatever the wizard's policy says (`plan` forces it), and only the\n * entries an import ADDED are taken off again by its undo.\n *\n * ## Addresses go in and never come out\n *\n * An address entry stores the address's fingerprint, never the address, so\n * the list keeps a promise not to email someone without holding who they\n * are. An export therefore reads domains only: an address cannot be read\n * back out of its fingerprint.\n *\n * ## The same door as the Compliance page\n *\n * Every hook asks what the route gate asks — a member of this organization\n * with reach over all of it, holding Use Sequences, in a workspace whose plan\n * includes Sequences — through the same verdicts (`engine/outreach-access.ts`).\n * A plan refuses every row for a member who would be refused, `apply` asks\n * again before it writes, a read answers nothing, and undo stops. Writes go\n * through the store's own adders, as a member's would: reason `manual`,\n * source `member`, the member as `addedByUid`. Each written chunk files one\n * line in the organization's activity log, as the page's add does per entry.\n */\n\n/** The fields' ids. */\nexport const OUTREACH_DNC_FIELDS = {\n entry: 'entry',\n kind: 'kind',\n note: 'note',\n reason: 'reason',\n source: 'source',\n addedByUid: 'addedByUid',\n addedAt: 'addedAt',\n sequenceId: 'sequenceId',\n} as const\n\nconst DOMAIN_ID = 'domain:'\nconst ADDRESS_ID = 'address:'\n\n/** Why a file never changes an entry already on the list. */\nexport const OUTREACH_DNC_ADD_ONLY_REASON =\n 'The do-not-contact list only grows from a file: an entry already on it is left as it is.'\n\n/** The activity lines an import and its undo file, one per chunk written or reverted. */\nexport const OUTREACH_DO_NOT_CONTACT_IMPORT_ACTIVITY = {\n add: (counts: EntryCounts) => `Imported ${countWords(counts)} to the Sequences do-not-contact list`,\n undo: (counts: EntryCounts) =>\n `Undid an import: removed ${countWords(counts)} from the Sequences do-not-contact list`,\n} as const\n\n/** How many of each kind a chunk wrote or removed. */\nexport interface EntryCounts {\n domains: number\n addresses: number\n}\n\nfunction countWords(counts: EntryCounts): string {\n const parts: string[] = []\n if (counts.domains) parts.push(`${counts.domains} ${counts.domains === 1 ? 'domain' : 'domains'}`)\n if (counts.addresses) parts.push(`${counts.addresses} ${counts.addresses === 1 ? 'address' : 'addresses'}`)\n return parts.join(' and ')\n}\n\n/** `getAll` takes this many references at most per call. */\nconst GET_ALL_CHUNK = 300\n\n/** The most rows one export page reads. */\nconst PAGE_MAX = 1000\nconst PAGE_DEFAULT = 500\n\n/** A row is not started with less than this left of the chunk's budget. */\nconst ROW_BUDGET_MS = 2_000\n\n/*==========================================\n * WHAT AN ENTRY CELL NAMES\n *=========================================*/\n\n/** The entry a cell or an id names: an address, by its key, or a domain. */\nexport type OutreachDoNotContactTarget =\n | { kind: 'address'; id: string; key: string; email: string | null }\n | { kind: 'domain'; id: string; domain: string }\n\n/**\n * The entry a cell names, or `null` for a value that is neither an address\n * nor a domain. An address-looking value that is not a usable address is\n * refused rather than read as its domain: a typo in one address must not\n * block a whole company.\n */\nexport function outreachDoNotContactTarget(value: unknown): OutreachDoNotContactTarget | null {\n let text = String(value ?? '').trim()\n // `Casey Morgan <casey@example.com>`, as a mail client copies it.\n const bracketed = /<([^<>]+)>\\s*$/.exec(text)\n if (bracketed) text = bracketed[1].trim()\n text = text.replace(/^mailto:/i, '')\n if (!text) return null\n const email = normalizeContactEmail(text)\n if (email) {\n const key = outreachDoNotContactKey(email)\n return key ? { kind: 'address', id: `${ADDRESS_ID}${key}`, key, email } : null\n }\n if (text.includes('@') && !text.startsWith('@')) return null\n const domain = normalizeOutreachDomain(text)\n return domain ? { kind: 'domain', id: `${DOMAIN_ID}${domain}`, domain } : null\n}\n\n/** The entry an Aglyn ID names, or `null`. */\nexport function outreachDoNotContactTargetFromId(id: unknown): OutreachDoNotContactTarget | null {\n const text = String(id ?? '').trim()\n if (text.startsWith(DOMAIN_ID)) {\n const domain = normalizeOutreachDomain(text.slice(DOMAIN_ID.length))\n return domain ? { kind: 'domain', id: `${DOMAIN_ID}${domain}`, domain } : null\n }\n if (text.startsWith(ADDRESS_ID)) {\n const key = text.slice(ADDRESS_ID.length).toLowerCase()\n return /^[0-9a-f]{64}$/.test(key) ? { kind: 'address', id: `${ADDRESS_ID}${key}`, key, email: null } : null\n }\n return null\n}\n\n/*==========================================\n * THE CATALOG\n *=========================================*/\n\nconst ENTRY_GROUP = { id: 'entry', label: 'Entry' }\n\nconst STANDARD_FIELDS: TransferField[] = [\n {\n id: OUTREACH_DNC_FIELDS.entry,\n label: 'Entry',\n group: ENTRY_GROUP.id,\n type: 'text',\n required: true,\n matchKey: true,\n maxLength: 320,\n aliases: ['email', 'email address', 'address', 'domain', 'website', 'do not contact', 'do-not-contact'],\n description:\n 'An email address or a domain. A domain blocks every address at it. An address is kept as a fingerprint, so it is never exported.',\n },\n {\n id: OUTREACH_DNC_FIELDS.note,\n label: 'Note',\n group: ENTRY_GROUP.id,\n type: 'longText',\n maxLength: 500,\n aliases: ['detail', 'details', 'notes', 'comment', 'why'],\n description: 'Why it is on the list. Written when the entry is added; an entry already on the list keeps its own.',\n },\n]\n\nconst DERIVED_FIELDS: TransferField[] = [\n {\n id: OUTREACH_DNC_FIELDS.kind,\n label: 'Kind',\n group: ENTRY_GROUP.id,\n type: 'text',\n description: 'Domain or Address, from the entry.',\n },\n]\n\nconst SYSTEM_FIELDS: TransferField[] = [\n {\n ...transferIdField(),\n description: '\"domain:\" and the domain, or \"address:\" and the address’s fingerprint.',\n },\n {\n id: OUTREACH_DNC_FIELDS.reason,\n label: 'Why',\n type: 'text',\n readOnly: true,\n description: 'Why it was added: by a member, a reply asking not to be emailed, an unsubscribe, a bounce, or a mail gateway that blocked the sender.',\n },\n {\n id: OUTREACH_DNC_FIELDS.source,\n label: 'Added by',\n type: 'text',\n readOnly: true,\n description: 'A member, or Sequences on its own when a reply, an unsubscribe or a bounce called for it.',\n },\n {\n id: OUTREACH_DNC_FIELDS.addedByUid,\n label: 'Added by member (user ID)',\n type: 'text',\n readOnly: true,\n },\n { id: OUTREACH_DNC_FIELDS.addedAt, label: 'Added', type: 'datetime', readOnly: true },\n {\n id: OUTREACH_DNC_FIELDS.sequenceId,\n label: 'Sequence ID',\n type: 'text',\n readOnly: true,\n description: 'The sequence whose email led to the entry, when one did.',\n },\n]\n\n/** The resource's catalog, the same for every organization. */\nexport function outreachDoNotContactCatalog(): TransferCatalogInput {\n return { standard: STANDARD_FIELDS, derived: DERIVED_FIELDS, system: SYSTEM_FIELDS, groups: [ENTRY_GROUP] }\n}\n\n/** Note is written with a new entry and never onto one already on the list. */\nexport const OUTREACH_DNC_LOCKED_RULES: readonly TransferLockedRule[] = [\n { fieldId: OUTREACH_DNC_FIELDS.note, reason: OUTREACH_DNC_ADD_ONLY_REASON, forced: { mode: 'keepExisting', blank: 'leave' } },\n]\n\n/*==========================================\n * THE RESOURCE\n *=========================================*/\n\nexport interface OutreachDoNotContactTransferDeps {\n firestore: FirebaseFirestore.Firestore\n now?: () => number\n /** The member's standing in the organization, as the route gate resolves it. */\n resolveOrgPermissions(uid: string, context: { orgId: string }): Promise<OutreachMembership>\n /** The organization document, or `null` when there is none. */\n readOrg(orgId: string): Promise<Record<string, unknown> | null>\n logOrgActivity(\n orgId: string,\n actor: { uid: string | null; email?: string | null },\n action: string,\n target: { type: 'org'; id: string },\n ): Promise<void>\n}\n\n/** An entry's values by field id, as an export writes them and a plan compares them. */\nfunction entryValues(\n target: OutreachDoNotContactTarget,\n entry: Omit<OutreachDoNotContactEntry, 'key'>,\n): Record<string, unknown> {\n return {\n [TRANSFER_ID_FIELD]: target.id,\n [OUTREACH_DNC_FIELDS.entry]: target.kind === 'domain' ? target.domain : target.email,\n [OUTREACH_DNC_FIELDS.kind]: target.kind === 'domain' ? 'Domain' : 'Address',\n [OUTREACH_DNC_FIELDS.note]: entry.detail,\n [OUTREACH_DNC_FIELDS.reason]: OUTREACH_DO_NOT_CONTACT_REASON_LABELS[entry.reason] ?? entry.reason,\n [OUTREACH_DNC_FIELDS.source]: OUTREACH_DO_NOT_CONTACT_SOURCE_LABELS[entry.source] ?? entry.source,\n [OUTREACH_DNC_FIELDS.addedByUid]: entry.addedByUid,\n [OUTREACH_DNC_FIELDS.addedAt]: entry.addedAtMs ? new Date(entry.addedAtMs).toISOString() : null,\n [OUTREACH_DNC_FIELDS.sequenceId]: entry.sequenceId,\n }\n}\n\n/**\n * What an undo compares an added entry with: everything that says who added\n * it and when. An entry taken off and added again since — by a member, or by\n * the sending runtime for a reply or a bounce — no longer matches, and is\n * not the import's to remove.\n */\nconst UNDO_FIELDS = [\n OUTREACH_DNC_FIELDS.note,\n OUTREACH_DNC_FIELDS.reason,\n OUTREACH_DNC_FIELDS.source,\n OUTREACH_DNC_FIELDS.addedByUid,\n OUTREACH_DNC_FIELDS.addedAt,\n] as const\n\nfunction undoWritten(values: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(UNDO_FIELDS.map((fieldId) => [fieldId, values[fieldId] ?? null]))\n}\n\n/** Rows keyed by field id, holding only the fields asked for. */\nfunction pick(values: Record<string, unknown>, fieldIds: readonly string[]): Record<string, unknown> {\n return Object.fromEntries(fieldIds.map((fieldId) => [fieldId, values[fieldId] ?? null]))\n}\n\n/** The list query the Compliance page's search and filters make, from an export's `filter`. */\nfunction domainListRequest(filter: Readonly<Record<string, unknown>> | undefined): ListQueryRequest {\n const clauses = (Array.isArray(filter?.['clauses']) ? (filter?.['clauses'] as unknown[]) : [])\n .filter(\n (clause): clause is { field: string; op: string; value: string } =>\n !!clause &&\n typeof (clause as Record<string, unknown>)['field'] === 'string' &&\n typeof (clause as Record<string, unknown>)['op'] === 'string' &&\n typeof (clause as Record<string, unknown>)['value'] === 'string',\n )\n .map(({ field, op, value }) => ({ field, op, value }))\n const search = (Array.isArray(filter?.['search']) ? (filter?.['search'] as unknown[]) : []).filter(\n (word): word is string => typeof word === 'string',\n )\n return { clauses, search }\n}\n\n/** The export cursor: the last row's order value and id. */\ninterface PageCursor {\n value?: unknown\n id: string\n}\n\nfunction encodeCursor(cursor: PageCursor): string {\n return JSON.stringify(cursor)\n}\n\nfunction decodeCursor(cursor: string | null): PageCursor | null {\n if (!cursor) return null\n try {\n const parsed = JSON.parse(cursor) as PageCursor\n return parsed && typeof parsed.id === 'string' ? parsed : null\n } catch {\n return null\n }\n}\n\n/** The import's record policy: a row that finds an entry is skipped, and no row picks a record to update. */\nfunction addOnlyPolicy(policy: TransferPolicy): TransferPolicy {\n const rows: Record<number, TransferPolicy['rows'][number]> = {}\n for (const [index, override] of Object.entries(policy.rows)) {\n rows[Number(index)] = override.action === 'skip' ? { action: 'skip' } : {}\n }\n return {\n ...policy,\n record: { ...policy.record, onMatch: 'skip', onAmbiguous: 'skip' },\n rows,\n }\n}\n\n/**\n * Rows the core matched as new that name one entry between them — `Acme.com`\n * and `www.acme.com`, an address in two spellings — are duplicates of the\n * first: the match key compares the cells, and the entry is what they name.\n */\nfunction withEntryDuplicates(input: BuildTransferPlanInput): RowMatchOutcome[] {\n const firstRowOf = new Map<string, number>()\n return input.rows.map((row, position) => {\n const match = input.matches[position] ?? { kind: 'new' }\n const target = outreachDoNotContactTarget(row.values[OUTREACH_DNC_FIELDS.entry])\n if (!target) return match\n const first = firstRowOf.get(target.id)\n if (first === undefined) {\n firstRowOf.set(target.id, row.index)\n return match\n }\n return match.kind === 'new'\n ? { kind: 'duplicateInFile', firstRow: first, via: { fieldId: OUTREACH_DNC_FIELDS.entry, value: target.kind === 'domain' ? target.domain : String(target.email) } }\n : match\n })\n}\n\nfunction summaryOf(rows: readonly PlannedTransferRow[]): TransferPlan['summary'] {\n const summary = { create: 0, update: 0, unchanged: 0, skip: 0, fail: 0, total: rows.length }\n for (const row of rows) summary[row.verdict] += 1\n return summary\n}\n\n/** The value a planned create writes to a field. */\nfunction plannedValue(row: PlannedTransferRow, fieldId: string): unknown {\n return row.diff.find((change) => change.fieldId === fieldId)?.after ?? null\n}\n\n/** The hooks this resource answers, every one present. */\nexport type OutreachDoNotContactTransferResource = PluginTransferResource &\n Required<\n Pick<TransferRecordsHooks, 'fields' | 'count' | 'readPage' | 'lookup' | 'plan' | 'lockedRules' | 'apply' | 'revert'>\n >\n\n/**\n * The do-not-contact list's server half. Specs pass an in-memory Firestore;\n * the console's declarations pass the Admin SDK's and the platform's\n * membership, organization and activity readers.\n */\nexport function createOutreachDoNotContactTransferResource(\n deps: OutreachDoNotContactTransferDeps,\n): OutreachDoNotContactTransferResource {\n const { firestore } = deps\n const now = deps.now ?? Date.now\n\n /** The sentence a member is refused with, or `null` when they may work the list. */\n async function accessRefusal(ctx: TransferResourceContext): Promise<string | null> {\n if (!ctx.actorUid) return 'Only a signed-in member can change the do-not-contact list.'\n const membership = await deps.resolveOrgPermissions(ctx.actorUid, { orgId: ctx.orgId })\n const refused = outreachMembershipRefusal(membership, ctx.orgId)\n if (refused) return refused.message\n return outreachEntitlementRefusal(await deps.readOrg(ctx.orgId))?.message ?? null\n }\n\n /** The entries the targets name, by Aglyn ID; absent for one not on the list. */\n async function readEntries(\n orgId: string,\n targets: readonly OutreachDoNotContactTarget[],\n ): Promise<Map<string, Omit<OutreachDoNotContactEntry, 'key'>>> {\n const found = new Map<string, Omit<OutreachDoNotContactEntry, 'key'>>()\n const unique = [...new Map(targets.map((target) => [target.id, target])).values()]\n const addresses = outreachDoNotContactCollection(firestore, orgId)\n const domains = outreachDoNotContactDomainCollection(firestore, orgId)\n for (let start = 0; start < unique.length; start += GET_ALL_CHUNK) {\n const chunk = unique.slice(start, start + GET_ALL_CHUNK)\n const snapshots = await firestore.getAll(\n ...chunk.map((target) => (target.kind === 'domain' ? domains.doc(target.domain) : addresses.doc(target.key))),\n )\n chunk.forEach((target, index) => {\n const snapshot = snapshots[index]\n if (!snapshot?.exists) return\n const data = snapshot.data()\n const entry =\n target.kind === 'domain'\n ? readOutreachDoNotContactDomainEntry(target.domain, data)\n : readOutreachDoNotContactEntry(target.key, data)\n if (!entry) return\n const { reason, source, addedByUid, addedAtMs, enrollmentId, sequenceId, detail } = entry\n found.set(target.id, { reason, source, addedByUid, addedAtMs, enrollmentId, sequenceId, detail })\n })\n }\n return found\n }\n\n /** The Compliance page's domains query, as one Admin query in its own order. */\n function domainQuery(orgId: string, plan: ListQueryPlan): FirebaseFirestore.Query {\n const query = applyListQuery(outreachDoNotContactDomainCollection(firestore, orgId), plan)\n // A date filter orders by when an entry was added; the id breaks ties so\n // a page boundary never splits or repeats a moment.\n return plan.orderBy.path === LIST_QUERY_ID_PATH\n ? query\n : query.orderBy(FieldPath.documentId(), plan.orderBy.direction)\n }\n\n /** Whether an export may read: org-wide members who may work the list. */\n async function mayRead(ctx: TransferResourceContext, options: TransferReadOptions | undefined): Promise<boolean> {\n // The list covers the whole organization; a reader scoped to some sites\n // is refused by the route gate, and here reads nothing.\n if (options?.scopeTokens) return false\n return (await accessRefusal(ctx)) === null\n }\n\n /** The selected domains, in id order; an address id names nothing an export can read. */\n function selectedDomains(ids: readonly string[]): Array<Extract<OutreachDoNotContactTarget, { kind: 'domain' }>> {\n const targets = ids\n .map(outreachDoNotContactTargetFromId)\n .filter((target): target is Extract<OutreachDoNotContactTarget, { kind: 'domain' }> => target?.kind === 'domain')\n return [...new Map(targets.map((target) => [target.id, target])).values()].sort((a, b) => a.domain.localeCompare(b.domain))\n }\n\n return {\n fields: () => outreachDoNotContactCatalog(),\n matchKeys: OUTREACH_DNC_MATCH_KEYS,\n lockedRules: () => OUTREACH_DNC_LOCKED_RULES,\n\n async count(ctx, options) {\n if (!(await mayRead(ctx, options))) return 0\n if (options.ids) {\n return (await readEntries(ctx.orgId, selectedDomains(options.ids))).size\n }\n const plan = planListQuery(OUTREACH_DO_NOT_CONTACT_DOMAIN_LIST_QUERY, domainListRequest(options.filter), nameSearchNormalizers)\n const counted = await applyListQuery(outreachDoNotContactDomainCollection(firestore, ctx.orgId), plan).count().get()\n return counted.data().count\n },\n\n async readPage(ctx, cursor, fieldIds, options) {\n if (!(await mayRead(ctx, options))) return { rows: [], next: null }\n const size = Math.min(PAGE_MAX, Math.max(1, Math.floor(options?.pageSize ?? PAGE_DEFAULT)))\n\n if (options?.ids) {\n const domains = selectedDomains(options.ids)\n const start = Math.max(0, Number(cursor ?? 0) || 0)\n const slice = domains.slice(start, start + size)\n const found = await readEntries(ctx.orgId, slice)\n const rows = slice.flatMap((target) => {\n const entry = found.get(target.id)\n return entry ? [pick(entryValues(target, entry), fieldIds)] : []\n })\n return { rows, next: start + size < domains.length ? String(start + size) : null }\n }\n\n const plan = planListQuery(OUTREACH_DO_NOT_CONTACT_DOMAIN_LIST_QUERY, domainListRequest(options?.filter), nameSearchNormalizers)\n let query = domainQuery(ctx.orgId, plan)\n const after = decodeCursor(cursor)\n if (after) {\n query =\n plan.orderBy.path === LIST_QUERY_ID_PATH\n ? query.startAfter(after.id)\n : query.startAfter(after.value ?? null, after.id)\n }\n const snapshot = await query.limit(size + 1).get()\n const docs = snapshot.docs.slice(0, size)\n const rows = docs.flatMap((doc) => {\n const entry = readOutreachDoNotContactDomainEntry(doc.id, doc.data())\n if (!entry) return []\n const { domain, ...rest } = entry\n return [pick(entryValues({ kind: 'domain', id: `${DOMAIN_ID}${doc.id}`, domain }, rest), fieldIds)]\n })\n const last = docs[docs.length - 1]\n const next =\n snapshot.docs.length > size && last\n ? encodeCursor({\n id: last.id,\n ...(plan.orderBy.path === LIST_QUERY_ID_PATH ? {} : { value: last.get(plan.orderBy.path) ?? null }),\n })\n : null\n return { rows, next }\n },\n\n async lookup(ctx, requests: readonly MatchLookupRequest[]) {\n const lookup = new Map<string, string[]>()\n const records = new Map<string, Readonly<Record<string, unknown>>>()\n // A member who may not work the list learns nothing about what is on it.\n if (await accessRefusal(ctx)) return { lookup, records }\n const asked: Array<{ at: string; target: OutreachDoNotContactTarget }> = []\n for (const request of requests) {\n for (const value of request.values) {\n const target =\n request.fieldId === TRANSFER_ID_FIELD\n ? outreachDoNotContactTargetFromId(value)\n : request.fieldId === OUTREACH_DNC_FIELDS.entry\n ? outreachDoNotContactTarget(value)\n : null\n if (target) asked.push({ at: matchLookupKey(request.fieldId, value), target })\n }\n }\n const found = await readEntries(ctx.orgId, asked.map((entry) => entry.target))\n for (const { at, target } of asked) {\n const entry = found.get(target.id)\n if (!entry) continue\n lookup.set(at, [target.id])\n // An address read by its id has no address to show; one asked for\n // by its address does.\n const known = records.get(target.id)\n if (!known || (known[OUTREACH_DNC_FIELDS.entry] == null && target.kind === 'address' && target.email)) {\n records.set(target.id, entryValues(target, entry))\n }\n }\n return { lookup, records }\n },\n\n async plan(ctx, input) {\n const policy = addOnlyPolicy(input.policy)\n const built = buildTransferPlan({ ...input, policy, matches: withEntryDuplicates(input) })\n // Defensive: whatever the policy said, nothing on the list is rewritten.\n const rows = built.rows.map((row): PlannedTransferRow =>\n row.verdict === 'update' ? { ...row, verdict: 'skip', reason: 'matchedSkipped', diff: [] } : row,\n )\n const plan: TransferPlan = { ...built, rows, summary: summaryOf(rows) }\n\n const refusal = await accessRefusal(ctx)\n if (refusal) {\n return withTransferResourceFindings(\n plan,\n plan.rows.map((row) => ({ row: row.index, detail: refusal, refuse: true })),\n )\n }\n\n const findings: TransferResourceFinding[] = []\n const creating: Array<{ row: PlannedTransferRow; target: OutreachDoNotContactTarget }> = []\n for (const row of plan.rows) {\n if (row.verdict !== 'create') continue\n const value = plannedValue(row, OUTREACH_DNC_FIELDS.entry)\n const target = outreachDoNotContactTarget(value)\n if (!target) {\n findings.push({\n row: row.index,\n fieldId: OUTREACH_DNC_FIELDS.entry,\n value: String(value ?? ''),\n detail: `\"${String(value ?? '')}\" is neither an email address nor a domain.`,\n refuse: true,\n })\n continue\n }\n creating.push({ row, target })\n if (target.kind === 'domain' && isPublicMailboxDomain(target.domain)) {\n findings.push({\n row: row.index,\n fieldId: OUTREACH_DNC_FIELDS.entry,\n value: target.domain,\n detail: `${target.domain} is a public mailbox provider: adding it blocks every address at ${target.domain}, not one person.`,\n })\n }\n }\n\n // An address whose domain is listed, or is added by this file, is covered already.\n const fileDomains = new Map<string, number>()\n for (const { row, target } of creating) {\n if (target.kind === 'domain' && !fileDomains.has(target.domain)) fileDomains.set(target.domain, row.index)\n }\n const addresses = creating.filter(\n (entry): entry is { row: PlannedTransferRow; target: Extract<OutreachDoNotContactTarget, { kind: 'address' }> } =>\n entry.target.kind === 'address',\n )\n const listed = addresses.length\n ? await lookupOutreachDoNotContactDomains(\n firestore,\n ctx.orgId,\n addresses.map((entry) => String(entry.target.email)),\n )\n : new Map<string, boolean | null>()\n for (const { row, target } of addresses) {\n const domain = outreachEmailDomain(target.email)\n if (!domain) continue\n const inFile = fileDomains.get(domain)\n if (inFile !== undefined) {\n findings.push({\n row: row.index,\n fieldId: OUTREACH_DNC_FIELDS.entry,\n value: String(target.email),\n detail: `Its domain, ${domain}, is added by row ${inFile + 1} of this file, which already covers this address.`,\n })\n } else if (listed.get(String(target.email)) === true) {\n findings.push({\n row: row.index,\n fieldId: OUTREACH_DNC_FIELDS.entry,\n value: String(target.email),\n detail: `Its domain, ${domain}, is already on the list, which already covers this address.`,\n })\n }\n }\n return withTransferResourceFindings(plan, findings)\n },\n\n async apply(ctx, chunk, writer) {\n const results: TransferRowResult[] = []\n const undo: TransferUndoEntry[] = []\n const added: EntryCounts = { domains: 0, addresses: 0 }\n const refusal = await accessRefusal(ctx)\n for (const row of chunk.rows) {\n const before = await writer.alreadyApplied(row.index)\n if (before) {\n results.push(before)\n continue\n }\n if (writer.timeLeftMs() < ROW_BUDGET_MS) break\n let result: TransferRowResult\n let entry: TransferUndoEntry | undefined\n const target = outreachDoNotContactTarget(plannedValue(row, OUTREACH_DNC_FIELDS.entry))\n if (row.verdict !== 'create') {\n // Only a create is planned to write; nothing on the list is rewritten.\n result = { row: row.index, outcome: 'skipped', ...(row.recordId ? { recordId: row.recordId } : {}), reason: 'matchedSkipped' }\n } else if (refusal) {\n result = { row: row.index, outcome: 'failed', reason: 'resourceRule', message: refusal }\n } else if (!target) {\n result = { row: row.index, outcome: 'failed', reason: 'resourceRule', message: 'Neither an email address nor a domain.' }\n } else {\n const note = plannedValue(row, OUTREACH_DNC_FIELDS.note)\n const common = {\n orgId: ctx.orgId,\n reason: 'manual' as const,\n source: 'member' as const,\n addedByUid: ctx.actorUid,\n nowMs: now(),\n detail: typeof note === 'string' ? note : null,\n }\n const written =\n target.kind === 'domain'\n ? await addOutreachDoNotContactDomain(firestore, { ...common, domain: target.domain })\n : await addOutreachDoNotContact(firestore, { ...common, email: String(target.email) })\n if (written.created) {\n result = { row: row.index, outcome: 'created', recordId: target.id }\n entry = {\n row: row.index,\n recordId: target.id,\n action: 'created',\n written: undoWritten(entryValues(target, written.entry)),\n }\n added[target.kind === 'domain' ? 'domains' : 'addresses'] += 1\n } else {\n // Added since the plan was made: the entry already there stands.\n result = { row: row.index, outcome: 'unchanged', recordId: target.id, reason: 'matchedSkipped' }\n }\n }\n await writer.markApplied(result, entry)\n results.push(result)\n if (entry) undo.push(entry)\n }\n if (added.domains || added.addresses) {\n await deps.logOrgActivity(ctx.orgId, { uid: ctx.actorUid }, OUTREACH_DO_NOT_CONTACT_IMPORT_ACTIVITY.add(added), {\n type: 'org',\n id: ctx.orgId,\n })\n }\n return { results, undo }\n },\n\n async revert(ctx, snapshot, decisions) {\n const refusal = await accessRefusal(ctx)\n if (refusal) throw new Error(refusal)\n const targets = snapshot.entries\n .map((entry) => outreachDoNotContactTargetFromId(entry.recordId))\n .filter((target): target is OutreachDoNotContactTarget => target !== null)\n const found = await readEntries(ctx.orgId, targets)\n const done: TransferUndoStep[] = []\n const conflicts: TransferUndoStep[] = []\n const removed: EntryCounts = { domains: 0, addresses: 0 }\n for (const entry of snapshot.entries) {\n const target = outreachDoNotContactTargetFromId(entry.recordId)\n const stored = target ? found.get(target.id) : undefined\n if (!target || !stored) {\n done.push({ action: 'nothing', recordId: entry.recordId, why: 'gone' })\n continue\n }\n const step = planTransferUndo(entry, entryValues(target, stored))\n if (step.action === 'conflict') {\n // Taken off and added again since. The person may still choose to\n // remove a member's re-add; an entry Sequences added on its own —\n // someone replied, unsubscribed or bounced — is never the import's.\n if (decisions?.[entry.recordId] !== 'revert' || stored.source === 'runtime') {\n conflicts.push(step)\n continue\n }\n } else if (step.action !== 'delete') {\n done.push(step)\n continue\n }\n const gone =\n target.kind === 'domain'\n ? await removeOutreachDoNotContactDomain(firestore, ctx.orgId, target.domain)\n : await removeOutreachDoNotContactEntry(firestore, ctx.orgId, target.key)\n if (gone) removed[target.kind === 'domain' ? 'domains' : 'addresses'] += 1\n done.push({ action: 'delete', recordId: entry.recordId })\n }\n if (removed.domains || removed.addresses) {\n await deps.logOrgActivity(ctx.orgId, { uid: ctx.actorUid }, OUTREACH_DO_NOT_CONTACT_IMPORT_ACTIVITY.undo(removed), {\n type: 'org',\n id: ctx.orgId,\n })\n }\n return { done, conflicts }\n },\n }\n}\n"],"names":["normalizeContactEmail","isPublicMailboxDomain","nameSearchNormalizers","buildTransferPlan","matchLookupKey","planTransferUndo","TRANSFER_ID_FIELD","transferIdField","withTransferResourceFindings","LIST_QUERY_ID_PATH","planListQuery","applyListQuery","FieldPath","OUTREACH_DNC_MATCH_KEYS","outreachDoNotContactKey","normalizeOutreachDomain","outreachEmailDomain","outreachEntitlementRefusal","outreachMembershipRefusal","OUTREACH_DO_NOT_CONTACT_DOMAIN_LIST_QUERY","OUTREACH_DO_NOT_CONTACT_REASON_LABELS","OUTREACH_DO_NOT_CONTACT_SOURCE_LABELS","addOutreachDoNotContact","addOutreachDoNotContactDomain","lookupOutreachDoNotContactDomains","outreachDoNotContactCollection","outreachDoNotContactDomainCollection","readOutreachDoNotContactDomainEntry","readOutreachDoNotContactEntry","removeOutreachDoNotContactDomain","removeOutreachDoNotContactEntry","OUTREACH_DNC_FIELDS","entry","kind","note","reason","source","addedByUid","addedAt","sequenceId","DOMAIN_ID","ADDRESS_ID","OUTREACH_DNC_ADD_ONLY_REASON","OUTREACH_DO_NOT_CONTACT_IMPORT_ACTIVITY","add","counts","countWords","undo","parts","domains","push","addresses","join","GET_ALL_CHUNK","PAGE_MAX","PAGE_DEFAULT","ROW_BUDGET_MS","outreachDoNotContactTarget","value","text","String","trim","bracketed","exec","replace","email","key","id","includes","startsWith","domain","outreachDoNotContactTargetFromId","slice","length","toLowerCase","test","ENTRY_GROUP","label","STANDARD_FIELDS","group","type","required","matchKey","maxLength","aliases","description","DERIVED_FIELDS","SYSTEM_FIELDS","readOnly","outreachDoNotContactCatalog","standard","derived","system","groups","OUTREACH_DNC_LOCKED_RULES","fieldId","forced","mode","blank","entryValues","target","detail","addedAtMs","Date","toISOString","UNDO_FIELDS","undoWritten","values","Object","fromEntries","map","pick","fieldIds","domainListRequest","filter","clauses","Array","isArray","clause","field","op","search","word","encodeCursor","cursor","JSON","stringify","decodeCursor","parsed","parse","addOnlyPolicy","policy","rows","index","override","entries","Number","action","record","onMatch","onAmbiguous","withEntryDuplicates","input","firstRowOf","Map","row","position","match","matches","first","get","undefined","set","firstRow","via","summaryOf","summary","create","update","unchanged","skip","fail","total","verdict","plannedValue","diff","find","change","after","createOutreachDoNotContactTransferResource","deps","firestore","now","accessRefusal","ctx","actorUid","membership","resolveOrgPermissions","orgId","refused","message","readOrg","readEntries","targets","found","unique","start","chunk","snapshots","getAll","doc","forEach","snapshot","exists","data","enrollmentId","domainQuery","plan","query","orderBy","path","documentId","direction","mayRead","options","scopeTokens","selectedDomains","ids","sort","a","b","localeCompare","fields","matchKeys","lockedRules","count","size","counted","readPage","last","next","Math","min","max","floor","pageSize","flatMap","startAfter","limit","docs","rest","lookup","requests","records","asked","request","at","known","built","refusal","refuse","findings","creating","fileDomains","has","listed","inFile","apply","writer","results","added","before","alreadyApplied","timeLeftMs","result","outcome","recordId","common","nowMs","written","created","markApplied","logOrgActivity","uid","revert","decisions","Error","done","conflicts","removed","stored","why","step","gone"],"mappings":";;AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,qBAAqB,QAAQ,kCAAiC;AACvE,SAASC,qBAAqB,QAAQ,6BAA4B;AAClE,SAASC,qBAAqB,QAAQ,qCAAoC;AAC1E,SACEC,iBAAiB,EACjBC,cAAc,EACdC,gBAAgB,EAChBC,iBAAiB,EACjBC,eAAe,EACfC,4BAA4B,QAcvB,6BAA4B;AAOnC,SACEC,kBAAkB,EAClBC,aAAa,QAGR,6CAA4C;AACnD,SAASC,cAAc,QAAQ,6CAA4C;AAC3E,SAASC,SAAS,QAAQ,2BAA0B;AACpD,SAASC,uBAAuB,QAAQ,qCAAiC;AACzE,SAASC,uBAAuB,QAAQ,8BAA0B;AAClE,SAASC,uBAAuB,EAAEC,mBAAmB,QAAQ,qCAAiC;AAC9F,SACEC,0BAA0B,EAC1BC,yBAAyB,QAEpB,+BAA2B;AAClC,SAASC,yCAAyC,QAAQ,+CAA2C;AACrG,SACEC,qCAAqC,EACrCC,qCAAqC,QAEhC,6BAAyB;AAChC,SACEC,uBAAuB,EACvBC,6BAA6B,EAC7BC,iCAAiC,EACjCC,8BAA8B,EAC9BC,oCAAoC,EACpCC,mCAAmC,EACnCC,6BAA6B,EAC7BC,gCAAgC,EAChCC,+BAA+B,QAC1B,qCAAiC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCC,GAED,qBAAqB,GACrB,OAAO,MAAMC,sBAAsB;IACjCC,OAAO;IACPC,MAAM;IACNC,MAAM;IACNC,QAAQ;IACRC,QAAQ;IACRC,YAAY;IACZC,SAAS;IACTC,YAAY;AACd,EAAU;AAEV,MAAMC,YAAY;AAClB,MAAMC,aAAa;AAEnB,2DAA2D,GAC3D,OAAO,MAAMC,+BACX,2FAA0F;AAE5F,uFAAuF,GACvF,OAAO,MAAMC,0CAA0C;IACrDC,KAAK,CAACC,SAAwB,CAAC,SAAS,EAAEC,WAAWD,QAAQ,qCAAqC,CAAC;IACnGE,MAAM,CAACF,SACL,CAAC,yBAAyB,EAAEC,WAAWD,QAAQ,uCAAuC,CAAC;AAC3F,EAAU;AAQV,SAASC,WAAWD,MAAmB;IACrC,MAAMG,QAAkB,EAAE;IAC1B,IAAIH,OAAOI,OAAO,EAAED,MAAME,IAAI,CAAC,GAAGL,OAAOI,OAAO,CAAC,CAAC,EAAEJ,OAAOI,OAAO,KAAK,IAAI,WAAW,WAAW;IACjG,IAAIJ,OAAOM,SAAS,EAAEH,MAAME,IAAI,CAAC,GAAGL,OAAOM,SAAS,CAAC,CAAC,EAAEN,OAAOM,SAAS,KAAK,IAAI,YAAY,aAAa;IAC1G,OAAOH,MAAMI,IAAI,CAAC;AACpB;AAEA,0DAA0D,GAC1D,MAAMC,gBAAgB;AAEtB,yCAAyC,GACzC,MAAMC,WAAW;AACjB,MAAMC,eAAe;AAErB,yEAAyE,GACzE,MAAMC,gBAAgB;AAWtB;;;;;CAKC,GACD,OAAO,SAASC,2BAA2BC,KAAc;IACvD,IAAIC,OAAOC,OAAOF,gBAAAA,QAAS,IAAIG,IAAI;IACnC,kEAAkE;IAClE,MAAMC,YAAY,iBAAiBC,IAAI,CAACJ;IACxC,IAAIG,WAAWH,OAAOG,SAAS,CAAC,EAAE,CAACD,IAAI;IACvCF,OAAOA,KAAKK,OAAO,CAAC,aAAa;IACjC,IAAI,CAACL,MAAM,OAAO;IAClB,MAAMM,QAAQjE,sBAAsB2D;IACpC,IAAIM,OAAO;QACT,MAAMC,MAAMpD,wBAAwBmD;QACpC,OAAOC,MAAM;YAAEjC,MAAM;YAAWkC,IAAI,GAAG1B,aAAayB,KAAK;YAAEA;YAAKD;QAAM,IAAI;IAC5E;IACA,IAAIN,KAAKS,QAAQ,CAAC,QAAQ,CAACT,KAAKU,UAAU,CAAC,MAAM,OAAO;IACxD,MAAMC,SAASvD,wBAAwB4C;IACvC,OAAOW,SAAS;QAAErC,MAAM;QAAUkC,IAAI,GAAG3B,YAAY8B,QAAQ;QAAEA;IAAO,IAAI;AAC5E;AAEA,4CAA4C,GAC5C,OAAO,SAASC,iCAAiCJ,EAAW;IAC1D,MAAMR,OAAOC,OAAOO,aAAAA,KAAM,IAAIN,IAAI;IAClC,IAAIF,KAAKU,UAAU,CAAC7B,YAAY;QAC9B,MAAM8B,SAASvD,wBAAwB4C,KAAKa,KAAK,CAAChC,UAAUiC,MAAM;QAClE,OAAOH,SAAS;YAAErC,MAAM;YAAUkC,IAAI,GAAG3B,YAAY8B,QAAQ;YAAEA;QAAO,IAAI;IAC5E;IACA,IAAIX,KAAKU,UAAU,CAAC5B,aAAa;QAC/B,MAAMyB,MAAMP,KAAKa,KAAK,CAAC/B,WAAWgC,MAAM,EAAEC,WAAW;QACrD,OAAO,iBAAiBC,IAAI,CAACT,OAAO;YAAEjC,MAAM;YAAWkC,IAAI,GAAG1B,aAAayB,KAAK;YAAEA;YAAKD,OAAO;QAAK,IAAI;IACzG;IACA,OAAO;AACT;AAEA;;2CAE2C,GAE3C,MAAMW,cAAc;IAAET,IAAI;IAASU,OAAO;AAAQ;AAElD,MAAMC,kBAAmC;IACvC;QACEX,IAAIpC,oBAAoBC,KAAK;QAC7B6C,OAAO;QACPE,OAAOH,YAAYT,EAAE;QACrBa,MAAM;QACNC,UAAU;QACVC,UAAU;QACVC,WAAW;QACXC,SAAS;YAAC;YAAS;YAAiB;YAAW;YAAU;YAAW;YAAkB;SAAiB;QACvGC,aACE;IACJ;IACA;QACElB,IAAIpC,oBAAoBG,IAAI;QAC5B2C,OAAO;QACPE,OAAOH,YAAYT,EAAE;QACrBa,MAAM;QACNG,WAAW;QACXC,SAAS;YAAC;YAAU;YAAW;YAAS;YAAW;SAAM;QACzDC,aAAa;IACf;CACD;AAED,MAAMC,iBAAkC;IACtC;QACEnB,IAAIpC,oBAAoBE,IAAI;QAC5B4C,OAAO;QACPE,OAAOH,YAAYT,EAAE;QACrBa,MAAM;QACNK,aAAa;IACf;CACD;AAED,MAAME,gBAAiC;IACrC,aACKhF;QACH8E,aAAa;;IAEf;QACElB,IAAIpC,oBAAoBI,MAAM;QAC9B0C,OAAO;QACPG,MAAM;QACNQ,UAAU;QACVH,aAAa;IACf;IACA;QACElB,IAAIpC,oBAAoBK,MAAM;QAC9ByC,OAAO;QACPG,MAAM;QACNQ,UAAU;QACVH,aAAa;IACf;IACA;QACElB,IAAIpC,oBAAoBM,UAAU;QAClCwC,OAAO;QACPG,MAAM;QACNQ,UAAU;IACZ;IACA;QAAErB,IAAIpC,oBAAoBO,OAAO;QAAEuC,OAAO;QAASG,MAAM;QAAYQ,UAAU;IAAK;IACpF;QACErB,IAAIpC,oBAAoBQ,UAAU;QAClCsC,OAAO;QACPG,MAAM;QACNQ,UAAU;QACVH,aAAa;IACf;CACD;AAED,6DAA6D,GAC7D,OAAO,SAASI;IACd,OAAO;QAAEC,UAAUZ;QAAiBa,SAASL;QAAgBM,QAAQL;QAAeM,QAAQ;YAACjB;SAAY;IAAC;AAC5G;AAEA,6EAA6E,GAC7E,OAAO,MAAMkB,4BAA2D;IACtE;QAAEC,SAAShE,oBAAoBG,IAAI;QAAEC,QAAQO;QAA8BsD,QAAQ;YAAEC,MAAM;YAAgBC,OAAO;QAAQ;IAAE;CAC7H,CAAA;AAqBD,sFAAsF,GACtF,SAASC,YACPC,MAAkC,EAClCpE,KAA6C;QAObZ,qDACAC;IANhC,OAAO;QACL,CAACf,kBAAkB,EAAE8F,OAAOjC,EAAE;QAC9B,CAACpC,oBAAoBC,KAAK,CAAC,EAAEoE,OAAOnE,IAAI,KAAK,WAAWmE,OAAO9B,MAAM,GAAG8B,OAAOnC,KAAK;QACpF,CAAClC,oBAAoBE,IAAI,CAAC,EAAEmE,OAAOnE,IAAI,KAAK,WAAW,WAAW;QAClE,CAACF,oBAAoBG,IAAI,CAAC,EAAEF,MAAMqE,MAAM;QACxC,CAACtE,oBAAoBI,MAAM,CAAC,GAAEf,sDAAAA,qCAAqC,CAACY,MAAMG,MAAM,CAAC,YAAnDf,sDAAuDY,MAAMG,MAAM;QACjG,CAACJ,oBAAoBK,MAAM,CAAC,GAAEf,sDAAAA,qCAAqC,CAACW,MAAMI,MAAM,CAAC,YAAnDf,sDAAuDW,MAAMI,MAAM;QACjG,CAACL,oBAAoBM,UAAU,CAAC,EAAEL,MAAMK,UAAU;QAClD,CAACN,oBAAoBO,OAAO,CAAC,EAAEN,MAAMsE,SAAS,GAAG,IAAIC,KAAKvE,MAAMsE,SAAS,EAAEE,WAAW,KAAK;QAC3F,CAACzE,oBAAoBQ,UAAU,CAAC,EAAEP,MAAMO,UAAU;IACpD;AACF;AAEA;;;;;CAKC,GACD,MAAMkE,cAAc;IAClB1E,oBAAoBG,IAAI;IACxBH,oBAAoBI,MAAM;IAC1BJ,oBAAoBK,MAAM;IAC1BL,oBAAoBM,UAAU;IAC9BN,oBAAoBO,OAAO;CAC5B;AAED,SAASoE,YAAYC,MAA+B;IAClD,OAAOC,OAAOC,WAAW,CAACJ,YAAYK,GAAG,CAAC,CAACf;YAAsBY;eAAV;YAACZ;aAASY,kBAAAA,MAAM,CAACZ,QAAQ,YAAfY,kBAAmB;SAAK;;AAC3F;AAEA,+DAA+D,GAC/D,SAASI,KAAKJ,MAA+B,EAAEK,QAA2B;IACxE,OAAOJ,OAAOC,WAAW,CAACG,SAASF,GAAG,CAAC,CAACf;YAAsBY;eAAV;YAACZ;aAASY,kBAAAA,MAAM,CAACZ,QAAQ,YAAfY,kBAAmB;SAAK;;AACxF;AAEA,6FAA6F,GAC7F,SAASM,kBAAkBC,MAAqD;IAC9E,MAAMC,UAAU,AAACC,CAAAA,MAAMC,OAAO,CAACH,0BAAAA,MAAQ,CAAC,UAAU,IAAKA,0BAAAA,MAAQ,CAAC,UAAU,GAAiB,EAAE,AAAD,EACzFA,MAAM,CACL,CAACI,SACC,CAAC,CAACA,UACF,OAAO,AAACA,MAAkC,CAAC,QAAQ,KAAK,YACxD,OAAO,AAACA,MAAkC,CAAC,KAAK,KAAK,YACrD,OAAO,AAACA,MAAkC,CAAC,QAAQ,KAAK,UAE3DR,GAAG,CAAC,CAAC,EAAES,KAAK,EAAEC,EAAE,EAAE9D,KAAK,EAAE,GAAM,CAAA;YAAE6D;YAAOC;YAAI9D;QAAM,CAAA;IACrD,MAAM+D,SAAS,AAACL,CAAAA,MAAMC,OAAO,CAACH,0BAAAA,MAAQ,CAAC,SAAS,IAAKA,0BAAAA,MAAQ,CAAC,SAAS,GAAiB,EAAE,AAAD,EAAGA,MAAM,CAChG,CAACQ,OAAyB,OAAOA,SAAS;IAE5C,OAAO;QAAEP;QAASM;IAAO;AAC3B;AAQA,SAASE,aAAaC,MAAkB;IACtC,OAAOC,KAAKC,SAAS,CAACF;AACxB;AAEA,SAASG,aAAaH,MAAqB;IACzC,IAAI,CAACA,QAAQ,OAAO;IACpB,IAAI;QACF,MAAMI,SAASH,KAAKI,KAAK,CAACL;QAC1B,OAAOI,UAAU,OAAOA,OAAO7D,EAAE,KAAK,WAAW6D,SAAS;IAC5D,EAAE,eAAM;QACN,OAAO;IACT;AACF;AAEA,2GAA2G,GAC3G,SAASE,cAAcC,MAAsB;IAC3C,MAAMC,OAAuD,CAAC;IAC9D,KAAK,MAAM,CAACC,OAAOC,SAAS,IAAI1B,OAAO2B,OAAO,CAACJ,OAAOC,IAAI,EAAG;QAC3DA,IAAI,CAACI,OAAOH,OAAO,GAAGC,SAASG,MAAM,KAAK,SAAS;YAAEA,QAAQ;QAAO,IAAI,CAAC;IAC3E;IACA,OAAO,aACFN;QACHO,QAAQ,aAAKP,OAAOO,MAAM;YAAEC,SAAS;YAAQC,aAAa;;QAC1DR;;AAEJ;AAEA;;;;CAIC,GACD,SAASS,oBAAoBC,KAA6B;IACxD,MAAMC,aAAa,IAAIC;IACvB,OAAOF,MAAMV,IAAI,CAACtB,GAAG,CAAC,CAACmC,KAAKC;YACZJ;QAAd,MAAMK,SAAQL,0BAAAA,MAAMM,OAAO,CAACF,SAAS,YAAvBJ,0BAA2B;YAAE7G,MAAM;QAAM;QACvD,MAAMmE,SAAS3C,2BAA2BwF,IAAItC,MAAM,CAAC5E,oBAAoBC,KAAK,CAAC;QAC/E,IAAI,CAACoE,QAAQ,OAAO+C;QACpB,MAAME,QAAQN,WAAWO,GAAG,CAAClD,OAAOjC,EAAE;QACtC,IAAIkF,UAAUE,WAAW;YACvBR,WAAWS,GAAG,CAACpD,OAAOjC,EAAE,EAAE8E,IAAIZ,KAAK;YACnC,OAAOc;QACT;QACA,OAAOA,MAAMlH,IAAI,KAAK,QAClB;YAAEA,MAAM;YAAmBwH,UAAUJ;YAAOK,KAAK;gBAAE3D,SAAShE,oBAAoBC,KAAK;gBAAE0B,OAAO0C,OAAOnE,IAAI,KAAK,WAAWmE,OAAO9B,MAAM,GAAGV,OAAOwC,OAAOnC,KAAK;YAAE;QAAE,IAChKkF;IACN;AACF;AAEA,SAASQ,UAAUvB,IAAmC;IACpD,MAAMwB,UAAU;QAAEC,QAAQ;QAAGC,QAAQ;QAAGC,WAAW;QAAGC,MAAM;QAAGC,MAAM;QAAGC,OAAO9B,KAAK3D,MAAM;IAAC;IAC3F,KAAK,MAAMwE,OAAOb,KAAMwB,OAAO,CAACX,IAAIkB,OAAO,CAAC,IAAI;IAChD,OAAOP;AACT;AAEA,kDAAkD,GAClD,SAASQ,aAAanB,GAAuB,EAAElD,OAAe;;QACrDkD;IAAP,gBAAOA,iBAAAA,IAAIoB,IAAI,CAACC,IAAI,CAAC,CAACC,SAAWA,OAAOxE,OAAO,KAAKA,6BAA7CkD,eAAuDuB,KAAK,mBAAI;AACzE;AAQA;;;;CAIC,GACD,OAAO,SAASC,2CACdC,IAAsC;QAG1BA;IADZ,MAAM,EAAEC,SAAS,EAAE,GAAGD;IACtB,MAAME,OAAMF,YAAAA,KAAKE,GAAG,YAARF,YAAYnE,KAAKqE,GAAG;IAEhC,kFAAkF,GAClF,eAAeC,cAAcC,GAA4B;;YAKhD7J;QAJP,IAAI,CAAC6J,IAAIC,QAAQ,EAAE,OAAO;QAC1B,MAAMC,aAAa,MAAMN,KAAKO,qBAAqB,CAACH,IAAIC,QAAQ,EAAE;YAAEG,OAAOJ,IAAII,KAAK;QAAC;QACrF,MAAMC,UAAUjK,0BAA0B8J,YAAYF,IAAII,KAAK;QAC/D,IAAIC,SAAS,OAAOA,QAAQC,OAAO;QACnC,gBAAOnK,8BAAAA,2BAA2B,MAAMyJ,KAAKW,OAAO,CAACP,IAAII,KAAK,uBAAvDjK,4BAA2DmK,OAAO,mBAAI;IAC/E;IAEA,+EAA+E,GAC/E,eAAeE,YACbJ,KAAa,EACbK,OAA8C;QAE9C,MAAMC,QAAQ,IAAIxC;QAClB,MAAMyC,SAAS;eAAI,IAAIzC,IAAIuC,QAAQzE,GAAG,CAAC,CAACV,SAAW;oBAACA,OAAOjC,EAAE;oBAAEiC;iBAAO,GAAGO,MAAM;SAAG;QAClF,MAAMxD,YAAY1B,+BAA+BkJ,WAAWO;QAC5D,MAAMjI,UAAUvB,qCAAqCiJ,WAAWO;QAChE,IAAK,IAAIQ,QAAQ,GAAGA,QAAQD,OAAOhH,MAAM,EAAEiH,SAASrI,cAAe;YACjE,MAAMsI,QAAQF,OAAOjH,KAAK,CAACkH,OAAOA,QAAQrI;YAC1C,MAAMuI,YAAY,MAAMjB,UAAUkB,MAAM,IACnCF,MAAM7E,GAAG,CAAC,CAACV,SAAYA,OAAOnE,IAAI,KAAK,WAAWgB,QAAQ6I,GAAG,CAAC1F,OAAO9B,MAAM,IAAInB,UAAU2I,GAAG,CAAC1F,OAAOlC,GAAG;YAE5GyH,MAAMI,OAAO,CAAC,CAAC3F,QAAQiC;gBACrB,MAAM2D,WAAWJ,SAAS,CAACvD,MAAM;gBACjC,IAAI,EAAC2D,4BAAAA,SAAUC,MAAM,GAAE;gBACvB,MAAMC,OAAOF,SAASE,IAAI;gBAC1B,MAAMlK,QACJoE,OAAOnE,IAAI,KAAK,WACZN,oCAAoCyE,OAAO9B,MAAM,EAAE4H,QACnDtK,8BAA8BwE,OAAOlC,GAAG,EAAEgI;gBAChD,IAAI,CAAClK,OAAO;gBACZ,MAAM,EAAEG,MAAM,EAAEC,MAAM,EAAEC,UAAU,EAAEiE,SAAS,EAAE6F,YAAY,EAAE5J,UAAU,EAAE8D,MAAM,EAAE,GAAGrE;gBACpFwJ,MAAMhC,GAAG,CAACpD,OAAOjC,EAAE,EAAE;oBAAEhC;oBAAQC;oBAAQC;oBAAYiE;oBAAW6F;oBAAc5J;oBAAY8D;gBAAO;YACjG;QACF;QACA,OAAOmF;IACT;IAEA,8EAA8E,GAC9E,SAASY,YAAYlB,KAAa,EAAEmB,IAAmB;QACrD,MAAMC,QAAQ3L,eAAee,qCAAqCiJ,WAAWO,QAAQmB;QACrF,yEAAyE;QACzE,oDAAoD;QACpD,OAAOA,KAAKE,OAAO,CAACC,IAAI,KAAK/L,qBACzB6L,QACAA,MAAMC,OAAO,CAAC3L,UAAU6L,UAAU,IAAIJ,KAAKE,OAAO,CAACG,SAAS;IAClE;IAEA,wEAAwE,GACxE,eAAeC,QAAQ7B,GAA4B,EAAE8B,OAAwC;QAC3F,wEAAwE;QACxE,wDAAwD;QACxD,IAAIA,2BAAAA,QAASC,WAAW,EAAE,OAAO;QACjC,OAAO,AAAC,MAAMhC,cAAcC,SAAU;IACxC;IAEA,uFAAuF,GACvF,SAASgC,gBAAgBC,GAAsB;QAC7C,MAAMxB,UAAUwB,IACbjG,GAAG,CAACvC,kCACJ2C,MAAM,CAAC,CAACd,SAA8EA,CAAAA,0BAAAA,OAAQnE,IAAI,MAAK;QAC1G,OAAO;eAAI,IAAI+G,IAAIuC,QAAQzE,GAAG,CAAC,CAACV,SAAW;oBAACA,OAAOjC,EAAE;oBAAEiC;iBAAO,GAAGO,MAAM;SAAG,CAACqG,IAAI,CAAC,CAACC,GAAGC,IAAMD,EAAE3I,MAAM,CAAC6I,aAAa,CAACD,EAAE5I,MAAM;IAC3H;IAEA,OAAO;QACL8I,QAAQ,IAAM3H;QACd4H,WAAWxM;QACXyM,aAAa,IAAMxH;QAEnB,MAAMyH,OAAMzC,GAAG,EAAE8B,OAAO;YACtB,IAAI,CAAE,MAAMD,QAAQ7B,KAAK8B,UAAW,OAAO;YAC3C,IAAIA,QAAQG,GAAG,EAAE;gBACf,OAAO,AAAC,CAAA,MAAMzB,YAAYR,IAAII,KAAK,EAAE4B,gBAAgBF,QAAQG,GAAG,EAAC,EAAGS,IAAI;YAC1E;YACA,MAAMnB,OAAO3L,cAAcS,2CAA2C8F,kBAAkB2F,QAAQ1F,MAAM,GAAGhH;YACzG,MAAMuN,UAAU,MAAM9M,eAAee,qCAAqCiJ,WAAWG,IAAII,KAAK,GAAGmB,MAAMkB,KAAK,GAAGjE,GAAG;YAClH,OAAOmE,QAAQvB,IAAI,GAAGqB,KAAK;QAC7B;QAEA,MAAMG,UAAS5C,GAAG,EAAElD,MAAM,EAAEZ,QAAQ,EAAE4F,OAAO;sBAsC0Be;YArCrE,IAAI,CAAE,MAAMhB,QAAQ7B,KAAK8B,UAAW,OAAO;gBAAExE,MAAM,EAAE;gBAAEwF,MAAM;YAAK;YAClE,MAAMJ,OAAOK,KAAKC,GAAG,CAACxK,UAAUuK,KAAKE,GAAG,CAAC,GAAGF,KAAKG,KAAK,SAACpB,2BAAAA,QAASqB,QAAQ,mBAAI1K;YAE5E,IAAIqJ,2BAAAA,QAASG,GAAG,EAAE;gBAChB,MAAM9J,UAAU6J,gBAAgBF,QAAQG,GAAG;gBAC3C,MAAMrB,QAAQmC,KAAKE,GAAG,CAAC,GAAGvF,OAAOZ,iBAAAA,SAAU,MAAM;gBACjD,MAAMpD,QAAQvB,QAAQuB,KAAK,CAACkH,OAAOA,QAAQ8B;gBAC3C,MAAMhC,QAAQ,MAAMF,YAAYR,IAAII,KAAK,EAAE1G;gBAC3C,MAAM4D,OAAO5D,MAAM0J,OAAO,CAAC,CAAC9H;oBAC1B,MAAMpE,QAAQwJ,MAAMlC,GAAG,CAAClD,OAAOjC,EAAE;oBACjC,OAAOnC,QAAQ;wBAAC+E,KAAKZ,YAAYC,QAAQpE,QAAQgF;qBAAU,GAAG,EAAE;gBAClE;gBACA,OAAO;oBAAEoB;oBAAMwF,MAAMlC,QAAQ8B,OAAOvK,QAAQwB,MAAM,GAAGb,OAAO8H,QAAQ8B,QAAQ;gBAAK;YACnF;YAEA,MAAMnB,OAAO3L,cAAcS,2CAA2C8F,kBAAkB2F,2BAAAA,QAAS1F,MAAM,GAAGhH;YAC1G,IAAIoM,QAAQF,YAAYtB,IAAII,KAAK,EAAEmB;YACnC,MAAM7B,QAAQzC,aAAaH;YAC3B,IAAI4C,OAAO;oBAIcA;gBAHvB8B,QACED,KAAKE,OAAO,CAACC,IAAI,KAAK/L,qBAClB6L,MAAM6B,UAAU,CAAC3D,MAAMrG,EAAE,IACzBmI,MAAM6B,UAAU,EAAC3D,eAAAA,MAAM9G,KAAK,YAAX8G,eAAe,MAAMA,MAAMrG,EAAE;YACtD;YACA,MAAM6H,WAAW,MAAMM,MAAM8B,KAAK,CAACZ,OAAO,GAAGlE,GAAG;YAChD,MAAM+E,OAAOrC,SAASqC,IAAI,CAAC7J,KAAK,CAAC,GAAGgJ;YACpC,MAAMpF,OAAOiG,KAAKH,OAAO,CAAC,CAACpC;gBACzB,MAAM9J,QAAQL,oCAAoCmK,IAAI3H,EAAE,EAAE2H,IAAII,IAAI;gBAClE,IAAI,CAAClK,OAAO,OAAO,EAAE;gBACrB,MAAM,EAAEsC,MAAM,EAAW,GAAGtC,OAATsM,wCAAStM;;;gBAC5B,OAAO;oBAAC+E,KAAKZ,YAAY;wBAAElE,MAAM;wBAAUkC,IAAI,GAAG3B,YAAYsJ,IAAI3H,EAAE,EAAE;wBAAEG;oBAAO,GAAGgK,OAAOtH;iBAAU;YACrG;YACA,MAAM2G,OAAOU,IAAI,CAACA,KAAK5J,MAAM,GAAG,EAAE;YAClC,MAAMmJ,OACJ5B,SAASqC,IAAI,CAAC5J,MAAM,GAAG+I,QAAQG,OAC3BhG,aAAa;gBACXxD,IAAIwJ,KAAKxJ,EAAE;eACPkI,KAAKE,OAAO,CAACC,IAAI,KAAK/L,qBAAqB,CAAC,IAAI;gBAAEiD,KAAK,GAAEiK,YAAAA,KAAKrE,GAAG,CAAC+C,KAAKE,OAAO,CAACC,IAAI,aAA1BmB,YAA+B;YAAK,MAEnG;YACN,OAAO;gBAAEvF;gBAAMwF;YAAK;QACtB;QAEA,MAAMW,QAAOzD,GAAG,EAAE0D,QAAuC;YACvD,MAAMD,SAAS,IAAIvF;YACnB,MAAMyF,UAAU,IAAIzF;YACpB,yEAAyE;YACzE,IAAI,MAAM6B,cAAcC,MAAM,OAAO;gBAAEyD;gBAAQE;YAAQ;YACvD,MAAMC,QAAmE,EAAE;YAC3E,KAAK,MAAMC,WAAWH,SAAU;gBAC9B,KAAK,MAAM9K,SAASiL,QAAQhI,MAAM,CAAE;oBAClC,MAAMP,SACJuI,QAAQ5I,OAAO,KAAKzF,oBAChBiE,iCAAiCb,SACjCiL,QAAQ5I,OAAO,KAAKhE,oBAAoBC,KAAK,GAC3CyB,2BAA2BC,SAC3B;oBACR,IAAI0C,QAAQsI,MAAMxL,IAAI,CAAC;wBAAE0L,IAAIxO,eAAeuO,QAAQ5I,OAAO,EAAErC;wBAAQ0C;oBAAO;gBAC9E;YACF;YACA,MAAMoF,QAAQ,MAAMF,YAAYR,IAAII,KAAK,EAAEwD,MAAM5H,GAAG,CAAC,CAAC9E,QAAUA,MAAMoE,MAAM;YAC5E,KAAK,MAAM,EAAEwI,EAAE,EAAExI,MAAM,EAAE,IAAIsI,MAAO;gBAClC,MAAM1M,QAAQwJ,MAAMlC,GAAG,CAAClD,OAAOjC,EAAE;gBACjC,IAAI,CAACnC,OAAO;gBACZuM,OAAO/E,GAAG,CAACoF,IAAI;oBAACxI,OAAOjC,EAAE;iBAAC;gBAC1B,kEAAkE;gBAClE,uBAAuB;gBACvB,MAAM0K,QAAQJ,QAAQnF,GAAG,CAAClD,OAAOjC,EAAE;gBACnC,IAAI,CAAC0K,SAAUA,KAAK,CAAC9M,oBAAoBC,KAAK,CAAC,IAAI,QAAQoE,OAAOnE,IAAI,KAAK,aAAamE,OAAOnC,KAAK,EAAG;oBACrGwK,QAAQjF,GAAG,CAACpD,OAAOjC,EAAE,EAAEgC,YAAYC,QAAQpE;gBAC7C;YACF;YACA,OAAO;gBAAEuM;gBAAQE;YAAQ;QAC3B;QAEA,MAAMpC,MAAKvB,GAAG,EAAEhC,KAAK;YACnB,MAAMX,SAASD,cAAcY,MAAMX,MAAM;YACzC,MAAM2G,QAAQ3O,kBAAkB,aAAK2I;gBAAOX;gBAAQiB,SAASP,oBAAoBC;;YACjF,yEAAyE;YACzE,MAAMV,OAAO0G,MAAM1G,IAAI,CAACtB,GAAG,CAAC,CAACmC,MAC3BA,IAAIkB,OAAO,KAAK,WAAW,aAAKlB;oBAAKkB,SAAS;oBAAQhI,QAAQ;oBAAkBkI,MAAM,EAAE;qBAAKpB;YAE/F,MAAMoD,OAAqB,aAAKyC;gBAAO1G;gBAAMwB,SAASD,UAAUvB;;YAEhE,MAAM2G,UAAU,MAAMlE,cAAcC;YACpC,IAAIiE,SAAS;gBACX,OAAOvO,6BACL6L,MACAA,KAAKjE,IAAI,CAACtB,GAAG,CAAC,CAACmC,MAAS,CAAA;wBAAEA,KAAKA,IAAIZ,KAAK;wBAAEhC,QAAQ0I;wBAASC,QAAQ;oBAAK,CAAA;YAE5E;YAEA,MAAMC,WAAsC,EAAE;YAC9C,MAAMC,WAAmF,EAAE;YAC3F,KAAK,MAAMjG,OAAOoD,KAAKjE,IAAI,CAAE;gBAC3B,IAAIa,IAAIkB,OAAO,KAAK,UAAU;gBAC9B,MAAMzG,QAAQ0G,aAAanB,KAAKlH,oBAAoBC,KAAK;gBACzD,MAAMoE,SAAS3C,2BAA2BC;gBAC1C,IAAI,CAAC0C,QAAQ;oBACX6I,SAAS/L,IAAI,CAAC;wBACZ+F,KAAKA,IAAIZ,KAAK;wBACdtC,SAAShE,oBAAoBC,KAAK;wBAClC0B,OAAOE,OAAOF,gBAAAA,QAAS;wBACvB2C,QAAQ,CAAC,CAAC,EAAEzC,OAAOF,gBAAAA,QAAS,IAAI,2CAA2C,CAAC;wBAC5EsL,QAAQ;oBACV;oBACA;gBACF;gBACAE,SAAShM,IAAI,CAAC;oBAAE+F;oBAAK7C;gBAAO;gBAC5B,IAAIA,OAAOnE,IAAI,KAAK,YAAYhC,sBAAsBmG,OAAO9B,MAAM,GAAG;oBACpE2K,SAAS/L,IAAI,CAAC;wBACZ+F,KAAKA,IAAIZ,KAAK;wBACdtC,SAAShE,oBAAoBC,KAAK;wBAClC0B,OAAO0C,OAAO9B,MAAM;wBACpB+B,QAAQ,GAAGD,OAAO9B,MAAM,CAAC,iEAAiE,EAAE8B,OAAO9B,MAAM,CAAC,iBAAiB,CAAC;oBAC9H;gBACF;YACF;YAEA,mFAAmF;YACnF,MAAM6K,cAAc,IAAInG;YACxB,KAAK,MAAM,EAAEC,GAAG,EAAE7C,MAAM,EAAE,IAAI8I,SAAU;gBACtC,IAAI9I,OAAOnE,IAAI,KAAK,YAAY,CAACkN,YAAYC,GAAG,CAAChJ,OAAO9B,MAAM,GAAG6K,YAAY3F,GAAG,CAACpD,OAAO9B,MAAM,EAAE2E,IAAIZ,KAAK;YAC3G;YACA,MAAMlF,YAAY+L,SAAShI,MAAM,CAC/B,CAAClF,QACCA,MAAMoE,MAAM,CAACnE,IAAI,KAAK;YAE1B,MAAMoN,SAASlM,UAAUsB,MAAM,GAC3B,MAAMjD,kCACJmJ,WACAG,IAAII,KAAK,EACT/H,UAAU2D,GAAG,CAAC,CAAC9E,QAAU4B,OAAO5B,MAAMoE,MAAM,CAACnC,KAAK,MAEpD,IAAI+E;YACR,KAAK,MAAM,EAAEC,GAAG,EAAE7C,MAAM,EAAE,IAAIjD,UAAW;gBACvC,MAAMmB,SAAStD,oBAAoBoF,OAAOnC,KAAK;gBAC/C,IAAI,CAACK,QAAQ;gBACb,MAAMgL,SAASH,YAAY7F,GAAG,CAAChF;gBAC/B,IAAIgL,WAAW/F,WAAW;oBACxB0F,SAAS/L,IAAI,CAAC;wBACZ+F,KAAKA,IAAIZ,KAAK;wBACdtC,SAAShE,oBAAoBC,KAAK;wBAClC0B,OAAOE,OAAOwC,OAAOnC,KAAK;wBAC1BoC,QAAQ,CAAC,YAAY,EAAE/B,OAAO,kBAAkB,EAAEgL,SAAS,EAAE,iDAAiD,CAAC;oBACjH;gBACF,OAAO,IAAID,OAAO/F,GAAG,CAAC1F,OAAOwC,OAAOnC,KAAK,OAAO,MAAM;oBACpDgL,SAAS/L,IAAI,CAAC;wBACZ+F,KAAKA,IAAIZ,KAAK;wBACdtC,SAAShE,oBAAoBC,KAAK;wBAClC0B,OAAOE,OAAOwC,OAAOnC,KAAK;wBAC1BoC,QAAQ,CAAC,YAAY,EAAE/B,OAAO,4DAA4D,CAAC;oBAC7F;gBACF;YACF;YACA,OAAO9D,6BAA6B6L,MAAM4C;QAC5C;QAEA,MAAMM,OAAMzE,GAAG,EAAEa,KAAK,EAAE6D,MAAM;YAC5B,MAAMC,UAA+B,EAAE;YACvC,MAAM1M,OAA4B,EAAE;YACpC,MAAM2M,QAAqB;gBAAEzM,SAAS;gBAAGE,WAAW;YAAE;YACtD,MAAM4L,UAAU,MAAMlE,cAAcC;YACpC,KAAK,MAAM7B,OAAO0C,MAAMvD,IAAI,CAAE;gBAC5B,MAAMuH,SAAS,MAAMH,OAAOI,cAAc,CAAC3G,IAAIZ,KAAK;gBACpD,IAAIsH,QAAQ;oBACVF,QAAQvM,IAAI,CAACyM;oBACb;gBACF;gBACA,IAAIH,OAAOK,UAAU,KAAKrM,eAAe;gBACzC,IAAIsM;gBACJ,IAAI9N;gBACJ,MAAMoE,SAAS3C,2BAA2B2G,aAAanB,KAAKlH,oBAAoBC,KAAK;gBACrF,IAAIiH,IAAIkB,OAAO,KAAK,UAAU;oBAC5B,uEAAuE;oBACvE2F,SAAS;wBAAE7G,KAAKA,IAAIZ,KAAK;wBAAE0H,SAAS;uBAAe9G,IAAI+G,QAAQ,GAAG;wBAAEA,UAAU/G,IAAI+G,QAAQ;oBAAC,IAAI,CAAC;wBAAI7N,QAAQ;;gBAC9G,OAAO,IAAI4M,SAAS;oBAClBe,SAAS;wBAAE7G,KAAKA,IAAIZ,KAAK;wBAAE0H,SAAS;wBAAU5N,QAAQ;wBAAgBiJ,SAAS2D;oBAAQ;gBACzF,OAAO,IAAI,CAAC3I,QAAQ;oBAClB0J,SAAS;wBAAE7G,KAAKA,IAAIZ,KAAK;wBAAE0H,SAAS;wBAAU5N,QAAQ;wBAAgBiJ,SAAS;oBAAyC;gBAC1H,OAAO;oBACL,MAAMlJ,OAAOkI,aAAanB,KAAKlH,oBAAoBG,IAAI;oBACvD,MAAM+N,SAAS;wBACb/E,OAAOJ,IAAII,KAAK;wBAChB/I,QAAQ;wBACRC,QAAQ;wBACRC,YAAYyI,IAAIC,QAAQ;wBACxBmF,OAAOtF;wBACPvE,QAAQ,OAAOnE,SAAS,WAAWA,OAAO;oBAC5C;oBACA,MAAMiO,UACJ/J,OAAOnE,IAAI,KAAK,WACZ,MAAMV,8BAA8BoJ,WAAW,aAAKsF;wBAAQ3L,QAAQ8B,OAAO9B,MAAM;0BACjF,MAAMhD,wBAAwBqJ,WAAW,aAAKsF;wBAAQhM,OAAOL,OAAOwC,OAAOnC,KAAK;;oBACtF,IAAIkM,QAAQC,OAAO,EAAE;wBACnBN,SAAS;4BAAE7G,KAAKA,IAAIZ,KAAK;4BAAE0H,SAAS;4BAAWC,UAAU5J,OAAOjC,EAAE;wBAAC;wBACnEnC,QAAQ;4BACNiH,KAAKA,IAAIZ,KAAK;4BACd2H,UAAU5J,OAAOjC,EAAE;4BACnBsE,QAAQ;4BACR0H,SAASzJ,YAAYP,YAAYC,QAAQ+J,QAAQnO,KAAK;wBACxD;wBACA0N,KAAK,CAACtJ,OAAOnE,IAAI,KAAK,WAAW,YAAY,YAAY,IAAI;oBAC/D,OAAO;wBACL,iEAAiE;wBACjE6N,SAAS;4BAAE7G,KAAKA,IAAIZ,KAAK;4BAAE0H,SAAS;4BAAaC,UAAU5J,OAAOjC,EAAE;4BAAEhC,QAAQ;wBAAiB;oBACjG;gBACF;gBACA,MAAMqN,OAAOa,WAAW,CAACP,QAAQ9N;gBACjCyN,QAAQvM,IAAI,CAAC4M;gBACb,IAAI9N,OAAOe,KAAKG,IAAI,CAAClB;YACvB;YACA,IAAI0N,MAAMzM,OAAO,IAAIyM,MAAMvM,SAAS,EAAE;gBACpC,MAAMuH,KAAK4F,cAAc,CAACxF,IAAII,KAAK,EAAE;oBAAEqF,KAAKzF,IAAIC,QAAQ;gBAAC,GAAGpI,wCAAwCC,GAAG,CAAC8M,QAAQ;oBAC9G1K,MAAM;oBACNb,IAAI2G,IAAII,KAAK;gBACf;YACF;YACA,OAAO;gBAAEuE;gBAAS1M;YAAK;QACzB;QAEA,MAAMyN,QAAO1F,GAAG,EAAEkB,QAAQ,EAAEyE,SAAS;YACnC,MAAM1B,UAAU,MAAMlE,cAAcC;YACpC,IAAIiE,SAAS,MAAM,IAAI2B,MAAM3B;YAC7B,MAAMxD,UAAUS,SAASzD,OAAO,CAC7BzB,GAAG,CAAC,CAAC9E,QAAUuC,iCAAiCvC,MAAMgO,QAAQ,GAC9D9I,MAAM,CAAC,CAACd,SAAiDA,WAAW;YACvE,MAAMoF,QAAQ,MAAMF,YAAYR,IAAII,KAAK,EAAEK;YAC3C,MAAMoF,OAA2B,EAAE;YACnC,MAAMC,YAAgC,EAAE;YACxC,MAAMC,UAAuB;gBAAE5N,SAAS;gBAAGE,WAAW;YAAE;YACxD,KAAK,MAAMnB,SAASgK,SAASzD,OAAO,CAAE;gBACpC,MAAMnC,SAAS7B,iCAAiCvC,MAAMgO,QAAQ;gBAC9D,MAAMc,SAAS1K,SAASoF,MAAMlC,GAAG,CAAClD,OAAOjC,EAAE,IAAIoF;gBAC/C,IAAI,CAACnD,UAAU,CAAC0K,QAAQ;oBACtBH,KAAKzN,IAAI,CAAC;wBAAEuF,QAAQ;wBAAWuH,UAAUhO,MAAMgO,QAAQ;wBAAEe,KAAK;oBAAO;oBACrE;gBACF;gBACA,MAAMC,OAAO3Q,iBAAiB2B,OAAOmE,YAAYC,QAAQ0K;gBACzD,IAAIE,KAAKvI,MAAM,KAAK,YAAY;oBAC9B,kEAAkE;oBAClE,kEAAkE;oBAClE,oEAAoE;oBACpE,IAAIgI,CAAAA,6BAAAA,SAAW,CAACzO,MAAMgO,QAAQ,CAAC,MAAK,YAAYc,OAAO1O,MAAM,KAAK,WAAW;wBAC3EwO,UAAU1N,IAAI,CAAC8N;wBACf;oBACF;gBACF,OAAO,IAAIA,KAAKvI,MAAM,KAAK,UAAU;oBACnCkI,KAAKzN,IAAI,CAAC8N;oBACV;gBACF;gBACA,MAAMC,OACJ7K,OAAOnE,IAAI,KAAK,WACZ,MAAMJ,iCAAiC8I,WAAWG,IAAII,KAAK,EAAE9E,OAAO9B,MAAM,IAC1E,MAAMxC,gCAAgC6I,WAAWG,IAAII,KAAK,EAAE9E,OAAOlC,GAAG;gBAC5E,IAAI+M,MAAMJ,OAAO,CAACzK,OAAOnE,IAAI,KAAK,WAAW,YAAY,YAAY,IAAI;gBACzE0O,KAAKzN,IAAI,CAAC;oBAAEuF,QAAQ;oBAAUuH,UAAUhO,MAAMgO,QAAQ;gBAAC;YACzD;YACA,IAAIa,QAAQ5N,OAAO,IAAI4N,QAAQ1N,SAAS,EAAE;gBACxC,MAAMuH,KAAK4F,cAAc,CAACxF,IAAII,KAAK,EAAE;oBAAEqF,KAAKzF,IAAIC,QAAQ;gBAAC,GAAGpI,wCAAwCI,IAAI,CAAC8N,UAAU;oBACjH7L,MAAM;oBACNb,IAAI2G,IAAII,KAAK;gBACf;YACF;YACA,OAAO;gBAAEyF;gBAAMC;YAAU;QAC3B;IACF;AACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
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 { TransferPlanGateHooks } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources';
|
|
18
|
+
/**
|
|
19
|
+
* Sequences' plan question for a transfer (AGL-3548): both resources
|
|
20
|
+
* declare `featureFlag: "outreach"`, and the transfer gate asks this for
|
|
21
|
+
* every intent — the refusal every Sequences route answers
|
|
22
|
+
* (`outreachEntitlementRefusal`), in the 403 `plan_required` body the
|
|
23
|
+
* transfer routes answer a plan with.
|
|
24
|
+
*/
|
|
25
|
+
export declare const outreachTransferPlanGate: NonNullable<TransferPlanGateHooks['planGate']>;
|
|
@@ -0,0 +1,35 @@
|
|
|
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 { outreachEntitlementRefusal } from "../engine/outreach-access.js";
|
|
17
|
+
/**
|
|
18
|
+
* Sequences' plan question for a transfer (AGL-3548): both resources
|
|
19
|
+
* declare `featureFlag: "outreach"`, and the transfer gate asks this for
|
|
20
|
+
* every intent — the refusal every Sequences route answers
|
|
21
|
+
* (`outreachEntitlementRefusal`), in the 403 `plan_required` body the
|
|
22
|
+
* transfer routes answer a plan with.
|
|
23
|
+
*/ export const outreachTransferPlanGate = (subject)=>{
|
|
24
|
+
const refusal = outreachEntitlementRefusal(subject.org);
|
|
25
|
+
return refusal ? {
|
|
26
|
+
status: 403,
|
|
27
|
+
body: {
|
|
28
|
+
error: refusal.message,
|
|
29
|
+
reason: 'plan_required',
|
|
30
|
+
code: 'outreach'
|
|
31
|
+
}
|
|
32
|
+
} : null;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=plan-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/transfer/plan-gate.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 { TransferPlanGateHooks } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources'\nimport { outreachEntitlementRefusal } from '../engine/outreach-access'\n\n/**\n * Sequences' plan question for a transfer (AGL-3548): both resources\n * declare `featureFlag: \"outreach\"`, and the transfer gate asks this for\n * every intent — the refusal every Sequences route answers\n * (`outreachEntitlementRefusal`), in the 403 `plan_required` body the\n * transfer routes answer a plan with.\n */\nexport const outreachTransferPlanGate: NonNullable<TransferPlanGateHooks['planGate']> = (subject) => {\n const refusal = outreachEntitlementRefusal(subject.org as Record<string, unknown>)\n return refusal ? { status: 403, body: { error: refusal.message, reason: 'plan_required', code: 'outreach' } } : null\n}\n"],"names":["outreachEntitlementRefusal","outreachTransferPlanGate","subject","refusal","org","status","body","error","message","reason","code"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAGD,SAASA,0BAA0B,QAAQ,+BAA2B;AAEtE;;;;;;CAMC,GACD,OAAO,MAAMC,2BAA2E,CAACC;IACvF,MAAMC,UAAUH,2BAA2BE,QAAQE,GAAG;IACtD,OAAOD,UAAU;QAAEE,QAAQ;QAAKC,MAAM;YAAEC,OAAOJ,QAAQK,OAAO;YAAEC,QAAQ;YAAiBC,MAAM;QAAW;IAAE,IAAI;AAClH,EAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
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 { OutreachDoNotContactTransferDeps } from './do-not-contact-transfer';
|
|
18
|
+
/**
|
|
19
|
+
* The do-not-contact transfer resource's reach into the platform: the Admin
|
|
20
|
+
* SDK, the membership resolver and organization read the route gate uses,
|
|
21
|
+
* and the organization's activity log. Loaded by the console's declarations
|
|
22
|
+
* the first time a transfer asks, never at boot.
|
|
23
|
+
*/
|
|
24
|
+
export declare function platformOutreachTransferDeps(): OutreachDoNotContactTransferDeps;
|
|
@@ -0,0 +1,39 @@
|
|
|
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 { firebaseAdmin } from "@aglyn/tenant-data-admin/server/firebase-admin";
|
|
17
|
+
import { logOrgActivity } from "@aglyn/tenant-data-admin/server/organizations";
|
|
18
|
+
import { resolveOrgPermissions } from "@aglyn/tenant-runtime/org-permissions";
|
|
19
|
+
/**
|
|
20
|
+
* The do-not-contact transfer resource's reach into the platform: the Admin
|
|
21
|
+
* SDK, the membership resolver and organization read the route gate uses,
|
|
22
|
+
* and the organization's activity log. Loaded by the console's declarations
|
|
23
|
+
* the first time a transfer asks, never at boot.
|
|
24
|
+
*/ export function platformOutreachTransferDeps() {
|
|
25
|
+
const firestore = firebaseAdmin.app().firestore();
|
|
26
|
+
return {
|
|
27
|
+
firestore,
|
|
28
|
+
now: Date.now,
|
|
29
|
+
resolveOrgPermissions: (uid, context)=>resolveOrgPermissions(uid, context),
|
|
30
|
+
readOrg: async (orgId)=>{
|
|
31
|
+
var _snapshot_data;
|
|
32
|
+
const snapshot = await firestore.collection('orgs').doc(orgId).get();
|
|
33
|
+
return snapshot.exists ? (_snapshot_data = snapshot.data()) != null ? _snapshot_data : {} : null;
|
|
34
|
+
},
|
|
35
|
+
logOrgActivity: (orgId, actor, action, target)=>logOrgActivity(orgId, actor, action, target)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=platform-transfer-deps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/transfer/platform-transfer-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 { firebaseAdmin } from '@aglyn/tenant-data-admin/server/firebase-admin'\nimport { logOrgActivity } from '@aglyn/tenant-data-admin/server/organizations'\nimport { resolveOrgPermissions } from '@aglyn/tenant-runtime/org-permissions'\nimport type { OutreachDoNotContactTransferDeps } from './do-not-contact-transfer'\n\n/**\n * The do-not-contact transfer resource's reach into the platform: the Admin\n * SDK, the membership resolver and organization read the route gate uses,\n * and the organization's activity log. Loaded by the console's declarations\n * the first time a transfer asks, never at boot.\n */\nexport function platformOutreachTransferDeps(): OutreachDoNotContactTransferDeps {\n const firestore = firebaseAdmin.app().firestore()\n return {\n firestore,\n now: Date.now,\n resolveOrgPermissions: (uid, context) => resolveOrgPermissions(uid, context),\n readOrg: async (orgId) => {\n const snapshot = await firestore.collection('orgs').doc(orgId).get()\n return snapshot.exists ? (snapshot.data() ?? {}) : null\n },\n logOrgActivity: (orgId, actor, action, target) => logOrgActivity(orgId, actor, action, target),\n }\n}\n"],"names":["firebaseAdmin","logOrgActivity","resolveOrgPermissions","platformOutreachTransferDeps","firestore","app","now","Date","uid","context","readOrg","orgId","snapshot","collection","doc","get","exists","data","actor","action","target"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,aAAa,QAAQ,iDAAgD;AAC9E,SAASC,cAAc,QAAQ,gDAA+C;AAC9E,SAASC,qBAAqB,QAAQ,wCAAuC;AAG7E;;;;;CAKC,GACD,OAAO,SAASC;IACd,MAAMC,YAAYJ,cAAcK,GAAG,GAAGD,SAAS;IAC/C,OAAO;QACLA;QACAE,KAAKC,KAAKD,GAAG;QACbJ,uBAAuB,CAACM,KAAKC,UAAYP,sBAAsBM,KAAKC;QACpEC,SAAS,OAAOC;gBAEYC;YAD1B,MAAMA,WAAW,MAAMR,UAAUS,UAAU,CAAC,QAAQC,GAAG,CAACH,OAAOI,GAAG;YAClE,OAAOH,SAASI,MAAM,IAAIJ,iBAAAA,SAASK,IAAI,cAAbL,iBAAmB,CAAC,IAAK;QACrD;QACAX,gBAAgB,CAACU,OAAOO,OAAOC,QAAQC,SAAWnB,eAAeU,OAAOO,OAAOC,QAAQC;IACzF;AACF"}
|
|
@@ -0,0 +1,48 @@
|
|
|
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 { PackageDependency } from '@aglyn/aglyn/data-transfer/package';
|
|
18
|
+
import { type OutreachSequenceDraft } from '../model/sequence-draft';
|
|
19
|
+
/** The resource key, and so the kind every sequence item carries. */
|
|
20
|
+
export declare const OUTREACH_SEQUENCES_TRANSFER_KEY = "outreach.sequences";
|
|
21
|
+
/** The kind a sequence's mailbox is named under; the workspace's connected mailboxes answer it. */
|
|
22
|
+
export declare const OUTREACH_MAILBOX_REFERENCE_KIND = "outreach.mailboxes";
|
|
23
|
+
/** The marketing plugin's campaigns resource, which a sequence's campaigns name. */
|
|
24
|
+
export declare const OUTREACH_CAMPAIGN_REFERENCE_KIND = "marketing.campaigns";
|
|
25
|
+
/** The CRM's email templates resource, which an email step's template names. */
|
|
26
|
+
export declare const OUTREACH_TEMPLATE_REFERENCE_KIND = "crm.email-templates";
|
|
27
|
+
/** A sequence as a package carries it. */
|
|
28
|
+
export type OutreachSequencePackageContent = OutreachSequenceDraft;
|
|
29
|
+
/** The package content of a stored sequence (or anything shaped like one): the editor's draft, nothing else. */
|
|
30
|
+
export declare function outreachSequencePackageContent(source: unknown): OutreachSequencePackageContent;
|
|
31
|
+
/** What a sequence names. */
|
|
32
|
+
export declare function outreachSequenceDependencies(content: OutreachSequencePackageContent): PackageDependency[];
|
|
33
|
+
/** The sequence with every reference moved through `idMap`; a dropped one is emptied. */
|
|
34
|
+
export declare function remapOutreachSequenceIds(content: OutreachSequencePackageContent, idMap: ReadonlyMap<string, string>): OutreachSequencePackageContent;
|
|
35
|
+
/** The rules an import of sequences keeps, shown with their reasons. */
|
|
36
|
+
export declare const OUTREACH_SEQUENCE_PACKAGE_RULES: readonly [{
|
|
37
|
+
readonly id: "draft";
|
|
38
|
+
readonly label: "An imported sequence arrives as a draft";
|
|
39
|
+
readonly reason: "A sequence emails people only once someone activates it, and an import never does. A sequence you replace keeps the status it already had.";
|
|
40
|
+
}, {
|
|
41
|
+
readonly id: "noEnrollments";
|
|
42
|
+
readonly label: "Nobody enrolled moves with it";
|
|
43
|
+
readonly reason: "A package carries how a sequence reads: its steps and settings. Who was enrolled and what they were sent stay where they happened.";
|
|
44
|
+
}, {
|
|
45
|
+
readonly id: "mailbox";
|
|
46
|
+
readonly label: "It sends from a mailbox connected here";
|
|
47
|
+
readonly reason: "A mailbox is connected by the person who sends from it, so an imported sequence is pointed at one of this workspace’s mailboxes.";
|
|
48
|
+
}];
|
|
@@ -0,0 +1,93 @@
|
|
|
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
|
+
* SEQUENCES AS PACKAGE ITEMS (AGL-3535) — what a sequence carries in a
|
|
18
|
+
* workspace package, what it names, and how a reference moves.
|
|
19
|
+
*
|
|
20
|
+
* An item is the sequence as the editor holds it (`OutreachSequenceDraft`):
|
|
21
|
+
* its name, site, mailbox, steps, settings and campaigns. Never its status,
|
|
22
|
+
* its counters or anyone enrolled in it — a package carries how a sequence
|
|
23
|
+
* reads, not who it reached — so a sequence exported and imported back is
|
|
24
|
+
* `identical`, and an import never brings sending with it.
|
|
25
|
+
*
|
|
26
|
+
* What it names: its site (`site`), its mailbox (`outreach.mailboxes`, a
|
|
27
|
+
* kind no package carries: mailboxes are connected, never imported), its
|
|
28
|
+
* campaigns (`marketing.campaigns`) and each email step's CRM template
|
|
29
|
+
* (`crm.emailTemplates`). A reference the person drops leaves the site and
|
|
30
|
+
* mailbox empty, the campaign off the list and the step on its own subject
|
|
31
|
+
* and body.
|
|
32
|
+
*
|
|
33
|
+
* Pure: the server half (`sequences-package.server.ts`) reads and writes.
|
|
34
|
+
*=========================================*/ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
35
|
+
import { remapPackageReference, TRANSFER_SITE_KIND } from "@aglyn/aglyn/data-transfer/package-plan";
|
|
36
|
+
import { readOutreachSequenceDraft } from "../model/sequence-draft.js";
|
|
37
|
+
/** The resource key, and so the kind every sequence item carries. */ export const OUTREACH_SEQUENCES_TRANSFER_KEY = 'outreach.sequences';
|
|
38
|
+
/** The kind a sequence's mailbox is named under; the workspace's connected mailboxes answer it. */ export const OUTREACH_MAILBOX_REFERENCE_KIND = 'outreach.mailboxes';
|
|
39
|
+
/** The marketing plugin's campaigns resource, which a sequence's campaigns name. */ export const OUTREACH_CAMPAIGN_REFERENCE_KIND = 'marketing.campaigns';
|
|
40
|
+
/** The CRM's email templates resource, which an email step's template names. */ export const OUTREACH_TEMPLATE_REFERENCE_KIND = 'crm.email-templates';
|
|
41
|
+
/** The package content of a stored sequence (or anything shaped like one): the editor's draft, nothing else. */ export function outreachSequencePackageContent(source) {
|
|
42
|
+
return readOutreachSequenceDraft(source);
|
|
43
|
+
}
|
|
44
|
+
/** What a sequence names. */ export function outreachSequenceDependencies(content) {
|
|
45
|
+
var _content_campaignIds, _content_steps;
|
|
46
|
+
const deps = [];
|
|
47
|
+
const seen = new Set();
|
|
48
|
+
const add = (kind, id)=>{
|
|
49
|
+
if (!id || seen.has(`${kind}/${id}`)) return;
|
|
50
|
+
seen.add(`${kind}/${id}`);
|
|
51
|
+
deps.push({
|
|
52
|
+
kind,
|
|
53
|
+
id
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
add(TRANSFER_SITE_KIND, content.hostId);
|
|
57
|
+
add(OUTREACH_MAILBOX_REFERENCE_KIND, content.mailboxId);
|
|
58
|
+
for (const campaignId of (_content_campaignIds = content.campaignIds) != null ? _content_campaignIds : [])add(OUTREACH_CAMPAIGN_REFERENCE_KIND, campaignId);
|
|
59
|
+
for (const step of (_content_steps = content.steps) != null ? _content_steps : []){
|
|
60
|
+
if (step.kind === 'email') add(OUTREACH_TEMPLATE_REFERENCE_KIND, step.templateId);
|
|
61
|
+
}
|
|
62
|
+
return deps;
|
|
63
|
+
}
|
|
64
|
+
/** The sequence with every reference moved through `idMap`; a dropped one is emptied. */ export function remapOutreachSequenceIds(content, idMap) {
|
|
65
|
+
var _remapPackageReference, _remapPackageReference1, _content_campaignIds, _content_steps;
|
|
66
|
+
return _extends({}, content, {
|
|
67
|
+
hostId: (_remapPackageReference = remapPackageReference(idMap, TRANSFER_SITE_KIND, content.hostId)) != null ? _remapPackageReference : '',
|
|
68
|
+
mailboxId: (_remapPackageReference1 = remapPackageReference(idMap, OUTREACH_MAILBOX_REFERENCE_KIND, content.mailboxId)) != null ? _remapPackageReference1 : '',
|
|
69
|
+
campaignIds: ((_content_campaignIds = content.campaignIds) != null ? _content_campaignIds : []).map((id)=>remapPackageReference(idMap, OUTREACH_CAMPAIGN_REFERENCE_KIND, id)).filter((id)=>Boolean(id)),
|
|
70
|
+
steps: ((_content_steps = content.steps) != null ? _content_steps : []).map((step)=>step.kind === 'email' ? _extends({}, step, {
|
|
71
|
+
templateId: remapPackageReference(idMap, OUTREACH_TEMPLATE_REFERENCE_KIND, step.templateId)
|
|
72
|
+
}) : step)
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/** The rules an import of sequences keeps, shown with their reasons. */ export const OUTREACH_SEQUENCE_PACKAGE_RULES = [
|
|
76
|
+
{
|
|
77
|
+
id: 'draft',
|
|
78
|
+
label: 'An imported sequence arrives as a draft',
|
|
79
|
+
reason: 'A sequence emails people only once someone activates it, and an import never does. A sequence you replace keeps the status it already had.'
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: 'noEnrollments',
|
|
83
|
+
label: 'Nobody enrolled moves with it',
|
|
84
|
+
reason: 'A package carries how a sequence reads: its steps and settings. Who was enrolled and what they were sent stay where they happened.'
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: 'mailbox',
|
|
88
|
+
label: 'It sends from a mailbox connected here',
|
|
89
|
+
reason: 'A mailbox is connected by the person who sends from it, so an imported sequence is pointed at one of this workspace’s mailboxes.'
|
|
90
|
+
}
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
//# sourceMappingURL=sequences-package.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/transfer/sequences-package.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\n/*==========================================\n * SEQUENCES AS PACKAGE ITEMS (AGL-3535) — what a sequence carries in a\n * workspace package, what it names, and how a reference moves.\n *\n * An item is the sequence as the editor holds it (`OutreachSequenceDraft`):\n * its name, site, mailbox, steps, settings and campaigns. Never its status,\n * its counters or anyone enrolled in it — a package carries how a sequence\n * reads, not who it reached — so a sequence exported and imported back is\n * `identical`, and an import never brings sending with it.\n *\n * What it names: its site (`site`), its mailbox (`outreach.mailboxes`, a\n * kind no package carries: mailboxes are connected, never imported), its\n * campaigns (`marketing.campaigns`) and each email step's CRM template\n * (`crm.emailTemplates`). A reference the person drops leaves the site and\n * mailbox empty, the campaign off the list and the step on its own subject\n * and body.\n *\n * Pure: the server half (`sequences-package.server.ts`) reads and writes.\n *=========================================*/\n\nimport type { PackageDependency } from '@aglyn/aglyn/data-transfer/package'\nimport { remapPackageReference, TRANSFER_SITE_KIND } from '@aglyn/aglyn/data-transfer/package-plan'\nimport { readOutreachSequenceDraft, type OutreachSequenceDraft } from '../model/sequence-draft'\n\n/** The resource key, and so the kind every sequence item carries. */\nexport const OUTREACH_SEQUENCES_TRANSFER_KEY = 'outreach.sequences'\n\n/** The kind a sequence's mailbox is named under; the workspace's connected mailboxes answer it. */\nexport const OUTREACH_MAILBOX_REFERENCE_KIND = 'outreach.mailboxes'\n\n/** The marketing plugin's campaigns resource, which a sequence's campaigns name. */\nexport const OUTREACH_CAMPAIGN_REFERENCE_KIND = 'marketing.campaigns'\n\n/** The CRM's email templates resource, which an email step's template names. */\nexport const OUTREACH_TEMPLATE_REFERENCE_KIND = 'crm.email-templates'\n\n/** A sequence as a package carries it. */\nexport type OutreachSequencePackageContent = OutreachSequenceDraft\n\n/** The package content of a stored sequence (or anything shaped like one): the editor's draft, nothing else. */\nexport function outreachSequencePackageContent(source: unknown): OutreachSequencePackageContent {\n return readOutreachSequenceDraft(source)\n}\n\n/** What a sequence names. */\nexport function outreachSequenceDependencies(content: OutreachSequencePackageContent): PackageDependency[] {\n const deps: PackageDependency[] = []\n const seen = new Set<string>()\n const add = (kind: string, id: string | null | undefined) => {\n if (!id || seen.has(`${kind}/${id}`)) return\n seen.add(`${kind}/${id}`)\n deps.push({ kind, id })\n }\n add(TRANSFER_SITE_KIND, content.hostId)\n add(OUTREACH_MAILBOX_REFERENCE_KIND, content.mailboxId)\n for (const campaignId of content.campaignIds ?? []) add(OUTREACH_CAMPAIGN_REFERENCE_KIND, campaignId)\n for (const step of content.steps ?? []) {\n if (step.kind === 'email') add(OUTREACH_TEMPLATE_REFERENCE_KIND, step.templateId)\n }\n return deps\n}\n\n/** The sequence with every reference moved through `idMap`; a dropped one is emptied. */\nexport function remapOutreachSequenceIds(\n content: OutreachSequencePackageContent,\n idMap: ReadonlyMap<string, string>,\n): OutreachSequencePackageContent {\n return {\n ...content,\n hostId: remapPackageReference(idMap, TRANSFER_SITE_KIND, content.hostId) ?? '',\n mailboxId: remapPackageReference(idMap, OUTREACH_MAILBOX_REFERENCE_KIND, content.mailboxId) ?? '',\n campaignIds: (content.campaignIds ?? [])\n .map((id) => remapPackageReference(idMap, OUTREACH_CAMPAIGN_REFERENCE_KIND, id))\n .filter((id): id is string => Boolean(id)),\n steps: (content.steps ?? []).map((step) =>\n step.kind === 'email'\n ? { ...step, templateId: remapPackageReference(idMap, OUTREACH_TEMPLATE_REFERENCE_KIND, step.templateId) }\n : step,\n ),\n }\n}\n\n/** The rules an import of sequences keeps, shown with their reasons. */\nexport const OUTREACH_SEQUENCE_PACKAGE_RULES = [\n {\n id: 'draft',\n label: 'An imported sequence arrives as a draft',\n reason:\n 'A sequence emails people only once someone activates it, and an import never does. A sequence you replace keeps the status it already had.',\n },\n {\n id: 'noEnrollments',\n label: 'Nobody enrolled moves with it',\n reason: 'A package carries how a sequence reads: its steps and settings. Who was enrolled and what they were sent stay where they happened.',\n },\n {\n id: 'mailbox',\n label: 'It sends from a mailbox connected here',\n reason: 'A mailbox is connected by the person who sends from it, so an imported sequence is pointed at one of this workspace’s mailboxes.',\n },\n] as const\n"],"names":["remapPackageReference","TRANSFER_SITE_KIND","readOutreachSequenceDraft","OUTREACH_SEQUENCES_TRANSFER_KEY","OUTREACH_MAILBOX_REFERENCE_KIND","OUTREACH_CAMPAIGN_REFERENCE_KIND","OUTREACH_TEMPLATE_REFERENCE_KIND","outreachSequencePackageContent","source","outreachSequenceDependencies","content","deps","seen","Set","add","kind","id","has","push","hostId","mailboxId","campaignId","campaignIds","step","steps","templateId","remapOutreachSequenceIds","idMap","map","filter","Boolean","OUTREACH_SEQUENCE_PACKAGE_RULES","label","reason"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;2CAkB2C;AAG3C,SAASA,qBAAqB,EAAEC,kBAAkB,QAAQ,0CAAyC;AACnG,SAASC,yBAAyB,QAAoC,6BAAyB;AAE/F,mEAAmE,GACnE,OAAO,MAAMC,kCAAkC,qBAAoB;AAEnE,iGAAiG,GACjG,OAAO,MAAMC,kCAAkC,qBAAoB;AAEnE,kFAAkF,GAClF,OAAO,MAAMC,mCAAmC,sBAAqB;AAErE,8EAA8E,GAC9E,OAAO,MAAMC,mCAAmC,sBAAqB;AAKrE,8GAA8G,GAC9G,OAAO,SAASC,+BAA+BC,MAAe;IAC5D,OAAON,0BAA0BM;AACnC;AAEA,2BAA2B,GAC3B,OAAO,SAASC,6BAA6BC,OAAuC;QAUzDA,sBACNA;IAVnB,MAAMC,OAA4B,EAAE;IACpC,MAAMC,OAAO,IAAIC;IACjB,MAAMC,MAAM,CAACC,MAAcC;QACzB,IAAI,CAACA,MAAMJ,KAAKK,GAAG,CAAC,GAAGF,KAAK,CAAC,EAAEC,IAAI,GAAG;QACtCJ,KAAKE,GAAG,CAAC,GAAGC,KAAK,CAAC,EAAEC,IAAI;QACxBL,KAAKO,IAAI,CAAC;YAAEH;YAAMC;QAAG;IACvB;IACAF,IAAIb,oBAAoBS,QAAQS,MAAM;IACtCL,IAAIV,iCAAiCM,QAAQU,SAAS;IACtD,KAAK,MAAMC,eAAcX,uBAAAA,QAAQY,WAAW,YAAnBZ,uBAAuB,EAAE,CAAEI,IAAIT,kCAAkCgB;IAC1F,KAAK,MAAME,SAAQb,iBAAAA,QAAQc,KAAK,YAAbd,iBAAiB,EAAE,CAAE;QACtC,IAAIa,KAAKR,IAAI,KAAK,SAASD,IAAIR,kCAAkCiB,KAAKE,UAAU;IAClF;IACA,OAAOd;AACT;AAEA,uFAAuF,GACvF,OAAO,SAASe,yBACdhB,OAAuC,EACvCiB,KAAkC;QAIxB3B,wBACGA,yBACGU,sBAGNA;IAPV,OAAO,aACFA;QACHS,MAAM,GAAEnB,yBAAAA,sBAAsB2B,OAAO1B,oBAAoBS,QAAQS,MAAM,aAA/DnB,yBAAoE;QAC5EoB,SAAS,GAAEpB,0BAAAA,sBAAsB2B,OAAOvB,iCAAiCM,QAAQU,SAAS,aAA/EpB,0BAAoF;QAC/FsB,aAAa,EAACZ,uBAAAA,QAAQY,WAAW,YAAnBZ,uBAAuB,EAAE,EACpCkB,GAAG,CAAC,CAACZ,KAAOhB,sBAAsB2B,OAAOtB,kCAAkCW,KAC3Ea,MAAM,CAAC,CAACb,KAAqBc,QAAQd;QACxCQ,OAAO,EAACd,iBAAAA,QAAQc,KAAK,YAAbd,iBAAiB,EAAE,EAAEkB,GAAG,CAAC,CAACL,OAChCA,KAAKR,IAAI,KAAK,UACV,aAAKQ;gBAAME,YAAYzB,sBAAsB2B,OAAOrB,kCAAkCiB,KAAKE,UAAU;iBACrGF;;AAGV;AAEA,sEAAsE,GACtE,OAAO,MAAMQ,kCAAkC;IAC7C;QACEf,IAAI;QACJgB,OAAO;QACPC,QACE;IACJ;IACA;QACEjB,IAAI;QACJgB,OAAO;QACPC,QAAQ;IACV;IACA;QACEjB,IAAI;QACJgB,OAAO;QACPC,QAAQ;IACV;CACD,CAAS"}
|
|
@@ -0,0 +1,31 @@
|
|
|
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 ExistingPackageItem } from '@aglyn/aglyn/data-transfer';
|
|
18
|
+
import type { TransferApplyResult, TransferApplyWriter, TransferPackageItemContent, TransferPackageItemWrite, TransferPackageRevertResult, TransferPackageRevertStep, TransferResourceContext } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources';
|
|
19
|
+
import type { TransferReferenceKind } from '@aglyn/aglyn/data-transfer';
|
|
20
|
+
import type { OutreachRouteDeps } from '../routes/route-deps';
|
|
21
|
+
import { type OutreachSequencePackageContent } from './sequences-package';
|
|
22
|
+
type Deps = Pick<OutreachRouteDeps, 'firestore' | 'now' | 'logOrgActivity' | 'gate'>;
|
|
23
|
+
export declare function createOutreachSequencesPackage(deps?: Deps): {
|
|
24
|
+
items(ctx: TransferResourceContext): Promise<ExistingPackageItem[]>;
|
|
25
|
+
readItems(ctx: TransferResourceContext, ids: readonly string[]): Promise<TransferPackageItemContent<import("../model/sequence-draft").OutreachSequenceDraft>[]>;
|
|
26
|
+
problems(ctx: TransferResourceContext, write: TransferPackageItemWrite<OutreachSequencePackageContent>): Promise<string[]>;
|
|
27
|
+
referenceTargets(ctx: TransferResourceContext, kinds: readonly string[]): Promise<TransferReferenceKind[]>;
|
|
28
|
+
writeItems(ctx: TransferResourceContext, items: ReadonlyArray<TransferPackageItemWrite<OutreachSequencePackageContent>>, writer: TransferApplyWriter): Promise<TransferApplyResult>;
|
|
29
|
+
revertItems(ctx: TransferResourceContext, steps: ReadonlyArray<TransferPackageRevertStep<OutreachSequencePackageContent>>): Promise<TransferPackageRevertResult>;
|
|
30
|
+
};
|
|
31
|
+
export {};
|