@dereekb/model 13.0.7 → 13.2.0

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/index.cjs.js CHANGED
@@ -1,239 +1,217 @@
1
1
  'use strict';
2
2
 
3
3
  var util = require('@dereekb/util');
4
- var classTransformer = require('class-transformer');
5
- var classValidator = require('class-validator');
4
+ var arktype = require('arktype');
6
5
  var makeError = require('make-error');
7
6
 
8
- /******************************************************************************
9
- Copyright (c) Microsoft Corporation.
10
-
11
- Permission to use, copy, modify, and/or distribute this software for any
12
- purpose with or without fee is hereby granted.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
15
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
16
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
17
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
18
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
19
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20
- PERFORMANCE OF THIS SOFTWARE.
21
- ***************************************************************************** */
22
- /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
23
-
24
-
25
- function __decorate(decorators, target, key, desc) {
26
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
27
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
28
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
29
- return c > 3 && r && Object.defineProperty(target, key, r), r;
30
- }
31
-
32
- function __metadata(metadataKey, metadataValue) {
33
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
34
- }
35
-
36
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
37
- var e = new Error(message);
38
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
39
- };
40
-
7
+ /**
8
+ * Maximum character length for address line fields (line1, line2).
9
+ */
41
10
  const ADDRESS_LINE_MAX_LENGTH = 50;
11
+ /**
12
+ * Maximum character length for city names.
13
+ */
42
14
  const ADDRESS_CITY_MAX_LENGTH = 80;
15
+ /**
16
+ * Maximum character length for full state names (e.g., "Texas").
17
+ */
43
18
  const ADDRESS_STATE_MAX_LENGTH = 30;
19
+ /**
20
+ * Maximum character length for two-letter state codes (e.g., "TX").
21
+ */
44
22
  const ADDRESS_STATE_CODE_MAX_LENGTH = 2;
23
+ /**
24
+ * Maximum character length for ZIP codes, accommodating ZIP+4 format (e.g., "77834-1234").
25
+ */
45
26
  const ADDRESS_ZIP_MAX_LENGTH = 11;
27
+ /**
28
+ * Maximum character length for country names.
29
+ */
46
30
  const ADDRESS_COUNTRY_MAX_LENGTH = 80;
47
- class AbstractUnitedStatesAddressWithoutStateParams {
48
- line1;
49
- line2;
50
- city;
51
- zip;
52
- }
53
- __decorate([
54
- classTransformer.Expose(),
55
- classValidator.IsString(),
56
- classValidator.IsNotEmpty(),
57
- classValidator.MaxLength(ADDRESS_LINE_MAX_LENGTH),
58
- __metadata("design:type", String)
59
- ], AbstractUnitedStatesAddressWithoutStateParams.prototype, "line1", void 0);
60
- __decorate([
61
- classTransformer.Expose(),
62
- classValidator.IsOptional(),
63
- classValidator.IsString(),
64
- classValidator.MaxLength(ADDRESS_LINE_MAX_LENGTH),
65
- __metadata("design:type", String)
66
- ], AbstractUnitedStatesAddressWithoutStateParams.prototype, "line2", void 0);
67
- __decorate([
68
- classTransformer.Expose(),
69
- classValidator.IsString(),
70
- classValidator.IsNotEmpty(),
71
- classValidator.MaxLength(ADDRESS_CITY_MAX_LENGTH),
72
- __metadata("design:type", String)
73
- ], AbstractUnitedStatesAddressWithoutStateParams.prototype, "city", void 0);
74
- __decorate([
75
- classTransformer.Expose(),
76
- classValidator.IsString(),
77
- classValidator.IsNotEmpty(),
78
- classValidator.Matches(util.ZIP_CODE_STRING_REGEX),
79
- classValidator.MaxLength(ADDRESS_ZIP_MAX_LENGTH),
80
- __metadata("design:type", String)
81
- ], AbstractUnitedStatesAddressWithoutStateParams.prototype, "zip", void 0);
82
- /**
83
- * UnitedStatesAddress that enforces a StateCode for the state value.
84
- */
85
- class UnitedStatesAddressWithStateCodeParams extends AbstractUnitedStatesAddressWithoutStateParams {
86
- state;
87
- }
88
- __decorate([
89
- classTransformer.Expose(),
90
- classValidator.IsString(),
91
- classValidator.Matches(util.US_STATE_CODE_STRING_REGEX),
92
- classValidator.MinLength(ADDRESS_STATE_CODE_MAX_LENGTH),
93
- classValidator.MaxLength(ADDRESS_STATE_CODE_MAX_LENGTH),
94
- __metadata("design:type", String)
95
- ], UnitedStatesAddressWithStateCodeParams.prototype, "state", void 0);
96
- /**
97
- * UnitedStatesAddress that enforces a State for the state value.
98
- */
99
- class UnitedStatesAddressWithStateStringParams extends AbstractUnitedStatesAddressWithoutStateParams {
100
- state;
101
- }
102
- __decorate([
103
- classTransformer.Expose(),
104
- classValidator.IsString(),
105
- classValidator.IsNotEmpty(),
106
- classValidator.MaxLength(ADDRESS_STATE_MAX_LENGTH),
107
- __metadata("design:type", String)
108
- ], UnitedStatesAddressWithStateStringParams.prototype, "state", void 0);
31
+ /**
32
+ * Base ArkType schema for United States address fields without the state.
33
+ */
34
+ const baseUnitedStatesAddressType = arktype.type({
35
+ line1: `0 < string <= ${ADDRESS_LINE_MAX_LENGTH}`,
36
+ 'line2?': `string <= ${ADDRESS_LINE_MAX_LENGTH}`,
37
+ city: `0 < string <= ${ADDRESS_CITY_MAX_LENGTH}`,
38
+ zip: [/^\d{5}(-\d{4})?$/, '&', `string <= ${ADDRESS_ZIP_MAX_LENGTH}`]
39
+ });
40
+ /**
41
+ * ArkType schema for a United States address with a two-letter state code (e.g., "TX").
42
+ */
43
+ const unitedStatesAddressWithStateCodeType = baseUnitedStatesAddressType.merge({
44
+ state: [util.US_STATE_CODE_STRING_REGEX, '&', `${ADDRESS_STATE_CODE_MAX_LENGTH} <= string <= ${ADDRESS_STATE_CODE_MAX_LENGTH}`]
45
+ });
46
+ /**
47
+ * ArkType schema for a United States address with a full state name (e.g., "Texas").
48
+ */
49
+ const unitedStatesAddressWithStateStringType = baseUnitedStatesAddressType.merge({
50
+ state: `0 < string <= ${ADDRESS_STATE_MAX_LENGTH}`
51
+ });
109
52
 
53
+ /**
54
+ * Fallback link type used when the actual type is not known.
55
+ */
110
56
  const UNKNOWN_WEBSITE_LINK_TYPE = 'u';
111
57
  /**
112
- * Max length of WebsiteLink's data type.
58
+ * Maximum character length for a {@link WebsiteLinkType} string.
113
59
  */
114
60
  const WEBSITE_LINK_TYPE_MAX_LENGTH = 32;
115
61
  /**
116
- * Alpha-numeric type between 1 and 32 characters only allowed.
62
+ * Regex pattern that validates a {@link WebsiteLinkType} as 1-32 alphanumeric characters.
117
63
  */
118
64
  const WEBSITE_LINK_TYPE_REGEX = /^[a-zA-Z0-9]{1,32}$/;
65
+ /**
66
+ * Checks whether the given string is a valid {@link WebsiteLinkType}.
67
+ *
68
+ * @param input - the string to validate
69
+ * @returns true if it matches the alphanumeric 1-32 character pattern
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * isValidWebsiteLinkType('fb'); // true
74
+ * isValidWebsiteLinkType(''); // false
75
+ * isValidWebsiteLinkType('a-b'); // false (hyphen not allowed)
76
+ * ```
77
+ */
119
78
  function isValidWebsiteLinkType(input) {
120
79
  return WEBSITE_LINK_TYPE_REGEX.test(input);
121
80
  }
122
81
  /**
123
- * Default max length of WebsiteLink's data string.
82
+ * Maximum character length for the encoded data string in a {@link WebsiteLink}.
124
83
  */
125
84
  const WEBSITE_LINK_ENCODED_DATA_MAX_LENGTH = 1000;
126
- class WebsiteLink {
127
- t;
128
- d;
129
- constructor(template) {
130
- if (template != null) {
131
- this.t = template.t;
132
- this.d = template.d;
133
- }
134
- }
135
- }
136
- __decorate([
137
- classTransformer.Expose(),
138
- classValidator.IsString(),
139
- classValidator.IsNotEmpty(),
140
- classValidator.Matches(WEBSITE_LINK_TYPE_REGEX),
141
- classValidator.MaxLength(WEBSITE_LINK_TYPE_MAX_LENGTH),
142
- __metadata("design:type", String)
143
- ], WebsiteLink.prototype, "t", void 0);
144
- __decorate([
145
- classTransformer.Expose(),
146
- classValidator.IsString(),
147
- classValidator.IsNotEmpty(),
148
- classValidator.MaxLength(WEBSITE_LINK_ENCODED_DATA_MAX_LENGTH),
149
- __metadata("design:type", String)
150
- ], WebsiteLink.prototype, "d", void 0);
85
+ /**
86
+ * ArkType schema for a {@link WebsiteLink}.
87
+ */
88
+ const websiteLinkType = arktype.type({
89
+ t: [WEBSITE_LINK_TYPE_REGEX, '&', `0 < string <= ${WEBSITE_LINK_TYPE_MAX_LENGTH}`],
90
+ d: `0 < string <= ${WEBSITE_LINK_ENCODED_DATA_MAX_LENGTH}`
91
+ });
151
92
 
152
93
  /**
153
- * Max length of WebsiteLink's data type.
94
+ * Maximum character length for a {@link WebsiteFileLinkType}. Matches {@link WEBSITE_LINK_TYPE_MAX_LENGTH}.
154
95
  */
155
96
  const WEBSITE_FILE_LINK_TYPE_MAX_LENGTH = WEBSITE_LINK_TYPE_MAX_LENGTH;
156
97
  /**
157
- * Has the same regex as WebsiteLinkType
98
+ * Validation regex for {@link WebsiteFileLinkType}. Matches {@link WEBSITE_LINK_TYPE_REGEX}.
158
99
  */
159
100
  const WEBSITE_FILE_LINK_TYPE_REGEX = WEBSITE_LINK_TYPE_REGEX;
160
101
  /**
161
- * Max length of WebsiteLink's data type.
102
+ * Maximum character length for a {@link WebsiteFileLinkMimeType}.
162
103
  */
