@encodeagent/platform-helper-util 1.2603.1071502 → 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.
Files changed (69) hide show
  1. package/README.md +277 -153
  2. package/dist/api.d.ts +38 -0
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +38 -2
  5. package/dist/api.js.map +1 -1
  6. package/dist/auth.d.ts +93 -0
  7. package/dist/auth.d.ts.map +1 -1
  8. package/dist/auth.js +93 -2
  9. package/dist/auth.js.map +1 -1
  10. package/dist/colors.d.ts +41 -0
  11. package/dist/colors.d.ts.map +1 -1
  12. package/dist/colors.js +41 -0
  13. package/dist/colors.js.map +1 -1
  14. package/dist/core.d.ts +262 -0
  15. package/dist/core.d.ts.map +1 -1
  16. package/dist/core.js +264 -2
  17. package/dist/core.js.map +1 -1
  18. package/dist/cost.d.ts +26 -0
  19. package/dist/cost.d.ts.map +1 -1
  20. package/dist/cost.js +27 -1
  21. package/dist/cost.js.map +1 -1
  22. package/dist/file.d.ts +38 -0
  23. package/dist/file.d.ts.map +1 -1
  24. package/dist/file.js +42 -2
  25. package/dist/file.js.map +1 -1
  26. package/dist/html.d.ts +83 -0
  27. package/dist/html.d.ts.map +1 -1
  28. package/dist/html.js +89 -37
  29. package/dist/html.js.map +1 -1
  30. package/dist/logger.d.ts +17 -0
  31. package/dist/logger.d.ts.map +1 -1
  32. package/dist/logger.js +28 -2
  33. package/dist/logger.js.map +1 -1
  34. package/dist/markdown.d.ts +20 -0
  35. package/dist/markdown.d.ts.map +1 -1
  36. package/dist/markdown.js +20 -0
  37. package/dist/markdown.js.map +1 -1
  38. package/dist/metadata.js +1 -1
  39. package/dist/metadata.js.map +1 -1
  40. package/dist/record.d.ts +141 -3
  41. package/dist/record.d.ts.map +1 -1
  42. package/dist/record.js +161 -65
  43. package/dist/record.js.map +1 -1
  44. package/dist/shortid.d.ts +21 -8
  45. package/dist/shortid.d.ts.map +1 -1
  46. package/dist/shortid.js +9 -5
  47. package/dist/shortid.js.map +1 -1
  48. package/dist/slug.d.ts +10 -0
  49. package/dist/slug.d.ts.map +1 -1
  50. package/dist/slug.js +10 -0
  51. package/dist/slug.js.map +1 -1
  52. package/dist/token.d.ts +1 -1
  53. package/dist/tree.d.ts +43 -0
  54. package/dist/tree.d.ts.map +1 -1
  55. package/dist/tree.js +43 -5
  56. package/dist/tree.js.map +1 -1
  57. package/dist/value-of-object.d.ts +41 -0
  58. package/dist/value-of-object.d.ts.map +1 -1
  59. package/dist/value-of-object.js +59 -17
  60. package/dist/value-of-object.js.map +1 -1
  61. package/dist/web-content.d.ts +52 -0
  62. package/dist/web-content.d.ts.map +1 -1
  63. package/dist/web-content.js +52 -0
  64. package/dist/web-content.js.map +1 -1
  65. package/dist/web.d.ts +51 -0
  66. package/dist/web.d.ts.map +1 -1
  67. package/dist/web.js +54 -1
  68. package/dist/web.js.map +1 -1
  69. package/package.json +10 -5
