@aglyn/plugins-crm 1.0.0-beta.218 → 1.0.0-beta.219
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 -13
- package/src/index.d.ts +1 -0
- package/src/index.js.map +1 -1
- package/src/lib/components/companies-bulk-bar.js +12 -4
- package/src/lib/components/companies-bulk-bar.js.map +1 -1
- package/src/lib/components/company-detail-page.js +11 -0
- package/src/lib/components/company-detail-page.js.map +1 -1
- package/src/lib/components/company-edit-drawer.js +12 -2
- package/src/lib/components/company-edit-drawer.js.map +1 -1
- package/src/lib/components/company-import-drawer.d.ts +1 -1
- package/src/lib/components/company-picker.js +10 -3
- package/src/lib/components/company-picker.js.map +1 -1
- package/src/lib/components/contact-detail-page.d.ts +4 -4
- package/src/lib/components/contact-detail-page.js +50 -53
- package/src/lib/components/contact-detail-page.js.map +1 -1
- package/src/lib/components/contact-list-columns.d.ts +3 -0
- package/src/lib/components/contact-list-columns.js +21 -5
- package/src/lib/components/contact-list-columns.js.map +1 -1
- package/src/lib/components/contact-merge-dialog.js +2 -1
- package/src/lib/components/contact-merge-dialog.js.map +1 -1
- package/src/lib/components/contact-timeline-card.js +4 -3
- package/src/lib/components/contact-timeline-card.js.map +1 -1
- package/src/lib/components/contacts-bulk-bar.d.ts +3 -3
- package/src/lib/components/contacts-bulk-bar.js +24 -51
- package/src/lib/components/contacts-bulk-bar.js.map +1 -1
- package/src/lib/components/contacts-section.js +9 -3
- package/src/lib/components/contacts-section.js.map +1 -1
- package/src/lib/components/crm-export-all-button.d.ts +1 -1
- package/src/lib/components/crm-export-all-button.js.map +1 -1
- package/src/lib/components/crm-send-email-dialog.js +9 -6
- package/src/lib/components/crm-send-email-dialog.js.map +1 -1
- package/src/lib/components/csv-import-drawer.js +2 -2
- package/src/lib/components/csv-import-drawer.js.map +1 -1
- package/src/lib/components/deal-detail-page.js +18 -2
- package/src/lib/components/deal-detail-page.js.map +1 -1
- package/src/lib/components/deal-edit-drawer.js +10 -0
- package/src/lib/components/deal-edit-drawer.js.map +1 -1
- package/src/lib/components/deals-bulk-bar.js +13 -5
- package/src/lib/components/deals-bulk-bar.js.map +1 -1
- package/src/lib/components/lead-campaigns-card.js +6 -0
- package/src/lib/components/lead-campaigns-card.js.map +1 -1
- package/src/lib/components/lead-detail-page.js +25 -5
- package/src/lib/components/lead-detail-page.js.map +1 -1
- package/src/lib/components/lead-properties-card.js +6 -0
- package/src/lib/components/lead-properties-card.js.map +1 -1
- package/src/lib/components/lead-surfaces-note.js +4 -5
- package/src/lib/components/lead-surfaces-note.js.map +1 -1
- package/src/lib/components/lead-unqualify-dialog.js +6 -0
- package/src/lib/components/lead-unqualify-dialog.js.map +1 -1
- package/src/lib/components/leads-bulk-bar.js +28 -3
- package/src/lib/components/leads-bulk-bar.js.map +1 -1
- package/src/lib/components/leads-section.js +36 -7
- package/src/lib/components/leads-section.js.map +1 -1
- package/src/lib/components/org-lead-surfaces-note.js +6 -2
- package/src/lib/components/org-lead-surfaces-note.js.map +1 -1
- package/src/lib/components/recipes-card.js +9 -4
- package/src/lib/components/recipes-card.js.map +1 -1
- package/src/lib/components/record-sharing-card.d.ts +57 -0
- package/src/lib/components/record-sharing-card.js +244 -0
- package/src/lib/components/record-sharing-card.js.map +1 -0
- package/src/lib/components/settings-section.js +7 -0
- package/src/lib/components/settings-section.js.map +1 -1
- package/src/lib/components/share-records-dialog.d.ts +28 -0
- package/src/lib/components/share-records-dialog.js +184 -0
- package/src/lib/components/share-records-dialog.js.map +1 -0
- package/src/lib/components/sharing-rule-drawer.d.ts +37 -0
- package/src/lib/components/sharing-rule-drawer.js +374 -0
- package/src/lib/components/sharing-rule-drawer.js.map +1 -0
- package/src/lib/components/sharing-rules-card.d.ts +24 -0
- package/src/lib/components/sharing-rules-card.js +287 -0
- package/src/lib/components/sharing-rules-card.js.map +1 -0
- package/src/lib/components/use-crm-api.d.ts +1 -1
- package/src/lib/components/use-crm-api.js.map +1 -1
- package/src/lib/components/use-site-route-context.d.ts +25 -0
- package/src/lib/components/use-site-route-context.js +58 -0
- package/src/lib/components/use-site-route-context.js.map +1 -0
- package/src/lib/constants/api-routes.d.ts +31 -0
- package/src/lib/constants/api-routes.js +27 -1
- package/src/lib/constants/api-routes.js.map +1 -1
- package/src/lib/declarations.console-server.d.ts +37 -0
- package/src/lib/declarations.console-server.js +103 -0
- package/src/lib/declarations.console-server.js.map +1 -0
- package/src/lib/declarations.server.d.ts +6 -0
- package/src/lib/declarations.server.js +33 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/hooks/use-contact-remove.d.ts +35 -0
- package/src/lib/hooks/use-contact-remove.js +77 -0
- package/src/lib/hooks/use-contact-remove.js.map +1 -0
- package/src/lib/hooks/use-crm-sharing.d.ts +30 -0
- package/src/lib/hooks/use-crm-sharing.js +109 -0
- package/src/lib/hooks/use-crm-sharing.js.map +1 -0
- package/src/lib/model/companies-csv.d.ts +1 -1
- package/src/lib/model/companies-csv.js +2 -2
- package/src/lib/model/companies-csv.js.map +1 -1
- package/src/lib/model/contact-holder.d.ts +68 -0
- package/src/lib/model/contact-holder.js +129 -0
- package/src/lib/model/contact-holder.js.map +1 -0
- package/src/lib/model/contact-interaction-links.d.ts +46 -0
- package/src/lib/model/contact-interaction-links.js +65 -0
- package/src/lib/model/contact-interaction-links.js.map +1 -0
- package/src/lib/model/contact-merge.d.ts +136 -0
- package/src/lib/model/contact-merge.js +412 -0
- package/src/lib/model/contact-merge.js.map +1 -0
- package/src/lib/model/contact-record.d.ts +7 -1
- package/src/lib/model/contact-record.js +6 -5
- package/src/lib/model/contact-record.js.map +1 -1
- package/src/lib/model/contact-remove.d.ts +48 -0
- package/src/lib/model/contact-remove.js +22 -0
- package/src/lib/model/contact-remove.js.map +1 -0
- package/src/lib/model/contacts-bulk-writes.d.ts +2 -71
- package/src/lib/model/contacts-bulk-writes.js +2 -82
- package/src/lib/model/contacts-bulk-writes.js.map +1 -1
- package/src/lib/model/contacts-csv.d.ts +2 -2
- package/src/lib/model/contacts-csv.js +2 -2
- package/src/lib/model/contacts-csv.js.map +1 -1
- package/src/lib/model/crm-csv.d.ts +239 -0
- package/src/lib/model/crm-csv.js +467 -0
- package/src/lib/model/crm-csv.js.map +1 -0
- package/src/lib/model/crm-digest.d.ts +185 -0
- package/src/lib/model/crm-digest.js +272 -0
- package/src/lib/model/crm-digest.js.map +1 -0
- package/src/lib/model/crm-import.d.ts +7 -1
- package/src/lib/model/crm-import.js +2 -1
- package/src/lib/model/crm-import.js.map +1 -1
- package/src/lib/model/crm-record-routes.d.ts +5 -0
- package/src/lib/model/crm-record-routes.js +7 -0
- package/src/lib/model/crm-record-routes.js.map +1 -1
- package/src/lib/model/crm-routes.d.ts +6 -5
- package/src/lib/model/crm-routes.js +7 -7
- package/src/lib/model/crm-routes.js.map +1 -1
- package/src/lib/model/crm-search-sources.d.ts +15 -0
- package/src/lib/model/crm-search-sources.js +162 -0
- package/src/lib/model/crm-search-sources.js.map +1 -0
- package/src/lib/model/crm-sharing-api.d.ts +32 -0
- package/src/lib/model/crm-sharing-api.js +59 -0
- package/src/lib/model/crm-sharing-api.js.map +1 -0
- package/src/lib/model/crm-sharing.d.ts +333 -0
- package/src/lib/model/crm-sharing.js +603 -0
- package/src/lib/model/crm-sharing.js.map +1 -0
- package/src/lib/model/deals-csv.d.ts +1 -1
- package/src/lib/model/deals-csv.js +4 -5
- package/src/lib/model/deals-csv.js.map +1 -1
- package/src/lib/model/lead-filters.d.ts +1 -1
- package/src/lib/model/leads-csv.d.ts +1 -1
- package/src/lib/model/leads-csv.js +1 -1
- package/src/lib/model/leads-csv.js.map +1 -1
- package/src/lib/model/tasks-csv.d.ts +1 -1
- package/src/lib/model/tasks-csv.js +1 -1
- package/src/lib/model/tasks-csv.js.map +1 -1
- package/src/lib/plan-entitlements.d.ts +75 -0
- package/src/lib/plan-entitlements.js +56 -0
- package/src/lib/plan-entitlements.js.map +1 -0
- package/src/lib/plugin.js +3 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/api-v1/contacts-merge.d.ts +20 -0
- package/src/lib/server/api-v1/contacts-merge.js +120 -0
- package/src/lib/server/api-v1/contacts-merge.js.map +1 -0
- package/src/lib/server/api-v1/contacts.d.ts +18 -0
- package/src/lib/server/api-v1/contacts.js +1076 -0
- package/src/lib/server/api-v1/contacts.js.map +1 -0
- package/src/lib/server/api-v1/crm-activities.d.ts +18 -0
- package/src/lib/server/api-v1/crm-activities.js +269 -0
- package/src/lib/server/api-v1/crm-activities.js.map +1 -0
- package/src/lib/server/api-v1/crm-companies.d.ts +18 -0
- package/src/lib/server/api-v1/crm-companies.js +391 -0
- package/src/lib/server/api-v1/crm-companies.js.map +1 -0
- package/src/lib/server/api-v1/crm-deals.d.ts +18 -0
- package/src/lib/server/api-v1/crm-deals.js +631 -0
- package/src/lib/server/api-v1/crm-deals.js.map +1 -0
- package/src/lib/server/api-v1/crm-email-templates.d.ts +18 -0
- package/src/lib/server/api-v1/crm-email-templates.js +336 -0
- package/src/lib/server/api-v1/crm-email-templates.js.map +1 -0
- package/src/lib/server/api-v1/crm-leads.d.ts +18 -0
- package/src/lib/server/api-v1/crm-leads.js +832 -0
- package/src/lib/server/api-v1/crm-leads.js.map +1 -0
- package/src/lib/server/api-v1/crm-pipelines.d.ts +76 -0
- package/src/lib/server/api-v1/crm-pipelines.js +146 -0
- package/src/lib/server/api-v1/crm-pipelines.js.map +1 -0
- package/src/lib/server/api-v1/crm-shared.d.ts +271 -0
- package/src/lib/server/api-v1/crm-shared.js +436 -0
- package/src/lib/server/api-v1/crm-shared.js.map +1 -0
- package/src/lib/server/api-v1/crm-tasks.d.ts +18 -0
- package/src/lib/server/api-v1/crm-tasks.js +398 -0
- package/src/lib/server/api-v1/crm-tasks.js.map +1 -0
- package/src/lib/server/api-v1/openapi.d.ts +29 -0
- package/src/lib/server/api-v1/openapi.js +985 -0
- package/src/lib/server/api-v1/openapi.js.map +1 -0
- package/src/lib/server/api-v1/usage.d.ts +26 -0
- package/src/lib/server/api-v1/usage.js +73 -0
- package/src/lib/server/api-v1/usage.js.map +1 -0
- package/src/lib/server/consent-group-participant.js +1 -1
- package/src/lib/server/consent-group-participant.js.map +1 -1
- package/src/lib/server/contact-lifecycle-floor.d.ts +89 -0
- package/src/lib/server/contact-lifecycle-floor.js +91 -0
- package/src/lib/server/contact-lifecycle-floor.js.map +1 -0
- package/src/lib/server/contact-remove.d.ts +75 -0
- package/src/lib/server/contact-remove.js +244 -0
- package/src/lib/server/contact-remove.js.map +1 -0
- package/src/lib/server/contact-update.js +2 -1
- package/src/lib/server/contact-update.js.map +1 -1
- package/src/lib/server/contacts-import.d.ts +47 -11
- package/src/lib/server/contacts-import.js +171 -71
- package/src/lib/server/contacts-import.js.map +1 -1
- package/src/lib/server/contacts-merge.d.ts +1 -1
- package/src/lib/server/contacts-merge.js +3 -2
- package/src/lib/server/contacts-merge.js.map +1 -1
- package/src/lib/server/convert-host-lead.d.ts +189 -0
- package/src/lib/server/convert-host-lead.js +518 -0
- package/src/lib/server/convert-host-lead.js.map +1 -0
- package/src/lib/server/crm-sharing.d.ts +108 -0
- package/src/lib/server/crm-sharing.js +790 -0
- package/src/lib/server/crm-sharing.js.map +1 -0
- package/src/lib/server/daily-digest-route.d.ts +107 -0
- package/src/lib/server/daily-digest-route.js +588 -0
- package/src/lib/server/daily-digest-route.js.map +1 -0
- package/src/lib/server/export-route.d.ts +60 -0
- package/src/lib/server/export-route.js +447 -0
- package/src/lib/server/export-route.js.map +1 -0
- package/src/lib/server/inbound-route.d.ts +74 -0
- package/src/lib/server/inbound-route.js +257 -0
- package/src/lib/server/inbound-route.js.map +1 -0
- package/src/lib/server/lead-convert.d.ts +1 -1
- package/src/lib/server/lead-convert.js +2 -2
- package/src/lib/server/lead-convert.js.map +1 -1
- package/src/lib/server/merge-contacts.d.ts +55 -0
- package/src/lib/server/merge-contacts.js +274 -0
- package/src/lib/server/merge-contacts.js.map +1 -0
- package/src/lib/server/pipeline-record-index.d.ts +36 -0
- package/src/lib/server/pipeline-record-index.js +87 -0
- package/src/lib/server/pipeline-record-index.js.map +1 -0
- package/src/lib/server/record-facts.js +2 -1
- package/src/lib/server/record-facts.js.map +1 -1
- package/src/lib/server/task-reminders-route.d.ts +82 -0
- package/src/lib/server/task-reminders-route.js +497 -0
- package/src/lib/server/task-reminders-route.js.map +1 -0
- package/src/lib/server-deal-stage.js +2 -1
- package/src/lib/server-deal-stage.js.map +1 -1
- package/src/lib/server.d.ts +5 -2
- package/src/lib/server.js +47 -2
- package/src/lib/server.js.map +1 -1
- package/src/lib/testing/stand-in-site-record-routes.d.ts +26 -0
- package/src/lib/testing/stand-in-site-record-routes.js +55 -0
- package/src/lib/testing/stand-in-site-record-routes.js.map +1 -0
- package/src/lib/usage-axes.d.ts +35 -0
- package/src/lib/usage-axes.js +68 -0
- package/src/lib/usage-axes.js.map +1 -0
- package/src/lib/components/use-emails-hub-path.d.ts +0 -24
- package/src/lib/components/use-emails-hub-path.js +0 -59
- package/src/lib/components/use-emails-hub-path.js.map +0 -1
|
@@ -0,0 +1,271 @@
|
|
|
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
|
+
/**
|
|
18
|
+
* What the CRM resources of `/v1` have in common (AGL-2606).
|
|
19
|
+
*
|
|
20
|
+
* Companies, pipelines, deals, tasks and activities are five collections
|
|
21
|
+
* with one shape (`CrmScoped`), one scope model (`crmScopeTokens`) and one
|
|
22
|
+
* set of questions every write has to answer — which site is this for, is
|
|
23
|
+
* that uid a member here, does the contact it names exist. Each handler
|
|
24
|
+
* module answers those through this file, so the answer cannot differ by
|
|
25
|
+
* resource.
|
|
26
|
+
*
|
|
27
|
+
* ## Reads are org-wide, writes name a site
|
|
28
|
+
*
|
|
29
|
+
* An API key is an ORGANIZATION credential (`api-keys.ts`), so a list here
|
|
30
|
+
* reads the whole collection: every company the org's sites know, whichever
|
|
31
|
+
* site created it. That is the same answer `GET /v1/contacts` gives, and it
|
|
32
|
+
* is right for the caller the key represents — an integration acting for the
|
|
33
|
+
* account, not a member sitting on one site.
|
|
34
|
+
*
|
|
35
|
+
* A write is different, because a CRM record carries `visibleTo` and the
|
|
36
|
+
* console enforces it: a record stamped for the wrong scope is a record a
|
|
37
|
+
* site's own team cannot open. So every create names the site it belongs to
|
|
38
|
+
* — `consentSiteId`, the parameter the contacts write already uses for the
|
|
39
|
+
* same question — and the record is stamped exactly as that site's console
|
|
40
|
+
* would stamp it ({@link crmCreateStamp}). There is no default site for the
|
|
41
|
+
* reason the contacts write gives: picking the org's only site works until
|
|
42
|
+
* the org has two.
|
|
43
|
+
*/
|
|
44
|
+
import { type ContactFieldDefinition, type CrmCollection, type CrmCustomValue, type CrmFieldObject, type CrmPicklist } from '@aglyn/aglyn/server';
|
|
45
|
+
import { Timestamp } from 'firebase-admin/firestore';
|
|
46
|
+
import { type ApiV1Context } from '@aglyn/tenant-data-admin/server/api-v1-kit';
|
|
47
|
+
/** A title, a name — one line. */
|
|
48
|
+
export declare const CRM_TITLE_MAX = 200;
|
|
49
|
+
/** Free text — notes, a body, a lost reason. */
|
|
50
|
+
export declare const CRM_TEXT_MAX = 5000;
|
|
51
|
+
/** A short label — an industry, an outcome, a job title. */
|
|
52
|
+
export declare const CRM_LABEL_MAX = 120;
|
|
53
|
+
/** A stored id — Firestore's own ceiling is 1,500 bytes; nothing here is close. */
|
|
54
|
+
export declare const CRM_ID_MAX = 200;
|
|
55
|
+
/**
|
|
56
|
+
* `orgs/{orgId}/{name}` — every CRM collection sits directly under the org.
|
|
57
|
+
*
|
|
58
|
+
* Nothing in this module dereferences `CRM_COLLECTIONS` at load time, on
|
|
59
|
+
* purpose: the `/v1` suites mock `@aglyn/aglyn/server` as a closed world,
|
|
60
|
+
* and a module-level `CRM_COLLECTIONS.x` would throw at import in every
|
|
61
|
+
* suite that never asked for the CRM, reading as a failure of theirs.
|
|
62
|
+
*/
|
|
63
|
+
export declare function crmCollection(ctx: ApiV1Context, name: CrmCollection): FirebaseFirestore.CollectionReference;
|
|
64
|
+
/**
|
|
65
|
+
* The records band, asked before a company or a deal is created (AGL-2611).
|
|
66
|
+
*
|
|
67
|
+
* `null` when there is room; the refusal otherwise, in the shape
|
|
68
|
+
* `POST /v1/contacts` has always answered at the same band — `plan_required`
|
|
69
|
+
* with a code, because on the one plan that refuses (Free) an upgrade is the
|
|
70
|
+
* whole remedy, and every paid plan meters the excess instead. The measure
|
|
71
|
+
* is the same three aggregates the monthly rollup bills from, so the API
|
|
72
|
+
* and the invoice cannot disagree about whether the band was full.
|
|
73
|
+
*/
|
|
74
|
+
export declare function crmRecordsBandRefusal(ctx: ApiV1Context): Promise<Response | null>;
|
|
75
|
+
/**
|
|
76
|
+
* The `consentSiteId` a create carries, validated.
|
|
77
|
+
*
|
|
78
|
+
* Required, and required to be one of the organization's own sites, for the
|
|
79
|
+
* reason the module header gives. The message names the field so an
|
|
80
|
+
* integrator sees the same key they would on a contact write.
|
|
81
|
+
*/
|
|
82
|
+
export declare function readCrmSite(ctx: ApiV1Context, noun: string, body: Record<string, unknown>): {
|
|
83
|
+
siteId: string;
|
|
84
|
+
} | {
|
|
85
|
+
response: Response;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* The fields every CRM create stamps, for a record created from `siteId`.
|
|
89
|
+
*
|
|
90
|
+
* `visibleTo` is `crmScopeTokens` — the contact create path's own expression,
|
|
91
|
+
* which is what puts an API-created deal in exactly the scope a deal created
|
|
92
|
+
* from that site's console would land in. `hostId` is provenance and is never
|
|
93
|
+
* rewritten. `createdByUid` is the literal `'api'` because a key has no uid;
|
|
94
|
+
* it is the attribution the contact create makes through `sources.api`, in
|
|
95
|
+
* the field the CRM types already carry.
|
|
96
|
+
*
|
|
97
|
+
* Both timestamps are set here, once, so a fresh record's `updated` equals
|
|
98
|
+
* its `created` and an `updatedAfter` sweep that started before the create
|
|
99
|
+
* picks it up.
|
|
100
|
+
*/
|
|
101
|
+
export declare function crmCreateStamp(ctx: ApiV1Context, siteId: string): {
|
|
102
|
+
visibleTo: import("@aglyn/aglyn/src").ScopeToken[];
|
|
103
|
+
hostId: string;
|
|
104
|
+
createdByUid: string;
|
|
105
|
+
createdAt: Timestamp;
|
|
106
|
+
updatedAt: Timestamp;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Whether `uid` is a member of the authenticated organization.
|
|
110
|
+
*
|
|
111
|
+
* One document read at `orgs/{orgId}/members/{uid}` — the roster
|
|
112
|
+
* `listOrgMembers` reads whole answers the same question for the price of
|
|
113
|
+
* the whole roster, and a create should not pay for members it never asked
|
|
114
|
+
* about.
|
|
115
|
+
*/
|
|
116
|
+
export declare function isOrgMember(ctx: ApiV1Context, uid: string): Promise<boolean>;
|
|
117
|
+
/** A clearable scalar: a value to write, `null` to delete, absent to leave. */
|
|
118
|
+
export type Clearable<T> = T | null | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* The membership check for an owner or assignee, run after the synchronous
|
|
121
|
+
* grammar so a body that is already refused never spends the read.
|
|
122
|
+
*/
|
|
123
|
+
export declare function memberError(ctx: ApiV1Context, field: string, uid: Clearable<string>): Promise<Record<string, string>>;
|
|
124
|
+
/**
|
|
125
|
+
* `values` as an `update()` payload: `null` becomes a field delete, an
|
|
126
|
+
* `undefined` is left out, so an omitted key leaves the field alone and an
|
|
127
|
+
* explicit `null` clears it — the PATCH contract every resource here shares.
|
|
128
|
+
*/
|
|
129
|
+
export declare function updatePayload(values: Record<string, unknown>): Record<string, unknown>;
|
|
130
|
+
/**
|
|
131
|
+
* `values` as a `create()` payload: `null` and `undefined` are both left out,
|
|
132
|
+
* because a fresh document has nothing to clear.
|
|
133
|
+
*/
|
|
134
|
+
export declare function createPayload(values: Record<string, unknown>): Record<string, unknown>;
|
|
135
|
+
/** The three records a CRM row can point at, by the field that points. */
|
|
136
|
+
export interface CrmRefs {
|
|
137
|
+
contactId?: string;
|
|
138
|
+
companyId?: string;
|
|
139
|
+
dealId?: string;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Each reference in `refs` that points at nothing, as `field → reason`.
|
|
143
|
+
*
|
|
144
|
+
* A dangling id is refused rather than stored because the console renders a
|
|
145
|
+
* task by the contact it names, and a task pointing at a contact that does
|
|
146
|
+
* not exist is a task nobody can find from anywhere. One read per reference
|
|
147
|
+
* given, none for a reference omitted.
|
|
148
|
+
*/
|
|
149
|
+
export declare function crmRefErrors(ctx: ApiV1Context, refs: CrmRefs): Promise<Record<string, string>>;
|
|
150
|
+
/**
|
|
151
|
+
* An ISO 8601 instant as milliseconds, or `null` when the value is not one.
|
|
152
|
+
*
|
|
153
|
+
* `Date.parse` is permissive — it takes `"2026"` and `"March 3"` — and a
|
|
154
|
+
* client sending a bare date almost always means midnight in THEIR zone,
|
|
155
|
+
* which we cannot know. So only the full form is accepted: a date, a `T`, a
|
|
156
|
+
* time and an offset (`Z` or `±hh:mm`). Anything less answers `null` and the
|
|
157
|
+
* caller names the field.
|
|
158
|
+
*/
|
|
159
|
+
export declare function parseIsoInstant(value: unknown): number | null;
|
|
160
|
+
/** Milliseconds as ISO 8601, or `null` for anything that is not a finite number. */
|
|
161
|
+
export declare function isoFromMs(value: unknown): string | null;
|
|
162
|
+
/** The `created`/`updated` pair every CRM view publishes. */
|
|
163
|
+
export declare function crmTimes(data: FirebaseFirestore.DocumentData): {
|
|
164
|
+
created: string;
|
|
165
|
+
updated: string;
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* A trimmed, bounded string from a body field, or `null` for an explicit
|
|
169
|
+
* `null`, or `undefined` when the field was not sent.
|
|
170
|
+
*
|
|
171
|
+
* `null` is how a PATCH clears an optional field — the caller turns it into
|
|
172
|
+
* a delete — so it has to survive as a value distinct from "absent". A
|
|
173
|
+
* number or a boolean is not silently stringified: the field is named.
|
|
174
|
+
*/
|
|
175
|
+
export declare function readOptionalText(body: Record<string, unknown>, key: string, max: number, errors: Record<string, string>): string | null | undefined;
|
|
176
|
+
/** One of a fixed list, or the field is named with the list. */
|
|
177
|
+
export declare function readChoice<T extends string>(body: Record<string, unknown>, key: string, choices: readonly T[], errors: Record<string, string>): T | undefined;
|
|
178
|
+
/**
|
|
179
|
+
* A reference id from a body field — trimmed and bounded, `null` to clear.
|
|
180
|
+
*
|
|
181
|
+
* Existence is the caller's question ({@link crmRefErrors}); this only rules
|
|
182
|
+
* out a value that could never be an id.
|
|
183
|
+
*/
|
|
184
|
+
export declare function readRefId(body: Record<string, unknown>, key: string, errors: Record<string, string>): string | null | undefined;
|
|
185
|
+
/** Every key of `body` that is not in `allowed`, named as not writable. */
|
|
186
|
+
export declare function refuseUnknownKeys(body: Record<string, unknown>, allowed: ReadonlySet<string>, noun: string, errors: Record<string, string>): void;
|
|
187
|
+
/** The `400 validation_failed` every CRM write and filter answers with. */
|
|
188
|
+
export declare function crmValidationFailed(ctx: ApiV1Context, noun: string, fields: Record<string, string>): Response;
|
|
189
|
+
/** One `?field=value` a list accepts, in the order it prefers to index them. */
|
|
190
|
+
export interface CrmEqualityFilter {
|
|
191
|
+
field: string;
|
|
192
|
+
value: string;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* The CRM list grammar: at most one Firestore clause, the rest on the page.
|
|
196
|
+
*
|
|
197
|
+
* ## Why one clause
|
|
198
|
+
*
|
|
199
|
+
* Every equality here has a single-field index, and every list in this API
|
|
200
|
+
* ends in `orderBy(__name__)`, so ONE `where` is served without anything
|
|
201
|
+
* shipped. Two equalities, or an equality beside a range, is a composite
|
|
202
|
+
* index per combination — five resources with four filters each is more
|
|
203
|
+
* indexes than the whole product carries today, every one a query that
|
|
204
|
+
* answers `500` in production until it is deployed by hand. So the FIRST
|
|
205
|
+
* filter in `filters` goes to Firestore, and the caller orders them by
|
|
206
|
+
* selectivity: an id before a status, because `?dealId=` selects a handful
|
|
207
|
+
* of rows and `?status=open` selects most of the collection. The rest are
|
|
208
|
+
* applied to the page, which can come back short — the
|
|
209
|
+
* [short page](apps/docs/api/conventions.md) every filtered list already
|
|
210
|
+
* documents.
|
|
211
|
+
*
|
|
212
|
+
* ## `updatedAfter` changes the order
|
|
213
|
+
*
|
|
214
|
+
* The one range filter, and the one filter that cannot be a post-filter
|
|
215
|
+
* without becoming useless: a sync asking "what changed since T" over an
|
|
216
|
+
* id-ordered list still walks the whole collection to find out. So when it is
|
|
217
|
+
* given the list is ordered by `updated` ascending (then id), the range goes
|
|
218
|
+
* to Firestore, and EVERY equality moves to the page — a range on one field
|
|
219
|
+
* beside an equality on another is the composite index above. The cursor
|
|
220
|
+
* carries the timestamp and the id together, at Firestore's own precision,
|
|
221
|
+
* because a millisecond cursor would replay a row updated in the same
|
|
222
|
+
* millisecond on the next page.
|
|
223
|
+
*/
|
|
224
|
+
export declare function listCrm(ctx: ApiV1Context, collection: FirebaseFirestore.CollectionReference, url: URL, filters: CrmEqualityFilter[], view: (doc: FirebaseFirestore.QueryDocumentSnapshot) => unknown): Promise<Response>;
|
|
225
|
+
/**
|
|
226
|
+
* The equality filters a list URL carries, in the caller's order, with an
|
|
227
|
+
* empty value meaning "absent" as every filter in this API does.
|
|
228
|
+
*/
|
|
229
|
+
export declare function readEqualityFilters(url: URL, fields: readonly string[]): CrmEqualityFilter[];
|
|
230
|
+
/**
|
|
231
|
+
* The org's custom field definitions, retired ones included and every
|
|
232
|
+
* object's, for a resource's `custom` validation (AGL-2661).
|
|
233
|
+
*
|
|
234
|
+
* One bounded read of a small collection, paid only when a body carries
|
|
235
|
+
* `custom` — the contacts resource's own reader, shared so the three
|
|
236
|
+
* resources judge a map the same way. Retired definitions come back too
|
|
237
|
+
* because the reader refuses a write under one BY NAME, which is a better
|
|
238
|
+
* answer than "no such field" for a key the integration wrote last month.
|
|
239
|
+
*/
|
|
240
|
+
export declare function readOrgFieldDefinitions(ctx: ApiV1Context): Promise<ContactFieldDefinition[]>;
|
|
241
|
+
/**
|
|
242
|
+
* The org's lead source list (AGL-3298) — the values a lead's
|
|
243
|
+
* `leadSource` is restricted to on every write through the API.
|
|
244
|
+
*/
|
|
245
|
+
export declare function readOrgLeadSourcePicklist(ctx: ApiV1Context): Promise<CrmPicklist>;
|
|
246
|
+
/**
|
|
247
|
+
* A body's `custom` map, judged against the org's definitions for ONE
|
|
248
|
+
* object, or the refusals to answer with (AGL-2661).
|
|
249
|
+
*
|
|
250
|
+
* `undefined` when the body carried no map — nothing to validate and
|
|
251
|
+
* nothing to write. The read happens only then, so a body without
|
|
252
|
+
* `custom` pays for no definitions.
|
|
253
|
+
*/
|
|
254
|
+
export declare function readCrmCustomBody(ctx: ApiV1Context, body: Record<string, unknown>, object: CrmFieldObject): Promise<{
|
|
255
|
+
values: Record<string, CrmCustomValue>;
|
|
256
|
+
} | {
|
|
257
|
+
errors: Record<string, string>;
|
|
258
|
+
} | undefined>;
|
|
259
|
+
/**
|
|
260
|
+
* A stored `custom` map as published: the map itself, or `{}` on a record
|
|
261
|
+
* that has none, so a client can index it without a guard (AGL-2661).
|
|
262
|
+
*/
|
|
263
|
+
export declare function crmCustomView(data: FirebaseFirestore.DocumentData): Record<string, CrmCustomValue>;
|
|
264
|
+
/**
|
|
265
|
+
* The `custom` values as a PATCH writes them: one dotted path per key, so
|
|
266
|
+
* the stored map is merged rather than replaced — `custom` on a PATCH
|
|
267
|
+
* means "these keys", and an integration correcting one value must not
|
|
268
|
+
* have to resend the other nine to keep them. A `null` stays a `null`:
|
|
269
|
+
* the key remains, explicitly cleared, the shape a `where` can find.
|
|
270
|
+
*/
|
|
271
|
+
export declare function crmCustomUpdate(values: Record<string, CrmCustomValue>): Record<string, unknown>;
|