@encodeagent/platform-helper-util 1.2603.1221241 → 1.2603.1311023
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/README.md +277 -153
- package/dist/api.d.ts +38 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +38 -2
- package/dist/api.js.map +1 -1
- package/dist/auth.d.ts +93 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +93 -2
- package/dist/auth.js.map +1 -1
- package/dist/colors.d.ts +41 -0
- package/dist/colors.d.ts.map +1 -1
- package/dist/colors.js +41 -0
- package/dist/colors.js.map +1 -1
- package/dist/core.d.ts +262 -0
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +264 -2
- package/dist/core.js.map +1 -1
- package/dist/cost.d.ts +26 -0
- package/dist/cost.d.ts.map +1 -1
- package/dist/cost.js +27 -1
- package/dist/cost.js.map +1 -1
- package/dist/file.d.ts +38 -0
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js +42 -2
- package/dist/file.js.map +1 -1
- package/dist/html.d.ts +83 -0
- package/dist/html.d.ts.map +1 -1
- package/dist/html.js +88 -35
- package/dist/html.js.map +1 -1
- package/dist/logger.d.ts +17 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +28 -2
- package/dist/logger.js.map +1 -1
- package/dist/markdown.d.ts +20 -0
- package/dist/markdown.d.ts.map +1 -1
- package/dist/markdown.js +20 -0
- package/dist/markdown.js.map +1 -1
- package/dist/metadata.js +1 -1
- package/dist/metadata.js.map +1 -1
- package/dist/record.d.ts +137 -5
- package/dist/record.d.ts.map +1 -1
- package/dist/record.js +184 -19
- package/dist/record.js.map +1 -1
- package/dist/shortid.d.ts +21 -8
- package/dist/shortid.d.ts.map +1 -1
- package/dist/shortid.js +9 -5
- package/dist/shortid.js.map +1 -1
- package/dist/slug.d.ts +10 -0
- package/dist/slug.d.ts.map +1 -1
- package/dist/slug.js +10 -0
- package/dist/slug.js.map +1 -1
- package/dist/token.d.ts +1 -1
- package/dist/tree.d.ts +43 -0
- package/dist/tree.d.ts.map +1 -1
- package/dist/tree.js +43 -5
- package/dist/tree.js.map +1 -1
- package/dist/value-of-object.d.ts +41 -0
- package/dist/value-of-object.d.ts.map +1 -1
- package/dist/value-of-object.js +59 -17
- package/dist/value-of-object.js.map +1 -1
- package/dist/web-content.d.ts +52 -0
- package/dist/web-content.d.ts.map +1 -1
- package/dist/web-content.js +52 -0
- package/dist/web-content.js.map +1 -1
- package/dist/web.d.ts +51 -0
- package/dist/web.d.ts.map +1 -1
- package/dist/web.js +54 -1
- package/dist/web.js.map +1 -1
- package/package.json +10 -5
package/dist/record.d.ts
CHANGED
|
@@ -23,31 +23,72 @@ export interface IRecord {
|
|
|
23
23
|
organizationId: string;
|
|
24
24
|
solutionId: string;
|
|
25
25
|
createdBy: string;
|
|
26
|
-
|
|
26
|
+
createdAt: number;
|
|
27
27
|
ownedBy: string;
|
|
28
|
-
|
|
28
|
+
ownedAt: number;
|
|
29
29
|
modifiedBy: string;
|
|
30
|
-
|
|
30
|
+
modifiedAt: number;
|
|
31
31
|
partitionKey: string;
|
|
32
32
|
isPublished?: boolean;
|
|
33
33
|
isGlobal?: boolean;
|
|
34
34
|
isPublishedBy?: string;
|
|
35
|
-
|
|
35
|
+
isPublishedAt?: string;
|
|
36
36
|
isGlobalBy?: string;
|
|
37
|
-
|
|
37
|
+
isGlobalAt?: string;
|
|
38
38
|
stateCode: number;
|
|
39
39
|
statusCode: number;
|
|
40
40
|
[key: string]: any;
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Strips server-managed and identity fields from a record so it can be submitted as a
|
|
44
|
+
* new create payload. Removes audit timestamps, CosmosDB system properties (`_rid`,
|
|
45
|
+
* `_self`, etc.), computed fields (`slug`, `searchDisplay`, `display`), and platform
|
|
46
|
+
* fields (`stateCode`, `statusCode`, `organizationId`, `solutionId`, `partitionKey`).
|
|
47
|
+
* Assigns a fresh GUID as `id`.
|
|
48
|
+
*/
|
|
42
49
|
export declare const convertRecordForCreate: (record: Record<string, any>) => Record<string, any>;
|
|
43
50
|
export interface IGetBaseRecordProps extends IContext {
|
|
44
51
|
entityName: string;
|
|
45
52
|
entityType?: string;
|
|
46
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Creates a minimal valid `IRecord` shell with a new GUID and audit fields populated
|
|
56
|
+
* from the provided context. All timestamps are set to the current moment.
|
|
57
|
+
* `partitionKey` is set to `organizationId` (CosmosDB convention).
|
|
58
|
+
*/
|
|
47
59
|
export declare const getBaseRecord: (context: IGetBaseRecordProps) => IRecord;
|
|
60
|
+
/**
|
|
61
|
+
* Returns the first non-empty string value found by iterating `displayFields` in order.
|
|
62
|
+
* Used internally by `getRecordDisplay` when an entity defines explicit display field names.
|
|
63
|
+
*/
|
|
48
64
|
export declare const getRecordDisplayByDisplayFields: (record: Record<string, any>, displayFields?: string[]) => string;
|
|
65
|
+
/**
|
|
66
|
+
* Returns a folder path string derived from a record's `entityName` and `entityType`.
|
|
67
|
+
* Format: `"entityName/entityType"` or just `"entityName"` when `entityNameOnly` is true
|
|
68
|
+
* or when `entityType` is absent. Returns `"Unknown"` when both are empty.
|
|
69
|
+
*/
|
|
49
70
|
export declare const getRecordEntityFolder: (data: Record<string, any>, entityNameOnly: boolean) => string;
|
|
71
|
+
/**
|
|
72
|
+
* Builds a storage folder path from explicit `entityName` and optional `entityType` strings
|
|
73
|
+
* (rather than reading from a record object). Returns `"Unknown"` when `entityName` is empty.
|
|
74
|
+
*/
|
|
50
75
|
export declare const getEntityFolder: (entityName: string, entityType?: string) => string;
|
|
76
|
+
/**
|
|
77
|
+
* Resolves the best human-readable display label for a record.
|
|
78
|
+
*
|
|
79
|
+
* Resolution priority:
|
|
80
|
+
* 1. Search highlight title (`_ui.highlight.title`)
|
|
81
|
+
* 2. `searchDisplay` (when `includeSearchDisplay` is true)
|
|
82
|
+
* 3. Entity `displayFields` (first non-empty field)
|
|
83
|
+
* 4. `firstName + lastName` full name
|
|
84
|
+
* 5. `displayValue`
|
|
85
|
+
* 6. `number – title` / `number – name` / `number – subject`
|
|
86
|
+
* 7. `display`, `text`, `symbol`, `code`
|
|
87
|
+
*
|
|
88
|
+
* The result is cleaned (normalizes whitespace and punctuation spacing) and optionally
|
|
89
|
+
* truncated to `maxLength` characters. Returns the record `id` when `allowUseRecordId`
|
|
90
|
+
* is true and no other value could be resolved.
|
|
91
|
+
*/
|
|
51
92
|
export declare const getRecordDisplay: (record: Record<string, any>, settings?: {
|
|
52
93
|
entity?: Record<string, any>;
|
|
53
94
|
displayFields?: string[];
|
|
@@ -56,13 +97,38 @@ export declare const getRecordDisplay: (record: Record<string, any>, settings?:
|
|
|
56
97
|
emptyReturnUndefined?: boolean;
|
|
57
98
|
allowUseRecordId?: boolean;
|
|
58
99
|
}) => string | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* Resolves the best short abstract/description text for a record.
|
|
102
|
+
*
|
|
103
|
+
* Resolution priority:
|
|
104
|
+
* 1. Search highlight (`highlight.searchContent[0]`)
|
|
105
|
+
* 2. `summary`, `description`, `abstract`
|
|
106
|
+
* 3. `searchContent` (only when `settings.includeContent` is true)
|
|
107
|
+
*
|
|
108
|
+
* Whitespace and punctuation are normalized before returning.
|
|
109
|
+
* Truncates to `settings.maxLength` characters when provided.
|
|
110
|
+
*/
|
|
59
111
|
export declare const getRecordAbstract: (record: Record<string, any>, settings?: {
|
|
60
112
|
entity?: Record<string, any>;
|
|
61
113
|
abstractFields?: string[];
|
|
62
114
|
maxLength?: number;
|
|
63
115
|
includeContent?: boolean;
|
|
64
116
|
}) => string;
|
|
117
|
+
/**
|
|
118
|
+
* Returns the first non-empty string value found by iterating `contentFields` in order.
|
|
119
|
+
* Used internally by `getRecordContent` when an entity defines explicit content field names.
|
|
120
|
+
*/
|
|
65
121
|
export declare const getRecordContentByContentFields: (record: Record<string, any>, contentFields?: string[]) => string;
|
|
122
|
+
/**
|
|
123
|
+
* Resolves the main body content for a record, suitable for indexing or display.
|
|
124
|
+
*
|
|
125
|
+
* Resolution priority:
|
|
126
|
+
* 1. Search highlight (`_ui.highlight.content`)
|
|
127
|
+
* 2. `searchContent` (when `includeSearchDisplay` is true)
|
|
128
|
+
* 3. Entity/settings `contentFields` (defaults to description, note, detail, content, …)
|
|
129
|
+
*
|
|
130
|
+
* Truncates to `maxLength` when provided.
|
|
131
|
+
*/
|
|
66
132
|
export declare const getRecordContent: (record: Record<string, any>, settings?: {
|
|
67
133
|
entity?: Record<string, any>;
|
|
68
134
|
contentFields?: string[];
|
|
@@ -70,18 +136,60 @@ export declare const getRecordContent: (record: Record<string, any>, settings?:
|
|
|
70
136
|
maxLength?: number;
|
|
71
137
|
emptyReturnUndefined?: boolean;
|
|
72
138
|
}) => string | undefined;
|
|
139
|
+
/**
|
|
140
|
+
* Formats a complete postal address from prefixed address fields on a record
|
|
141
|
+
* (e.g. `prefix = "billing"` reads `billingLine1`, `billingCity`, `billingState`, …).
|
|
142
|
+
* Returns `""` when the record does not contain the minimum required fields
|
|
143
|
+
* (city + state + country, or postalCode + country).
|
|
144
|
+
*/
|
|
73
145
|
export declare const getRecordAddress: (record: Record<string, any>, prefix: string) => string;
|
|
146
|
+
/**
|
|
147
|
+
* Returns the primary media URL for a record, trying `media`, `photoUrl`, and
|
|
148
|
+
* `source.photoUrl` in that order. Returns `""` when none are set.
|
|
149
|
+
*/
|
|
74
150
|
export declare const getRecordMedia: (record: Record<string, any>) => string;
|
|
151
|
+
/**
|
|
152
|
+
* Constructs a display name for a user-like record.
|
|
153
|
+
*
|
|
154
|
+
* Resolution order: `fullName` → `firstName + lastName` → `name` → `email`.
|
|
155
|
+
* `skipFullNameProp`, `skipNameProp`, `skipEmailProp` let callers exclude specific steps.
|
|
156
|
+
* Simplified Chinese locale (Windows locale code 2052) has spaces stripped from the assembled name.
|
|
157
|
+
* Multiple consecutive spaces are collapsed to a single space.
|
|
158
|
+
*/
|
|
75
159
|
export declare const getRecordFullName: (user: Record<string, any>, settings?: {
|
|
76
160
|
skipFullNameProp?: boolean;
|
|
77
161
|
skipNameProp?: boolean;
|
|
78
162
|
skipEmailProp?: boolean;
|
|
79
163
|
}) => string;
|
|
164
|
+
/**
|
|
165
|
+
* Returns a formatted email address string for a record that has a valid `email` field.
|
|
166
|
+
* Format: `"Full Name <email@example.com>"`, or just `"email@example.com"` when
|
|
167
|
+
* `emailOnly` is true or no display name is available.
|
|
168
|
+
* Returns `undefined` when the record has no valid email.
|
|
169
|
+
*/
|
|
80
170
|
export declare const getRecordEmailAddress: (record: Record<string, any>, emailOnly?: boolean) => string | undefined;
|
|
171
|
+
/**
|
|
172
|
+
* Builds an Open Graph / page metadata object for a record, suitable for `<head>` tags.
|
|
173
|
+
* Returns `{ id, title, description, type: "article", image? }`.
|
|
174
|
+
* Title is derived from `getRecordDisplay` (or `getRecordAbstract` when display is empty),
|
|
175
|
+
* optionally prefixed with `settings.siteName`.
|
|
176
|
+
*/
|
|
81
177
|
export declare const getRecordPageMetadata: (record: Record<string, any>, settings?: {
|
|
82
178
|
siteName?: string;
|
|
83
179
|
}) => Record<string, any>;
|
|
180
|
+
/**
|
|
181
|
+
* Computes the current slug via `getRecordSlug` and ensures it is present in both
|
|
182
|
+
* `record.slug` (current) and `record.slugs` (historical list, deduplicated).
|
|
183
|
+
* Call this before persisting a record to keep slug history intact for redirects.
|
|
184
|
+
*/
|
|
84
185
|
export declare const applyRecordSlug: (record: Record<string, any>) => Record<string, any>;
|
|
186
|
+
/**
|
|
187
|
+
* Derives a URL slug for a record.
|
|
188
|
+
* Uses `record.customSlug` when set; otherwise derives from `getRecordDisplay`.
|
|
189
|
+
* The slug is truncated to 128 characters and suffixed with the second GUID segment
|
|
190
|
+
* of the record ID (e.g. `"my-post-e29b"`) to guarantee global uniqueness.
|
|
191
|
+
* Returns `undefined` when the record has no `id`.
|
|
192
|
+
*/
|
|
85
193
|
export declare const getRecordSlug: (record: Record<string, any>) => string | undefined;
|
|
86
194
|
export type TRecordFilePath = {
|
|
87
195
|
solutionId: string;
|
|
@@ -90,9 +198,33 @@ export type TRecordFilePath = {
|
|
|
90
198
|
entityName: string;
|
|
91
199
|
fieldName?: string;
|
|
92
200
|
};
|
|
201
|
+
/**
|
|
202
|
+
* Builds the storage path for a file attached to a record.
|
|
203
|
+
* Format: `"{solutionId}/{organizationId}/{entityName}/{recordId}/{fieldName}"`.
|
|
204
|
+
* `fieldName` defaults to `"file"` when not provided.
|
|
205
|
+
*/
|
|
93
206
|
export declare const getRecordFilePath: (props: TRecordFilePath) => string;
|
|
207
|
+
/**
|
|
208
|
+
* Extracts an `IContext` from a record that carries context fields directly
|
|
209
|
+
* (e.g. an API request body that has been enriched with caller context).
|
|
210
|
+
* Picks `solutionId`, `domain`, `sourceIp`, `userId`, `organizationId`,
|
|
211
|
+
* `user`, `organization`, and `solution`.
|
|
212
|
+
*/
|
|
94
213
|
export declare const getContextFromRecord: (record: Record<string, any>) => IContext;
|
|
214
|
+
/**
|
|
215
|
+
* Returns true when a record is marked global but belongs to a different organization
|
|
216
|
+
* than the one in the current context. Used to identify marketplace/shared content.
|
|
217
|
+
*/
|
|
95
218
|
export declare const fromOtherOrganization: (context: IContext, record: Record<string, any>) => boolean;
|
|
219
|
+
/**
|
|
220
|
+
* Returns true when the record's ID appears in the current user's favorites list
|
|
221
|
+
* for the record's entity type (`context.user.favorites[entityName]`).
|
|
222
|
+
*/
|
|
96
223
|
export declare const isFavorite: (context: IContext, record: Record<string, any>) => boolean;
|
|
224
|
+
/**
|
|
225
|
+
* Returns true when a record is global and its owning organization differs from the
|
|
226
|
+
* current context's organization. Equivalent to `fromOtherOrganization` but compares
|
|
227
|
+
* against `context.organization.id` instead of `context.organizationId`.
|
|
228
|
+
*/
|
|
97
229
|
export declare const isFromMarketplace: (context: Record<string, any>, record: Record<string, any>) => boolean;
|
|
98
230
|
//# sourceMappingURL=record.d.ts.map
|
package/dist/record.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../src/record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,MAAM,WAAW,OAAO;
|
|
1
|
+
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../src/record.ts"],"names":[],"mappings":"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"}
|
package/dist/record.js
CHANGED
|
@@ -21,14 +21,21 @@ exports.isFromMarketplace = exports.isFavorite = exports.fromOtherOrganization =
|
|
|
21
21
|
const lodash_1 = require("lodash");
|
|
22
22
|
const core_1 = require("./core");
|
|
23
23
|
const slug_1 = require("./slug");
|
|
24
|
+
/**
|
|
25
|
+
* Strips server-managed and identity fields from a record so it can be submitted as a
|
|
26
|
+
* new create payload. Removes audit timestamps, CosmosDB system properties (`_rid`,
|
|
27
|
+
* `_self`, etc.), computed fields (`slug`, `searchDisplay`, `display`), and platform
|
|
28
|
+
* fields (`stateCode`, `statusCode`, `organizationId`, `solutionId`, `partitionKey`).
|
|
29
|
+
* Assigns a fresh GUID as `id`.
|
|
30
|
+
*/
|
|
24
31
|
const convertRecordForCreate = (record) => {
|
|
25
32
|
const newRecord = (0, lodash_1.cloneDeep)(record);
|
|
26
33
|
delete newRecord.createdBy;
|
|
27
|
-
delete newRecord.
|
|
34
|
+
delete newRecord.createdAt;
|
|
28
35
|
delete newRecord.ownedBy;
|
|
29
|
-
delete newRecord.
|
|
36
|
+
delete newRecord.ownedAt;
|
|
30
37
|
delete newRecord.modifiedBy;
|
|
31
|
-
delete newRecord.
|
|
38
|
+
delete newRecord.modifiedAt;
|
|
32
39
|
delete newRecord["_rid"];
|
|
33
40
|
delete newRecord["_self"];
|
|
34
41
|
delete newRecord["_etag"];
|
|
@@ -52,6 +59,11 @@ const convertRecordForCreate = (record) => {
|
|
|
52
59
|
return newRecord;
|
|
53
60
|
};
|
|
54
61
|
exports.convertRecordForCreate = convertRecordForCreate;
|
|
62
|
+
/**
|
|
63
|
+
* Creates a minimal valid `IRecord` shell with a new GUID and audit fields populated
|
|
64
|
+
* from the provided context. All timestamps are set to the current moment.
|
|
65
|
+
* `partitionKey` is set to `organizationId` (CosmosDB convention).
|
|
66
|
+
*/
|
|
55
67
|
const getBaseRecord = (context) => {
|
|
56
68
|
const { userId, organizationId, solutionId, entityName, entityType } = context;
|
|
57
69
|
return {
|
|
@@ -59,19 +71,23 @@ const getBaseRecord = (context) => {
|
|
|
59
71
|
entityName,
|
|
60
72
|
entityType,
|
|
61
73
|
createdBy: userId,
|
|
62
|
-
|
|
74
|
+
createdAt: (0, core_1.getTimestamp)(),
|
|
63
75
|
ownedBy: userId,
|
|
64
|
-
|
|
76
|
+
ownedAt: (0, core_1.getTimestamp)(),
|
|
65
77
|
modifiedBy: userId,
|
|
66
|
-
|
|
78
|
+
modifiedAt: (0, core_1.getTimestamp)(),
|
|
67
79
|
stateCode: 0,
|
|
68
80
|
statusCode: 0,
|
|
69
81
|
organizationId,
|
|
70
82
|
solutionId,
|
|
71
|
-
partitionKey: organizationId
|
|
83
|
+
partitionKey: organizationId
|
|
72
84
|
};
|
|
73
85
|
};
|
|
74
86
|
exports.getBaseRecord = getBaseRecord;
|
|
87
|
+
/**
|
|
88
|
+
* Returns the first non-empty string value found by iterating `displayFields` in order.
|
|
89
|
+
* Used internally by `getRecordDisplay` when an entity defines explicit display field names.
|
|
90
|
+
*/
|
|
75
91
|
const getRecordDisplayByDisplayFields = (record, displayFields) => {
|
|
76
92
|
let result = "";
|
|
77
93
|
if (displayFields && (0, lodash_1.isArray)(displayFields) && !(0, core_1.isNonEmptyString)(result)) {
|
|
@@ -82,13 +98,24 @@ const getRecordDisplayByDisplayFields = (record, displayFields) => {
|
|
|
82
98
|
return result;
|
|
83
99
|
};
|
|
84
100
|
exports.getRecordDisplayByDisplayFields = getRecordDisplayByDisplayFields;
|
|
101
|
+
/**
|
|
102
|
+
* Returns a folder path string derived from a record's `entityName` and `entityType`.
|
|
103
|
+
* Format: `"entityName/entityType"` or just `"entityName"` when `entityNameOnly` is true
|
|
104
|
+
* or when `entityType` is absent. Returns `"Unknown"` when both are empty.
|
|
105
|
+
*/
|
|
85
106
|
const getRecordEntityFolder = (data, entityNameOnly) => {
|
|
86
|
-
let entityFolder = (0, core_1.isNonEmptyString)(data.entityType) && !entityNameOnly
|
|
107
|
+
let entityFolder = (0, core_1.isNonEmptyString)(data.entityType) && !entityNameOnly
|
|
108
|
+
? `${data.entityName ?? ""}/${data.entityType}`
|
|
109
|
+
: (data.entityName ?? "");
|
|
87
110
|
if (entityFolder.length == 0)
|
|
88
111
|
entityFolder = "Unknown";
|
|
89
112
|
return entityFolder;
|
|
90
113
|
};
|
|
91
114
|
exports.getRecordEntityFolder = getRecordEntityFolder;
|
|
115
|
+
/**
|
|
116
|
+
* Builds a storage folder path from explicit `entityName` and optional `entityType` strings
|
|
117
|
+
* (rather than reading from a record object). Returns `"Unknown"` when `entityName` is empty.
|
|
118
|
+
*/
|
|
92
119
|
const getEntityFolder = (entityName, entityType) => {
|
|
93
120
|
let entityFolder = (0, core_1.isNonEmptyString)(entityType) ? `${entityName}/${entityType}` : entityName;
|
|
94
121
|
if (entityFolder.length == 0)
|
|
@@ -96,6 +123,22 @@ const getEntityFolder = (entityName, entityType) => {
|
|
|
96
123
|
return entityFolder;
|
|
97
124
|
};
|
|
98
125
|
exports.getEntityFolder = getEntityFolder;
|
|
126
|
+
/**
|
|
127
|
+
* Resolves the best human-readable display label for a record.
|
|
128
|
+
*
|
|
129
|
+
* Resolution priority:
|
|
130
|
+
* 1. Search highlight title (`_ui.highlight.title`)
|
|
131
|
+
* 2. `searchDisplay` (when `includeSearchDisplay` is true)
|
|
132
|
+
* 3. Entity `displayFields` (first non-empty field)
|
|
133
|
+
* 4. `firstName + lastName` full name
|
|
134
|
+
* 5. `displayValue`
|
|
135
|
+
* 6. `number – title` / `number – name` / `number – subject`
|
|
136
|
+
* 7. `display`, `text`, `symbol`, `code`
|
|
137
|
+
*
|
|
138
|
+
* The result is cleaned (normalizes whitespace and punctuation spacing) and optionally
|
|
139
|
+
* truncated to `maxLength` characters. Returns the record `id` when `allowUseRecordId`
|
|
140
|
+
* is true and no other value could be resolved.
|
|
141
|
+
*/
|
|
99
142
|
const getRecordDisplay = (record, settings) => {
|
|
100
143
|
if (!(0, core_1.isObject)(record))
|
|
101
144
|
return "";
|
|
@@ -119,7 +162,9 @@ const getRecordDisplay = (record, settings) => {
|
|
|
119
162
|
if (!(0, core_1.isNonEmptyString)(result, true) && (0, core_1.isNonEmptyString)(record.displayValue, true)) {
|
|
120
163
|
result = record.displayValue;
|
|
121
164
|
}
|
|
122
|
-
const number = !(0, core_1.isNonEmptyString)(result, true) && (0, core_1.isNonEmptyString)(record.number, true)
|
|
165
|
+
const number = !(0, core_1.isNonEmptyString)(result, true) && (0, core_1.isNonEmptyString)(record.number, true)
|
|
166
|
+
? `${record.number} - `
|
|
167
|
+
: "";
|
|
123
168
|
if (!(0, core_1.isNonEmptyString)(result, true) && (0, core_1.isNonEmptyString)(record.title, true)) {
|
|
124
169
|
result = `${number}${record.title}`;
|
|
125
170
|
}
|
|
@@ -156,9 +201,21 @@ const getRecordDisplay = (record, settings) => {
|
|
|
156
201
|
if ((0, lodash_1.isNumber)(maxLength) && result.length > maxLength) {
|
|
157
202
|
result = `${result.substring(0, maxLength)} ...`;
|
|
158
203
|
}
|
|
159
|
-
return ((0, core_1.isNonEmptyString)(result, true) ? result : allowUseRecordId ? record.id : "") ??
|
|
204
|
+
return (((0, core_1.isNonEmptyString)(result, true) ? result : allowUseRecordId ? record.id : "") ??
|
|
205
|
+
(settings?.emptyReturnUndefined ? undefined : ""));
|
|
160
206
|
};
|
|
161
207
|
exports.getRecordDisplay = getRecordDisplay;
|
|
208
|
+
/**
|
|
209
|
+
* Resolves the best short abstract/description text for a record.
|
|
210
|
+
*
|
|
211
|
+
* Resolution priority:
|
|
212
|
+
* 1. Search highlight (`highlight.searchContent[0]`)
|
|
213
|
+
* 2. `summary`, `description`, `abstract`
|
|
214
|
+
* 3. `searchContent` (only when `settings.includeContent` is true)
|
|
215
|
+
*
|
|
216
|
+
* Whitespace and punctuation are normalized before returning.
|
|
217
|
+
* Truncates to `settings.maxLength` characters when provided.
|
|
218
|
+
*/
|
|
162
219
|
const getRecordAbstract = (record, settings) => {
|
|
163
220
|
if (!(0, core_1.isObject)(record))
|
|
164
221
|
return "";
|
|
@@ -172,7 +229,9 @@ const getRecordAbstract = (record, settings) => {
|
|
|
172
229
|
result = record.description;
|
|
173
230
|
if (!(0, core_1.isNonEmptyString)(result) && (0, core_1.isNonEmptyString)(record.abstract))
|
|
174
231
|
result = record.abstract;
|
|
175
|
-
if (settings?.includeContent &&
|
|
232
|
+
if (settings?.includeContent &&
|
|
233
|
+
!(0, core_1.isNonEmptyString)(result) &&
|
|
234
|
+
(0, core_1.isNonEmptyString)(record.searchContent)) {
|
|
176
235
|
result = record.searchContent;
|
|
177
236
|
}
|
|
178
237
|
result = result
|
|
@@ -193,6 +252,10 @@ const getRecordAbstract = (record, settings) => {
|
|
|
193
252
|
return result;
|
|
194
253
|
};
|
|
195
254
|
exports.getRecordAbstract = getRecordAbstract;
|
|
255
|
+
/**
|
|
256
|
+
* Returns the first non-empty string value found by iterating `contentFields` in order.
|
|
257
|
+
* Used internally by `getRecordContent` when an entity defines explicit content field names.
|
|
258
|
+
*/
|
|
196
259
|
const getRecordContentByContentFields = (record, contentFields) => {
|
|
197
260
|
let result = "";
|
|
198
261
|
if (contentFields && (0, lodash_1.isArray)(contentFields) && !(0, core_1.isNonEmptyString)(result)) {
|
|
@@ -203,6 +266,16 @@ const getRecordContentByContentFields = (record, contentFields) => {
|
|
|
203
266
|
return result;
|
|
204
267
|
};
|
|
205
268
|
exports.getRecordContentByContentFields = getRecordContentByContentFields;
|
|
269
|
+
/**
|
|
270
|
+
* Resolves the main body content for a record, suitable for indexing or display.
|
|
271
|
+
*
|
|
272
|
+
* Resolution priority:
|
|
273
|
+
* 1. Search highlight (`_ui.highlight.content`)
|
|
274
|
+
* 2. `searchContent` (when `includeSearchDisplay` is true)
|
|
275
|
+
* 3. Entity/settings `contentFields` (defaults to description, note, detail, content, …)
|
|
276
|
+
*
|
|
277
|
+
* Truncates to `maxLength` when provided.
|
|
278
|
+
*/
|
|
206
279
|
const getRecordContent = (record, settings) => {
|
|
207
280
|
if (!(0, core_1.isObject)(record))
|
|
208
281
|
return "";
|
|
@@ -210,7 +283,21 @@ const getRecordContent = (record, settings) => {
|
|
|
210
283
|
const includeSearchDisplay = settings?.includeSearchDisplay == true;
|
|
211
284
|
const maxLength = settings?.maxLength;
|
|
212
285
|
const entity = settings?.entity;
|
|
213
|
-
const contentFields = settings?.contentFields ??
|
|
286
|
+
const contentFields = settings?.contentFields ??
|
|
287
|
+
entity?.contentFields ?? [
|
|
288
|
+
"description",
|
|
289
|
+
"note",
|
|
290
|
+
"detail",
|
|
291
|
+
"content",
|
|
292
|
+
"summary",
|
|
293
|
+
"introduction",
|
|
294
|
+
"abstract",
|
|
295
|
+
"title",
|
|
296
|
+
"subject",
|
|
297
|
+
"firstName",
|
|
298
|
+
"lastName",
|
|
299
|
+
"name"
|
|
300
|
+
];
|
|
214
301
|
if ((0, core_1.isNonEmptyString)(record._ui?.highlight?.content)) {
|
|
215
302
|
result = record._ui?.highlight?.content;
|
|
216
303
|
}
|
|
@@ -223,24 +310,41 @@ const getRecordContent = (record, settings) => {
|
|
|
223
310
|
if ((0, lodash_1.isNumber)(maxLength) && (0, core_1.isNonEmptyString)(result, true) && result.length > maxLength) {
|
|
224
311
|
result = `${result.substring(0, maxLength)} ...`;
|
|
225
312
|
}
|
|
226
|
-
return (0, core_1.isNonEmptyString)(result, true)
|
|
313
|
+
return (0, core_1.isNonEmptyString)(result, true)
|
|
314
|
+
? result.trim()
|
|
315
|
+
: settings?.emptyReturnUndefined
|
|
316
|
+
? undefined
|
|
317
|
+
: "";
|
|
227
318
|
};
|
|
228
319
|
exports.getRecordContent = getRecordContent;
|
|
320
|
+
/**
|
|
321
|
+
* Formats a complete postal address from prefixed address fields on a record
|
|
322
|
+
* (e.g. `prefix = "billing"` reads `billingLine1`, `billingCity`, `billingState`, …).
|
|
323
|
+
* Returns `""` when the record does not contain the minimum required fields
|
|
324
|
+
* (city + state + country, or postalCode + country).
|
|
325
|
+
*/
|
|
229
326
|
const getRecordAddress = (record, prefix) => {
|
|
230
327
|
if (!(0, core_1.isObject)(record))
|
|
231
328
|
return "";
|
|
232
329
|
const line1 = (0, core_1.isNonEmptyString)(record[`${prefix}Line1`]) ? record[`${prefix}Line1`] : "";
|
|
233
330
|
const line2 = (0, core_1.isNonEmptyString)(record[`${prefix}Line2`]) ? record[`${prefix}Line2`] : "";
|
|
234
331
|
const city = (0, core_1.isNonEmptyString)(record[`${prefix}City`]) ? record[`${prefix}City`] : "";
|
|
235
|
-
const postalCode = (0, core_1.isNonEmptyString)(record[`${prefix}PostalCode`])
|
|
332
|
+
const postalCode = (0, core_1.isNonEmptyString)(record[`${prefix}PostalCode`])
|
|
333
|
+
? record[`${prefix}PostalCode`]
|
|
334
|
+
: "";
|
|
236
335
|
const state = (0, core_1.isNonEmptyString)(record[`${prefix}State`]) ? record[`${prefix}State`] : "";
|
|
237
336
|
const country = (0, core_1.isNonEmptyString)(record[`${prefix}Country`]) ? record[`${prefix}Country`] : "";
|
|
238
|
-
if ((line1.length > 0 && city.length > 0 && state.length > 0 && country.length > 0) ||
|
|
337
|
+
if ((line1.length > 0 && city.length > 0 && state.length > 0 && country.length > 0) ||
|
|
338
|
+
(postalCode.length > 0 && country.length > 0)) {
|
|
239
339
|
return `${line1} ${line2},${city},${state},${postalCode},${country}`;
|
|
240
340
|
}
|
|
241
341
|
return "";
|
|
242
342
|
};
|
|
243
343
|
exports.getRecordAddress = getRecordAddress;
|
|
344
|
+
/**
|
|
345
|
+
* Returns the primary media URL for a record, trying `media`, `photoUrl`, and
|
|
346
|
+
* `source.photoUrl` in that order. Returns `""` when none are set.
|
|
347
|
+
*/
|
|
244
348
|
const getRecordMedia = (record) => {
|
|
245
349
|
if (!(0, core_1.isObject)(record))
|
|
246
350
|
return "";
|
|
@@ -253,6 +357,14 @@ const getRecordMedia = (record) => {
|
|
|
253
357
|
return "";
|
|
254
358
|
};
|
|
255
359
|
exports.getRecordMedia = getRecordMedia;
|
|
360
|
+
/**
|
|
361
|
+
* Constructs a display name for a user-like record.
|
|
362
|
+
*
|
|
363
|
+
* Resolution order: `fullName` → `firstName + lastName` → `name` → `email`.
|
|
364
|
+
* `skipFullNameProp`, `skipNameProp`, `skipEmailProp` let callers exclude specific steps.
|
|
365
|
+
* Simplified Chinese locale (Windows locale code 2052) has spaces stripped from the assembled name.
|
|
366
|
+
* Multiple consecutive spaces are collapsed to a single space.
|
|
367
|
+
*/
|
|
256
368
|
const getRecordFullName = (user, settings) => {
|
|
257
369
|
const { skipFullNameProp, skipNameProp, skipEmailProp } = settings ?? {};
|
|
258
370
|
if (!(0, core_1.isObject)(user))
|
|
@@ -262,7 +374,9 @@ const getRecordFullName = (user, settings) => {
|
|
|
262
374
|
let fullName = (0, core_1.isNonEmptyString)(user.fullName) && !skipFullNameProp ? user.fullName.trim() : "";
|
|
263
375
|
const firstName = (0, core_1.isNonEmptyString)(user.firstName) ? user.firstName.trim() : "";
|
|
264
376
|
const lastName = (0, core_1.isNonEmptyString)(user.lastName) ? user.lastName.trim() : "";
|
|
265
|
-
if (fullName.length == 0 ||
|
|
377
|
+
if (fullName.length == 0 ||
|
|
378
|
+
(firstName.length > 0 && lastName.length > 0) ||
|
|
379
|
+
(fullName.length > 0 && fullName == email)) {
|
|
266
380
|
fullName = `${firstName} ${lastName.length > 0 ? " " + lastName : ""}`.trim();
|
|
267
381
|
}
|
|
268
382
|
if (user.lcid === 2052)
|
|
@@ -275,6 +389,12 @@ const getRecordFullName = (user, settings) => {
|
|
|
275
389
|
return fullName;
|
|
276
390
|
};
|
|
277
391
|
exports.getRecordFullName = getRecordFullName;
|
|
392
|
+
/**
|
|
393
|
+
* Returns a formatted email address string for a record that has a valid `email` field.
|
|
394
|
+
* Format: `"Full Name <email@example.com>"`, or just `"email@example.com"` when
|
|
395
|
+
* `emailOnly` is true or no display name is available.
|
|
396
|
+
* Returns `undefined` when the record has no valid email.
|
|
397
|
+
*/
|
|
278
398
|
const getRecordEmailAddress = (record, emailOnly) => {
|
|
279
399
|
if ((0, core_1.isObject)(record) && (0, core_1.isEmail)(record.email)) {
|
|
280
400
|
const fullName = (0, exports.getRecordFullName)(record);
|
|
@@ -288,6 +408,12 @@ const getRecordEmailAddress = (record, emailOnly) => {
|
|
|
288
408
|
return undefined;
|
|
289
409
|
};
|
|
290
410
|
exports.getRecordEmailAddress = getRecordEmailAddress;
|
|
411
|
+
/**
|
|
412
|
+
* Builds an Open Graph / page metadata object for a record, suitable for `<head>` tags.
|
|
413
|
+
* Returns `{ id, title, description, type: "article", image? }`.
|
|
414
|
+
* Title is derived from `getRecordDisplay` (or `getRecordAbstract` when display is empty),
|
|
415
|
+
* optionally prefixed with `settings.siteName`.
|
|
416
|
+
*/
|
|
291
417
|
const getRecordPageMetadata = (record, settings) => {
|
|
292
418
|
const result = {};
|
|
293
419
|
const recordDisplay = (0, exports.getRecordDisplay)(record);
|
|
@@ -295,12 +421,15 @@ const getRecordPageMetadata = (record, settings) => {
|
|
|
295
421
|
result.title =
|
|
296
422
|
(0, core_1.isObject)(settings) && settings?.siteName
|
|
297
423
|
? `${settings?.siteName} - ${(0, exports.getRecordAbstract)(record, {
|
|
298
|
-
maxLength: 64
|
|
424
|
+
maxLength: 64
|
|
299
425
|
})}`
|
|
300
426
|
: (0, exports.getRecordAbstract)(record, { maxLength: 64 });
|
|
301
427
|
}
|
|
302
428
|
else {
|
|
303
|
-
result.title =
|
|
429
|
+
result.title =
|
|
430
|
+
(0, core_1.isObject)(settings) && settings?.siteName
|
|
431
|
+
? `${settings?.siteName} - ${recordDisplay}`
|
|
432
|
+
: recordDisplay;
|
|
304
433
|
}
|
|
305
434
|
result.id = record.id;
|
|
306
435
|
result.description = (0, exports.getRecordAbstract)(record, { maxLength: 128 });
|
|
@@ -311,6 +440,11 @@ const getRecordPageMetadata = (record, settings) => {
|
|
|
311
440
|
return result;
|
|
312
441
|
};
|
|
313
442
|
exports.getRecordPageMetadata = getRecordPageMetadata;
|
|
443
|
+
/**
|
|
444
|
+
* Computes the current slug via `getRecordSlug` and ensures it is present in both
|
|
445
|
+
* `record.slug` (current) and `record.slugs` (historical list, deduplicated).
|
|
446
|
+
* Call this before persisting a record to keep slug history intact for redirects.
|
|
447
|
+
*/
|
|
314
448
|
const applyRecordSlug = (record) => {
|
|
315
449
|
const curSlug = (0, exports.getRecordSlug)(record);
|
|
316
450
|
if (curSlug) {
|
|
@@ -324,6 +458,13 @@ const applyRecordSlug = (record) => {
|
|
|
324
458
|
return record;
|
|
325
459
|
};
|
|
326
460
|
exports.applyRecordSlug = applyRecordSlug;
|
|
461
|
+
/**
|
|
462
|
+
* Derives a URL slug for a record.
|
|
463
|
+
* Uses `record.customSlug` when set; otherwise derives from `getRecordDisplay`.
|
|
464
|
+
* The slug is truncated to 128 characters and suffixed with the second GUID segment
|
|
465
|
+
* of the record ID (e.g. `"my-post-e29b"`) to guarantee global uniqueness.
|
|
466
|
+
* Returns `undefined` when the record has no `id`.
|
|
467
|
+
*/
|
|
327
468
|
const getRecordSlug = (record) => {
|
|
328
469
|
if (!record.id)
|
|
329
470
|
return undefined;
|
|
@@ -337,12 +478,23 @@ const getRecordSlug = (record) => {
|
|
|
337
478
|
return curSlug;
|
|
338
479
|
};
|
|
339
480
|
exports.getRecordSlug = getRecordSlug;
|
|
481
|
+
/**
|
|
482
|
+
* Builds the storage path for a file attached to a record.
|
|
483
|
+
* Format: `"{solutionId}/{organizationId}/{entityName}/{recordId}/{fieldName}"`.
|
|
484
|
+
* `fieldName` defaults to `"file"` when not provided.
|
|
485
|
+
*/
|
|
340
486
|
const getRecordFilePath = (props) => {
|
|
341
487
|
const { solutionId, organizationId, recordId, entityName } = props;
|
|
342
488
|
const fieldName = props.fieldName ?? "file";
|
|
343
489
|
return `${solutionId}/${organizationId}/${entityName}/${recordId}/${fieldName}`;
|
|
344
490
|
};
|
|
345
491
|
exports.getRecordFilePath = getRecordFilePath;
|
|
492
|
+
/**
|
|
493
|
+
* Extracts an `IContext` from a record that carries context fields directly
|
|
494
|
+
* (e.g. an API request body that has been enriched with caller context).
|
|
495
|
+
* Picks `solutionId`, `domain`, `sourceIp`, `userId`, `organizationId`,
|
|
496
|
+
* `user`, `organization`, and `solution`.
|
|
497
|
+
*/
|
|
346
498
|
const getContextFromRecord = (record) => {
|
|
347
499
|
const { solutionId, domain, sourceIp, userId, organizationId, user, organization, solution } = record;
|
|
348
500
|
return {
|
|
@@ -353,19 +505,32 @@ const getContextFromRecord = (record) => {
|
|
|
353
505
|
organizationId,
|
|
354
506
|
user,
|
|
355
507
|
organization,
|
|
356
|
-
solution
|
|
508
|
+
solution
|
|
357
509
|
};
|
|
358
510
|
};
|
|
359
511
|
exports.getContextFromRecord = getContextFromRecord;
|
|
512
|
+
/**
|
|
513
|
+
* Returns true when a record is marked global but belongs to a different organization
|
|
514
|
+
* than the one in the current context. Used to identify marketplace/shared content.
|
|
515
|
+
*/
|
|
360
516
|
const fromOtherOrganization = (context, record) => {
|
|
361
517
|
return record.isGlobal && record.organizationId != context.organizationId;
|
|
362
518
|
};
|
|
363
519
|
exports.fromOtherOrganization = fromOtherOrganization;
|
|
520
|
+
/**
|
|
521
|
+
* Returns true when the record's ID appears in the current user's favorites list
|
|
522
|
+
* for the record's entity type (`context.user.favorites[entityName]`).
|
|
523
|
+
*/
|
|
364
524
|
const isFavorite = (context, record) => {
|
|
365
525
|
const favorites = context.user?.favorites ? context.user?.favorites[record.entityName] : [];
|
|
366
526
|
return favorites.includes(record.id);
|
|
367
527
|
};
|
|
368
528
|
exports.isFavorite = isFavorite;
|
|
529
|
+
/**
|
|
530
|
+
* Returns true when a record is global and its owning organization differs from the
|
|
531
|
+
* current context's organization. Equivalent to `fromOtherOrganization` but compares
|
|
532
|
+
* against `context.organization.id` instead of `context.organizationId`.
|
|
533
|
+
*/
|
|
369
534
|
const isFromMarketplace = (context, record) => {
|
|
370
535
|
return record.isGlobal && record.organizationId != context?.organization?.id;
|
|
371
536
|
};
|