163
104
  const WEBSITE_FILE_LINK_MIME_TYPE_MAX_LENGTH = 128;
164
105
  /**
165
- * Default max length of WebsiteLink's data string.
106
+ * Regex pattern that validates a MIME type string (e.g., "text/plain", "application/vnd.api+json").
166
107
  */
167
108
  const WEBSITE_FILE_LINK_MIME_TYPE_REGEX = /^\w+\/[-+.\w]+$/;
168
109
  /**
169
- * Max length of WebsiteLink's data type.
110
+ * Maximum character length for a {@link WebsiteFileLinkName}.
170
111
  */
171
112
  const WEBSITE_FILE_LINK_NAME_MAX_LENGTH = 128;
172
113
  /**
173
- * Max length of WebsiteLink's data type.
114
+ * Maximum character length for {@link WebsiteFileLinkData}, derived from the total encoded data budget
115
+ * minus the separator characters, type, MIME type, and name fields.
174
116
  */
175
117
  const WEBSITE_FILE_LINK_DATA_MAX_LENGTH = WEBSITE_LINK_ENCODED_DATA_MAX_LENGTH - 3 - WEBSITE_FILE_LINK_TYPE_MAX_LENGTH - WEBSITE_FILE_LINK_MIME_TYPE_MAX_LENGTH - WEBSITE_FILE_LINK_NAME_MAX_LENGTH;
118
+ /**
119
+ * Regex pattern for file link data — disallows the pipe character since it is used as the encoding separator.
120
+ */
176
121
  const WEBSITE_FILE_LINK_DATA_REGEX = /^[^|]+$/;
177
- class WebsiteFileLink {
178
- type;
179
- mime;
180
- name;
181
- data;
182
- constructor(template) {
183
- if (template != null) {
184
- this.type = template.type;
185
- this.mime = template.mime;
186
- this.name = template.name;
187
- this.data = template.data;
188
- }
189
- }
190
- }
191
- __decorate([
192
- classTransformer.Expose(),
193
- classValidator.IsOptional(),
194
- classValidator.IsString(),
195
- classValidator.Matches(WEBSITE_FILE_LINK_TYPE_REGEX),
196
- classValidator.MaxLength(WEBSITE_LINK_TYPE_MAX_LENGTH),
197
- __metadata("design:type", String)
198
- ], WebsiteFileLink.prototype, "type", void 0);
199
- __decorate([
200
- classTransformer.Expose(),
201
- classValidator.IsOptional(),
202
- classValidator.IsString(),
203
- classValidator.Matches(WEBSITE_FILE_LINK_MIME_TYPE_REGEX),
204
- classValidator.MaxLength(WEBSITE_FILE_LINK_MIME_TYPE_MAX_LENGTH),
205
- __metadata("design:type", String)
206
- ], WebsiteFileLink.prototype, "mime", void 0);
207
- __decorate([
208
- classTransformer.Expose(),
209
- classValidator.IsOptional(),
210
- classValidator.IsString(),
211
- classValidator.MaxLength(WEBSITE_FILE_LINK_NAME_MAX_LENGTH),
212
- __metadata("design:type", String)
213
- ], WebsiteFileLink.prototype, "name", void 0);
214
- __decorate([
215
- classValidator.IsString(),
216
- classValidator.IsNotEmpty(),
217
- classValidator.Matches(WEBSITE_FILE_LINK_DATA_REGEX),
218
- classValidator.MaxLength(WEBSITE_FILE_LINK_DATA_MAX_LENGTH),
219
- __metadata("design:type", String)
220
- ], WebsiteFileLink.prototype, "data", void 0);
122
+ /**
123
+ * ArkType schema for a {@link WebsiteFileLink}.
124
+ */
125
+ const websiteFileLinkType = arktype.type({
126
+ 'type?': [WEBSITE_FILE_LINK_TYPE_REGEX, '&', `string <= ${WEBSITE_LINK_TYPE_MAX_LENGTH}`],
127
+ 'mime?': [WEBSITE_FILE_LINK_MIME_TYPE_REGEX, '&', `string <= ${WEBSITE_FILE_LINK_MIME_TYPE_MAX_LENGTH}`],
128
+ 'name?': `string <= ${WEBSITE_FILE_LINK_NAME_MAX_LENGTH}`,
129
+ data: [WEBSITE_FILE_LINK_DATA_REGEX, '&', `0 < string <= ${WEBSITE_FILE_LINK_DATA_MAX_LENGTH}`]
130
+ });
131
+ /**
132
+ * The {@link WebsiteLinkType} code used to identify a {@link WebsiteLink} as a file link.
133
+ */
221
134
  const WEBSITE_FILE_LINK_WEBSITE_LINK_TYPE = 'f';
135
+ /**
136
+ * Converts a {@link WebsiteFileLink} to a {@link WebsiteLink} by encoding its fields into the data string.
137
+ *
138
+ * @param input - the file link to convert
139
+ * @returns a WebsiteLink with type "f" and pipe-encoded data
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * const fileLink: WebsiteFileLink = { type: 't', mime: 'text/plain', data: 'https://example.com/file.txt', name: 'file' };
144
+ * const link = websiteFileLinkToWebsiteLink(fileLink);
145
+ * // link.t === 'f'
146
+ * ```
147
+ */
222
148
  function websiteFileLinkToWebsiteLink(input) {
223
149
  return {
224
150
  t: WEBSITE_FILE_LINK_WEBSITE_LINK_TYPE,
225
151
  d: encodeWebsiteFileLinkToWebsiteLinkEncodedData(input)
226
152
  };
227
153
  }
154
+ /**
155
+ * Converts a {@link WebsiteLink} back to a {@link WebsiteFileLink} by decoding the pipe-separated data string.
156
+ *
157
+ * @param input - a WebsiteLink whose data field contains an encoded file link
158
+ * @returns the decoded file link with type, MIME, name, and data fields
159
+ *
160
+ * @example
161
+ * ```typescript
162
+ * const link: WebsiteLink = { t: 'f', d: 't|text/plain|https://example.com/file.txt|file' };
163
+ * const fileLink = websiteLinkToWebsiteLinkFile(link);
164
+ * // fileLink.data === 'https://example.com/file.txt'
165
+ * ```
166
+ */
228
167
  function websiteLinkToWebsiteLinkFile(input) {
229
168
  const encodedData = input.d;
230
169
  return decodeWebsiteLinkEncodedDataToWebsiteFileLink(encodedData);
231
170
  }
171
+ /**
172
+ * Separator character used when encoding/decoding file link fields into a single string.
173
+ */
232
174
  const WEBSITE_FILE_LINK_ENCODE_SEPARATOR = '|';
175
+ /**
176
+ * Encodes a {@link WebsiteFileLink} into a pipe-separated string suitable for storage in a {@link WebsiteLink}'s data field.
177
+ *
178
+ * Fields are encoded in order: type, MIME, data, name. Empty/undefined fields become empty strings.
179
+ *
180
+ * @param input - the file link to encode
181
+ * @returns a pipe-separated encoded string
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * const encoded = encodeWebsiteFileLinkToWebsiteLinkEncodedData({
186
+ * type: 't',
187
+ * mime: 'test/test',
188
+ * name: 'test-name',
189
+ * data: 'https://example.com/'
190
+ * });
191
+ * // encoded === 't|test/test|https://example.com/|test-name'
192
+ * ```
193
+ */
233
194
  function encodeWebsiteFileLinkToWebsiteLinkEncodedData(input) {
234
195
  const encoded = [input.type, input.mime, input.data, input.name].map((x) => x || '').join(WEBSITE_FILE_LINK_ENCODE_SEPARATOR);
235
196
  return encoded;
236
197
  }
