@aglyn/aglyn 1.0.0-beta.198 → 1.0.0-beta.200
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 +11 -11
- package/src/lib/app-utils/activity-search.d.ts +39 -0
- package/src/lib/app-utils/activity-search.js +85 -0
- package/src/lib/app-utils/activity-search.js.map +1 -0
- package/src/lib/app-utils/admin-audit-index.d.ts +104 -0
- package/src/lib/app-utils/admin-audit-index.js +177 -0
- package/src/lib/app-utils/admin-audit-index.js.map +1 -0
- package/src/lib/app-utils/artifact-list-keys.d.ts +51 -0
- package/src/lib/app-utils/artifact-list-keys.js +144 -0
- package/src/lib/app-utils/artifact-list-keys.js.map +1 -0
- package/src/lib/app-utils/content-query-fields.d.ts +69 -0
- package/src/lib/app-utils/content-query-fields.js +79 -0
- package/src/lib/app-utils/content-query-fields.js.map +1 -0
- package/src/lib/app-utils/crm.d.ts +151 -1
- package/src/lib/app-utils/crm.js +388 -1
- package/src/lib/app-utils/crm.js.map +1 -1
- package/src/lib/app-utils/dataset-models.d.ts +75 -24
- package/src/lib/app-utils/dataset-models.js +107 -40
- package/src/lib/app-utils/dataset-models.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.js +40 -40
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/email-search.d.ts +36 -0
- package/src/lib/app-utils/email-search.js +53 -0
- package/src/lib/app-utils/email-search.js.map +1 -0
- package/src/lib/app-utils/forms.d.ts +83 -3
- package/src/lib/app-utils/forms.js +67 -0
- package/src/lib/app-utils/forms.js.map +1 -1
- package/src/lib/app-utils/marketplace-listing-visibility.d.ts +7 -6
- package/src/lib/app-utils/marketplace-listing-visibility.js +12 -10
- package/src/lib/app-utils/marketplace-listing-visibility.js.map +1 -1
- package/src/lib/app-utils/media-embedded-fields.d.ts +471 -0
- package/src/lib/app-utils/media-embedded-fields.js +619 -0
- package/src/lib/app-utils/media-embedded-fields.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/exif.d.ts +160 -0
- package/src/lib/app-utils/media-embedded-metadata/exif.js +1267 -0
- package/src/lib/app-utils/media-embedded-metadata/exif.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/gif.d.ts +44 -0
- package/src/lib/app-utils/media-embedded-metadata/gif.js +134 -0
- package/src/lib/app-utils/media-embedded-metadata/gif.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/heif.d.ts +23 -0
- package/src/lib/app-utils/media-embedded-metadata/heif.js +354 -0
- package/src/lib/app-utils/media-embedded-metadata/heif.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/icc.d.ts +22 -0
- package/src/lib/app-utils/media-embedded-metadata/icc.js +85 -0
- package/src/lib/app-utils/media-embedded-metadata/icc.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/image-blocks.d.ts +145 -0
- package/src/lib/app-utils/media-embedded-metadata/image-blocks.js +200 -0
- package/src/lib/app-utils/media-embedded-metadata/image-blocks.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/index.d.ts +93 -0
- package/src/lib/app-utils/media-embedded-metadata/index.js +744 -0
- package/src/lib/app-utils/media-embedded-metadata/index.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/iptc.d.ts +59 -0
- package/src/lib/app-utils/media-embedded-metadata/iptc.js +529 -0
- package/src/lib/app-utils/media-embedded-metadata/iptc.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/jpeg.d.ts +43 -0
- package/src/lib/app-utils/media-embedded-metadata/jpeg.js +456 -0
- package/src/lib/app-utils/media-embedded-metadata/jpeg.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/mp4.d.ts +37 -0
- package/src/lib/app-utils/media-embedded-metadata/mp4.js +621 -0
- package/src/lib/app-utils/media-embedded-metadata/mp4.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/ooxml.d.ts +131 -0
- package/src/lib/app-utils/media-embedded-metadata/ooxml.js +1058 -0
- package/src/lib/app-utils/media-embedded-metadata/ooxml.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf-objects.d.ts +223 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf-objects.js +936 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf-objects.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf.d.ts +82 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf.js +1167 -0
- package/src/lib/app-utils/media-embedded-metadata/pdf.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/png.d.ts +41 -0
- package/src/lib/app-utils/media-embedded-metadata/png.js +512 -0
- package/src/lib/app-utils/media-embedded-metadata/png.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/svg.d.ts +30 -0
- package/src/lib/app-utils/media-embedded-metadata/svg.js +154 -0
- package/src/lib/app-utils/media-embedded-metadata/svg.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/tiff.d.ts +40 -0
- package/src/lib/app-utils/media-embedded-metadata/tiff.js +158 -0
- package/src/lib/app-utils/media-embedded-metadata/tiff.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/types.d.ts +60 -0
- package/src/lib/app-utils/media-embedded-metadata/types.js +32 -0
- package/src/lib/app-utils/media-embedded-metadata/types.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/webm.d.ts +26 -0
- package/src/lib/app-utils/media-embedded-metadata/webm.js +417 -0
- package/src/lib/app-utils/media-embedded-metadata/webm.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/webp.d.ts +37 -0
- package/src/lib/app-utils/media-embedded-metadata/webp.js +272 -0
- package/src/lib/app-utils/media-embedded-metadata/webp.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/xml.d.ts +231 -0
- package/src/lib/app-utils/media-embedded-metadata/xml.js +598 -0
- package/src/lib/app-utils/media-embedded-metadata/xml.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/xmp.d.ts +100 -0
- package/src/lib/app-utils/media-embedded-metadata/xmp.js +1475 -0
- package/src/lib/app-utils/media-embedded-metadata/xmp.js.map +1 -0
- package/src/lib/app-utils/media-embedded-metadata/zip.d.ts +93 -0
- package/src/lib/app-utils/media-embedded-metadata/zip.js +531 -0
- package/src/lib/app-utils/media-embedded-metadata/zip.js.map +1 -0
- package/src/lib/app-utils/media-metadata.d.ts +79 -0
- package/src/lib/app-utils/media-metadata.js +74 -0
- package/src/lib/app-utils/media-metadata.js.map +1 -1
- package/src/lib/app-utils/message-search.d.ts +40 -0
- package/src/lib/app-utils/message-search.js +168 -0
- package/src/lib/app-utils/message-search.js.map +1 -0
- package/src/lib/app-utils/name-search.d.ts +95 -0
- package/src/lib/app-utils/name-search.js +108 -0
- package/src/lib/app-utils/name-search.js.map +1 -1
- package/src/lib/app-utils/server.d.ts +2 -0
- package/src/lib/app-utils/server.js +2 -0
- package/src/lib/app-utils/server.js.map +1 -1
- package/src/lib/foundation/definitions/platform.types.d.ts +11 -0
- package/src/lib/foundation/definitions/platform.types.js.map +1 -1
- package/src/server.d.ts +1 -0
- package/src/server.js +7 -0
- package/src/server.js.map +1 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ import { displayNameSearchFields } from "./name-search.js";
|
|
18
|
+
/*
|
|
19
|
+
* THE KEYS A SITE ARTIFACT'S LISTS QUERY BY (AGL-3321).
|
|
20
|
+
*
|
|
21
|
+
* The screens, layouts, reusable components and templates of a site are
|
|
22
|
+
* listed, searched and filtered by Firestore queries, so every key a list
|
|
23
|
+
* asks about has to be WRITTEN — a query cannot find a document by a value it
|
|
24
|
+
* derives, and cannot find one that lacks the field at all:
|
|
25
|
+
*
|
|
26
|
+
* nameLower / nameTokens / nameReversed
|
|
27
|
+
* the name keys (`displayNameSearchFields`), on all four;
|
|
28
|
+
* kind on a component, `site` or `email` — a component stored
|
|
29
|
+
* before AGL-3287 carries none and is read as `site`, so the
|
|
30
|
+
* "Used in: Page" filter needs the word stored;
|
|
31
|
+
* on a template, `page`, `component` or `layout` — a template
|
|
32
|
+
* stored with none is read as a page template;
|
|
33
|
+
* source.type on a template, its provenance — one stored with no
|
|
34
|
+
* `source`, or with the legacy `workspace`, was saved here,
|
|
35
|
+
* which is `authored`;
|
|
36
|
+
* libraryRow on a template, whether it is its own row of the templates
|
|
37
|
+
* library: a multi-page STARTER is one row (AGL-696), led by
|
|
38
|
+
* its first live page, so the other pages carry `false` — and
|
|
39
|
+
* so does a deleted template (`artifactDeleteListKeys`), which
|
|
40
|
+
* is how the library's query leaves tombstones out;
|
|
41
|
+
*
|
|
42
|
+
* A DELETED screen gets none of them. The email templates list orders by
|
|
43
|
+
* `nameLower`, and an email template's delete clears its name keys so the
|
|
44
|
+
* tombstone leaves that order (a query cannot ask for `deletedAt` to be
|
|
45
|
+
* absent) — so no create, restore or backfill may stamp them back.
|
|
46
|
+
*
|
|
47
|
+
* Every CREATE stamps them (`artifactCreateListKeys`) and every rename
|
|
48
|
+
* restamps the name keys (`artifactRenameListKeys`).
|
|
49
|
+
* `tools/scripts/backfill-artifacts-list-keys.mjs` stamps the documents
|
|
50
|
+
* written before them; a script cannot import this library, so it reads the
|
|
51
|
+
* documents the way this module does, and both sides answer
|
|
52
|
+
* `tools/scripts/lib/artifact-list-keys.fixtures.json` — this module's spec
|
|
53
|
+
* and the backfill's `--self-test`.
|
|
54
|
+
*/ /** The site artifact collections whose lists query these keys. */ export const LISTED_ARTIFACT_COLLECTIONS = [
|
|
55
|
+
'screens',
|
|
56
|
+
'layouts',
|
|
57
|
+
'components',
|
|
58
|
+
'templates'
|
|
59
|
+
];
|
|
60
|
+
/** Whether a host subcollection is one whose lists query these keys. */ export const isListedArtifactCollection = (collection)=>LISTED_ARTIFACT_COLLECTIONS.includes(collection);
|
|
61
|
+
/** The kinds a template's `kind` holds; absent reads as `page`. */ const TEMPLATE_KINDS = [
|
|
62
|
+
'page',
|
|
63
|
+
'component',
|
|
64
|
+
'layout'
|
|
65
|
+
];
|
|
66
|
+
/**
|
|
67
|
+
* A provenance word no writer stores any more: a detached marketplace copy
|
|
68
|
+
* was stamped `workspace` before it was stamped `authored` (AGL-3321).
|
|
69
|
+
*/ const LEGACY_AUTHORED_SOURCE = 'workspace';
|
|
70
|
+
const record = (value)=>value && typeof value === 'object' ? value : {};
|
|
71
|
+
/**
|
|
72
|
+
* The name a list finds an artifact by.
|
|
73
|
+
*
|
|
74
|
+
* Its `displayName` — except a page of a multi-page STARTER, which the
|
|
75
|
+
* templates library lists as ONE row under the starter's name
|
|
76
|
+
* (`source.starterName`), so every page of it carries that name's keys and a
|
|
77
|
+
* search for the starter finds the row whichever page leads it.
|
|
78
|
+
*/ export function artifactSearchName(collection, doc) {
|
|
79
|
+
if (collection === 'templates') {
|
|
80
|
+
const starterName = record(doc['source'])['starterName'];
|
|
81
|
+
if (typeof starterName === 'string' && starterName.trim()) return starterName;
|
|
82
|
+
}
|
|
83
|
+
return doc['displayName'];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The list keys a CREATE of `doc` into `collection` stamps: the name keys,
|
|
87
|
+
* and the stored default of a kind a reader otherwise infers. Nothing for a
|
|
88
|
+
* collection no artifact list queries.
|
|
89
|
+
*
|
|
90
|
+
* Spread AFTER the document's own fields: the keys are derived from them.
|
|
91
|
+
*/ export function artifactCreateListKeys(collection, doc) {
|
|
92
|
+
if (!isListedArtifactCollection(collection)) return {};
|
|
93
|
+
if (collection === 'screens' && doc['deletedAt'] != null) return {};
|
|
94
|
+
const keys = _extends({}, displayNameSearchFields(artifactSearchName(collection, doc)));
|
|
95
|
+
if (collection === 'components' && doc['kind'] !== 'email') keys['kind'] = 'site';
|
|
96
|
+
if (collection === 'templates') {
|
|
97
|
+
if (!TEMPLATE_KINDS.includes(String(doc['kind']))) keys['kind'] = 'page';
|
|
98
|
+
// Provenance is server-managed (AGL-666), and a writer that states it is
|
|
99
|
+
// never overridden here. None at all, or the legacy word a detached copy
|
|
100
|
+
// carried, was saved here, which is `authored`.
|
|
101
|
+
const sourceType = record(doc['source'])['type'];
|
|
102
|
+
if (typeof sourceType !== 'string' || sourceType === LEGACY_AUTHORED_SOURCE) {
|
|
103
|
+
keys['source'] = _extends({}, record(doc['source']), {
|
|
104
|
+
type: 'authored'
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
keys['libraryRow'] = doc['deletedAt'] == null && leadsItsStarter(doc);
|
|
108
|
+
}
|
|
109
|
+
return keys;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Whether a template leads its starter's library row when the starter is
|
|
113
|
+
* written whole: every template that is not a starter page does, and of a
|
|
114
|
+
* starter's pages the first (`starterOrder` 0). A later delete moves the lead
|
|
115
|
+
* to the next live page — see `artifactDeleteListKeys`.
|
|
116
|
+
*/ function leadsItsStarter(doc) {
|
|
117
|
+
var _source_starterOrder;
|
|
118
|
+
const source = record(doc['source']);
|
|
119
|
+
const starterId = source['starterId'];
|
|
120
|
+
if (typeof starterId !== 'string' || !starterId) return true;
|
|
121
|
+
return Number((_source_starterOrder = source['starterOrder']) != null ? _source_starterOrder : 0) === 0;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* The list keys a SOFT DELETE writes beside `deletedAt`: a deleted template
|
|
125
|
+
* is no longer a library row. A caller deleting the page that LEADS a
|
|
126
|
+
* starter's row gives the lead to the next live page (`libraryRow: true`),
|
|
127
|
+
* or the starter disappears from the library with pages still in it.
|
|
128
|
+
*/ export function artifactDeleteListKeys(collection) {
|
|
129
|
+
return collection === 'templates' ? {
|
|
130
|
+
libraryRow: false
|
|
131
|
+
} : {};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* The name keys a RENAME writes beside the new `displayName`. `doc` is the
|
|
135
|
+
* document as read, for the one case whose search name is not its display
|
|
136
|
+
* name (a starter page — see `artifactSearchName`).
|
|
137
|
+
*/ export function artifactRenameListKeys(collection, displayName, doc = {}) {
|
|
138
|
+
if (!isListedArtifactCollection(collection)) return {};
|
|
139
|
+
return displayNameSearchFields(artifactSearchName(collection, _extends({}, doc, {
|
|
140
|
+
displayName
|
|
141
|
+
})));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
//# sourceMappingURL=artifact-list-keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/artifact-list-keys.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 { displayNameSearchFields } from './name-search'\n\n/*\n * THE KEYS A SITE ARTIFACT'S LISTS QUERY BY (AGL-3321).\n *\n * The screens, layouts, reusable components and templates of a site are\n * listed, searched and filtered by Firestore queries, so every key a list\n * asks about has to be WRITTEN — a query cannot find a document by a value it\n * derives, and cannot find one that lacks the field at all:\n *\n * nameLower / nameTokens / nameReversed\n * the name keys (`displayNameSearchFields`), on all four;\n * kind on a component, `site` or `email` — a component stored\n * before AGL-3287 carries none and is read as `site`, so the\n * \"Used in: Page\" filter needs the word stored;\n * on a template, `page`, `component` or `layout` — a template\n * stored with none is read as a page template;\n * source.type on a template, its provenance — one stored with no\n * `source`, or with the legacy `workspace`, was saved here,\n * which is `authored`;\n * libraryRow on a template, whether it is its own row of the templates\n * library: a multi-page STARTER is one row (AGL-696), led by\n * its first live page, so the other pages carry `false` — and\n * so does a deleted template (`artifactDeleteListKeys`), which\n * is how the library's query leaves tombstones out;\n *\n * A DELETED screen gets none of them. The email templates list orders by\n * `nameLower`, and an email template's delete clears its name keys so the\n * tombstone leaves that order (a query cannot ask for `deletedAt` to be\n * absent) — so no create, restore or backfill may stamp them back.\n *\n * Every CREATE stamps them (`artifactCreateListKeys`) and every rename\n * restamps the name keys (`artifactRenameListKeys`).\n * `tools/scripts/backfill-artifacts-list-keys.mjs` stamps the documents\n * written before them; a script cannot import this library, so it reads the\n * documents the way this module does, and both sides answer\n * `tools/scripts/lib/artifact-list-keys.fixtures.json` — this module's spec\n * and the backfill's `--self-test`.\n */\n\n/** The site artifact collections whose lists query these keys. */\nexport const LISTED_ARTIFACT_COLLECTIONS = [\n 'screens',\n 'layouts',\n 'components',\n 'templates',\n] as const\n\nexport type ListedArtifactCollection =\n (typeof LISTED_ARTIFACT_COLLECTIONS)[number]\n\n/** Whether a host subcollection is one whose lists query these keys. */\nexport const isListedArtifactCollection = (\n collection: string,\n): collection is ListedArtifactCollection =>\n (LISTED_ARTIFACT_COLLECTIONS as readonly string[]).includes(collection)\n\n/** The kinds a template's `kind` holds; absent reads as `page`. */\nconst TEMPLATE_KINDS = ['page', 'component', 'layout']\n\n/**\n * A provenance word no writer stores any more: a detached marketplace copy\n * was stamped `workspace` before it was stamped `authored` (AGL-3321).\n */\nconst LEGACY_AUTHORED_SOURCE = 'workspace'\n\nconst record = (value: unknown): Record<string, unknown> =>\n value && typeof value === 'object' ? (value as Record<string, unknown>) : {}\n\n/**\n * The name a list finds an artifact by.\n *\n * Its `displayName` — except a page of a multi-page STARTER, which the\n * templates library lists as ONE row under the starter's name\n * (`source.starterName`), so every page of it carries that name's keys and a\n * search for the starter finds the row whichever page leads it.\n */\nexport function artifactSearchName(\n collection: string,\n doc: Record<string, unknown>,\n): unknown {\n if (collection === 'templates') {\n const starterName = record(doc['source'])['starterName']\n if (typeof starterName === 'string' && starterName.trim()) return starterName\n }\n return doc['displayName']\n}\n\n/**\n * The list keys a CREATE of `doc` into `collection` stamps: the name keys,\n * and the stored default of a kind a reader otherwise infers. Nothing for a\n * collection no artifact list queries.\n *\n * Spread AFTER the document's own fields: the keys are derived from them.\n */\nexport function artifactCreateListKeys(\n collection: string,\n doc: Record<string, unknown>,\n): Record<string, unknown> {\n if (!isListedArtifactCollection(collection)) return {}\n if (collection === 'screens' && doc['deletedAt'] != null) return {}\n const keys: Record<string, unknown> = {\n ...displayNameSearchFields(artifactSearchName(collection, doc)),\n }\n if (collection === 'components' && doc['kind'] !== 'email') keys['kind'] = 'site'\n if (collection === 'templates') {\n if (!TEMPLATE_KINDS.includes(String(doc['kind']))) keys['kind'] = 'page'\n // Provenance is server-managed (AGL-666), and a writer that states it is\n // never overridden here. None at all, or the legacy word a detached copy\n // carried, was saved here, which is `authored`.\n const sourceType = record(doc['source'])['type']\n if (typeof sourceType !== 'string' || sourceType === LEGACY_AUTHORED_SOURCE) {\n keys['source'] = { ...record(doc['source']), type: 'authored' }\n }\n keys['libraryRow'] = doc['deletedAt'] == null && leadsItsStarter(doc)\n }\n return keys\n}\n\n/**\n * Whether a template leads its starter's library row when the starter is\n * written whole: every template that is not a starter page does, and of a\n * starter's pages the first (`starterOrder` 0). A later delete moves the lead\n * to the next live page — see `artifactDeleteListKeys`.\n */\nfunction leadsItsStarter(doc: Record<string, unknown>): boolean {\n const source = record(doc['source'])\n const starterId = source['starterId']\n if (typeof starterId !== 'string' || !starterId) return true\n return Number(source['starterOrder'] ?? 0) === 0\n}\n\n/**\n * The list keys a SOFT DELETE writes beside `deletedAt`: a deleted template\n * is no longer a library row. A caller deleting the page that LEADS a\n * starter's row gives the lead to the next live page (`libraryRow: true`),\n * or the starter disappears from the library with pages still in it.\n */\nexport function artifactDeleteListKeys(\n collection: string,\n): Record<string, unknown> {\n return collection === 'templates' ? { libraryRow: false } : {}\n}\n\n/**\n * The name keys a RENAME writes beside the new `displayName`. `doc` is the\n * document as read, for the one case whose search name is not its display\n * name (a starter page — see `artifactSearchName`).\n */\nexport function artifactRenameListKeys(\n collection: string,\n displayName: unknown,\n doc: Record<string, unknown> = {},\n): Record<string, unknown> {\n if (!isListedArtifactCollection(collection)) return {}\n return displayNameSearchFields(\n artifactSearchName(collection, { ...doc, displayName }),\n )\n}\n"],"names":["displayNameSearchFields","LISTED_ARTIFACT_COLLECTIONS","isListedArtifactCollection","collection","includes","TEMPLATE_KINDS","LEGACY_AUTHORED_SOURCE","record","value","artifactSearchName","doc","starterName","trim","artifactCreateListKeys","keys","String","sourceType","type","leadsItsStarter","source","starterId","Number","artifactDeleteListKeys","libraryRow","artifactRenameListKeys","displayName"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,uBAAuB,QAAQ,mBAAe;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCC,GAED,gEAAgE,GAChE,OAAO,MAAMC,8BAA8B;IACzC;IACA;IACA;IACA;CACD,CAAS;AAKV,sEAAsE,GACtE,OAAO,MAAMC,6BAA6B,CACxCC,aAEA,AAACF,4BAAkDG,QAAQ,CAACD,YAAW;AAEzE,iEAAiE,GACjE,MAAME,iBAAiB;IAAC;IAAQ;IAAa;CAAS;AAEtD;;;CAGC,GACD,MAAMC,yBAAyB;AAE/B,MAAMC,SAAS,CAACC,QACdA,SAAS,OAAOA,UAAU,WAAYA,QAAoC,CAAC;AAE7E;;;;;;;CAOC,GACD,OAAO,SAASC,mBACdN,UAAkB,EAClBO,GAA4B;IAE5B,IAAIP,eAAe,aAAa;QAC9B,MAAMQ,cAAcJ,OAAOG,GAAG,CAAC,SAAS,CAAC,CAAC,cAAc;QACxD,IAAI,OAAOC,gBAAgB,YAAYA,YAAYC,IAAI,IAAI,OAAOD;IACpE;IACA,OAAOD,GAAG,CAAC,cAAc;AAC3B;AAEA;;;;;;CAMC,GACD,OAAO,SAASG,uBACdV,UAAkB,EAClBO,GAA4B;IAE5B,IAAI,CAACR,2BAA2BC,aAAa,OAAO,CAAC;IACrD,IAAIA,eAAe,aAAaO,GAAG,CAAC,YAAY,IAAI,MAAM,OAAO,CAAC;IAClE,MAAMI,OAAgC,aACjCd,wBAAwBS,mBAAmBN,YAAYO;IAE5D,IAAIP,eAAe,gBAAgBO,GAAG,CAAC,OAAO,KAAK,SAASI,IAAI,CAAC,OAAO,GAAG;IAC3E,IAAIX,eAAe,aAAa;QAC9B,IAAI,CAACE,eAAeD,QAAQ,CAACW,OAAOL,GAAG,CAAC,OAAO,IAAII,IAAI,CAAC,OAAO,GAAG;QAClE,yEAAyE;QACzE,yEAAyE;QACzE,gDAAgD;QAChD,MAAME,aAAaT,OAAOG,GAAG,CAAC,SAAS,CAAC,CAAC,OAAO;QAChD,IAAI,OAAOM,eAAe,YAAYA,eAAeV,wBAAwB;YAC3EQ,IAAI,CAAC,SAAS,GAAG,aAAKP,OAAOG,GAAG,CAAC,SAAS;gBAAGO,MAAM;;QACrD;QACAH,IAAI,CAAC,aAAa,GAAGJ,GAAG,CAAC,YAAY,IAAI,QAAQQ,gBAAgBR;IACnE;IACA,OAAOI;AACT;AAEA;;;;;CAKC,GACD,SAASI,gBAAgBR,GAA4B;QAIrCS;IAHd,MAAMA,SAASZ,OAAOG,GAAG,CAAC,SAAS;IACnC,MAAMU,YAAYD,MAAM,CAAC,YAAY;IACrC,IAAI,OAAOC,cAAc,YAAY,CAACA,WAAW,OAAO;IACxD,OAAOC,QAAOF,uBAAAA,MAAM,CAAC,eAAe,YAAtBA,uBAA0B,OAAO;AACjD;AAEA;;;;;CAKC,GACD,OAAO,SAASG,uBACdnB,UAAkB;IAElB,OAAOA,eAAe,cAAc;QAAEoB,YAAY;IAAM,IAAI,CAAC;AAC/D;AAEA;;;;CAIC,GACD,OAAO,SAASC,uBACdrB,UAAkB,EAClBsB,WAAoB,EACpBf,MAA+B,CAAC,CAAC;IAEjC,IAAI,CAACR,2BAA2BC,aAAa,OAAO,CAAC;IACrD,OAAOH,wBACLS,mBAAmBN,YAAY,aAAKO;QAAKe;;AAE7C"}
|
|
@@ -0,0 +1,69 @@
|
|
|
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
|
+
* The field the console's entries table searches (AGL-3321): every word
|
|
19
|
+
* prefix of the entry's title, as `nameSearchTokens` writes them, which the
|
|
20
|
+
* table's quick search and its Title "contains" filter ask with
|
|
21
|
+
* `array-contains` on the Firestore query.
|
|
22
|
+
*
|
|
23
|
+
* DERIVED, and never carried in a bundle. Every writer of `title` stamps it
|
|
24
|
+
* through {@link entryTitleSearchFields}: the entry editor's save, the
|
|
25
|
+
* resources route's create, the bundle import, and the seed and changelog
|
|
26
|
+
* scripts. `tools/scripts/backfill-entries-title-tokens.mjs` stamps the
|
|
27
|
+
* entries written before it. An entry without it still lists; it just cannot
|
|
28
|
+
* be found by a word of its title.
|
|
29
|
+
*/
|
|
30
|
+
export declare const ENTRY_TITLE_TOKENS_FIELD = "titleTokens";
|
|
31
|
+
/**
|
|
32
|
+
* The search half of a write that sets an entry's `title`. An entry with no
|
|
33
|
+
* title gets an empty array, so the field is present on every entry and the
|
|
34
|
+
* backfill has nothing left to find.
|
|
35
|
+
*/
|
|
36
|
+
export declare function entryTitleSearchFields(title: unknown): {
|
|
37
|
+
[ENTRY_TITLE_TOKENS_FIELD]: string[];
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Where an author's schema type is stored as the WORD the console's Authors
|
|
41
|
+
* table filters by (AGL-3321).
|
|
42
|
+
*
|
|
43
|
+
* `type` holds `HostEntityType` in whichever spelling wrote it: the number
|
|
44
|
+
* from the authors tab, a string `"1"`/`"2"` from an older bundle, nothing at
|
|
45
|
+
* all on a record `contentAuthorSchemaType` reads as `Organization`. A query
|
|
46
|
+
* matches one stored value, so an equality on `type` would miss every record
|
|
47
|
+
* spelled another way. This field is that one value.
|
|
48
|
+
*/
|
|
49
|
+
export declare const AUTHOR_SCHEMA_TYPE_FIELD = "schemaType";
|
|
50
|
+
/**
|
|
51
|
+
* The fields the Authors table's query reads (AGL-3321), derived from what the
|
|
52
|
+
* record already says: the name's lower-cased key and word-prefix tokens,
|
|
53
|
+
* normalized exactly as `nameSearchKey` / `nameSearchTokens` normalize a typed
|
|
54
|
+
* value, and the schema type as the row reads it.
|
|
55
|
+
*
|
|
56
|
+
* Spread at EVERY write of an author's `name` or `type` — the resources
|
|
57
|
+
* route's create, the authors tab's edit, the bundle import — and stamped on
|
|
58
|
+
* older records by `tools/scripts/backfill-authors-search-fields.mjs`. A
|
|
59
|
+
* record without them still reaches the picker, which reads every author; it
|
|
60
|
+
* is only the table's filters and search that cannot see it.
|
|
61
|
+
*/
|
|
62
|
+
export declare function contentAuthorQueryFields(author: {
|
|
63
|
+
name?: unknown;
|
|
64
|
+
type?: unknown;
|
|
65
|
+
}): {
|
|
66
|
+
nameLower: string;
|
|
67
|
+
nameTokens: string[];
|
|
68
|
+
[AUTHOR_SCHEMA_TYPE_FIELD]: 'Person' | 'Organization';
|
|
69
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
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 { contentAuthorSchemaType } from "./content-authors.js";
|
|
17
|
+
import { nameSearchKey, nameSearchTokens } from "./name-search.js";
|
|
18
|
+
/*
|
|
19
|
+
* The fields the console's content tables QUERY, stamped by the writes that
|
|
20
|
+
* set an entry's title or an author's name (AGL-3321).
|
|
21
|
+
*
|
|
22
|
+
* ⛔ Kept apart from `collection-entries` and `content-authors`. Those two are
|
|
23
|
+
* read by the compose pipeline, so whatever they import ships in the site
|
|
24
|
+
* runtime a published page loads (`check:tenant-wire-weight`). These helpers
|
|
25
|
+
* are only ever called by the console and its routes, and `name-search` has
|
|
26
|
+
* no business on a customer's page.
|
|
27
|
+
*/ /**
|
|
28
|
+
* The field the console's entries table searches (AGL-3321): every word
|
|
29
|
+
* prefix of the entry's title, as `nameSearchTokens` writes them, which the
|
|
30
|
+
* table's quick search and its Title "contains" filter ask with
|
|
31
|
+
* `array-contains` on the Firestore query.
|
|
32
|
+
*
|
|
33
|
+
* DERIVED, and never carried in a bundle. Every writer of `title` stamps it
|
|
34
|
+
* through {@link entryTitleSearchFields}: the entry editor's save, the
|
|
35
|
+
* resources route's create, the bundle import, and the seed and changelog
|
|
36
|
+
* scripts. `tools/scripts/backfill-entries-title-tokens.mjs` stamps the
|
|
37
|
+
* entries written before it. An entry without it still lists; it just cannot
|
|
38
|
+
* be found by a word of its title.
|
|
39
|
+
*/ export const ENTRY_TITLE_TOKENS_FIELD = 'titleTokens';
|
|
40
|
+
/**
|
|
41
|
+
* The search half of a write that sets an entry's `title`. An entry with no
|
|
42
|
+
* title gets an empty array, so the field is present on every entry and the
|
|
43
|
+
* backfill has nothing left to find.
|
|
44
|
+
*/ export function entryTitleSearchFields(title) {
|
|
45
|
+
return {
|
|
46
|
+
[ENTRY_TITLE_TOKENS_FIELD]: nameSearchTokens(typeof title === 'string' ? title : '')
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Where an author's schema type is stored as the WORD the console's Authors
|
|
51
|
+
* table filters by (AGL-3321).
|
|
52
|
+
*
|
|
53
|
+
* `type` holds `HostEntityType` in whichever spelling wrote it: the number
|
|
54
|
+
* from the authors tab, a string `"1"`/`"2"` from an older bundle, nothing at
|
|
55
|
+
* all on a record `contentAuthorSchemaType` reads as `Organization`. A query
|
|
56
|
+
* matches one stored value, so an equality on `type` would miss every record
|
|
57
|
+
* spelled another way. This field is that one value.
|
|
58
|
+
*/ export const AUTHOR_SCHEMA_TYPE_FIELD = 'schemaType';
|
|
59
|
+
/**
|
|
60
|
+
* The fields the Authors table's query reads (AGL-3321), derived from what the
|
|
61
|
+
* record already says: the name's lower-cased key and word-prefix tokens,
|
|
62
|
+
* normalized exactly as `nameSearchKey` / `nameSearchTokens` normalize a typed
|
|
63
|
+
* value, and the schema type as the row reads it.
|
|
64
|
+
*
|
|
65
|
+
* Spread at EVERY write of an author's `name` or `type` — the resources
|
|
66
|
+
* route's create, the authors tab's edit, the bundle import — and stamped on
|
|
67
|
+
* older records by `tools/scripts/backfill-authors-search-fields.mjs`. A
|
|
68
|
+
* record without them still reaches the picker, which reads every author; it
|
|
69
|
+
* is only the table's filters and search that cannot see it.
|
|
70
|
+
*/ export function contentAuthorQueryFields(author) {
|
|
71
|
+
const name = typeof author.name === 'string' ? author.name : '';
|
|
72
|
+
return {
|
|
73
|
+
nameLower: nameSearchKey(name),
|
|
74
|
+
nameTokens: nameSearchTokens(name),
|
|
75
|
+
[AUTHOR_SCHEMA_TYPE_FIELD]: contentAuthorSchemaType(author.type)
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
//# sourceMappingURL=content-query-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/content-query-fields.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 { contentAuthorSchemaType } from './content-authors'\nimport type { HostEntityType } from '../foundation/definitions/platform.types'\nimport { nameSearchKey, nameSearchTokens } from './name-search'\n\n/*\n * The fields the console's content tables QUERY, stamped by the writes that\n * set an entry's title or an author's name (AGL-3321).\n *\n * ⛔ Kept apart from `collection-entries` and `content-authors`. Those two are\n * read by the compose pipeline, so whatever they import ships in the site\n * runtime a published page loads (`check:tenant-wire-weight`). These helpers\n * are only ever called by the console and its routes, and `name-search` has\n * no business on a customer's page.\n */\n\n/**\n * The field the console's entries table searches (AGL-3321): every word\n * prefix of the entry's title, as `nameSearchTokens` writes them, which the\n * table's quick search and its Title \"contains\" filter ask with\n * `array-contains` on the Firestore query.\n *\n * DERIVED, and never carried in a bundle. Every writer of `title` stamps it\n * through {@link entryTitleSearchFields}: the entry editor's save, the\n * resources route's create, the bundle import, and the seed and changelog\n * scripts. `tools/scripts/backfill-entries-title-tokens.mjs` stamps the\n * entries written before it. An entry without it still lists; it just cannot\n * be found by a word of its title.\n */\nexport const ENTRY_TITLE_TOKENS_FIELD = 'titleTokens'\n\n/**\n * The search half of a write that sets an entry's `title`. An entry with no\n * title gets an empty array, so the field is present on every entry and the\n * backfill has nothing left to find.\n */\nexport function entryTitleSearchFields(title: unknown): {\n [ENTRY_TITLE_TOKENS_FIELD]: string[]\n} {\n return {\n [ENTRY_TITLE_TOKENS_FIELD]: nameSearchTokens(\n typeof title === 'string' ? title : '',\n ),\n }\n}\n\n/**\n * Where an author's schema type is stored as the WORD the console's Authors\n * table filters by (AGL-3321).\n *\n * `type` holds `HostEntityType` in whichever spelling wrote it: the number\n * from the authors tab, a string `\"1\"`/`\"2\"` from an older bundle, nothing at\n * all on a record `contentAuthorSchemaType` reads as `Organization`. A query\n * matches one stored value, so an equality on `type` would miss every record\n * spelled another way. This field is that one value.\n */\nexport const AUTHOR_SCHEMA_TYPE_FIELD = 'schemaType'\n\n/**\n * The fields the Authors table's query reads (AGL-3321), derived from what the\n * record already says: the name's lower-cased key and word-prefix tokens,\n * normalized exactly as `nameSearchKey` / `nameSearchTokens` normalize a typed\n * value, and the schema type as the row reads it.\n *\n * Spread at EVERY write of an author's `name` or `type` — the resources\n * route's create, the authors tab's edit, the bundle import — and stamped on\n * older records by `tools/scripts/backfill-authors-search-fields.mjs`. A\n * record without them still reaches the picker, which reads every author; it\n * is only the table's filters and search that cannot see it.\n */\nexport function contentAuthorQueryFields(author: {\n name?: unknown\n type?: unknown\n}): {\n nameLower: string\n nameTokens: string[]\n [AUTHOR_SCHEMA_TYPE_FIELD]: 'Person' | 'Organization'\n} {\n const name = typeof author.name === 'string' ? author.name : ''\n return {\n nameLower: nameSearchKey(name),\n nameTokens: nameSearchTokens(name),\n [AUTHOR_SCHEMA_TYPE_FIELD]: contentAuthorSchemaType(\n author.type as HostEntityType | string | number | undefined | null,\n ),\n }\n}\n"],"names":["contentAuthorSchemaType","nameSearchKey","nameSearchTokens","ENTRY_TITLE_TOKENS_FIELD","entryTitleSearchFields","title","AUTHOR_SCHEMA_TYPE_FIELD","contentAuthorQueryFields","author","name","nameLower","nameTokens","type"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,uBAAuB,QAAQ,uBAAmB;AAE3D,SAASC,aAAa,EAAEC,gBAAgB,QAAQ,mBAAe;AAE/D;;;;;;;;;CASC,GAED;;;;;;;;;;;;CAYC,GACD,OAAO,MAAMC,2BAA2B,cAAa;AAErD;;;;CAIC,GACD,OAAO,SAASC,uBAAuBC,KAAc;IAGnD,OAAO;QACL,CAACF,yBAAyB,EAAED,iBAC1B,OAAOG,UAAU,WAAWA,QAAQ;IAExC;AACF;AAEA;;;;;;;;;CASC,GACD,OAAO,MAAMC,2BAA2B,aAAY;AAEpD;;;;;;;;;;;CAWC,GACD,OAAO,SAASC,yBAAyBC,MAGxC;IAKC,MAAMC,OAAO,OAAOD,OAAOC,IAAI,KAAK,WAAWD,OAAOC,IAAI,GAAG;IAC7D,OAAO;QACLC,WAAWT,cAAcQ;QACzBE,YAAYT,iBAAiBO;QAC7B,CAACH,yBAAyB,EAAEN,wBAC1BQ,OAAOI,IAAI;IAEf;AACF"}
|
|
@@ -47,7 +47,7 @@ import { type AglynPostalAddress, type OrgCrmAssignmentRule } from '../foundatio
|
|
|
47
47
|
import { type ConsentGroup } from './consent-groups';
|
|
48
48
|
import { type ContactLifecycleStage, type CrmActivityKind, type CrmTaskKind } from './crm-kinds';
|
|
49
49
|
import { type ContactInteraction, type ContactSegment, type ContactSource } from './contacts';
|
|
50
|
-
import type
|
|
50
|
+
import { type EmailState } from './email-state';
|
|
51
51
|
import { type ScopeToken } from './scope-tokens';
|
|
52
52
|
export * from './crm-kinds';
|
|
53
53
|
/**
|
|
@@ -1769,3 +1769,153 @@ export declare const CRM_MEDIA_IDS_MAX = 20;
|
|
|
1769
1769
|
* that names its current location.
|
|
1770
1770
|
*/
|
|
1771
1771
|
export declare function normalizeCrmMediaIds(value: unknown): string[];
|
|
1772
|
+
/** The search box's word-prefix tokens, on every CRM record a list searches. */
|
|
1773
|
+
export declare const CRM_SEARCH_TOKENS_FIELD = "searchTokens";
|
|
1774
|
+
/** The same tokens behind each `visibleTo` token — see the block header. */
|
|
1775
|
+
export declare const CRM_SCOPED_SEARCH_TOKENS_FIELD = "scopedSearchTokens";
|
|
1776
|
+
/** What joins a scope token to a search token — the platform's one join (`SCOPED_SEARCH_JOIN`). */
|
|
1777
|
+
export declare const CRM_SCOPED_SEARCH_JOIN = "~";
|
|
1778
|
+
/**
|
|
1779
|
+
* The most search tokens one record keeps. A name, an address, a company
|
|
1780
|
+
* and a title are a few dozen prefixes; the cap is what keeps a record with
|
|
1781
|
+
* twenty long tags from spending hundreds of index entries on them.
|
|
1782
|
+
*/
|
|
1783
|
+
export declare const CRM_SEARCH_TOKENS_MAX = 200;
|
|
1784
|
+
/** The collections whose lists query the fields below. */
|
|
1785
|
+
export type CrmListCollection = 'leads' | 'contacts' | 'companies' | 'deals' | 'crmTasks';
|
|
1786
|
+
/**
|
|
1787
|
+
* The word-prefix tokens of several values, merged: every prefix (up to
|
|
1788
|
+
* twelve characters) of every whitespace-separated word, lower-cased —
|
|
1789
|
+
* exactly `nameSearchTokens` per value — plus, for an email address, the
|
|
1790
|
+
* words it is made of, so `acme` finds `dana@acme.com` and `dana` does too.
|
|
1791
|
+
*/
|
|
1792
|
+
export declare function crmSearchTokens(values: readonly unknown[]): string[];
|
|
1793
|
+
/**
|
|
1794
|
+
* The two search fields for a record whose search reads `values`: the
|
|
1795
|
+
* tokens, and the same tokens behind each of its scope tokens through the
|
|
1796
|
+
* platform's one scoped writer (`scopedSearchTokens`).
|
|
1797
|
+
*/
|
|
1798
|
+
export declare function crmSearchFields(visibleTo: unknown, values: readonly unknown[]): {
|
|
1799
|
+
searchTokens: string[];
|
|
1800
|
+
scopedSearchTokens: string[];
|
|
1801
|
+
};
|
|
1802
|
+
/**
|
|
1803
|
+
* The address verdict as a list asks it (AGL-3245): the state's status, or
|
|
1804
|
+
* `none` when nothing is known — stored rather than left absent, because a
|
|
1805
|
+
* query cannot find a field's absence and "Nothing known" is a filter.
|
|
1806
|
+
*/
|
|
1807
|
+
export declare const CRM_EMAIL_STATUS_FIELD = "emailStatus";
|
|
1808
|
+
export declare const CRM_EMAIL_STATUS_NONE = "none";
|
|
1809
|
+
export declare function crmEmailStatusKey(record: Record<string, unknown> | null | undefined): string;
|
|
1810
|
+
/** A lead's lead source as the list compares it: the picklist's key, `null` for none. */
|
|
1811
|
+
export declare const CRM_LEAD_SOURCE_KEY_FIELD = "leadSourceKey";
|
|
1812
|
+
export declare function crmLeadSourceKey(value: unknown): string | null;
|
|
1813
|
+
/** What a lead's search box reads (AGL-3246). */
|
|
1814
|
+
export declare const CRM_LEAD_SEARCH_SOURCES: readonly ["name", "email", "company", "jobTitle", "tags"];
|
|
1815
|
+
/**
|
|
1816
|
+
* A lead's campaigns behind each of its `visibleTo` tokens
|
|
1817
|
+
* (`host:abc~{campaignId}`), for the Leads list's Campaign filter under a
|
|
1818
|
+
* site: there the scope clause is the query's one array clause, and a
|
|
1819
|
+
* campaign asked of these keys answers both at once — the way the search
|
|
1820
|
+
* folds into the scope through `scopedSearchTokens`.
|
|
1821
|
+
*/
|
|
1822
|
+
export declare const CRM_LEAD_SCOPED_CAMPAIGNS_FIELD = "scopedCampaignIds";
|
|
1823
|
+
/**
|
|
1824
|
+
* Every field the Leads list queries by, from the lead as stored (or as it
|
|
1825
|
+
* will be once written): the search tokens, its campaigns behind its scope,
|
|
1826
|
+
* the status — `new` for a lead nobody has touched, written so `status in
|
|
1827
|
+
* [new, working]` finds it — the lead source key and the address verdict.
|
|
1828
|
+
*/
|
|
1829
|
+
export declare function crmLeadListFields(record: object): {
|
|
1830
|
+
searchTokens: string[];
|
|
1831
|
+
scopedSearchTokens: string[];
|
|
1832
|
+
scopedCampaignIds: string[];
|
|
1833
|
+
status: CrmLeadStatus;
|
|
1834
|
+
leadSourceKey: string | null;
|
|
1835
|
+
emailStatus: string;
|
|
1836
|
+
};
|
|
1837
|
+
/** What a company's search box reads: its name and its domain. */
|
|
1838
|
+
export declare const CRM_COMPANY_SEARCH_SOURCES: readonly ["name", "domain"];
|
|
1839
|
+
export declare function crmCompanyListFields(record: object): {
|
|
1840
|
+
searchTokens: string[];
|
|
1841
|
+
scopedSearchTokens: string[];
|
|
1842
|
+
};
|
|
1843
|
+
/**
|
|
1844
|
+
* What a deal's search box reads: its title (AGL-3315) — as word prefixes,
|
|
1845
|
+
* and as `titleLower`, the whole title's key, which a reader whose access
|
|
1846
|
+
* is some sites searches by its start.
|
|
1847
|
+
*/
|
|
1848
|
+
export declare function crmDealListFields(record: object): {
|
|
1849
|
+
searchTokens: string[];
|
|
1850
|
+
scopedSearchTokens: string[];
|
|
1851
|
+
titleLower: string;
|
|
1852
|
+
};
|
|
1853
|
+
/** What a task's search box reads: its title. */
|
|
1854
|
+
export declare function crmTaskListFields(record: object): {
|
|
1855
|
+
searchTokens: string[];
|
|
1856
|
+
scopedSearchTokens: string[];
|
|
1857
|
+
};
|
|
1858
|
+
export declare const CRM_CONTACT_FACET_KEYS_FIELD = "facetKeys";
|
|
1859
|
+
/** The group a key names at the organization level: any holder. */
|
|
1860
|
+
export declare const CRM_FACET_KEY_ANY_GROUP = "*";
|
|
1861
|
+
/** The most facet keys one contact keeps. */
|
|
1862
|
+
export declare const CRM_FACET_KEYS_MAX = 600;
|
|
1863
|
+
/** The facet fields a contact list filters by, as their keys name them. */
|
|
1864
|
+
export type CrmFacetKeyField = 'owner' | 'stage' | 'source' | 'company' | 'tag' | 'orders' | 'ltv' | `custom.${string}`;
|
|
1865
|
+
/** A facet value as its key spells it, or `null` for a value a key cannot hold. */
|
|
1866
|
+
export declare function crmFacetKeyValue(value: unknown): string | null;
|
|
1867
|
+
/** One facet key: `{group}:{field}` for presence, `{group}:{field}={value}` for a value. */
|
|
1868
|
+
export declare function crmFacetKey(group: string, field: CrmFacetKeyField, value?: string): string;
|
|
1869
|
+
/** Every facet key a contact carries — see the block above. */
|
|
1870
|
+
export declare function crmContactFacetKeys(record: object): string[];
|
|
1871
|
+
/**
|
|
1872
|
+
* What a contact's search box reads: the shared identity — the canonical
|
|
1873
|
+
* name and every address — and the two profile values a person is looked
|
|
1874
|
+
* up by, through their top-level search echoes (`HostContact.phone`,
|
|
1875
|
+
* `HostContact.companyName`): the company's words, and the phone's digits.
|
|
1876
|
+
*/
|
|
1877
|
+
export declare const CRM_CONTACT_SEARCH_SOURCES: readonly ["name", "email", "alternateEmails", "companyName"];
|
|
1878
|
+
/**
|
|
1879
|
+
* A phone number as the words a search box finds it by: its digits whole,
|
|
1880
|
+
* without a leading country code of one to three digits, and its last seven
|
|
1881
|
+
* and last four — so `5551234`, `555123` and `4567` all find +1 555 123 4567.
|
|
1882
|
+
* Typed as digits: a search reads one word, and `(555)` is not one of these.
|
|
1883
|
+
*/
|
|
1884
|
+
export declare function crmPhoneSearchWords(phone: unknown): string[];
|
|
1885
|
+
export declare function crmContactListFields(record: object): {
|
|
1886
|
+
searchTokens: string[];
|
|
1887
|
+
scopedSearchTokens: string[];
|
|
1888
|
+
facetKeys: string[];
|
|
1889
|
+
emailStatus: string;
|
|
1890
|
+
};
|
|
1891
|
+
/**
|
|
1892
|
+
* The stored fields each collection's list fields are computed from. A
|
|
1893
|
+
* write that sets one of them must restamp the record — or spread
|
|
1894
|
+
* {@link crmListFields} over the document it wrote.
|
|
1895
|
+
*/
|
|
1896
|
+
export declare const CRM_LIST_FIELD_INPUTS: Readonly<Record<CrmListCollection, readonly string[]>>;
|
|
1897
|
+
/** Every list field of one record, from the record as stored. */
|
|
1898
|
+
export declare function crmListFields(collection: CrmListCollection, record: object): Record<string, unknown>;
|
|
1899
|
+
/**
|
|
1900
|
+
* The list fields a stored record carries WRONGLY — the patch that brings
|
|
1901
|
+
* it level, `{}` when it already is. What a restamp and a backfill write.
|
|
1902
|
+
*/
|
|
1903
|
+
export declare function crmListFieldsPatch(collection: CrmListCollection, record: object): Record<string, unknown>;
|
|
1904
|
+
/**
|
|
1905
|
+
* The field each collection's list ORDERS or asks `null` of, which a record
|
|
1906
|
+
* must therefore carry even when it has no value: a contact, a company and a
|
|
1907
|
+
* deal carry `nextTaskAtMs` ("No next activity" asks `== null`), and a task
|
|
1908
|
+
* carries `dueAtMs` (every task view orders by it, and Firestore leaves a
|
|
1909
|
+
* document without the ordered field out of the answer). An absent field is
|
|
1910
|
+
* neither `null` nor anything else a query can ask for.
|
|
1911
|
+
*/
|
|
1912
|
+
export declare const CRM_LIST_NULLABLE_FIELD: Readonly<Record<CrmListCollection, string | null>>;
|
|
1913
|
+
/**
|
|
1914
|
+
* The list fields a NEW record is written with: {@link crmListFields}, and
|
|
1915
|
+
* the collection's {@link CRM_LIST_NULLABLE_FIELD} as `null` when the record
|
|
1916
|
+
* does not set it — nothing is scheduled against a record that did not
|
|
1917
|
+
* exist, and a task created undated is still one its views must reach.
|
|
1918
|
+
*/
|
|
1919
|
+
export declare function crmNewRecordListFields(collection: CrmListCollection, record: object): Record<string, unknown>;
|
|
1920
|
+
/** Whether a patch touches a field the collection's list fields are computed from. */
|
|
1921
|
+
export declare function crmListFieldsTouched(collection: CrmListCollection, patch: Record<string, unknown>): boolean;
|