package/dist/record.d.ts CHANGED
@@ -23,25 +23,72 @@ export interface IRecord {
23
23
  organizationId: string;
24
24
  solutionId: string;
25
25
  createdBy: string;
26
- createdOn: number;
26
+ createdAt: number;
27
27
  ownedBy: string;
28
- ownedOn: number;
28
+ ownedAt: number;
29
29
  modifiedBy: string;
30
- modifiedOn: number;
30
+ modifiedAt: number;
31
31
  partitionKey: string;
32
32
  isPublished?: boolean;
33
33
  isGlobal?: boolean;
34
+ isPublishedBy?: string;
35
+ isPublishedAt?: string;
36
+ isGlobalBy?: string;
37
+ isGlobalAt?: string;
38
+ stateCode: number;
39
+ statusCode: number;
34
40
  [key: string]: any;
35
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
+ */
36
49
  export declare const convertRecordForCreate: (record: Record<string, any>) => Record<string, any>;
37
50
  export interface IGetBaseRecordProps extends IContext {
38
51
  entityName: string;
39
52
  entityType?: string;
40
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
+ */
41
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
+ */
42
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
+ */
43
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
+ */
44
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
+ */
45
92
  export declare const getRecordDisplay: (record: Record<string, any>, settings?: {
46
93
  entity?: Record<string, any>;
47
94
  displayFields?: string[];
@@ -50,13 +97,38 @@ export declare const getRecordDisplay: (record: Record<string, any>, settings?:
50
97
  emptyReturnUndefined?: boolean;
51
98
  allowUseRecordId?: boolean;
52
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
+ */
53
111
  export declare const getRecordAbstract: (record: Record<string, any>, settings?: {
54
112
  entity?: Record<string, any>;
55
113
  abstractFields?: string[];
56
114
  maxLength?: number;
57
115
  includeContent?: boolean;
58
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
+ */
59
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
+ */
60
132
  export declare const getRecordContent: (record: Record<string, any>, settings?: {
61
133
  entity?: Record<string, any>;
62
134
  contentFields?: string[];
@@ -64,18 +136,60 @@ export declare const getRecordContent: (record: Record<string, any>, settings?:
64
136
  maxLength?: number;
65
137
  emptyReturnUndefined?: boolean;
66
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
+ */
67
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
+ */
68
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
+ */
69
159
  export declare const getRecordFullName: (user: Record<string, any>, settings?: {
70
160
  skipFullNameProp?: boolean;
71
161
  skipNameProp?: boolean;
72
162
  skipEmailProp?: boolean;
73
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
+ */
74
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
+ */
75
177
  export declare const getRecordPageMetadata: (record: Record<string, any>, settings?: {
76
178
  siteName?: string;
77
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
+ */
78
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
+ */
79
193
  export declare const getRecordSlug: (record: Record<string, any>) => string | undefined;
80
194
  export type TRecordFilePath = {
81
195
  solutionId: string;
@@ -84,9 +198,33 @@ export type TRecordFilePath = {
84
198
  entityName: string;
85
199
  fieldName?: string;
86
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
+ */
87
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
+ */
88
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
+ */
89
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
+ */
90
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
+ */
91
229
  export declare const isFromMarketplace: (context: Record<string, any>, record: Record<string, any>) => boolean;
92
230
  //# sourceMappingURL=record.d.ts.map
@@ -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;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,eAAO,MAAM,sBAAsB,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,wBA6BjE,CAAC;AAEF,MAAM,WAAW,mBAAoB,SAAQ,QAAQ;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,aAAa,GAAI,SAAS,mBAAmB,KAAG,OAkB5D,CAAA;AAED,eAAO,MAAM,+BAA+B,GACxC,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,gBAAgB,MAAM,EAAE,WAa3B,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAC9B,MAAM,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,gBAAgB,OAAO,KACxB,MAOF,CAAC;AAEF,eAAO,MAAM,eAAe,GACxB,YAAY,MAAM,EAClB,aAAa,MAAM,KACpB,MAMF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GACzB,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,WAAW;IACP,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B,KACF,MAAM,GAAG,SAoFX,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC1B,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,WAAW;IACP,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B,KACF,MA8CF,CAAC;AAEF,eAAO,MAAM,+BAA+B,GACxC,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,gBAAgB,MAAM,EAAE,WAa3B,CAAC;AAEF,eAAO,MAAM,gBAAgB,GACzB,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,WAAW;IACP,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAClC,KACF,MAAM,GAAG,SAoDX,CAAC;AAEF,eAAO,MAAM,gBAAgB,GACzB,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,QAAQ,MAAM,KACf,MAiCF,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAG,MAO5D,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC1B,MAAM,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,WAAW;IACP,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;CAC3B,KACF,MAmCF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAC9B,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,YAAY,OAAO,KACpB,MAAM,GAAG,SAWX,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAC9B,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,WAAW;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,wBA0BnC,CAAC;AAEF,eAAO,MAAM,eAAe,GACxB,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,CAUpB,CAAC;AAEF,eAAO,MAAM,aAAa,GACtB,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC5B,MAAM,GAAG,SAaX,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,OAAO,eAAe,KAAG,MAI1D,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAG,QAqBlE,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAC9B,SAAS,QAAQ,EACjB,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC5B,OAIF,CAAC;AAEF,eAAO,MAAM,UAAU,GACnB,SAAS,QAAQ,EACjB,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC5B,OAGF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC1B,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC5B,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC5B,OAIF,CAAC"}
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.createdOn;
34
+ delete newRecord.createdAt;
28
35
  delete newRecord.ownedBy;
29
- delete newRecord.ownedOn;
36
+ delete newRecord.ownedAt;
30
37
  delete newRecord.modifiedBy;
31
- delete newRecord.modifiedOn;
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,11 +71,11 @@ const getBaseRecord = (context) => {
59
71
  entityName,
60
72
  entityType,
61
73
  createdBy: userId,
62
- createdOn: (0, core_1.getTimestamp)(),
74
+ createdAt: (0, core_1.getTimestamp)(),
63
75
  ownedBy: userId,
64
- ownedOn: (0, core_1.getTimestamp)(),
76
+ ownedAt: (0, core_1.getTimestamp)(),
65
77
  modifiedBy: userId,
66
- modifiedOn: (0, core_1.getTimestamp)(),
78
+ modifiedAt: (0, core_1.getTimestamp)(),
67
79
  stateCode: 0,
68
80
  statusCode: 0,
69
81
  organizationId,
@@ -72,6 +84,10 @@ const getBaseRecord = (context) => {
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,24 +98,47 @@ 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
107
  let entityFolder = (0, core_1.isNonEmptyString)(data.entityType) && !entityNameOnly
87
108
  ? `${data.entityName ?? ""}/${data.entityType}`
88
- : data.entityName ?? "";
109
+ : (data.entityName ?? "");
89
110
  if (entityFolder.length == 0)
90
111
  entityFolder = "Unknown";
91
112
  return entityFolder;
92
113
  };
93
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
+ */
94
119
  const getEntityFolder = (entityName, entityType) => {
95
- let entityFolder = (0, core_1.isNonEmptyString)(entityType)
96
- ? `${entityName}/${entityType}`
97
- : entityName;
120
+ let entityFolder = (0, core_1.isNonEmptyString)(entityType) ? `${entityName}/${entityType}` : entityName;
98
121
  if (entityFolder.length == 0)
99
122
  entityFolder = "Unknown";
100
123
  return entityFolder;
101
124
  };
102
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
+ */
103
142
  const getRecordDisplay = (record, settings) => {
104
143
  if (!(0, core_1.isObject)(record))
105
144
  return "";
@@ -115,15 +154,12 @@ const getRecordDisplay = (record, settings) => {
115
154
  if (includeSearchDisplay && !(0, core_1.isNonEmptyString)(result, true)) {
116
155
  result = record.searchDisplay;
117
156
  }
118
- if (displayFields &&
119
- (0, lodash_1.isArray)(displayFields) &&
120
- !(0, core_1.isNonEmptyString)(result, true)) {
157
+ if (displayFields && (0, lodash_1.isArray)(displayFields) && !(0, core_1.isNonEmptyString)(result, true)) {
121
158
  result = (0, exports.getRecordDisplayByDisplayFields)(record, displayFields);
122
159
  }
123
160
  if (!(0, core_1.isNonEmptyString)(result, true))
124
161
  result = (0, exports.getRecordFullName)(record);
125
- if (!(0, core_1.isNonEmptyString)(result, true) &&
126
- (0, core_1.isNonEmptyString)(record.displayValue, true)) {
162
+ if (!(0, core_1.isNonEmptyString)(result, true) && (0, core_1.isNonEmptyString)(record.displayValue, true)) {
127
163
  result = record.displayValue;
128
164
  }
129
165
  const number = !(0, core_1.isNonEmptyString)(result, true) && (0, core_1.isNonEmptyString)(record.number, true)
@@ -135,8 +171,7 @@ const getRecordDisplay = (record, settings) => {
135
171
  if (!(0, core_1.isNonEmptyString)(result, true) && (0, core_1.isNonEmptyString)(record.name, true)) {
136
172
  result = `${number}${record.name}`;
137
173
  }
138
- if (!(0, core_1.isNonEmptyString)(result, true) &&
139
- (0, core_1.isNonEmptyString)(record.subject, true)) {
174
+ if (!(0, core_1.isNonEmptyString)(result, true) && (0, core_1.isNonEmptyString)(record.subject, true)) {
140
175
  result = `${number}${record.subject}`;
141
176
  }
142
177
  if (!(0, core_1.isNonEmptyString)(result, true) && (0, core_1.isNonEmptyString)(record.display, true)) {
@@ -145,8 +180,7 @@ const getRecordDisplay = (record, settings) => {
145
180
  if (!(0, core_1.isNonEmptyString)(result, true) && (0, core_1.isNonEmptyString)(record.text, true)) {
146
181
  result = record.text;
147
182
  }
148
- if (!(0, core_1.isNonEmptyString)(result, true) &&
149
- (0, core_1.isNonEmptyString)(record.symbol, true)) {
183
+ if (!(0, core_1.isNonEmptyString)(result, true) && (0, core_1.isNonEmptyString)(record.symbol, true)) {
150
184
  result = record.symbol;
151
185
  }
152
186
  if (!(0, core_1.isNonEmptyString)(result, true) && (0, core_1.isNonEmptyString)(record.code, true)) {
@@ -167,19 +201,26 @@ const getRecordDisplay = (record, settings) => {
167
201
  if ((0, lodash_1.isNumber)(maxLength) && result.length > maxLength) {
168
202
  result = `${result.substring(0, maxLength)} ...`;
169
203
  }
170
- return (((0, core_1.isNonEmptyString)(result, true)
171
- ? result
172
- : allowUseRecordId
173
- ? record.id
174
- : "") ?? (settings?.emptyReturnUndefined ? undefined : ""));
204
+ return (((0, core_1.isNonEmptyString)(result, true) ? result : allowUseRecordId ? record.id : "") ??
205
+ (settings?.emptyReturnUndefined ? undefined : ""));
175
206
  };
176
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
+ */
177
219
  const getRecordAbstract = (record, settings) => {
178
220
  if (!(0, core_1.isObject)(record))
179
221
  return "";
180
222
  let result = "";
181
- if ((0, lodash_1.isArray)(record?.highlight?.searchContent) &&
182
- record?.highlight?.searchContent?.length > 0) {
223
+ if ((0, lodash_1.isArray)(record?.highlight?.searchContent) && record?.highlight?.searchContent?.length > 0) {
183
224
  result = record.highlight.searchContent[0];
184
225
  }
185
226
  if (!(0, core_1.isNonEmptyString)(result) && (0, core_1.isNonEmptyString)(record.summary))
@@ -205,14 +246,16 @@ const getRecordAbstract = (record, settings) => {
205
246
  .replace(/;/g, "; ")
206
247
  .replace(new RegExp(`( ){2,}`, "g"), " ")
207
248
  .trim();
208
- if (settings &&
209
- (0, lodash_1.isNumber)(settings?.maxLength) &&
210
- result.length > settings?.maxLength) {
249
+ if (settings && (0, lodash_1.isNumber)(settings?.maxLength) && result.length > settings?.maxLength) {
211
250
  result = `${result.substring(0, settings?.maxLength)} ...`;
212
251
  }
213
252
  return result;
214
253
  };
215
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
+ */
216
259
  const getRecordContentByContentFields = (record, contentFields) => {
217
260
  let result = "";
218
261
  if (contentFields && (0, lodash_1.isArray)(contentFields) && !(0, core_1.isNonEmptyString)(result)) {
@@ -223,6 +266,16 @@ const getRecordContentByContentFields = (record, contentFields) => {
223
266
  return result;
224
267
  };
225
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
+ */
226
279
  const getRecordContent = (record, settings) => {
227
280
  if (!(0, core_1.isObject)(record))
228
281
  return "";
@@ -251,14 +304,10 @@ const getRecordContent = (record, settings) => {
251
304
  if (includeSearchDisplay && !(0, core_1.isNonEmptyString)(result, true)) {
252
305
  result = record.searchContent;
253
306
  }
254
- if (contentFields &&
255
- (0, lodash_1.isArray)(contentFields) &&
256
- !(0, core_1.isNonEmptyString)(result, true)) {
307
+ if (contentFields && (0, lodash_1.isArray)(contentFields) && !(0, core_1.isNonEmptyString)(result, true)) {
257
308
  result = (0, exports.getRecordContentByContentFields)(record, contentFields);
258
309
  }
259
- if ((0, lodash_1.isNumber)(maxLength) &&
260
- (0, core_1.isNonEmptyString)(result, true) &&
261
- result.length > maxLength) {
310
+ if ((0, lodash_1.isNumber)(maxLength) && (0, core_1.isNonEmptyString)(result, true) && result.length > maxLength) {
262
311
  result = `${result.substring(0, maxLength)} ...`;
263
312
  }
264
313
  return (0, core_1.isNonEmptyString)(result, true)
@@ -268,37 +317,34 @@ const getRecordContent = (record, settings) => {
268
317
  : "";
269
318
  };
270
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
+ */
271
326
  const getRecordAddress = (record, prefix) => {
272
327
  if (!(0, core_1.isObject)(record))
273
328
  return "";
274
- const line1 = (0, core_1.isNonEmptyString)(record[`${prefix}Line1`])
275
- ? record[`${prefix}Line1`]
276
- : "";
277
- const line2 = (0, core_1.isNonEmptyString)(record[`${prefix}Line2`])
278
- ? record[`${prefix}Line2`]
279
- : "";
280
- const city = (0, core_1.isNonEmptyString)(record[`${prefix}City`])
281
- ? record[`${prefix}City`]
282
- : "";
329
+ const line1 = (0, core_1.isNonEmptyString)(record[`${prefix}Line1`]) ? record[`${prefix}Line1`] : "";
330
+ const line2 = (0, core_1.isNonEmptyString)(record[`${prefix}Line2`]) ? record[`${prefix}Line2`] : "";
331
+ const city = (0, core_1.isNonEmptyString)(record[`${prefix}City`]) ? record[`${prefix}City`] : "";
283
332
  const postalCode = (0, core_1.isNonEmptyString)(record[`${prefix}PostalCode`])
284
333
  ? record[`${prefix}PostalCode`]
285
334
  : "";
286
- const state = (0, core_1.isNonEmptyString)(record[`${prefix}State`])
287
- ? record[`${prefix}State`]
288
- : "";
289
- const country = (0, core_1.isNonEmptyString)(record[`${prefix}Country`])
290
- ? record[`${prefix}Country`]
291
- : "";
292
- if ((line1.length > 0 &&
293
- city.length > 0 &&
294
- state.length > 0 &&
295
- country.length > 0) ||
335
+ const state = (0, core_1.isNonEmptyString)(record[`${prefix}State`]) ? record[`${prefix}State`] : "";
336
+ const country = (0, core_1.isNonEmptyString)(record[`${prefix}Country`]) ? record[`${prefix}Country`] : "";
337
+ if ((line1.length > 0 && city.length > 0 && state.length > 0 && country.length > 0) ||
296
338
  (postalCode.length > 0 && country.length > 0)) {
297
339
  return `${line1} ${line2},${city},${state},${postalCode},${country}`;
298
340
  }
299
341
  return "";
300
342
  };
301
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
+ */
302
348
  const getRecordMedia = (record) => {
303
349
  if (!(0, core_1.isObject)(record))
304
350
  return "";
@@ -311,21 +357,23 @@ const getRecordMedia = (record) => {
311
357
  return "";
312
358
  };
313
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
+ */
314
368
  const getRecordFullName = (user, settings) => {
315
369
  const { skipFullNameProp, skipNameProp, skipEmailProp } = settings ?? {};
316
370
  if (!(0, core_1.isObject)(user))
317
371
  return "";
318
372
  const email = (0, core_1.isNonEmptyString)(user.email) ? user.email.trim() : "";
319
373
  const name = (0, core_1.isNonEmptyString)(user.name) ? user.name.trim() : "";
320
- let fullName = (0, core_1.isNonEmptyString)(user.fullName) && !skipFullNameProp
321
- ? user.fullName.trim()
322
- : "";
323
- const firstName = (0, core_1.isNonEmptyString)(user.firstName)
324
- ? user.firstName.trim()
325
- : "";
326
- const lastName = (0, core_1.isNonEmptyString)(user.lastName)
327
- ? user.lastName.trim()
328
- : "";
374
+ let fullName = (0, core_1.isNonEmptyString)(user.fullName) && !skipFullNameProp ? user.fullName.trim() : "";
375
+ const firstName = (0, core_1.isNonEmptyString)(user.firstName) ? user.firstName.trim() : "";
376
+ const lastName = (0, core_1.isNonEmptyString)(user.lastName) ? user.lastName.trim() : "";
329
377
  if (fullName.length == 0 ||
330
378
  (firstName.length > 0 && lastName.length > 0) ||
331
379
  (fullName.length > 0 && fullName == email)) {
@@ -341,6 +389,12 @@ const getRecordFullName = (user, settings) => {
341
389
  return fullName;
342
390
  };
343
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
+ */
344
398
  const getRecordEmailAddress = (record, emailOnly) => {
345
399
  if ((0, core_1.isObject)(record) && (0, core_1.isEmail)(record.email)) {
346
400
  const fullName = (0, exports.getRecordFullName)(record);
@@ -354,6 +408,12 @@ const getRecordEmailAddress = (record, emailOnly) => {
354
408
  return undefined;
355
409
  };
356
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
+ */
357
417
  const getRecordPageMetadata = (record, settings) => {
358
418
  const result = {};
359
419
  const recordDisplay = (0, exports.getRecordDisplay)(record);
@@ -380,6 +440,11 @@ const getRecordPageMetadata = (record, settings) => {
380
440
  return result;
381
441
  };
382
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
+ */
383
448
  const applyRecordSlug = (record) => {
384
449
  const curSlug = (0, exports.getRecordSlug)(record);
385
450
  if (curSlug) {
@@ -393,6 +458,13 @@ const applyRecordSlug = (record) => {
393
458
  return record;
394
459
  };
395
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
+ */
396
468
  const getRecordSlug = (record) => {
397
469
  if (!record.id)
398
470
  return undefined;
@@ -406,12 +478,23 @@ const getRecordSlug = (record) => {
406
478
  return curSlug;
407
479
  };
408
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
+ */
409
486
  const getRecordFilePath = (props) => {
410
487
  const { solutionId, organizationId, recordId, entityName } = props;
411
488
  const fieldName = props.fieldName ?? "file";
412
489
  return `${solutionId}/${organizationId}/${entityName}/${recordId}/${fieldName}`;
413
490
  };
414
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
+ */
415
498
  const getContextFromRecord = (record) => {
416
499
  const { solutionId, domain, sourceIp, userId, organizationId, user, organization, solution } = record;
417
500
  return {
@@ -426,17 +509,30 @@ const getContextFromRecord = (record) => {
426
509
  };
427
510
  };
428
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
+ */
429
516
  const fromOtherOrganization = (context, record) => {
430
- return (record.isGlobal && record.organizationId != context.organizationId);
517
+ return record.isGlobal && record.organizationId != context.organizationId;
431
518
  };
432
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
+ */
433
524
  const isFavorite = (context, record) => {
434
525
  const favorites = context.user?.favorites ? context.user?.favorites[record.entityName] : [];
435
526
  return favorites.includes(record.id);
436
527
  };
437
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
+ */
438
534
  const isFromMarketplace = (context, record) => {
439
- return (record.isGlobal && record.organizationId != context?.organization?.id);
535
+ return record.isGlobal && record.organizationId != context?.organization?.id;
440
536
  };
441
537
  exports.isFromMarketplace = isFromMarketplace;
442
538
  //# sourceMappingURL=record.js.map