198
+ /**
199
+ * Decodes a pipe-separated encoded string back into a {@link WebsiteFileLink}.
200
+ *
201
+ * Empty fields in the encoded string are omitted from the result (falsy values are filtered out).
202
+ *
203
+ * @param input - the pipe-separated encoded string
204
+ * @returns the decoded file link
205
+ *
206
+ * @example
207
+ * ```typescript
208
+ * const fileLink = decodeWebsiteLinkEncodedDataToWebsiteFileLink('t|test/test|https://example.com/|test-name');
209
+ * // fileLink.type === 't'
210
+ * // fileLink.mime === 'test/test'
211
+ * // fileLink.data === 'https://example.com/'
212
+ * // fileLink.name === 'test-name'
213
+ * ```
214
+ */
237
215
  function decodeWebsiteLinkEncodedDataToWebsiteFileLink(input) {
238
216
  const [type, mime, data, name] = util.splitJoinRemainder(input, WEBSITE_FILE_LINK_ENCODE_SEPARATOR, 4);
239
217
  return util.filterFalsyAndEmptyValues({
@@ -245,16 +223,40 @@ function decodeWebsiteLinkEncodedDataToWebsiteFileLink(input) {
245
223
  }
246
224
 
247
225
  /**
248
- * Used for isolating a username from a website that has the username as the base url.
226
+ * Isolates a username from a URL where the username is the first path segment after the domain.
227
+ *
228
+ * Strips trailing slashes and query parameters. Used by social platforms like Facebook, Instagram, and Twitter
229
+ * where the profile URL pattern is `https://domain.com/{username}`.
249
230
  *
250
- * Example:
251
- * - https://facebook.com/facebook
231
+ * @example
232
+ * ```typescript
233
+ * WEBSITE_LINK_ISOLATE_BASE_URL_PROFILE_ID('https://www.facebook.com/myuser');
234
+ * // returns 'myuser'
235
+ * ```
252
236
  */
253
237
  const WEBSITE_LINK_ISOLATE_BASE_URL_PROFILE_ID = util.isolateWebsitePathFunction({
254
238
  isolatePathComponents: 0,
255
239
  removeTrailingSlash: true,
256
240
  removeQueryParameters: true
257
241
  });
242
+ /**
243
+ * Extracts a username from either a raw username string or a full profile URL where the username is the first path segment.
244
+ *
245
+ * Optionally prepends a prefix (e.g., "@" for TikTok, "$" for Cash App).
246
+ *
247
+ * @param input - a username or full profile URL
248
+ * @param prefix - optional prefix to prepend to the extracted username
249
+ * @returns the isolated username, optionally prefixed
250
+ *
251
+ * @example
252
+ * ```typescript
253
+ * usernameFromUsernameOrWebsiteWithBaseUrlUsername('https://facebook.com/myuser');
254
+ * // returns 'myuser'
255
+ *
256
+ * usernameFromUsernameOrWebsiteWithBaseUrlUsername('myuser', '@');
257
+ * // returns '@myuser'
258
+ * ```
259
+ */
258
260
  function usernameFromUsernameOrWebsiteWithBaseUrlUsername(input, prefix) {
259
261
  const username = util.toRelativeSlashPathStartType(WEBSITE_LINK_ISOLATE_BASE_URL_PROFILE_ID(usernameOrWebsiteUrlToWebsiteUrl(input)));
260
262
  if (prefix) {
@@ -264,14 +266,46 @@ function usernameFromUsernameOrWebsiteWithBaseUrlUsername(input, prefix) {
264
266
  return username;
265
267
  }
266
268
  }
269
+ /**
270
+ * Extracts a username from either a raw username string or a full profile URL using a custom path isolation function.
271
+ *
272
+ * Used for platforms with non-standard URL patterns (e.g., Snapchat's `/add/{username}`, YouTube's `/c/{username}`).
273
+ *
274
+ * @param input - a username or full profile URL
275
+ * @param isolateFn - custom function that extracts the relevant path segment from the URL
276
+ * @returns the isolated username
277
+ */
267
278
  function usernameFromUsernameOrWebsiteWithOneOffBaseUrlUsername(input, isolateFn) {
268
279
  return util.toRelativeSlashPathStartType(isolateFn(usernameOrWebsiteUrlToWebsiteUrl(input)));
269
280
  }
281
+ /**
282
+ * Normalizes a string that may be either a plain username or a full website URL into a consistent URL format.
283
+ *
284
+ * If the input has a website domain, it is returned as-is. Otherwise, it is treated as a path and converted to an absolute slash path.
285
+ *
286
+ * @param input - a username or website URL
287
+ * @returns a normalized website URL
288
+ */
270
289
  function usernameOrWebsiteUrlToWebsiteUrl(input) {
271
290
  return util.hasWebsiteDomain(input) ? input : util.toAbsoluteSlashPathStartType(util.removeHttpFromUrl(input));
272
291
  }
273
292
  // MARK: Website
293
+ /**
294
+ * {@link WebsiteLinkType} code for generic website URLs.
295
+ */
274
296
  const WEBSITE_URL_WEBSITE_LINK_TYPE = 'w';
297
+ /**
298
+ * Converts a generic website URL into a {@link WebsiteLink}, stripping the HTTP/HTTPS protocol.
299
+ *
300
+ * @param input - the full website URL
301
+ * @returns a WebsiteLink with the protocol removed from the data
302
+ *
303
+ * @example
304
+ * ```typescript
305
+ * const link = websiteUrlToWebsiteLink('https://example.com/page');
306
+ * // link.t === 'w', link.d === 'example.com/page'
307
+ * ```
308
+ */
275
309
  function websiteUrlToWebsiteLink(input) {
276
310
  return {
277
311
  t: WEBSITE_URL_WEBSITE_LINK_TYPE,
@@ -279,7 +313,16 @@ function websiteUrlToWebsiteLink(input) {
279
313
  };
280
314
  }
281
315
  // MARK: Email
316
+ /**
317
+ * {@link WebsiteLinkType} code for email addresses.
318
+ */
282
319
  const EMAIL_URL_WEBSITE_LINK_TYPE = 'e';
320
+ /**
321
+ * Converts an email address into a {@link WebsiteLink}.
322
+ *
323
+ * @param input - the email address
324
+ * @returns a WebsiteLink storing the email as data
325
+ */
283
326
  function emailAddressToWebsiteLink(input) {
284
327
  return {
285
328
  t: EMAIL_URL_WEBSITE_LINK_TYPE,
@@ -287,7 +330,16 @@ function emailAddressToWebsiteLink(input) {
287
330
  };
288
331
  }
289
332
  // MARK: Phone
333
+ /**
334
+ * {@link WebsiteLinkType} code for phone numbers.
335
+ */
290
336
  const PHONE_URL_WEBSITE_LINK_TYPE = 'p';
337
+ /**
338
+ * Converts an E.164 phone number into a {@link WebsiteLink}.
339
+ *
340
+ * @param input - the phone number in E.164 format
341
+ * @returns a WebsiteLink storing the phone number as data
342
+ */
291
343
  function phoneNumberToWebsiteLink(input) {
292
344
  return {
293
345
  t: PHONE_URL_WEBSITE_LINK_TYPE,
@@ -295,148 +347,325 @@ function phoneNumberToWebsiteLink(input) {
295
347
  };
296
348
  }
297
349
  // MARK: Facebook
350
+ /** Base URL for Facebook profiles. */
298
351
  const FACEBOOK_BASE_URL = `https://www.facebook.com`;
352
+ /** {@link WebsiteLinkType} code for Facebook. */
299
353
  const FACEBOOK_WEBSITE_LINK_TYPE = 'fb';
354
+ /**
355
+ * Converts a Facebook profile ID or URL into a {@link WebsiteLink}.
356
+ *
357
+ * Accepts either a raw username or a full Facebook profile URL.
358
+ *
359
+ * @param input - a Facebook profile ID or full profile URL
360
+ * @returns a WebsiteLink with the isolated username as data
361
+ *
362
+ * @example
363
+ * ```typescript
364
+ * facebookProfileUrlToWebsiteLink('https://www.facebook.com/myuser');
365
+ * // { t: 'fb', d: 'myuser' }
366
+ *
367
+ * facebookProfileUrlToWebsiteLink('myuser');
368
+ * // { t: 'fb', d: 'myuser' }
369
+ * ```
370
+ */
300
371
  function facebookProfileUrlToWebsiteLink(input) {
301
372
  return {
302
373
  t: FACEBOOK_WEBSITE_LINK_TYPE,
303
374
  d: usernameFromUsernameOrWebsiteWithBaseUrlUsername(input)
304
375
  };
305
376
  }
377
+ /**
378
+ * Constructs a full Facebook profile URL from a profile ID.
379
+ *
380
+ * @param profileId - the Facebook profile ID or username
381
+ * @returns the full profile URL
382
+ */
306
383
  function facebookProfileUrl(profileId) {
307
384
  return `${FACEBOOK_BASE_URL}/${profileId}`;
308
385
  }
309
386
  // MARK: Instagram
387
+ /** Base URL for Instagram profiles. */
310
388
  const INSTAGRAM_BASE_URL = `https://www.instagram.com`;
389
+ /** {@link WebsiteLinkType} code for Instagram. */
311
390
  const INSTAGRAM_WEBSITE_LINK_TYPE = 'ig';
391
+ /**
392
+ * Converts an Instagram profile ID or URL into a {@link WebsiteLink}.
393
+ *
394
+ * @param input - an Instagram username or full profile URL
395
+ * @returns a WebsiteLink with the isolated username as data
396
+ */
312
397
  function instagramProfileUrlToWebsiteLink(input) {
313
398
  return {
314
399
  t: INSTAGRAM_WEBSITE_LINK_TYPE,
315
400
  d: usernameFromUsernameOrWebsiteWithBaseUrlUsername(input)
316
401
  };
317
402
  }
403
+ /**
404
+ * Constructs a full Instagram profile URL from a profile ID.
405
+ *
406
+ * @param profileId - the Instagram username
407
+ * @returns the full profile URL
408
+ */
318
409
  function instagramProfileUrl(profileId) {
319
410
  return `${INSTAGRAM_BASE_URL}/${profileId}`;
320
411
  }
321
412
  // MARK: Twitter
413
+ /** Base URL for Twitter profiles. */
322
414
  const TWITTER_BASE_URL = `https://www.twitter.com`;
415
+ /** {@link WebsiteLinkType} code for Twitter. */
323
416
  const TWITTER_WEBSITE_LINK_TYPE = 'tw';
417
+ /**
418
+ * Converts a Twitter profile ID or URL into a {@link WebsiteLink}.
419
+ *
420
+ * @param input - a Twitter username or full profile URL
421
+ * @returns a WebsiteLink with the isolated username as data
422
+ */
324
423
  function twitterProfileUrlToWebsiteLink(input) {
325
424
  return {
326
425
  t: TWITTER_WEBSITE_LINK_TYPE,
327
426
  d: usernameFromUsernameOrWebsiteWithBaseUrlUsername(input)
328
427
  };
329
428
  }
429
+ /**
430
+ * Constructs a full Twitter profile URL from a profile ID.
431
+ *
432
+ * @param profileId - the Twitter username
433
+ * @returns the full profile URL
434
+ */
330
435
  function twitterProfileUrl(profileId) {
331
436
  return `${TWITTER_BASE_URL}/${profileId}`;
332
437
  }
333
438
  // MARK: Tiktok
439
+ /** Base URL for TikTok profiles. */
334
440
  const TIKTOK_BASE_URL = `https://tiktok.com`;
441
+ /** TikTok usernames are prefixed with "@" in URLs and stored data. */
335
442
  const TIKTOK_USERNAME_PREFIX = '@';
443
+ /** {@link WebsiteLinkType} code for TikTok. */
336
444
  const TIKTOK_WEBSITE_LINK_TYPE = 'tt';
445
+ /**
446
+ * Converts a TikTok profile ID or URL into a {@link WebsiteLink}.
447
+ *
448
+ * Automatically prepends the "@" prefix if not already present.
449
+ *
450
+ * @param input - a TikTok username (with or without "@") or full profile URL
451
+ * @returns a WebsiteLink with the "@"-prefixed username as data
452
+ */
337
453
  function tiktokProfileUrlToWebsiteLink(input) {
338
454
  return {
339
455
  t: TIKTOK_WEBSITE_LINK_TYPE,
340
456
  d: usernameFromUsernameOrWebsiteWithBaseUrlUsername(input, TIKTOK_USERNAME_PREFIX)
341
457
  };
342
458
  }
459
+ /**
460
+ * Constructs a full TikTok profile URL from a profile ID.
461
+ *
462
+ * @param profileId - the TikTok username (without "@" prefix)
463
+ * @returns the full profile URL with "@" prefix
464
+ */
343
465
  function tiktokProfileUrl(profileId) {
344
466
  return `${TIKTOK_BASE_URL}/@${profileId}`;
345
467
  }
346
468
  // MARK: Snapchat
469
+ /** Base URL for Snapchat profiles. */
347
470
  const SNAPCHAT_BASE_URL = `https://snapchat.com`;
471
+ /** {@link WebsiteLinkType} code for Snapchat. */
348
472
  const SNAPCHAT_WEBSITE_LINK_TYPE = 'sc';
473
+ /**
474
+ * Isolates a Snapchat username from a URL, ignoring the `/add/` base path segment.
475
+ */
349
476
  const SNAPCHAT_WEBSITE_LINK_ISOLATE_PROFILE_ID = util.isolateWebsitePathFunction({
350
477
  ignoredBasePath: 'add',
351
478
  isolatePathComponents: 0,
352
479
  removeTrailingSlash: true,
353
480
  removeQueryParameters: true
354
481
  });
482
+ /**
483
+ * Converts a Snapchat profile ID or URL into a {@link WebsiteLink}.
484
+ *
485
+ * Handles Snapchat's `/add/{username}` URL pattern.
486
+ *
487
+ * @param input - a Snapchat username or full profile URL
488
+ * @returns a WebsiteLink with the isolated username as data
489
+ */
355
490
  function snapchatProfileUrlToWebsiteLink(input) {
356
491
  return {
357
492
  t: SNAPCHAT_WEBSITE_LINK_TYPE,
358
493
  d: usernameFromUsernameOrWebsiteWithOneOffBaseUrlUsername(input, SNAPCHAT_WEBSITE_LINK_ISOLATE_PROFILE_ID)
359
494
  };
360
495
  }
496
+ /**
497
+ * Constructs a full Snapchat profile URL from a profile ID.
498
+ *
499
+ * @param profileId - the Snapchat username
500
+ * @returns the full profile URL with `/add/` path
501
+ */
361
502
  function snapchatProfileUrl(profileId) {
362
503
  return `${SNAPCHAT_BASE_URL}/add/${profileId}`;
363
504
  }
364
505
  // MARK: YouTube
506
+ /** Base URL for YouTube channels. */
365
507
  const YOUTUBE_BASE_URL = `https://youtube.com`;
508
+ /** {@link WebsiteLinkType} code for YouTube. */
366
509
  const YOUTUBE_WEBSITE_LINK_TYPE = 'yt';
510
+ /**
511
+ * Isolates a YouTube channel name from a URL, ignoring the `/c/` base path segment.
512
+ */
367
513
  const YOUTUBE_WEBSITE_LINK_ISOLATE_PROFILE_ID = util.isolateWebsitePathFunction({
368
514
  ignoredBasePath: 'c',
369
515
  isolatePathComponents: 0,
370
516
  removeTrailingSlash: true,
371
517
  removeQueryParameters: true
372
518
  });
519
+ /**
520
+ * Converts a YouTube channel ID or URL into a {@link WebsiteLink}.
521
+ *
522
+ * Handles YouTube's `/c/{channel}` URL pattern.
523
+ *
524
+ * @param input - a YouTube channel name or full channel URL
525
+ * @returns a WebsiteLink with the isolated channel name as data
526
+ */
373
527
  function youtubeProfileUrlToWebsiteLink(input) {
374
528
  return {
375
529
  t: YOUTUBE_WEBSITE_LINK_TYPE,
376
530
  d: usernameFromUsernameOrWebsiteWithOneOffBaseUrlUsername(input, YOUTUBE_WEBSITE_LINK_ISOLATE_PROFILE_ID)
377
531
  };
378
532
  }
533
+ /**
534
+ * Constructs a full YouTube channel URL from a profile ID.
535
+ *
536
+ * @param profileId - the YouTube channel name
537
+ * @returns the full channel URL with `/c/` path
538
+ */
379
539
  function youtubeProfileUrl(profileId) {
380
540
  return `${YOUTUBE_BASE_URL}/c/${profileId}`;
381
541
  }
382
542
  // MARK: PayPal
543
+ /** Base URL for PayPal.me profiles. */
383
544
  const PAYPAL_BASE_URL = `https://paypal.me`;
545
+ /** {@link WebsiteLinkType} code for PayPal. */
384
546
  const PAYPAL_WEBSITE_LINK_TYPE = 'pp';
547
+ /**
548
+ * Converts a PayPal profile ID or URL into a {@link WebsiteLink}.
549
+ *
550
+ * @param input - a PayPal username or full PayPal.me URL
551
+ * @returns a WebsiteLink with the isolated username as data
552
+ */
385
553
  function paypalProfileUrlToWebsiteLink(input) {
386
554
  return {
387
555
  t: PAYPAL_WEBSITE_LINK_TYPE,
388
556
  d: usernameFromUsernameOrWebsiteWithBaseUrlUsername(input)
389
557
  };
390
558
  }
559
+ /**
560
+ * Constructs a full PayPal.me profile URL from a profile ID.
561
+ *
562
+ * @param profileId - the PayPal username
563
+ * @returns the full PayPal.me URL
564
+ */
391
565
  function paypalProfileUrl(profileId) {
392
566
  return `${PAYPAL_BASE_URL}/${profileId}`;
393
567
  }
394
568
  // MARK: Cashapp
569
+ /** Base URL for Cash App profiles. */
395
570
  const CASHAPP_BASE_URL = `https://cash.app`;
571
+ /** Cash App usernames are prefixed with "$" (cashtag). */
396
572
  const CASHAPP_USERNAME_PREFIX = '$';
573
+ /** {@link WebsiteLinkType} code for Cash App. */
397
574
  const CASHAPP_WEBSITE_LINK_TYPE = 'ca';
575
+ /**
576
+ * Converts a Cash App profile ID or URL into a {@link WebsiteLink}.
577
+ *
578
+ * Automatically prepends the "$" prefix if not already present.
579
+ *
580
+ * @param input - a Cash App username (with or without "$") or full profile URL
581
+ * @returns a WebsiteLink with the "$"-prefixed username as data
582
+ */
398
583
  function cashappProfileUrlToWebsiteLink(input) {
399
584
  return {
400
585
  t: CASHAPP_WEBSITE_LINK_TYPE,
401
586
  d: usernameFromUsernameOrWebsiteWithBaseUrlUsername(input, CASHAPP_USERNAME_PREFIX)
402
587
  };
403
588
  }
589
+ /**
590
+ * Constructs a full Cash App profile URL from a profile ID.
591
+ *
592
+ * @param profileId - the Cash App username (without "$" prefix)
593
+ * @returns the full Cash App URL with "$" prefix
594
+ */
404
595
  function cashappProfileUrl(profileId) {
405
596
  return `${CASHAPP_BASE_URL}/$${profileId}`;
406
597
  }
407
598
  // MARK: Venmo
599
+ /** Base URL for Venmo profiles. */
408
600
  const VENMO_BASE_URL = `https://account.venmo.com`;
601
+ /** {@link WebsiteLinkType} code for Venmo. */
409
602
  const VENMO_WEBSITE_LINK_TYPE = 'vn';
603
+ /**
604
+ * Isolates a Venmo username from a URL, ignoring the `/u/` base path segment.
605
+ */
410
606
  const VENMO_WEBSITE_LINK_ISOLATE_PROFILE_ID = util.isolateWebsitePathFunction({
411
607
  ignoredBasePath: 'u',
412
608
  isolatePathComponents: 0,
413
609
  removeTrailingSlash: true,
414
610
  removeQueryParameters: true
415
611
  });
612
+ /**
613
+ * Converts a Venmo profile ID or URL into a {@link WebsiteLink}.
614
+ *
615
+ * Handles Venmo's `/u/{username}` URL pattern.
616
+ *
617
+ * @param input - a Venmo username or full profile URL
618
+ * @returns a WebsiteLink with the isolated username as data
619
+ */
416
620
  function venmoProfileUrlToWebsiteLink(input) {
417
621
  return {
418
622
  t: VENMO_WEBSITE_LINK_TYPE,
419
623
  d: usernameFromUsernameOrWebsiteWithOneOffBaseUrlUsername(input, VENMO_WEBSITE_LINK_ISOLATE_PROFILE_ID)
420
624
  };
421
625
  }
626
+ /**
627
+ * Constructs a full Venmo profile URL from a profile ID.
628
+ *
629
+ * @param profileId - the Venmo username
630
+ * @returns the full profile URL with `/u/` path
631
+ */
422
632
  function venmoProfileUrl(profileId) {
423
633
  return `${VENMO_BASE_URL}/u/${profileId}`;
424
634
  }
425
635
  // MARK: Spotify
636
+ /** Base URL for Spotify profiles. */
426
637
  const SPOTIFY_BASE_URL = `https://open.spotify.com/`;
638
+ /** {@link WebsiteLinkType} code for Spotify. */
427
639
  const SPOTIFY_WEBSITE_LINK_TYPE = 'sp';
640
+ /**
641
+ * Isolates a Spotify username from a URL, ignoring the `/user/` base path segment.
642
+ */
428
643
  const SPOTIFY_WEBSITE_LINK_ISOLATE_PROFILE_ID = util.isolateWebsitePathFunction({
429
644
  ignoredBasePath: 'user',
430
645
  isolatePathComponents: 0,
431
646
  removeTrailingSlash: true,
432
647
  removeQueryParameters: true
433
648
  });
649
+ /**
650
+ * Converts a Spotify profile ID or URL into a {@link WebsiteLink}.
651
+ *
652
+ * Handles Spotify's `/user/{username}` URL pattern.
653
+ *
654
+ * @param input - a Spotify username or full profile URL
655
+ * @returns a WebsiteLink with the isolated username as data
656
+ */
434
657
  function spotifyProfileUrlToWebsiteLink(input) {
435
658
  return {
436
659
  t: SPOTIFY_WEBSITE_LINK_TYPE,
437
660
  d: usernameFromUsernameOrWebsiteWithOneOffBaseUrlUsername(input, SPOTIFY_WEBSITE_LINK_ISOLATE_PROFILE_ID)
438
661
  };
439
662
  }
663
+ /**
664
+ * Constructs a full Spotify profile URL from a profile ID.
665
+ *
666
+ * @param profileId - the Spotify username
667
+ * @returns the full profile URL with `/user/` path
668
+ */
440
669
  function spotifyProfileUrl(profileId) {
441
670
  return `${SPOTIFY_BASE_URL}/user/${profileId}`;
442
671
  }
@@ -445,10 +674,17 @@ const GRANTED_SYS_ADMIN_ROLE_KEY = 'sysadmin';
445
674
  const GRANTED_OWNER_ROLE_KEY = 'owner';
446
675
  const GRANTED_ADMIN_ROLE_KEY = 'admin';
447
676
  /**
448
- * Returns true if the input role is a GrantedAdminRole or a GrantedOwnerRole.
677
+ * Checks whether the given role represents an admin-level permission (either "admin" or "owner").
449
678
  *
450
- * @param role
451
- * @returns
679
+ * @param role - the role to check
680
+ * @returns true if the role is an admin or owner role
681
+ *
682
+ * @example
683
+ * ```typescript
684
+ * isGrantedAdminLevelRole('admin'); // true
685
+ * isGrantedAdminLevelRole('owner'); // true
686
+ * isGrantedAdminLevelRole('read'); // false
687
+ * ```
452
688
  */
453
689
  function isGrantedAdminLevelRole(role) {
454
690
  return role === GRANTED_ADMIN_ROLE_KEY || role === GRANTED_OWNER_ROLE_KEY;
@@ -458,27 +694,75 @@ const GRANTED_UPDATE_ROLE_KEY = 'update';
458
694
  const GRANTED_DELETE_ROLE_KEY = 'delete';
459
695
  const FULL_ACCESS_ROLE_KEY = '__FULL__';
460
696
  const NO_ACCESS_ROLE_KEY = '__EMPTY__';
697
+ /**
698
+ * Creates a {@link GrantedRoleMap} that explicitly denies all access.
699
+ *
700
+ * @returns a role map with only the no-access marker set
701
+ *
702
+ * @example
703
+ * ```typescript
704
+ * const map = noAccessRoleMap();
705
+ * isNoAccessRoleMap(map); // true
706
+ * ```
707
+ */
461
708
  function noAccessRoleMap() {
462
709
  return {
463
710
  [NO_ACCESS_ROLE_KEY]: true
464
711
  };
465
712
  }
713
+ /**
714
+ * Type guard that checks whether a role map is a no-access map.
715
+ *
716
+ * @param input - the role map to check
717
+ * @returns true if the map has the no-access marker
718
+ */
466
719
  function isNoAccessRoleMap(input) {
467
720
  return input[NO_ACCESS_ROLE_KEY] === true;
468
721
  }
722
+ /**
723
+ * Creates a {@link GrantedRoleMap} that grants full access to all roles.
724
+ *
725
+ * @returns a role map with the full-access marker set
726
+ *
727
+ * @example
728
+ * ```typescript
729
+ * const map = fullAccessRoleMap();
730
+ * isFullAccessRoleMap(map); // true
731
+ * ```
732
+ */
469
733
  function fullAccessRoleMap() {
470
734
  return {
471
735
  [FULL_ACCESS_ROLE_KEY]: true
472
736
  };
473
737
  }
738
+ /**
739
+ * Type guard that checks whether a role map is a full-access map.
740
+ *
741
+ * @param input - the role map to check
742
+ * @returns true if the map has the full-access marker
743
+ */
474
744
  function isFullAccessRoleMap(input) {
475
745
  return input[FULL_ACCESS_ROLE_KEY] === true;
476
746
  }
477
747
  /**
478
- * Creates a GrantedRoleMapReader.
748
+ * Creates a {@link GrantedRoleMapReader} for querying granted roles from a role map.
479
749
  *
480
- * @param map
481
- * @returns
750
+ * The reader handles full-access and no-access maps as special cases, and provides methods
751
+ * for checking individual roles or sets of roles.
752
+ *
753
+ * @param map - the granted role map to read from
754
+ * @returns a reader instance for querying the map
755
+ *
756
+ * @example
757
+ * ```typescript
758
+ * const roleMap: GrantedRoleMap = { read: true, first: true };
759
+ * const reader = grantedRoleMapReader(roleMap);
760
+ *
761
+ * reader.hasRole('read'); // true
762
+ * reader.hasRole('delete'); // false
763
+ * reader.containsRoles('any', ['read']); // true
764
+ * reader.containsRoles('all', ['read', 'delete']); // false
765
+ * ```
482
766
  */
483
767
  function grantedRoleMapReader(map) {
484
768
  return new GrantedRoleMapReaderInstance(map);
@@ -540,21 +824,62 @@ class GrantedRoleMapReaderInstance {
540
824
  }
541
825
  }
542
826
  /**
543
- * Converts the input array of roles to a GrantedRoleKeysMap.
827
+ * Converts an array of role strings into a {@link GrantedRoleKeysMap} where each role is mapped to the given boolean value.
544
828
  *
545
- * @param roles
546
- * @returns
829
+ * @param roles - the role strings to include
830
+ * @param value - the boolean value to assign to each role (defaults to true)
831
+ * @returns a map of roles to boolean values
832
+ *
833
+ * @example
834
+ * ```typescript
835
+ * const map = grantedRoleKeysMapFromArray(['read', 'update']);
836
+ * // { read: true, update: true }
837
+ * ```
547
838
  */
548
839
  function grantedRoleKeysMapFromArray(roles, value = true) {
549
840
  return util.arrayToObject(roles, (x) => x, () => value);
550
841
  }
551
842
 
843
+ /**
844
+ * Creates a {@link ContextGrantedModelRoles} with a no-access role map, indicating the context has no permissions.
845
+ *
846
+ * @param context - the context that was evaluated
847
+ * @param data - optional model data, if it was loaded
848
+ * @returns a ContextGrantedModelRoles with no access
849
+ *
850
+ * @example
851
+ * ```typescript
852
+ * const result = noAccessContextGrantedModelRoles(userContext);
853
+ * // result.roleMap contains the no-access marker
854
+ * ```
855
+ */
552
856
  function noAccessContextGrantedModelRoles(context, data) {
553
857
  return contextGrantedModelRoles(context, data, noAccessRoleMap());
554
858
  }
859
+ /**
860
+ * Creates a {@link ContextGrantedModelRoles} with a full-access role map, granting all permissions.
861
+ *
862
+ * @param context - the context that was evaluated
863
+ * @param data - optional model data
864
+ * @returns a ContextGrantedModelRoles with full access
865
+ *
866
+ * @example
867
+ * ```typescript
868
+ * const result = fullAccessGrantedModelRoles(adminContext, modelData);
869
+ * // result.roleMap contains the full-access marker
870
+ * ```
871
+ */
555
872
  function fullAccessGrantedModelRoles(context, data) {
556
873
  return contextGrantedModelRoles(context, data, fullAccessRoleMap());
557
874
  }
875
+ /**
876
+ * Creates a {@link ContextGrantedModelRoles} with the given role map, data, and context.
877
+ *
878
+ * @param context - the context that was evaluated
879
+ * @param data - the model data, if loaded
880
+ * @param roles - the granted role map
881
+ * @returns a ContextGrantedModelRoles combining all inputs
882
+ */
558
883
  function contextGrantedModelRoles(context, data, roles) {
559
884
  return {
560
885
  data,
@@ -605,6 +930,22 @@ class AbstractModelPermissionService {
605
930
  }
606
931
  }
607
932
 
933
+ /**
934
+ * Creates a factory that normalizes a {@link SyncEntityCommonTypeIdPairFactoryInput} into a full {@link SyncEntityCommonTypeIdPair}.
935
+ *
936
+ * If the input is a string, it is treated as a commonId and paired with the given commonType.
937
+ * If the input is already a pair, it is returned as-is.
938
+ *
939
+ * @param commonType - the default common type to use when input is a plain string
940
+ * @returns a factory function that produces SyncEntityCommonTypeIdPair instances
941
+ *
942
+ * @example
943
+ * ```typescript
944
+ * const factory = syncEntityCommonTypeIdPairFactory('user');
945
+ * factory('abc123'); // { commonType: 'user', commonId: 'abc123' }
946
+ * factory({ commonType: 'user', commonId: 'abc123' }); // passed through as-is
947
+ * ```
948
+ */
608
949
  function syncEntityCommonTypeIdPairFactory(commonType) {
609
950
  return (input) => {
610
951
  if (typeof input === 'string') {
@@ -619,10 +960,23 @@ function syncEntityCommonTypeIdPairFactory(commonType) {
619
960
  };
620
961
  }
621
962
  /**
622
- * Creates a SyncEntityFactory.
963
+ * Creates a {@link SyncEntityFactory} that produces {@link SyncEntity} instances from a common type/id pair.
623
964
  *
624
- * @param config
625
- * @returns
965
+ * The factory attaches the configured source info and optionally transforms the commonId into an entity id
966
+ * using the provided idFactory (defaults to identity).
967
+ *
968
+ * @param config - source info and optional id factory
969
+ * @returns a factory that creates SyncEntity instances
970
+ *
971
+ * @example
972
+ * ```typescript
973
+ * const factory = syncEntityFactory({
974
+ * sourceInfo: { id: 'api', name: 'External API' }
975
+ * });
976
+ *
977
+ * const entity = factory({ commonType: 'user', commonId: 'abc123' });
978
+ * // entity.id === 'abc123', entity.sourceInfo.id === 'api'
979
+ * ```
626
980
  */
627
981
  function syncEntityFactory(config) {
628
982
  const { idFactory: inputIdFactory, sourceInfo } = config;
@@ -682,6 +1036,26 @@ class SynchronizationFailedError extends makeError.BaseError {
682
1036
  }
683
1037
  }
684
1038
 
1039
+ /**
1040
+ * Creates a {@link SyncEntitySynchronizer} from the given configuration.
1041
+ *
1042
+ * Registers common type synchronizers and provides lookup by common type. Throws
1043
+ * {@link UnregisteredSyncEntityCommonTypeError} if an unregistered common type is requested.
1044
+ *
1045
+ * @param config - contains the list of common type synchronizers to register
1046
+ * @returns a synchronizer that delegates to the appropriate common type synchronizer
1047
+ * @throws {UnregisteredSyncEntityCommonTypeError} when requesting an unregistered common type
1048
+ *
1049
+ * @example
1050
+ * ```typescript
1051
+ * const synchronizer = syncEntitySynchronizer({
1052
+ * commonTypeSynchronizers: [userSynchronizer, orderSynchronizer]
1053
+ * });
1054
+ *
1055
+ * const instance = await synchronizer.synchronizeInstance({ commonType: 'user', commonId: '123' });
1056
+ * const result = await instance.synchronize();
1057
+ * ```
1058
+ */
685
1059
  function syncEntitySynchronizer(config) {
686
1060
  const map = new Map(config.commonTypeSynchronizers.map((x) => [x.commonType, x]));
687
1061
  const commonTypes = Array.from(map.keys());
@@ -702,6 +1076,21 @@ function syncEntitySynchronizer(config) {
702
1076
  };
703
1077
  }
704
1078
 
1079
+ /**
1080
+ * Creates a {@link BasicSyncEntityCommonTypeSynchronizer} that orchestrates synchronization across multiple sources
1081
+ * for a specific entity common type.
1082
+ *
1083
+ * The synchronizer follows a primary/secondary/replica flow:
1084
+ * 1. The primary source is synchronized first (exactly one required).
1085
+ * 2. Secondary sources are synchronized sequentially; if a secondary reports deletion while primary did not, the sync restarts once.
1086
+ * 3. Replica sources are synchronized concurrently (up to 3 in parallel).
1087
+ *
1088
+ * @param config - common type, sources, and context loader
1089
+ * @returns a synchronizer for the configured common type
1090
+ * @throws {NoPrimarySyncSourceError} when no primary source is found
1091
+ * @throws {MultiplePrimarySyncSourceError} when more than one primary source is found
1092
+ * @throws {SynchronizationFailedError} when primary or secondary sync returns failed/error
1093
+ */
705
1094
  function basicSyncEntityCommonTypeSynchronizerInstanceFactory(config) {
706
1095
  const { commonType, sources, entitySourceContextLoader, dynamicSources = false } = config;
707
1096
  const syncEntityCommonTypeIdPairForType = syncEntityCommonTypeIdPairFactory(commonType);
@@ -895,111 +1284,114 @@ function basicSyncEntityCommonTypeSynchronizerInstanceFactory(config) {
895
1284
  return result;
896
1285
  }
897
1286
 
898
- // MARK: String
899
- function transformStringToBoolean(defaultValue) {
900
- return (params) => util.stringToBoolean(params.value, defaultValue);
901
- }
902
- // MARK: Comma Separated Values
903
- function transformCommaSeparatedValueToArray(mapFn) {
904
- return (params) => {
905
- let result;
906
- if (params.value) {
907
- if (Array.isArray(params.value)) {
908
- result = params.value;
909
- }
910
- else {
911
- result = util.splitCommaSeparatedString(params.value, mapFn);
912
- }
913
- }
914
- return result;
915
- };
916
- }
917
- const transformCommaSeparatedNumberValueToArray = transformCommaSeparatedValueToArray((x) => Number(x));
918
- const transformCommaSeparatedStringValueToArray = transformCommaSeparatedValueToArray((x) => x);
919
-
920
- // MARK: Transform Annotations
921
- function TransformCommaSeparatedValueToArray(mapFn) {
922
- return classTransformer.Transform(transformCommaSeparatedValueToArray(mapFn));
923
- }
924
- const TransformCommaSeparatedStringValueToArray = () => classTransformer.Transform(transformCommaSeparatedStringValueToArray);
925
- const TransformCommaSeparatedNumberValueToArray = () => classTransformer.Transform(transformCommaSeparatedNumberValueToArray);
926
- const TransformStringValueToBoolean = () => classTransformer.Transform(transformStringToBoolean());
927
-
1287
+ /**
1288
+ * Creates a function that validates input against an ArkType schema and then processes it.
1289
+ *
1290
+ * On validation success, calls the configured handler function. On validation failure, delegates to the error handler.
1291
+ *
1292
+ * @param config - schema, handler function, and validation error handler
1293
+ * @returns a function that validates and processes input objects
1294
+ *
1295
+ * @example
1296
+ * ```typescript
1297
+ * const processUser = transformAndValidateObject({
1298
+ * schema: userType,
1299
+ * fn: async (user) => ({ id: user.id }),
1300
+ * handleValidationError: async (errors) => { throw new Error(errors.summary); }
1301
+ * });
1302
+ *
1303
+ * const result = await processUser({ id: '123', name: 'John' });
1304
+ * ```
1305
+ */
928
1306
  function transformAndValidateObject(config) {
929
1307
  const transformToResult = transformAndValidateObjectResult(config);
930
1308
  const { handleValidationError } = config;
931
- return (input, context) => transformToResult(input, context).then(async (x) => {
932
- const object = x.object;
933
- let result;
1309
+ return async (input, context) => {
1310
+ const x = await transformToResult(input, context);
934
1311
  if (x.success) {
935
- result = x.result;
936
- }
937
- else {
938
- result = await handleValidationError(x.validationErrors);
1312
+ return { object: x.object, result: x.result };
939
1313
  }
940
- return {
941
- object,
942
- result
943
- };
944
- });
1314
+ // Error handler is expected to throw. If it doesn't, there is no validated object to return.
1315
+ const result = await handleValidationError(x.validationErrors);
1316
+ return { object: undefined, result };
1317
+ };
945
1318
  }
946
1319
  /**
947
- * Creates a new TransformAndValidateObjectFactory.
1320
+ * Creates a reusable factory for generating transform-and-validate functions with shared defaults.
1321
+ *
1322
+ * The factory pre-configures error handling so individual function calls
1323
+ * only need to specify the schema and handler.
948
1324
  *
949
- * @param defaults
950
- * @returns
1325
+ * @param defaults - default error handler
1326
+ * @returns a factory function that creates TransformAndValidateObjectFunction instances
951
1327
  */
952
1328
  function transformAndValidateObjectFactory(defaults) {
953
- const { handleValidationError: defaultHandleValidationError, optionsForContext, defaultValidationOptions } = defaults;
954
- return (classType, fn, handleValidationError) => {
1329
+ const { handleValidationError: defaultHandleValidationError } = defaults;
1330
+ return (schema, fn, handleValidationError) => {
955
1331
  const config = {
956
- classType,
1332
+ schema,
957
1333
  fn,
958
- handleValidationError: handleValidationError ?? defaultHandleValidationError,
959
- optionsForContext,
960
- defaultValidationOptions
1334
+ handleValidationError: handleValidationError ?? defaultHandleValidationError
961
1335
  };
962
1336
  return transformAndValidateObject(config);
963
1337
  };
964
1338
  }
965
1339
  /**
966
- * Factory function that wraps the input class type and handler function to first transform the input object to a the given class, and then validate it.
1340
+ * Creates a function that validates input against an ArkType schema and returns a discriminated result.
967
1341
  *
968
- * @param classType
969
- * @param fn
970
- * @returns
1342
+ * Returns `{ success: true, object, result }` on valid input, or `{ success: false, validationErrors }` on failure.
1343
+ * The caller is responsible for handling the error case.
1344
+ *
1345
+ * @param config - schema and handler function
1346
+ * @returns a function that returns a success/error discriminated result
1347
+ *
1348
+ * @example
1349
+ * ```typescript
1350
+ * const validateUser = transformAndValidateObjectResult({
1351
+ * schema: userType,
1352
+ * fn: async (user) => ({ saved: true })
1353
+ * });
1354
+ *
1355
+ * const result = await validateUser({ name: 'John' });
1356
+ * if (result.success) {
1357
+ * console.log(result.result);
1358
+ * } else {
1359
+ * console.log(result.validationErrors.summary);
1360
+ * }
1361
+ * ```
971
1362
  */
972
1363
  function transformAndValidateObjectResult(config) {
973
- const { defaultValidationOptions, classType, fn, optionsForContext: inputOptionsForContext } = config;
974
- const optionsForContext = inputOptionsForContext ?? (() => ({}));
975
- return async (input, context) => {
976
- const { transform: transformOptions, validate: validateOptions } = optionsForContext(context);
977
- const object = classTransformer.plainToInstance(classType, input, {
978
- ...transformOptions,
979
- // Note: Each variable on the target class must be marked with the @Expose() annotation.
980
- excludeExtraneousValues: true
981
- });
982
- const validationErrors = await classValidator.validate(object, {
983
- forbidUnknownValues: false, // allow classes without annotations by default
984
- ...defaultValidationOptions,
985
- ...validateOptions
986
- });
987
- if (validationErrors.length) {
988
- return { object, validationErrors, success: false };
989
- }
990
- else {
991
- const result = await fn(object);
992
- return { object, result, success: true };
1364
+ const { schema, fn } = config;
1365
+ return async (input) => {
1366
+ const out = schema(input);
1367
+ if (out instanceof arktype.type.errors) {
1368
+ return { validationErrors: out, success: false };
993
1369
  }
1370
+ const object = out;
1371
+ const result = await fn(object);
1372
+ return { object, result, success: true };
994
1373
  };
995
1374
  }
996
1375
 
1376
+ /**
1377
+ * Creates a factory for transform-and-validate functions that return the result with the parsed object attached as `params`.
1378
+ *
1379
+ * @param defaults - shared error handler defaults
1380
+ * @returns a factory that produces functions returning {@link TransformAndValidateFunctionResult}
1381
+ */
997
1382
  function transformAndValidateFunctionResultFactory(defaults) {
998
1383
  return toTransformAndValidateFunctionResultFactory(transformAndValidateObjectFactory(defaults));
999
1384
  }
1385
+ /**
1386
+ * Wraps an existing {@link TransformAndValidateObjectFactory} to produce functions that attach the parsed object
1387
+ * as `params` on the result.
1388
+ *
1389
+ * @param transformAndValidateObjectFactory - the base factory to wrap
1390
+ * @returns a factory that produces functions returning results with `params` attached
1391
+ */
1000
1392
  function toTransformAndValidateFunctionResultFactory(transformAndValidateObjectFactory) {
1001
- return (classType, fn, handleValidationError) => {
1002
- const transformAndValidateObjectFn = transformAndValidateObjectFactory(classType, fn, handleValidationError);
1393
+ return (schema, fn, handleValidationError) => {
1394
+ const transformAndValidateObjectFn = transformAndValidateObjectFactory(schema, fn, handleValidationError);
1003
1395
  return (input, context) => {
1004
1396
  return toTransformAndValidateFunctionResult(transformAndValidateObjectFn(input, context));
1005
1397
  };
@@ -1014,10 +1406,18 @@ function toTransformAndValidateFunctionResult(objectOutput) {
1014
1406
  });
1015
1407
  }
1016
1408
 
1409
+ /**
1410
+ * Creates a factory for transform-and-validate functions that return only the result (discarding the parsed object).
1411
+ *
1412
+ * Useful when you only need the processed output and don't need access to the validated input.
1413
+ *
1414
+ * @param defaults - shared error handler defaults
1415
+ * @returns a factory that produces functions returning only the handler's result
1416
+ */
1017
1417
  function transformAndValidateResultFactory(defaults) {
1018
1418
  const factory = transformAndValidateObjectFactory(defaults);
1019
- return (classType, fn, handleValidationError) => {
1020
- const transformAndValidateObjectFn = factory(classType, fn, handleValidationError);
1419
+ return (schema, fn, handleValidationError) => {
1420
+ const transformAndValidateObjectFn = factory(schema, fn, handleValidationError);
1021
1421
  return async (input, context) => {
1022
1422
  const { result } = await transformAndValidateObjectFn(input, context);
1023
1423
  return result;
@@ -1026,152 +1426,80 @@ function transformAndValidateResultFactory(defaults) {
1026
1426
  }
1027
1427
 
1028
1428
  /**
1029
- * isISO8601DayString validator
1030
- */
1031
- function IsISO8601DayString(validationOptions) {
1032
- return function (object, propertyName) {
1033
- classValidator.registerDecorator({
1034
- name: 'isISO8601DayString',
1035
- target: object.constructor,
1036
- propertyName: propertyName,
1037
- options: validationOptions,
1038
- validator: {
1039
- validate: util.isISO8601DayString,
1040
- defaultMessage: classValidator.buildMessage((eachPrefix, args) => eachPrefix + `$property value of "${args?.value}" is not a ISO8601DayString.`, validationOptions)
1041
- }
1042
- });
1043
- };
1429
+ * ArkType schema for a model key (non-empty string).
1430
+ */
1431
+ const modelKeyType = arktype.type('string > 0');
1432
+ /**
1433
+ * ArkType schema for a model id (non-empty string).
1434
+ */
1435
+ const modelIdType = arktype.type('string > 0');
1436
+ /**
1437
+ * ArkType schema for target model params with a required `key` field.
1438
+ */
1439
+ const targetModelParamsType = arktype.type({
1440
+ key: modelKeyType
1441
+ });
1442
+ /**
1443
+ * ArkType schema for target model id params with a required `id` field.
1444
+ */
1445
+ const targetModelIdParamsType = arktype.type({
1446
+ id: modelIdType
1447
+ });
1448
+
1449
+ function clearable(definition) {
1450
+ if (typeof definition === 'string') {
1451
+ return `${definition} | null | undefined`;
1452
+ }
1453
+ return definition.or('null').or('undefined');
1044
1454
  }
1045
1455
 
1046
1456
  /**
1047
- * isMinuteOfDay validator
1048
- */
1049
- function IsMinuteOfDay(validationOptions) {
1050
- return function (object, propertyName) {
1051
- classValidator.registerDecorator({
1052
- name: 'isMinuteOfDay',
1053
- target: object.constructor,
1054
- propertyName: propertyName,
1055
- options: validationOptions,
1056
- validator: {
1057
- validate: util.isMinuteOfDay,
1058
- defaultMessage: classValidator.buildMessage((eachPrefix, args) => eachPrefix + `$property value of "${args?.value}" is not a valid minute of the day.`, validationOptions)
1059
- }
1060
- });
1061
- };
1062
- }
1457
+ * ArkType schema for a valid ISO 8601 day string (e.g., "2024-01-15").
1458
+ */
1459
+ const iso8601DayStringType = arktype.type('string > 0').narrow((val, ctx) => (val != null && util.isISO8601DayString(val)) || ctx.mustBe('a valid ISO 8601 day string'));
1063
1460
 
1064
1461
  /**
1065
- * isE164PhoneNumber validator that does not allowed extensions.
1066
- */
1067
- function IsE164PhoneNumber(validationOptions) {
1068
- return function (object, propertyName) {
1069
- classValidator.registerDecorator({
1070
- name: 'isE164PhoneNumber',
1071
- target: object.constructor,
1072
- propertyName: propertyName,
1073
- options: validationOptions,
1074
- validator: {
1075
- validate: (x) => util.isE164PhoneNumber(x, false),
1076
- defaultMessage: classValidator.buildMessage((eachPrefix, args) => eachPrefix + `$property value of "${args?.value}" is not a E164PhoneNumber with no extension.`, validationOptions)
1077
- }
1078
- });
1079
- };
1080
- }
1462
+ * ArkType schema for a valid minute of the day (0-1439).
1463
+ */
1464
+ const minuteOfDayType = arktype.type('number').narrow((val, ctx) => (val != null && util.isMinuteOfDay(val)) || ctx.mustBe('a valid minute of the day (0-1439)'));
1465
+
1081
1466
  /**
1082
- * isE164PhoneNumber validator that allows extensions.
1083
- *
1084
- * @param validationOptions
1085
- * @returns
1086
- */
1087
- function IsE164PhoneNumberWithOptionalExtension(validationOptions) {
1088
- return function (object, propertyName) {
1089
- classValidator.registerDecorator({
1090
- name: 'isE164PhoneNumber',
1091
- target: object.constructor,
1092
- propertyName: propertyName,
1093
- options: validationOptions,
1094
- validator: {
1095
- validate: (x) => util.isE164PhoneNumber(x, true),
1096
- defaultMessage: classValidator.buildMessage((eachPrefix, args) => eachPrefix + `$property value of "${args?.value}" is not an E164PhoneNumber or has an invalid extension.`, validationOptions)
1097
- }
1098
- });
1099
- };
1100
- }
1467
+ * ArkType schema for a valid E.164 phone number without an extension.
1468
+ */
1469
+ const e164PhoneNumberType = arktype.type('string > 0').narrow((val, ctx) => (val != null && util.isE164PhoneNumber(val, false)) || ctx.mustBe('a valid E.164 phone number without an extension'));
1101
1470
  /**
1102
- * isE164PhoneNumberWithExtension validator
1103
- *
1104
- * @param validationOptions
1105
- * @returns
1106
- */
1107
- function IsE164PhoneNumberWithExtension(validationOptions) {
1108
- return function (object, propertyName) {
1109
- classValidator.registerDecorator({
1110
- name: 'isE164PhoneNumberWithExtension',
1111
- target: object.constructor,
1112
- propertyName: propertyName,
1113
- options: validationOptions,
1114
- validator: {
1115
- validate: util.isE164PhoneNumberWithExtension,
1116
- defaultMessage: classValidator.buildMessage((eachPrefix, args) => eachPrefix + `$property value of "${args?.value}" is not a E164PhoneNumberWithExtension.`, validationOptions)
1117
- }
1118
- });
1119
- };
1120
- }
1471
+ * ArkType schema for a valid E.164 phone number, optionally with an extension.
1472
+ */
1473
+ const e164PhoneNumberWithOptionalExtensionType = arktype.type('string > 0').narrow((val, ctx) => (val != null && util.isE164PhoneNumber(val, true)) || ctx.mustBe('a valid E.164 phone number'));
1474
+ /**
1475
+ * ArkType schema for a valid E.164 phone number that includes an extension.
1476
+ */
1477
+ const e164PhoneNumberWithExtensionType = arktype.type('string > 0').narrow((val, ctx) => (val != null && util.isE164PhoneNumberWithExtension(val)) || ctx.mustBe('a valid E.164 phone number with an extension'));
1121
1478
 
1122
1479
  /**
1123
- * isUniqueKeyedFunction validator
1480
+ * Creates an ArkType schema that validates an array has no duplicate keys.
1481
+ *
1482
+ * @param readKey - function that extracts the key from each array element
1483
+ * @returns an ArkType schema that narrows `T[]` to ensure uniqueness
1484
+ *
1485
+ * @example
1486
+ * ```typescript
1487
+ * const uniqueItemsType = uniqueKeyedType((item: Item) => item.id);
1488
+ * ```
1124
1489
  */
1125
- function IsUniqueKeyed(readKey, validationOptions) {
1490
+ function uniqueKeyedType(readKey) {
1126
1491
  const isUniqueKeyed = util.isUniqueKeyedFunction(readKey);
1127
- return function (object, propertyName) {
1128
- classValidator.registerDecorator({
1129
- name: 'isUniqueKeyed',
1130
- target: object.constructor,
1131
- propertyName: propertyName,
1132
- options: validationOptions,
1133
- validator: {
1134
- validate: isUniqueKeyed,
1135
- defaultMessage: classValidator.buildMessage((eachPrefix, args) => eachPrefix + `$property value has one or more values with the same key. Keys must be unique.`, validationOptions)
1136
- }
1137
- });
1138
- };
1492
+ return arktype.type('unknown[]').narrow((val, ctx) => (val != null && isUniqueKeyed(val)) || ctx.mustBe('an array with unique keys'));
1139
1493
  }
1140
1494
 
1141
1495
  /**
1142
- * isWebsiteUrl validator
1143
- */
1144
- function IsWebsiteUrl(validationOptions) {
1145
- return function (object, propertyName) {
1146
- classValidator.registerDecorator({
1147
- name: 'isWebsiteUrl',
1148
- target: object.constructor,
1149
- propertyName: propertyName,
1150
- options: validationOptions,
1151
- validator: {
1152
- validate: util.isWebsiteUrl,
1153
- defaultMessage: classValidator.buildMessage((eachPrefix, args) => eachPrefix + `$property value of "${args?.value}" is not a valid website url.`, validationOptions)
1154
- }
1155
- });
1156
- };
1157
- }
1496
+ * ArkType schema for a valid website URL (with or without protocol prefix).
1497
+ */
1498
+ const websiteUrlType = arktype.type('string > 0').narrow((val, ctx) => (val != null && util.isWebsiteUrl(val)) || ctx.mustBe('a valid website URL'));
1158
1499
  /**
1159
- * isWebsiteUrlWithPrefix validator
1160
- */
1161
- function IsWebsiteUrlWithPrefix(validationOptions) {
1162
- return function (object, propertyName) {
1163
- classValidator.registerDecorator({
1164
- name: 'isWebsiteUrlWithPrefix',
1165
- target: object.constructor,
1166
- propertyName: propertyName,
1167
- options: validationOptions,
1168
- validator: {
1169
- validate: util.isWebsiteUrlWithPrefix,
1170
- defaultMessage: classValidator.buildMessage((eachPrefix, args) => eachPrefix + `$property value of "${args?.value}" is not a valid website url that starts with a http/https prefix.`, validationOptions)
1171
- }
1172
- });
1173
- };
1174
- }
1500
+ * ArkType schema for a valid website URL that starts with `http://` or `https://`.
1501
+ */
1502
+ const websiteUrlWithPrefixType = arktype.type('string > 0').narrow((val, ctx) => (val != null && util.isWebsiteUrlWithPrefix(val)) || ctx.mustBe('a valid website URL starting with http:// or https://'));
1175
1503
 
1176
1504
  exports.ADDRESS_CITY_MAX_LENGTH = ADDRESS_CITY_MAX_LENGTH;
1177
1505
  exports.ADDRESS_COUNTRY_MAX_LENGTH = ADDRESS_COUNTRY_MAX_LENGTH;
@@ -1180,7 +1508,6 @@ exports.ADDRESS_STATE_CODE_MAX_LENGTH = ADDRESS_STATE_CODE_MAX_LENGTH;
1180
1508
  exports.ADDRESS_STATE_MAX_LENGTH = ADDRESS_STATE_MAX_LENGTH;
1181
1509
  exports.ADDRESS_ZIP_MAX_LENGTH = ADDRESS_ZIP_MAX_LENGTH;
1182
1510
  exports.AbstractModelPermissionService = AbstractModelPermissionService;
1183
- exports.AbstractUnitedStatesAddressWithoutStateParams = AbstractUnitedStatesAddressWithoutStateParams;
1184
1511
  exports.CASHAPP_BASE_URL = CASHAPP_BASE_URL;
1185
1512
  exports.CASHAPP_USERNAME_PREFIX = CASHAPP_USERNAME_PREFIX;
1186
1513
  exports.CASHAPP_WEBSITE_LINK_TYPE = CASHAPP_WEBSITE_LINK_TYPE;
@@ -1197,14 +1524,6 @@ exports.GRANTED_UPDATE_ROLE_KEY = GRANTED_UPDATE_ROLE_KEY;
1197
1524
  exports.GrantedRoleMapReaderInstance = GrantedRoleMapReaderInstance;
1198
1525
  exports.INSTAGRAM_BASE_URL = INSTAGRAM_BASE_URL;
1199
1526
  exports.INSTAGRAM_WEBSITE_LINK_TYPE = INSTAGRAM_WEBSITE_LINK_TYPE;
1200
- exports.IsE164PhoneNumber = IsE164PhoneNumber;
1201
- exports.IsE164PhoneNumberWithExtension = IsE164PhoneNumberWithExtension;
1202
- exports.IsE164PhoneNumberWithOptionalExtension = IsE164PhoneNumberWithOptionalExtension;
1203
- exports.IsISO8601DayString = IsISO8601DayString;
1204
- exports.IsMinuteOfDay = IsMinuteOfDay;
1205
- exports.IsUniqueKeyed = IsUniqueKeyed;
1206
- exports.IsWebsiteUrl = IsWebsiteUrl;
1207
- exports.IsWebsiteUrlWithPrefix = IsWebsiteUrlWithPrefix;
1208
1527
  exports.NO_ACCESS_ROLE_KEY = NO_ACCESS_ROLE_KEY;
1209
1528
  exports.PAYPAL_BASE_URL = PAYPAL_BASE_URL;
1210
1529
  exports.PAYPAL_WEBSITE_LINK_TYPE = PAYPAL_WEBSITE_LINK_TYPE;
@@ -1220,13 +1539,7 @@ exports.TIKTOK_USERNAME_PREFIX = TIKTOK_USERNAME_PREFIX;
1220
1539
  exports.TIKTOK_WEBSITE_LINK_TYPE = TIKTOK_WEBSITE_LINK_TYPE;
1221
1540
  exports.TWITTER_BASE_URL = TWITTER_BASE_URL;
1222
1541
  exports.TWITTER_WEBSITE_LINK_TYPE = TWITTER_WEBSITE_LINK_TYPE;
1223
- exports.TransformCommaSeparatedNumberValueToArray = TransformCommaSeparatedNumberValueToArray;
1224
- exports.TransformCommaSeparatedStringValueToArray = TransformCommaSeparatedStringValueToArray;
1225
- exports.TransformCommaSeparatedValueToArray = TransformCommaSeparatedValueToArray;
1226
- exports.TransformStringValueToBoolean = TransformStringValueToBoolean;
1227
1542
  exports.UNKNOWN_WEBSITE_LINK_TYPE = UNKNOWN_WEBSITE_LINK_TYPE;
1228
- exports.UnitedStatesAddressWithStateCodeParams = UnitedStatesAddressWithStateCodeParams;
1229
- exports.UnitedStatesAddressWithStateStringParams = UnitedStatesAddressWithStateStringParams;
1230
1543
  exports.VENMO_BASE_URL = VENMO_BASE_URL;
1231
1544
  exports.VENMO_WEBSITE_LINK_ISOLATE_PROFILE_ID = VENMO_WEBSITE_LINK_ISOLATE_PROFILE_ID;
1232
1545
  exports.VENMO_WEBSITE_LINK_TYPE = VENMO_WEBSITE_LINK_TYPE;
@@ -1244,16 +1557,18 @@ exports.WEBSITE_LINK_ISOLATE_BASE_URL_PROFILE_ID = WEBSITE_LINK_ISOLATE_BASE_URL
1244
1557
  exports.WEBSITE_LINK_TYPE_MAX_LENGTH = WEBSITE_LINK_TYPE_MAX_LENGTH;
1245
1558
  exports.WEBSITE_LINK_TYPE_REGEX = WEBSITE_LINK_TYPE_REGEX;
1246
1559
  exports.WEBSITE_URL_WEBSITE_LINK_TYPE = WEBSITE_URL_WEBSITE_LINK_TYPE;
1247
- exports.WebsiteFileLink = WebsiteFileLink;
1248
- exports.WebsiteLink = WebsiteLink;
1249
1560
  exports.YOUTUBE_BASE_URL = YOUTUBE_BASE_URL;
1250
1561
  exports.YOUTUBE_WEBSITE_LINK_ISOLATE_PROFILE_ID = YOUTUBE_WEBSITE_LINK_ISOLATE_PROFILE_ID;
1251
1562
  exports.YOUTUBE_WEBSITE_LINK_TYPE = YOUTUBE_WEBSITE_LINK_TYPE;
1252
1563
  exports.basicSyncEntityCommonTypeSynchronizerInstanceFactory = basicSyncEntityCommonTypeSynchronizerInstanceFactory;
1253
1564
  exports.cashappProfileUrl = cashappProfileUrl;
1254
1565
  exports.cashappProfileUrlToWebsiteLink = cashappProfileUrlToWebsiteLink;
1566
+ exports.clearable = clearable;
1255
1567
  exports.contextGrantedModelRoles = contextGrantedModelRoles;
1256
1568
  exports.decodeWebsiteLinkEncodedDataToWebsiteFileLink = decodeWebsiteLinkEncodedDataToWebsiteFileLink;
1569
+ exports.e164PhoneNumberType = e164PhoneNumberType;
1570
+ exports.e164PhoneNumberWithExtensionType = e164PhoneNumberWithExtensionType;
1571
+ exports.e164PhoneNumberWithOptionalExtensionType = e164PhoneNumberWithOptionalExtensionType;
1257
1572
  exports.emailAddressToWebsiteLink = emailAddressToWebsiteLink;
1258
1573
  exports.encodeWebsiteFileLinkToWebsiteLinkEncodedData = encodeWebsiteFileLinkToWebsiteLinkEncodedData;
1259
1574
  exports.facebookProfileUrl = facebookProfileUrl;
@@ -1268,6 +1583,10 @@ exports.isFullAccessRoleMap = isFullAccessRoleMap;
1268
1583
  exports.isGrantedAdminLevelRole = isGrantedAdminLevelRole;
1269
1584
  exports.isNoAccessRoleMap = isNoAccessRoleMap;
1270
1585
  exports.isValidWebsiteLinkType = isValidWebsiteLinkType;
1586
+ exports.iso8601DayStringType = iso8601DayStringType;
1587
+ exports.minuteOfDayType = minuteOfDayType;
1588
+ exports.modelIdType = modelIdType;
1589
+ exports.modelKeyType = modelKeyType;
1271
1590
  exports.noAccessContextGrantedModelRoles = noAccessContextGrantedModelRoles;
1272
1591
  exports.noAccessRoleMap = noAccessRoleMap;
1273
1592
  exports.paypalProfileUrl = paypalProfileUrl;
@@ -1280,6 +1599,8 @@ exports.spotifyProfileUrlToWebsiteLink = spotifyProfileUrlToWebsiteLink;
1280
1599
  exports.syncEntityCommonTypeIdPairFactory = syncEntityCommonTypeIdPairFactory;
1281
1600
  exports.syncEntityFactory = syncEntityFactory;
1282
1601
  exports.syncEntitySynchronizer = syncEntitySynchronizer;
1602
+ exports.targetModelIdParamsType = targetModelIdParamsType;
1603
+ exports.targetModelParamsType = targetModelParamsType;
1283
1604
  exports.tiktokProfileUrl = tiktokProfileUrl;
1284
1605
  exports.tiktokProfileUrlToWebsiteLink = tiktokProfileUrlToWebsiteLink;
1285
1606
  exports.toTransformAndValidateFunctionResult = toTransformAndValidateFunctionResult;
@@ -1289,20 +1610,23 @@ exports.transformAndValidateObject = transformAndValidateObject;
1289
1610
  exports.transformAndValidateObjectFactory = transformAndValidateObjectFactory;
1290
1611
  exports.transformAndValidateObjectResult = transformAndValidateObjectResult;
1291
1612
  exports.transformAndValidateResultFactory = transformAndValidateResultFactory;
1292
- exports.transformCommaSeparatedNumberValueToArray = transformCommaSeparatedNumberValueToArray;
1293
- exports.transformCommaSeparatedStringValueToArray = transformCommaSeparatedStringValueToArray;
1294
- exports.transformCommaSeparatedValueToArray = transformCommaSeparatedValueToArray;
1295
- exports.transformStringToBoolean = transformStringToBoolean;
1296
1613
  exports.twitterProfileUrl = twitterProfileUrl;
1297
1614
  exports.twitterProfileUrlToWebsiteLink = twitterProfileUrlToWebsiteLink;
1615
+ exports.uniqueKeyedType = uniqueKeyedType;
1616
+ exports.unitedStatesAddressWithStateCodeType = unitedStatesAddressWithStateCodeType;
1617
+ exports.unitedStatesAddressWithStateStringType = unitedStatesAddressWithStateStringType;
1298
1618
  exports.usernameFromUsernameOrWebsiteWithBaseUrlUsername = usernameFromUsernameOrWebsiteWithBaseUrlUsername;
1299
1619
  exports.usernameFromUsernameOrWebsiteWithOneOffBaseUrlUsername = usernameFromUsernameOrWebsiteWithOneOffBaseUrlUsername;
1300
1620
  exports.usernameOrWebsiteUrlToWebsiteUrl = usernameOrWebsiteUrlToWebsiteUrl;
1301
1621
  exports.venmoProfileUrl = venmoProfileUrl;
1302
1622
  exports.venmoProfileUrlToWebsiteLink = venmoProfileUrlToWebsiteLink;
1303
1623
  exports.websiteFileLinkToWebsiteLink = websiteFileLinkToWebsiteLink;
1624
+ exports.websiteFileLinkType = websiteFileLinkType;
1304
1625
  exports.websiteLinkToWebsiteLinkFile = websiteLinkToWebsiteLinkFile;
1626
+ exports.websiteLinkType = websiteLinkType;
1305
1627
  exports.websiteUrlToWebsiteLink = websiteUrlToWebsiteLink;
1628
+ exports.websiteUrlType = websiteUrlType;
1629
+ exports.websiteUrlWithPrefixType = websiteUrlWithPrefixType;
1306
1630
  exports.youtubeProfileUrl = youtubeProfileUrl;
1307
1631
  exports.youtubeProfileUrlToWebsiteLink = youtubeProfileUrlToWebsiteLink;
1308
1632
  //# sourceMappingURL=index.cjs.js.map