@dereekb/model 13.0.0 → 13.0.2
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.default.js +1 -0
- package/index.cjs.js +752 -878
- package/index.cjs.mjs +2 -0
- package/index.esm.js +752 -878
- package/package.json +12 -16
package/index.esm.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { ZIP_CODE_STRING_REGEX, US_STATE_CODE_STRING_REGEX, splitJoinRemainder, filterFalsyAndEmptyValues, isolateWebsitePathFunction, toRelativeSlashPathStartType, addPrefix, hasWebsiteDomain, toAbsoluteSlashPathStartType, removeHttpFromUrl, forEachKeyValue, iterableToArray, arrayToObject, MAP_IDENTITY, makeValuesGroupMap, cachedGetter, filterMaybeArrayValues, sortByNumberFunction, performAsyncTasks, pushArrayItemsIntoArray, splitCommaSeparatedString, stringToBoolean, mapPromiseOrValue, isISO8601DayString, isMinuteOfDay, isE164PhoneNumber, isE164PhoneNumberWithExtension, isUniqueKeyedFunction, isWebsiteUrl, isWebsiteUrlWithPrefix } from '@dereekb/util';
|
|
2
2
|
import { Expose, Transform, plainToInstance } from 'class-transformer';
|
|
3
3
|
import { IsString, IsNotEmpty, MaxLength, IsOptional, Matches, MinLength, validate, registerDecorator, buildMessage } from 'class-validator';
|
|
4
|
-
import '
|
|
5
|
-
import 'core-js/modules/es.iterator.map.js';
|
|
6
|
-
import 'core-js/modules/es.map.get-or-insert.js';
|
|
7
|
-
import 'core-js/modules/es.map.get-or-insert-computed.js';
|
|
4
|
+
import { BaseError } from 'make-error';
|
|
8
5
|
|
|
9
6
|
/******************************************************************************
|
|
10
7
|
Copyright (c) Microsoft Corporation.
|
|
@@ -46,37 +43,67 @@ const ADDRESS_STATE_CODE_MAX_LENGTH = 2;
|
|
|
46
43
|
const ADDRESS_ZIP_MAX_LENGTH = 11;
|
|
47
44
|
const ADDRESS_COUNTRY_MAX_LENGTH = 80;
|
|
48
45
|
class AbstractUnitedStatesAddressWithoutStateParams {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
46
|
+
line1;
|
|
47
|
+
line2;
|
|
48
|
+
city;
|
|
49
|
+
zip;
|
|
50
|
+
}
|
|
51
|
+
__decorate([
|
|
52
|
+
Expose(),
|
|
53
|
+
IsString(),
|
|
54
|
+
IsNotEmpty(),
|
|
55
|
+
MaxLength(ADDRESS_LINE_MAX_LENGTH),
|
|
56
|
+
__metadata("design:type", String)
|
|
57
|
+
], AbstractUnitedStatesAddressWithoutStateParams.prototype, "line1", void 0);
|
|
58
|
+
__decorate([
|
|
59
|
+
Expose(),
|
|
60
|
+
IsOptional(),
|
|
61
|
+
IsString(),
|
|
62
|
+
MaxLength(ADDRESS_LINE_MAX_LENGTH),
|
|
63
|
+
__metadata("design:type", String)
|
|
64
|
+
], AbstractUnitedStatesAddressWithoutStateParams.prototype, "line2", void 0);
|
|
65
|
+
__decorate([
|
|
66
|
+
Expose(),
|
|
67
|
+
IsString(),
|
|
68
|
+
IsNotEmpty(),
|
|
69
|
+
MaxLength(ADDRESS_CITY_MAX_LENGTH),
|
|
70
|
+
__metadata("design:type", String)
|
|
71
|
+
], AbstractUnitedStatesAddressWithoutStateParams.prototype, "city", void 0);
|
|
72
|
+
__decorate([
|
|
73
|
+
Expose(),
|
|
74
|
+
IsString(),
|
|
75
|
+
IsNotEmpty(),
|
|
76
|
+
Matches(ZIP_CODE_STRING_REGEX),
|
|
77
|
+
MaxLength(ADDRESS_ZIP_MAX_LENGTH),
|
|
78
|
+
__metadata("design:type", String)
|
|
79
|
+
], AbstractUnitedStatesAddressWithoutStateParams.prototype, "zip", void 0);
|
|
60
80
|
/**
|
|
61
81
|
* UnitedStatesAddress that enforces a StateCode for the state value.
|
|
62
82
|
*/
|
|
63
83
|
class UnitedStatesAddressWithStateCodeParams extends AbstractUnitedStatesAddressWithoutStateParams {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
84
|
+
state;
|
|
85
|
+
}
|
|
86
|
+
__decorate([
|
|
87
|
+
Expose(),
|
|
88
|
+
IsString(),
|
|
89
|
+
Matches(US_STATE_CODE_STRING_REGEX),
|
|
90
|
+
MinLength(ADDRESS_STATE_CODE_MAX_LENGTH),
|
|
91
|
+
MaxLength(ADDRESS_STATE_CODE_MAX_LENGTH),
|
|
92
|
+
__metadata("design:type", String)
|
|
93
|
+
], UnitedStatesAddressWithStateCodeParams.prototype, "state", void 0);
|
|
70
94
|
/**
|
|
71
95
|
* UnitedStatesAddress that enforces a State for the state value.
|
|
72
96
|
*/
|
|
73
97
|
class UnitedStatesAddressWithStateStringParams extends AbstractUnitedStatesAddressWithoutStateParams {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
98
|
+
state;
|
|
99
|
+
}
|
|
100
|
+
__decorate([
|
|
101
|
+
Expose(),
|
|
102
|
+
IsString(),
|
|
103
|
+
IsNotEmpty(),
|
|
104
|
+
MaxLength(ADDRESS_STATE_MAX_LENGTH),
|
|
105
|
+
__metadata("design:type", String)
|
|
106
|
+
], UnitedStatesAddressWithStateStringParams.prototype, "state", void 0);
|
|
80
107
|
|
|
81
108
|
const UNKNOWN_WEBSITE_LINK_TYPE = 'u';
|
|
82
109
|
/**
|
|
@@ -88,24 +115,37 @@ const WEBSITE_LINK_TYPE_MAX_LENGTH = 32;
|
|
|
88
115
|
*/
|
|
89
116
|
const WEBSITE_LINK_TYPE_REGEX = /^[a-zA-Z0-9]{1,32}$/;
|
|
90
117
|
function isValidWebsiteLinkType(input) {
|
|
91
|
-
|
|
118
|
+
return WEBSITE_LINK_TYPE_REGEX.test(input);
|
|
92
119
|
}
|
|
93
120
|
/**
|
|
94
121
|
* Default max length of WebsiteLink's data string.
|
|
95
122
|
*/
|
|
96
123
|
const WEBSITE_LINK_ENCODED_DATA_MAX_LENGTH = 1000;
|
|
97
124
|
class WebsiteLink {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
125
|
+
t;
|
|
126
|
+
d;
|
|
127
|
+
constructor(template) {
|
|
128
|
+
if (template != null) {
|
|
129
|
+
this.t = template.t;
|
|
130
|
+
this.d = template.d;
|
|
131
|
+
}
|
|
104
132
|
}
|
|
105
|
-
}
|
|
106
133
|
}
|
|
107
|
-
__decorate([
|
|
108
|
-
|
|
134
|
+
__decorate([
|
|
135
|
+
Expose(),
|
|
136
|
+
IsString(),
|
|
137
|
+
IsNotEmpty(),
|
|
138
|
+
Matches(WEBSITE_LINK_TYPE_REGEX),
|
|
139
|
+
MaxLength(WEBSITE_LINK_TYPE_MAX_LENGTH),
|
|
140
|
+
__metadata("design:type", String)
|
|
141
|
+
], WebsiteLink.prototype, "t", void 0);
|
|
142
|
+
__decorate([
|
|
143
|
+
Expose(),
|
|
144
|
+
IsString(),
|
|
145
|
+
IsNotEmpty(),
|
|
146
|
+
MaxLength(WEBSITE_LINK_ENCODED_DATA_MAX_LENGTH),
|
|
147
|
+
__metadata("design:type", String)
|
|
148
|
+
], WebsiteLink.prototype, "d", void 0);
|
|
109
149
|
|
|
110
150
|
/**
|
|
111
151
|
* Max length of WebsiteLink's data type.
|
|
@@ -133,47 +173,73 @@ const WEBSITE_FILE_LINK_NAME_MAX_LENGTH = 128;
|
|
|
133
173
|
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;
|
|
134
174
|
const WEBSITE_FILE_LINK_DATA_REGEX = /^[^|]+$/;
|
|
135
175
|
class WebsiteFileLink {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
176
|
+
type;
|
|
177
|
+
mime;
|
|
178
|
+
name;
|
|
179
|
+
data;
|
|
180
|
+
constructor(template) {
|
|
181
|
+
if (template != null) {
|
|
182
|
+
this.type = template.type;
|
|
183
|
+
this.mime = template.mime;
|
|
184
|
+
this.name = template.name;
|
|
185
|
+
this.data = template.data;
|
|
186
|
+
}
|
|
146
187
|
}
|
|
147
|
-
}
|
|
148
188
|
}
|
|
149
|
-
__decorate([
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
189
|
+
__decorate([
|
|
190
|
+
Expose(),
|
|
191
|
+
IsOptional(),
|
|
192
|
+
IsString(),
|
|
193
|
+
Matches(WEBSITE_FILE_LINK_TYPE_REGEX),
|
|
194
|
+
MaxLength(WEBSITE_LINK_TYPE_MAX_LENGTH),
|
|
195
|
+
__metadata("design:type", String)
|
|
196
|
+
], WebsiteFileLink.prototype, "type", void 0);
|
|
197
|
+
__decorate([
|
|
198
|
+
Expose(),
|
|
199
|
+
IsOptional(),
|
|
200
|
+
IsString(),
|
|
201
|
+
Matches(WEBSITE_FILE_LINK_MIME_TYPE_REGEX),
|
|
202
|
+
MaxLength(WEBSITE_FILE_LINK_MIME_TYPE_MAX_LENGTH),
|
|
203
|
+
__metadata("design:type", String)
|
|
204
|
+
], WebsiteFileLink.prototype, "mime", void 0);
|
|
205
|
+
__decorate([
|
|
206
|
+
Expose(),
|
|
207
|
+
IsOptional(),
|
|
208
|
+
IsString(),
|
|
209
|
+
MaxLength(WEBSITE_FILE_LINK_NAME_MAX_LENGTH),
|
|
210
|
+
__metadata("design:type", String)
|
|
211
|
+
], WebsiteFileLink.prototype, "name", void 0);
|
|
212
|
+
__decorate([
|
|
213
|
+
IsString(),
|
|
214
|
+
IsNotEmpty(),
|
|
215
|
+
Matches(WEBSITE_FILE_LINK_DATA_REGEX),
|
|
216
|
+
MaxLength(WEBSITE_FILE_LINK_DATA_MAX_LENGTH),
|
|
217
|
+
__metadata("design:type", String)
|
|
218
|
+
], WebsiteFileLink.prototype, "data", void 0);
|
|
153
219
|
const WEBSITE_FILE_LINK_WEBSITE_LINK_TYPE = 'f';
|
|
154
220
|
function websiteFileLinkToWebsiteLink(input) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
221
|
+
return {
|
|
222
|
+
t: WEBSITE_FILE_LINK_WEBSITE_LINK_TYPE,
|
|
223
|
+
d: encodeWebsiteFileLinkToWebsiteLinkEncodedData(input)
|
|
224
|
+
};
|
|
159
225
|
}
|
|
160
226
|
function websiteLinkToWebsiteLinkFile(input) {
|
|
161
|
-
|
|
162
|
-
|
|
227
|
+
const encodedData = input.d;
|
|
228
|
+
return decodeWebsiteLinkEncodedDataToWebsiteFileLink(encodedData);
|
|
163
229
|
}
|
|
164
230
|
const WEBSITE_FILE_LINK_ENCODE_SEPARATOR = '|';
|
|
165
231
|
function encodeWebsiteFileLinkToWebsiteLinkEncodedData(input) {
|
|
166
|
-
|
|
167
|
-
|
|
232
|
+
const encoded = [input.type, input.mime, input.data, input.name].map((x) => x || '').join(WEBSITE_FILE_LINK_ENCODE_SEPARATOR);
|
|
233
|
+
return encoded;
|
|
168
234
|
}
|
|
169
235
|
function decodeWebsiteLinkEncodedDataToWebsiteFileLink(input) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
236
|
+
const [type, mime, data, name] = splitJoinRemainder(input, WEBSITE_FILE_LINK_ENCODE_SEPARATOR, 4);
|
|
237
|
+
return filterFalsyAndEmptyValues({
|
|
238
|
+
type,
|
|
239
|
+
mime,
|
|
240
|
+
name,
|
|
241
|
+
data
|
|
242
|
+
});
|
|
177
243
|
}
|
|
178
244
|
|
|
179
245
|
/**
|
|
@@ -183,193 +249,194 @@ function decodeWebsiteLinkEncodedDataToWebsiteFileLink(input) {
|
|
|
183
249
|
* - https://facebook.com/facebook
|
|
184
250
|
*/
|
|
185
251
|
const WEBSITE_LINK_ISOLATE_BASE_URL_PROFILE_ID = isolateWebsitePathFunction({
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
252
|
+
isolatePathComponents: 0,
|
|
253
|
+
removeTrailingSlash: true,
|
|
254
|
+
removeQueryParameters: true
|
|
189
255
|
});
|
|
190
256
|
function usernameFromUsernameOrWebsiteWithBaseUrlUsername(input, prefix) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
257
|
+
const username = toRelativeSlashPathStartType(WEBSITE_LINK_ISOLATE_BASE_URL_PROFILE_ID(usernameOrWebsiteUrlToWebsiteUrl(input)));
|
|
258
|
+
if (prefix) {
|
|
259
|
+
return addPrefix(prefix, username);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
return username;
|
|
263
|
+
}
|
|
197
264
|
}
|
|
198
265
|
function usernameFromUsernameOrWebsiteWithOneOffBaseUrlUsername(input, isolateFn) {
|
|
199
|
-
|
|
266
|
+
return toRelativeSlashPathStartType(isolateFn(usernameOrWebsiteUrlToWebsiteUrl(input)));
|
|
200
267
|
}
|
|
201
268
|
function usernameOrWebsiteUrlToWebsiteUrl(input) {
|
|
202
|
-
|
|
269
|
+
return hasWebsiteDomain(input) ? input : toAbsoluteSlashPathStartType(removeHttpFromUrl(input));
|
|
203
270
|
}
|
|
204
271
|
// MARK: Website
|
|
205
272
|
const WEBSITE_URL_WEBSITE_LINK_TYPE = 'w';
|
|
206
273
|
function websiteUrlToWebsiteLink(input) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
274
|
+
return {
|
|
275
|
+
t: WEBSITE_URL_WEBSITE_LINK_TYPE,
|
|
276
|
+
d: removeHttpFromUrl(input) // website urls are stored as-is without http/https
|
|
277
|
+
};
|
|
211
278
|
}
|
|
212
279
|
// MARK: Email
|
|
213
280
|
const EMAIL_URL_WEBSITE_LINK_TYPE = 'e';
|
|
214
281
|
function emailAddressToWebsiteLink(input) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
282
|
+
return {
|
|
283
|
+
t: EMAIL_URL_WEBSITE_LINK_TYPE,
|
|
284
|
+
d: input
|
|
285
|
+
};
|
|
219
286
|
}
|
|
220
287
|
// MARK: Phone
|
|
221
288
|
const PHONE_URL_WEBSITE_LINK_TYPE = 'p';
|
|
222
289
|
function phoneNumberToWebsiteLink(input) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
290
|
+
return {
|
|
291
|
+
t: PHONE_URL_WEBSITE_LINK_TYPE,
|
|
292
|
+
d: input
|
|
293
|
+
};
|
|
227
294
|
}
|
|
228
295
|
// MARK: Facebook
|
|
229
296
|
const FACEBOOK_BASE_URL = `https://www.facebook.com`;
|
|
230
297
|
const FACEBOOK_WEBSITE_LINK_TYPE = 'fb';
|
|
231
298
|
function facebookProfileUrlToWebsiteLink(input) {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
299
|
+
return {
|
|
300
|
+
t: FACEBOOK_WEBSITE_LINK_TYPE,
|
|
301
|
+
d: usernameFromUsernameOrWebsiteWithBaseUrlUsername(input)
|
|
302
|
+
};
|
|
236
303
|
}
|
|
237
304
|
function facebookProfileUrl(profileId) {
|
|
238
|
-
|
|
305
|
+
return `${FACEBOOK_BASE_URL}/${profileId}`;
|
|
239
306
|
}
|
|
240
307
|
// MARK: Instagram
|
|
241
308
|
const INSTAGRAM_BASE_URL = `https://www.instagram.com`;
|
|
242
309
|
const INSTAGRAM_WEBSITE_LINK_TYPE = 'ig';
|
|
243
310
|
function instagramProfileUrlToWebsiteLink(input) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
311
|
+
return {
|
|
312
|
+
t: INSTAGRAM_WEBSITE_LINK_TYPE,
|
|
313
|
+
d: usernameFromUsernameOrWebsiteWithBaseUrlUsername(input)
|
|
314
|
+
};
|
|
248
315
|
}
|
|
249
316
|
function instagramProfileUrl(profileId) {
|
|
250
|
-
|
|
317
|
+
return `${INSTAGRAM_BASE_URL}/${profileId}`;
|
|
251
318
|
}
|
|
252
319
|
// MARK: Twitter
|
|
253
320
|
const TWITTER_BASE_URL = `https://www.twitter.com`;
|
|
254
321
|
const TWITTER_WEBSITE_LINK_TYPE = 'tw';
|
|
255
322
|
function twitterProfileUrlToWebsiteLink(input) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
323
|
+
return {
|
|
324
|
+
t: TWITTER_WEBSITE_LINK_TYPE,
|
|
325
|
+
d: usernameFromUsernameOrWebsiteWithBaseUrlUsername(input)
|
|
326
|
+
};
|
|
260
327
|
}
|
|
261
328
|
function twitterProfileUrl(profileId) {
|
|
262
|
-
|
|
329
|
+
return `${TWITTER_BASE_URL}/${profileId}`;
|
|
263
330
|
}
|
|
264
331
|
// MARK: Tiktok
|
|
265
332
|
const TIKTOK_BASE_URL = `https://tiktok.com`;
|
|
266
333
|
const TIKTOK_USERNAME_PREFIX = '@';
|
|
267
334
|
const TIKTOK_WEBSITE_LINK_TYPE = 'tt';
|
|
268
335
|
function tiktokProfileUrlToWebsiteLink(input) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
336
|
+
return {
|
|
337
|
+
t: TIKTOK_WEBSITE_LINK_TYPE,
|
|
338
|
+
d: usernameFromUsernameOrWebsiteWithBaseUrlUsername(input, TIKTOK_USERNAME_PREFIX)
|
|
339
|
+
};
|
|
273
340
|
}
|
|
274
341
|
function tiktokProfileUrl(profileId) {
|
|
275
|
-
|
|
342
|
+
return `${TIKTOK_BASE_URL}/@${profileId}`;
|
|
276
343
|
}
|
|
277
344
|
// MARK: Snapchat
|
|
278
345
|
const SNAPCHAT_BASE_URL = `https://snapchat.com`;
|
|
279
346
|
const SNAPCHAT_WEBSITE_LINK_TYPE = 'sc';
|
|
280
347
|
const SNAPCHAT_WEBSITE_LINK_ISOLATE_PROFILE_ID = isolateWebsitePathFunction({
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
348
|
+
ignoredBasePath: 'add',
|
|
349
|
+
isolatePathComponents: 0,
|
|
350
|
+
removeTrailingSlash: true,
|
|
351
|
+
removeQueryParameters: true
|
|
285
352
|
});
|
|
286
353
|
function snapchatProfileUrlToWebsiteLink(input) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
354
|
+
return {
|
|
355
|
+
t: SNAPCHAT_WEBSITE_LINK_TYPE,
|
|
356
|
+
d: usernameFromUsernameOrWebsiteWithOneOffBaseUrlUsername(input, SNAPCHAT_WEBSITE_LINK_ISOLATE_PROFILE_ID)
|
|
357
|
+
};
|
|
291
358
|
}
|
|
292
359
|
function snapchatProfileUrl(profileId) {
|
|
293
|
-
|
|
360
|
+
return `${SNAPCHAT_BASE_URL}/add/${profileId}`;
|
|
294
361
|
}
|
|
295
362
|
// MARK: YouTube
|
|
296
363
|
const YOUTUBE_BASE_URL = `https://youtube.com`;
|
|
297
364
|
const YOUTUBE_WEBSITE_LINK_TYPE = 'yt';
|
|
298
365
|
const YOUTUBE_WEBSITE_LINK_ISOLATE_PROFILE_ID = isolateWebsitePathFunction({
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
366
|
+
ignoredBasePath: 'c',
|
|
367
|
+
isolatePathComponents: 0,
|
|
368
|
+
removeTrailingSlash: true,
|
|
369
|
+
removeQueryParameters: true
|
|
303
370
|
});
|
|
304
371
|
function youtubeProfileUrlToWebsiteLink(input) {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
372
|
+
return {
|
|
373
|
+
t: YOUTUBE_WEBSITE_LINK_TYPE,
|
|
374
|
+
d: usernameFromUsernameOrWebsiteWithOneOffBaseUrlUsername(input, YOUTUBE_WEBSITE_LINK_ISOLATE_PROFILE_ID)
|
|
375
|
+
};
|
|
309
376
|
}
|
|
310
377
|
function youtubeProfileUrl(profileId) {
|
|
311
|
-
|
|
378
|
+
return `${YOUTUBE_BASE_URL}/c/${profileId}`;
|
|
312
379
|
}
|
|
313
380
|
// MARK: PayPal
|
|
314
381
|
const PAYPAL_BASE_URL = `https://paypal.me`;
|
|
315
382
|
const PAYPAL_WEBSITE_LINK_TYPE = 'pp';
|
|
316
383
|
function paypalProfileUrlToWebsiteLink(input) {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
384
|
+
return {
|
|
385
|
+
t: PAYPAL_WEBSITE_LINK_TYPE,
|
|
386
|
+
d: usernameFromUsernameOrWebsiteWithBaseUrlUsername(input)
|
|
387
|
+
};
|
|
321
388
|
}
|
|
322
389
|
function paypalProfileUrl(profileId) {
|
|
323
|
-
|
|
390
|
+
return `${PAYPAL_BASE_URL}/${profileId}`;
|
|
324
391
|
}
|
|
325
392
|
// MARK: Cashapp
|
|
326
393
|
const CASHAPP_BASE_URL = `https://cash.app`;
|
|
327
394
|
const CASHAPP_USERNAME_PREFIX = '$';
|
|
328
395
|
const CASHAPP_WEBSITE_LINK_TYPE = 'ca';
|
|
329
396
|
function cashappProfileUrlToWebsiteLink(input) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
397
|
+
return {
|
|
398
|
+
t: CASHAPP_WEBSITE_LINK_TYPE,
|
|
399
|
+
d: usernameFromUsernameOrWebsiteWithBaseUrlUsername(input, CASHAPP_USERNAME_PREFIX)
|
|
400
|
+
};
|
|
334
401
|
}
|
|
335
402
|
function cashappProfileUrl(profileId) {
|
|
336
|
-
|
|
403
|
+
return `${CASHAPP_BASE_URL}/$${profileId}`;
|
|
337
404
|
}
|
|
338
405
|
// MARK: Venmo
|
|
339
406
|
const VENMO_BASE_URL = `https://account.venmo.com`;
|
|
340
407
|
const VENMO_WEBSITE_LINK_TYPE = 'vn';
|
|
341
408
|
const VENMO_WEBSITE_LINK_ISOLATE_PROFILE_ID = isolateWebsitePathFunction({
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
409
|
+
ignoredBasePath: 'u',
|
|
410
|
+
isolatePathComponents: 0,
|
|
411
|
+
removeTrailingSlash: true,
|
|
412
|
+
removeQueryParameters: true
|
|
346
413
|
});
|
|
347
414
|
function venmoProfileUrlToWebsiteLink(input) {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
415
|
+
return {
|
|
416
|
+
t: VENMO_WEBSITE_LINK_TYPE,
|
|
417
|
+
d: usernameFromUsernameOrWebsiteWithOneOffBaseUrlUsername(input, VENMO_WEBSITE_LINK_ISOLATE_PROFILE_ID)
|
|
418
|
+
};
|
|
352
419
|
}
|
|
353
420
|
function venmoProfileUrl(profileId) {
|
|
354
|
-
|
|
421
|
+
return `${VENMO_BASE_URL}/u/${profileId}`;
|
|
355
422
|
}
|
|
356
423
|
// MARK: Spotify
|
|
357
424
|
const SPOTIFY_BASE_URL = `https://open.spotify.com/`;
|
|
358
425
|
const SPOTIFY_WEBSITE_LINK_TYPE = 'sp';
|
|
359
426
|
const SPOTIFY_WEBSITE_LINK_ISOLATE_PROFILE_ID = isolateWebsitePathFunction({
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
427
|
+
ignoredBasePath: 'user',
|
|
428
|
+
isolatePathComponents: 0,
|
|
429
|
+
removeTrailingSlash: true,
|
|
430
|
+
removeQueryParameters: true
|
|
364
431
|
});
|
|
365
432
|
function spotifyProfileUrlToWebsiteLink(input) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
433
|
+
return {
|
|
434
|
+
t: SPOTIFY_WEBSITE_LINK_TYPE,
|
|
435
|
+
d: usernameFromUsernameOrWebsiteWithOneOffBaseUrlUsername(input, SPOTIFY_WEBSITE_LINK_ISOLATE_PROFILE_ID)
|
|
436
|
+
};
|
|
370
437
|
}
|
|
371
438
|
function spotifyProfileUrl(profileId) {
|
|
372
|
-
|
|
439
|
+
return `${SPOTIFY_BASE_URL}/user/${profileId}`;
|
|
373
440
|
}
|
|
374
441
|
|
|
375
442
|
const GRANTED_SYS_ADMIN_ROLE_KEY = 'sysadmin';
|
|
@@ -382,7 +449,7 @@ const GRANTED_ADMIN_ROLE_KEY = 'admin';
|
|
|
382
449
|
* @returns
|
|
383
450
|
*/
|
|
384
451
|
function isGrantedAdminLevelRole(role) {
|
|
385
|
-
|
|
452
|
+
return role === GRANTED_ADMIN_ROLE_KEY || role === GRANTED_OWNER_ROLE_KEY;
|
|
386
453
|
}
|
|
387
454
|
const GRANTED_READ_ROLE_KEY = 'read';
|
|
388
455
|
const GRANTED_UPDATE_ROLE_KEY = 'update';
|
|
@@ -390,20 +457,20 @@ const GRANTED_DELETE_ROLE_KEY = 'delete';
|
|
|
390
457
|
const FULL_ACCESS_ROLE_KEY = '__FULL__';
|
|
391
458
|
const NO_ACCESS_ROLE_KEY = '__EMPTY__';
|
|
392
459
|
function noAccessRoleMap() {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
460
|
+
return {
|
|
461
|
+
[NO_ACCESS_ROLE_KEY]: true
|
|
462
|
+
};
|
|
396
463
|
}
|
|
397
464
|
function isNoAccessRoleMap(input) {
|
|
398
|
-
|
|
465
|
+
return input[NO_ACCESS_ROLE_KEY] === true;
|
|
399
466
|
}
|
|
400
467
|
function fullAccessRoleMap() {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
468
|
+
return {
|
|
469
|
+
[FULL_ACCESS_ROLE_KEY]: true
|
|
470
|
+
};
|
|
404
471
|
}
|
|
405
472
|
function isFullAccessRoleMap(input) {
|
|
406
|
-
|
|
473
|
+
return input[FULL_ACCESS_ROLE_KEY] === true;
|
|
407
474
|
}
|
|
408
475
|
/**
|
|
409
476
|
* Creates a GrantedRoleMapReader.
|
|
@@ -412,61 +479,63 @@ function isFullAccessRoleMap(input) {
|
|
|
412
479
|
* @returns
|
|
413
480
|
*/
|
|
414
481
|
function grantedRoleMapReader(map) {
|
|
415
|
-
|
|
482
|
+
return new GrantedRoleMapReaderInstance(map);
|
|
416
483
|
}
|
|
417
484
|
class GrantedRoleMapReaderInstance {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
hasNoAccess() {
|
|
423
|
-
return this._map[NO_ACCESS_ROLE_KEY];
|
|
424
|
-
}
|
|
425
|
-
truthMap(input) {
|
|
426
|
-
const result = {};
|
|
427
|
-
forEachKeyValue(input, {
|
|
428
|
-
forEach: ([role, value]) => {
|
|
429
|
-
if (this.hasRole(role)) {
|
|
430
|
-
result[role] = value;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
});
|
|
434
|
-
return result;
|
|
435
|
-
}
|
|
436
|
-
hasRole(role) {
|
|
437
|
-
return this.hasRoles('any', role);
|
|
438
|
-
}
|
|
439
|
-
hasRoles(setIncludes, inputRoles) {
|
|
440
|
-
if (this._map[FULL_ACCESS_ROLE_KEY]) {
|
|
441
|
-
return true;
|
|
442
|
-
} else {
|
|
443
|
-
return this.containsRoles(setIncludes, inputRoles);
|
|
485
|
+
_map;
|
|
486
|
+
constructor(map) {
|
|
487
|
+
this._map = map;
|
|
444
488
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
const roles = iterableToArray(inputRoles);
|
|
448
|
-
if (setIncludes === 'any') {
|
|
449
|
-
return this.containsAnyRole(roles);
|
|
450
|
-
} else {
|
|
451
|
-
return this.containsEachRole(roles);
|
|
489
|
+
hasNoAccess() {
|
|
490
|
+
return this._map[NO_ACCESS_ROLE_KEY];
|
|
452
491
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
492
|
+
truthMap(input) {
|
|
493
|
+
const result = {};
|
|
494
|
+
forEachKeyValue(input, {
|
|
495
|
+
forEach: ([role, value]) => {
|
|
496
|
+
if (this.hasRole(role)) {
|
|
497
|
+
result[role] = value;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
return result;
|
|
502
|
+
}
|
|
503
|
+
hasRole(role) {
|
|
504
|
+
return this.hasRoles('any', role);
|
|
505
|
+
}
|
|
506
|
+
hasRoles(setIncludes, inputRoles) {
|
|
507
|
+
if (this._map[FULL_ACCESS_ROLE_KEY]) {
|
|
508
|
+
return true;
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
return this.containsRoles(setIncludes, inputRoles);
|
|
512
|
+
}
|
|
459
513
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
514
|
+
containsRoles(setIncludes, inputRoles) {
|
|
515
|
+
const roles = iterableToArray(inputRoles);
|
|
516
|
+
if (setIncludes === 'any') {
|
|
517
|
+
return this.containsAnyRole(roles);
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
return this.containsEachRole(roles);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
containsAnyRole(roles) {
|
|
524
|
+
for (const role of roles) {
|
|
525
|
+
if (this._map[role]) {
|
|
526
|
+
return true;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
465
529
|
return false;
|
|
466
|
-
}
|
|
467
530
|
}
|
|
468
|
-
|
|
469
|
-
|
|
531
|
+
containsEachRole(roles) {
|
|
532
|
+
for (const role of roles) {
|
|
533
|
+
if (!this._map[role]) {
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return true;
|
|
538
|
+
}
|
|
470
539
|
}
|
|
471
540
|
/**
|
|
472
541
|
* Converts the input array of roles to a GrantedRoleKeysMap.
|
|
@@ -475,74 +544,77 @@ class GrantedRoleMapReaderInstance {
|
|
|
475
544
|
* @returns
|
|
476
545
|
*/
|
|
477
546
|
function grantedRoleKeysMapFromArray(roles, value = true) {
|
|
478
|
-
|
|
547
|
+
return arrayToObject(roles, (x) => x, () => value);
|
|
479
548
|
}
|
|
480
549
|
|
|
481
550
|
function noAccessContextGrantedModelRoles(context, data) {
|
|
482
|
-
|
|
551
|
+
return contextGrantedModelRoles(context, data, noAccessRoleMap());
|
|
483
552
|
}
|
|
484
553
|
function fullAccessGrantedModelRoles(context, data) {
|
|
485
|
-
|
|
554
|
+
return contextGrantedModelRoles(context, data, fullAccessRoleMap());
|
|
486
555
|
}
|
|
487
556
|
function contextGrantedModelRoles(context, data, roles) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
557
|
+
return {
|
|
558
|
+
data,
|
|
559
|
+
context,
|
|
560
|
+
roleMap: roles
|
|
561
|
+
};
|
|
493
562
|
}
|
|
494
563
|
|
|
495
564
|
/**
|
|
496
565
|
* Abstract ModelPermissionService implementation.
|
|
497
566
|
*/
|
|
498
567
|
class AbstractModelPermissionService {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
}
|
|
503
|
-
get modelLoader() {
|
|
504
|
-
return this._modelLoader;
|
|
505
|
-
}
|
|
506
|
-
async roleMapForKeyContext(key, context) {
|
|
507
|
-
const model = await this.modelLoader.loadModelForKey(key, context);
|
|
508
|
-
let result;
|
|
509
|
-
if (model != null) {
|
|
510
|
-
result = await this.roleMapForModelContext(model, context);
|
|
511
|
-
} else {
|
|
512
|
-
result = noAccessContextGrantedModelRoles(context);
|
|
568
|
+
_modelLoader;
|
|
569
|
+
constructor(modelLoader) {
|
|
570
|
+
this._modelLoader = modelLoader;
|
|
513
571
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
572
|
+
get modelLoader() {
|
|
573
|
+
return this._modelLoader;
|
|
574
|
+
}
|
|
575
|
+
async roleMapForKeyContext(key, context) {
|
|
576
|
+
const model = await this.modelLoader.loadModelForKey(key, context);
|
|
577
|
+
let result;
|
|
578
|
+
if (model != null) {
|
|
579
|
+
result = await this.roleMapForModelContext(model, context);
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
result = noAccessContextGrantedModelRoles(context);
|
|
583
|
+
}
|
|
584
|
+
return result;
|
|
585
|
+
}
|
|
586
|
+
async roleMapForModelContext(model, context) {
|
|
587
|
+
const output = await this.outputForModel(model, context);
|
|
588
|
+
let result;
|
|
589
|
+
if (output != null && this.isUsableOutputForRoles(output, context)) {
|
|
590
|
+
result = await this.getRoleMapForOutput(output, context, model);
|
|
591
|
+
}
|
|
592
|
+
else {
|
|
593
|
+
result = noAccessContextGrantedModelRoles(context, output);
|
|
594
|
+
}
|
|
595
|
+
return result;
|
|
596
|
+
}
|
|
597
|
+
async getRoleMapForOutput(output, context, model) {
|
|
598
|
+
const roleMap = await this.roleMapForModel(output, context, model);
|
|
599
|
+
return contextGrantedModelRoles(context, output, roleMap);
|
|
600
|
+
}
|
|
601
|
+
isUsableOutputForRoles(output, context) {
|
|
602
|
+
return true; // can override in parent functions to further filter roles.
|
|
523
603
|
}
|
|
524
|
-
return result;
|
|
525
|
-
}
|
|
526
|
-
async getRoleMapForOutput(output, context, model) {
|
|
527
|
-
const roleMap = await this.roleMapForModel(output, context, model);
|
|
528
|
-
return contextGrantedModelRoles(context, output, roleMap);
|
|
529
|
-
}
|
|
530
|
-
isUsableOutputForRoles(output, context) {
|
|
531
|
-
return true; // can override in parent functions to further filter roles.
|
|
532
|
-
}
|
|
533
604
|
}
|
|
534
605
|
|
|
535
606
|
function syncEntityCommonTypeIdPairFactory(commonType) {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
607
|
+
return (input) => {
|
|
608
|
+
if (typeof input === 'string') {
|
|
609
|
+
return {
|
|
610
|
+
commonType,
|
|
611
|
+
commonId: input
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
else {
|
|
615
|
+
return input;
|
|
616
|
+
}
|
|
617
|
+
};
|
|
546
618
|
}
|
|
547
619
|
/**
|
|
548
620
|
* Creates a SyncEntityFactory.
|
|
@@ -551,496 +623,323 @@ function syncEntityCommonTypeIdPairFactory(commonType) {
|
|
|
551
623
|
* @returns
|
|
552
624
|
*/
|
|
553
625
|
function syncEntityFactory(config) {
|
|
554
|
-
|
|
555
|
-
idFactory
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
return {
|
|
566
|
-
commonType,
|
|
567
|
-
commonId,
|
|
568
|
-
id,
|
|
569
|
-
sourceInfo
|
|
626
|
+
const { idFactory: inputIdFactory, sourceInfo } = config;
|
|
627
|
+
const idFactory = inputIdFactory ?? MAP_IDENTITY;
|
|
628
|
+
return (input) => {
|
|
629
|
+
const { commonType, commonId } = input;
|
|
630
|
+
const id = idFactory(commonId);
|
|
631
|
+
return {
|
|
632
|
+
commonType,
|
|
633
|
+
commonId,
|
|
634
|
+
id,
|
|
635
|
+
sourceInfo
|
|
636
|
+
};
|
|
570
637
|
};
|
|
571
|
-
};
|
|
572
638
|
}
|
|
573
639
|
|
|
574
|
-
var makeError = {exports: {}};
|
|
575
|
-
|
|
576
|
-
(function (module, exports$1) {
|
|
577
|
-
|
|
578
|
-
// ===================================================================
|
|
579
|
-
|
|
580
|
-
var construct = typeof Reflect !== "undefined" ? Reflect.construct : undefined;
|
|
581
|
-
var defineProperty = Object.defineProperty;
|
|
582
|
-
|
|
583
|
-
// -------------------------------------------------------------------
|
|
584
|
-
|
|
585
|
-
var captureStackTrace = Error.captureStackTrace;
|
|
586
|
-
if (captureStackTrace === undefined) {
|
|
587
|
-
captureStackTrace = function captureStackTrace(error) {
|
|
588
|
-
var container = new Error();
|
|
589
|
-
|
|
590
|
-
defineProperty(error, "stack", {
|
|
591
|
-
configurable: true,
|
|
592
|
-
get: function getStack() {
|
|
593
|
-
var stack = container.stack;
|
|
594
|
-
|
|
595
|
-
// Replace property with value for faster future accesses.
|
|
596
|
-
defineProperty(this, "stack", {
|
|
597
|
-
configurable: true,
|
|
598
|
-
value: stack,
|
|
599
|
-
writable: true,
|
|
600
|
-
});
|
|
601
|
-
|
|
602
|
-
return stack;
|
|
603
|
-
},
|
|
604
|
-
set: function setStack(stack) {
|
|
605
|
-
defineProperty(error, "stack", {
|
|
606
|
-
configurable: true,
|
|
607
|
-
value: stack,
|
|
608
|
-
writable: true,
|
|
609
|
-
});
|
|
610
|
-
},
|
|
611
|
-
});
|
|
612
|
-
};
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
// -------------------------------------------------------------------
|
|
616
|
-
|
|
617
|
-
function BaseError(message) {
|
|
618
|
-
if (message !== undefined) {
|
|
619
|
-
defineProperty(this, "message", {
|
|
620
|
-
configurable: true,
|
|
621
|
-
value: message,
|
|
622
|
-
writable: true,
|
|
623
|
-
});
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
var cname = this.constructor.name;
|
|
627
|
-
if (cname !== undefined && cname !== this.name) {
|
|
628
|
-
defineProperty(this, "name", {
|
|
629
|
-
configurable: true,
|
|
630
|
-
value: cname,
|
|
631
|
-
writable: true,
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
captureStackTrace(this, this.constructor);
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
BaseError.prototype = Object.create(Error.prototype, {
|
|
639
|
-
// See: https://github.com/JsCommunity/make-error/issues/4
|
|
640
|
-
constructor: {
|
|
641
|
-
configurable: true,
|
|
642
|
-
value: BaseError,
|
|
643
|
-
writable: true,
|
|
644
|
-
},
|
|
645
|
-
});
|
|
646
|
-
|
|
647
|
-
// -------------------------------------------------------------------
|
|
648
|
-
|
|
649
|
-
// Sets the name of a function if possible (depends of the JS engine).
|
|
650
|
-
var setFunctionName = (function() {
|
|
651
|
-
function setFunctionName(fn, name) {
|
|
652
|
-
return defineProperty(fn, "name", {
|
|
653
|
-
configurable: true,
|
|
654
|
-
value: name,
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
try {
|
|
658
|
-
var f = function() {};
|
|
659
|
-
setFunctionName(f, "foo");
|
|
660
|
-
if (f.name === "foo") {
|
|
661
|
-
return setFunctionName;
|
|
662
|
-
}
|
|
663
|
-
} catch (_) {}
|
|
664
|
-
})();
|
|
665
|
-
|
|
666
|
-
// -------------------------------------------------------------------
|
|
667
|
-
|
|
668
|
-
function makeError(constructor, super_) {
|
|
669
|
-
if (super_ == null || super_ === Error) {
|
|
670
|
-
super_ = BaseError;
|
|
671
|
-
} else if (typeof super_ !== "function") {
|
|
672
|
-
throw new TypeError("super_ should be a function");
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
var name;
|
|
676
|
-
if (typeof constructor === "string") {
|
|
677
|
-
name = constructor;
|
|
678
|
-
constructor =
|
|
679
|
-
construct !== undefined
|
|
680
|
-
? function() {
|
|
681
|
-
return construct(super_, arguments, this.constructor);
|
|
682
|
-
}
|
|
683
|
-
: function() {
|
|
684
|
-
super_.apply(this, arguments);
|
|
685
|
-
};
|
|
686
|
-
|
|
687
|
-
// If the name can be set, do it once and for all.
|
|
688
|
-
if (setFunctionName !== undefined) {
|
|
689
|
-
setFunctionName(constructor, name);
|
|
690
|
-
name = undefined;
|
|
691
|
-
}
|
|
692
|
-
} else if (typeof constructor !== "function") {
|
|
693
|
-
throw new TypeError("constructor should be either a string or a function");
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
// Also register the super constructor also as `constructor.super_` just
|
|
697
|
-
// like Node's `util.inherits()`.
|
|
698
|
-
//
|
|
699
|
-
// eslint-disable-next-line dot-notation
|
|
700
|
-
constructor.super_ = constructor["super"] = super_;
|
|
701
|
-
|
|
702
|
-
var properties = {
|
|
703
|
-
constructor: {
|
|
704
|
-
configurable: true,
|
|
705
|
-
value: constructor,
|
|
706
|
-
writable: true,
|
|
707
|
-
},
|
|
708
|
-
};
|
|
709
|
-
|
|
710
|
-
// If the name could not be set on the constructor, set it on the
|
|
711
|
-
// prototype.
|
|
712
|
-
if (name !== undefined) {
|
|
713
|
-
properties.name = {
|
|
714
|
-
configurable: true,
|
|
715
|
-
value: name,
|
|
716
|
-
writable: true,
|
|
717
|
-
};
|
|
718
|
-
}
|
|
719
|
-
constructor.prototype = Object.create(super_.prototype, properties);
|
|
720
|
-
|
|
721
|
-
return constructor;
|
|
722
|
-
}
|
|
723
|
-
exports$1 = module.exports = makeError;
|
|
724
|
-
exports$1.BaseError = BaseError;
|
|
725
|
-
} (makeError, makeError.exports));
|
|
726
|
-
|
|
727
|
-
var makeErrorExports = makeError.exports;
|
|
728
|
-
|
|
729
640
|
/**
|
|
730
641
|
* Error thrown when the common type is not known/registered.
|
|
731
642
|
*/
|
|
732
|
-
class UnregisteredSyncEntityCommonTypeError extends
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
643
|
+
class UnregisteredSyncEntityCommonTypeError extends BaseError {
|
|
644
|
+
commonType;
|
|
645
|
+
constructor(commonType) {
|
|
646
|
+
super(`The common type "${commonType}" is not registered.`);
|
|
647
|
+
this.commonType = commonType;
|
|
648
|
+
}
|
|
738
649
|
}
|
|
739
650
|
/**
|
|
740
651
|
* Error thrown when no primary sync source is found for an entity.
|
|
741
652
|
*/
|
|
742
|
-
class NoPrimarySyncSourceError extends
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
653
|
+
class NoPrimarySyncSourceError extends BaseError {
|
|
654
|
+
entity;
|
|
655
|
+
constructor(entity) {
|
|
656
|
+
super(`No primary sync source found for entity "${entity.commonType}:${entity.commonId}".`);
|
|
657
|
+
this.entity = entity;
|
|
658
|
+
}
|
|
748
659
|
}
|
|
749
660
|
/**
|
|
750
661
|
* Error thrown when multiple primary sync sources are found for an entity.
|
|
751
662
|
*/
|
|
752
|
-
class MultiplePrimarySyncSourceError extends
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
663
|
+
class MultiplePrimarySyncSourceError extends BaseError {
|
|
664
|
+
entity;
|
|
665
|
+
constructor(entity) {
|
|
666
|
+
super(`Multiple primary sync sources found for entity "${entity.commonType}:${entity.commonId}".`);
|
|
667
|
+
this.entity = entity;
|
|
668
|
+
}
|
|
758
669
|
}
|
|
759
670
|
/**
|
|
760
671
|
* Error thrown when a synchronization fails for an entity.
|
|
761
672
|
*/
|
|
762
|
-
class SynchronizationFailedError extends
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
673
|
+
class SynchronizationFailedError extends BaseError {
|
|
674
|
+
entity;
|
|
675
|
+
error;
|
|
676
|
+
constructor(entity, error) {
|
|
677
|
+
super(`Synchronization failed for entity "${entity.commonType}:${entity.commonId}". Error: ${error}`);
|
|
678
|
+
this.entity = entity;
|
|
679
|
+
this.error = error;
|
|
680
|
+
}
|
|
770
681
|
}
|
|
771
682
|
|
|
772
683
|
function syncEntitySynchronizer(config) {
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
684
|
+
const map = new Map(config.commonTypeSynchronizers.map((x) => [x.commonType, x]));
|
|
685
|
+
const commonTypes = Array.from(map.keys());
|
|
686
|
+
const commonTypeSynchronizer = (input) => {
|
|
687
|
+
const synchronizer = map.get(input);
|
|
688
|
+
if (!synchronizer) {
|
|
689
|
+
throw new UnregisteredSyncEntityCommonTypeError(input);
|
|
690
|
+
}
|
|
691
|
+
return synchronizer;
|
|
692
|
+
};
|
|
693
|
+
return {
|
|
694
|
+
commonTypes,
|
|
695
|
+
commonTypeSynchronizer,
|
|
696
|
+
synchronizeInstance: (input) => {
|
|
697
|
+
const synchronizer = commonTypeSynchronizer(input.commonType);
|
|
698
|
+
return synchronizer.synchronizeInstance(input);
|
|
699
|
+
}
|
|
700
|
+
};
|
|
790
701
|
}
|
|
791
702
|
|
|
792
703
|
function basicSyncEntityCommonTypeSynchronizerInstanceFactory(config) {
|
|
793
|
-
|
|
794
|
-
commonType
|
|
795
|
-
sources,
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
} = config;
|
|
799
|
-
const syncEntityCommonTypeIdPairForType = syncEntityCommonTypeIdPairFactory(commonType);
|
|
800
|
-
const sourcesByContextType = makeValuesGroupMap(sources, x => x.contextType);
|
|
801
|
-
const allGlobalSources = sourcesByContextType.get('global') ?? [];
|
|
802
|
-
const allContextSources = sourcesByContextType.get('context') ?? [];
|
|
803
|
-
/**
|
|
804
|
-
* Loads the relevant sources for the given entity and context.
|
|
805
|
-
*
|
|
806
|
-
* @param entitySourceContext The contextual information for the entity.
|
|
807
|
-
* @returns The relevant sources for the entity.
|
|
808
|
-
*/
|
|
809
|
-
function loadSources(entityCommonTypeIdPair, entitySourceContext) {
|
|
810
|
-
const {
|
|
811
|
-
globalSources,
|
|
812
|
-
contextSources
|
|
813
|
-
} = entitySourceContext;
|
|
814
|
-
// load/filter global sources
|
|
815
|
-
const globalMap = new Map(globalSources.map(x => {
|
|
816
|
-
let sourceId;
|
|
817
|
-
let flowType;
|
|
818
|
-
if (typeof x === 'string') {
|
|
819
|
-
sourceId = x;
|
|
820
|
-
flowType = 'unset';
|
|
821
|
-
} else {
|
|
822
|
-
sourceId = x.sourceId;
|
|
823
|
-
flowType = x.flowType;
|
|
824
|
-
}
|
|
825
|
-
return [sourceId, {
|
|
826
|
-
sourceId,
|
|
827
|
-
flowType
|
|
828
|
-
}];
|
|
829
|
-
}));
|
|
830
|
-
const relevantGlobalSources = filterMaybeArrayValues(allGlobalSources.map(x => {
|
|
831
|
-
const sourceContext = globalMap.get(x.info.id);
|
|
832
|
-
let result;
|
|
833
|
-
if (sourceContext != null) {
|
|
834
|
-
result = {
|
|
835
|
-
entityCommonTypeIdPair,
|
|
836
|
-
flowType: sourceContext.flowType ?? x.defaultFlowType ?? 'unset',
|
|
837
|
-
source: x
|
|
838
|
-
};
|
|
839
|
-
}
|
|
840
|
-
return result;
|
|
841
|
-
}));
|
|
842
|
-
// load/filter context sources
|
|
843
|
-
const contextMap = new Map(contextSources.map(x => [x.sourceId, x]));
|
|
844
|
-
const relevantContextSources = filterMaybeArrayValues(allContextSources.map(x => {
|
|
845
|
-
const sourceContext = contextMap.get(x.info.id);
|
|
846
|
-
let result;
|
|
847
|
-
if (sourceContext != null) {
|
|
848
|
-
const flowType = sourceContext.flowType ?? x.defaultFlowType ?? 'unset';
|
|
849
|
-
result = {
|
|
850
|
-
entityCommonTypeIdPair,
|
|
851
|
-
flowType,
|
|
852
|
-
source: x,
|
|
853
|
-
context: sourceContext
|
|
854
|
-
};
|
|
855
|
-
}
|
|
856
|
-
return result;
|
|
857
|
-
}));
|
|
858
|
-
const allSources = [...relevantGlobalSources, ...relevantContextSources];
|
|
859
|
-
// sort by order, with primary first
|
|
860
|
-
allSources.sort(sortByNumberFunction(x => {
|
|
861
|
-
let result;
|
|
862
|
-
switch (x.flowType) {
|
|
863
|
-
case 'primary':
|
|
864
|
-
result = 1;
|
|
865
|
-
break;
|
|
866
|
-
case 'secondary':
|
|
867
|
-
result = 2;
|
|
868
|
-
break;
|
|
869
|
-
case 'unset':
|
|
870
|
-
default:
|
|
871
|
-
result = 3;
|
|
872
|
-
break;
|
|
873
|
-
}
|
|
874
|
-
return result;
|
|
875
|
-
}));
|
|
876
|
-
return allSources;
|
|
877
|
-
}
|
|
878
|
-
const synchronizeInstance = async input => {
|
|
879
|
-
const syncEntityCommonTypeIdPair = syncEntityCommonTypeIdPairForType(input);
|
|
880
|
-
const _loadRelevantSources = async () => {
|
|
881
|
-
const entitySourceContext = await entitySourceContextLoader(syncEntityCommonTypeIdPair);
|
|
882
|
-
const relevantSources = loadSources(syncEntityCommonTypeIdPair, entitySourceContext);
|
|
883
|
-
return relevantSources;
|
|
884
|
-
};
|
|
885
|
-
let loadRelevantSources;
|
|
886
|
-
if (dynamicSources) {
|
|
887
|
-
// if dynamic, reload each time and do not cache
|
|
888
|
-
loadRelevantSources = _loadRelevantSources;
|
|
889
|
-
} else {
|
|
890
|
-
// if not dynamic, make a cached getter
|
|
891
|
-
loadRelevantSources = cachedGetter(_loadRelevantSources);
|
|
892
|
-
}
|
|
704
|
+
const { commonType, sources, entitySourceContextLoader, dynamicSources = false } = config;
|
|
705
|
+
const syncEntityCommonTypeIdPairForType = syncEntityCommonTypeIdPairFactory(commonType);
|
|
706
|
+
const sourcesByContextType = makeValuesGroupMap(sources, (x) => x.contextType);
|
|
707
|
+
const allGlobalSources = sourcesByContextType.get('global') ?? [];
|
|
708
|
+
const allContextSources = sourcesByContextType.get('context') ?? [];
|
|
893
709
|
/**
|
|
894
|
-
*
|
|
710
|
+
* Loads the relevant sources for the given entity and context.
|
|
711
|
+
*
|
|
712
|
+
* @param entitySourceContext The contextual information for the entity.
|
|
713
|
+
* @returns The relevant sources for the entity.
|
|
895
714
|
*/
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
case 0:
|
|
906
|
-
throw new NoPrimarySyncSourceError(syncEntityCommonTypeIdPair);
|
|
907
|
-
case 1:
|
|
908
|
-
break;
|
|
909
|
-
default:
|
|
910
|
-
throw new MultiplePrimarySyncSourceError(syncEntityCommonTypeIdPair);
|
|
911
|
-
}
|
|
912
|
-
function synchronizeInstance(source, deleted) {
|
|
913
|
-
const [input, sourceInstance] = source;
|
|
914
|
-
const promise = deleted ? sourceInstance.synchronizeDelete() : sourceInstance.synchronize();
|
|
915
|
-
return promise.catch(error => {
|
|
916
|
-
const errorResult = {
|
|
917
|
-
type: 'error',
|
|
918
|
-
error,
|
|
919
|
-
entity: {
|
|
920
|
-
...syncEntityCommonTypeIdPair,
|
|
921
|
-
sourceInfo: input.source.info,
|
|
922
|
-
id: ''
|
|
715
|
+
function loadSources(entityCommonTypeIdPair, entitySourceContext) {
|
|
716
|
+
const { globalSources, contextSources } = entitySourceContext;
|
|
717
|
+
// load/filter global sources
|
|
718
|
+
const globalMap = new Map(globalSources.map((x) => {
|
|
719
|
+
let sourceId;
|
|
720
|
+
let flowType;
|
|
721
|
+
if (typeof x === 'string') {
|
|
722
|
+
sourceId = x;
|
|
723
|
+
flowType = 'unset';
|
|
923
724
|
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
725
|
+
else {
|
|
726
|
+
sourceId = x.sourceId;
|
|
727
|
+
flowType = x.flowType;
|
|
728
|
+
}
|
|
729
|
+
return [sourceId, { sourceId, flowType }];
|
|
730
|
+
}));
|
|
731
|
+
const relevantGlobalSources = filterMaybeArrayValues(allGlobalSources.map((x) => {
|
|
732
|
+
const sourceContext = globalMap.get(x.info.id);
|
|
733
|
+
let result;
|
|
734
|
+
if (sourceContext != null) {
|
|
735
|
+
result = {
|
|
736
|
+
entityCommonTypeIdPair,
|
|
737
|
+
flowType: sourceContext.flowType ?? x.defaultFlowType ?? 'unset',
|
|
738
|
+
source: x
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
return result;
|
|
742
|
+
}));
|
|
743
|
+
// load/filter context sources
|
|
744
|
+
const contextMap = new Map(contextSources.map((x) => [x.sourceId, x]));
|
|
745
|
+
const relevantContextSources = filterMaybeArrayValues(allContextSources.map((x) => {
|
|
746
|
+
const sourceContext = contextMap.get(x.info.id);
|
|
747
|
+
let result;
|
|
748
|
+
if (sourceContext != null) {
|
|
749
|
+
const flowType = sourceContext.flowType ?? x.defaultFlowType ?? 'unset';
|
|
750
|
+
result = {
|
|
751
|
+
entityCommonTypeIdPair,
|
|
752
|
+
flowType,
|
|
753
|
+
source: x,
|
|
754
|
+
context: sourceContext
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
return result;
|
|
758
|
+
}));
|
|
759
|
+
const allSources = [...relevantGlobalSources, ...relevantContextSources];
|
|
760
|
+
// sort by order, with primary first
|
|
761
|
+
allSources.sort(sortByNumberFunction((x) => {
|
|
762
|
+
let result;
|
|
763
|
+
switch (x.flowType) {
|
|
764
|
+
case 'primary':
|
|
765
|
+
result = 1;
|
|
766
|
+
break;
|
|
767
|
+
case 'secondary':
|
|
768
|
+
result = 2;
|
|
769
|
+
break;
|
|
770
|
+
case 'unset':
|
|
771
|
+
default:
|
|
772
|
+
result = 3;
|
|
773
|
+
break;
|
|
774
|
+
}
|
|
775
|
+
return result;
|
|
776
|
+
}));
|
|
777
|
+
return allSources;
|
|
778
|
+
}
|
|
779
|
+
const synchronizeInstance = async (input) => {
|
|
780
|
+
const syncEntityCommonTypeIdPair = syncEntityCommonTypeIdPairForType(input);
|
|
781
|
+
const _loadRelevantSources = async () => {
|
|
782
|
+
const entitySourceContext = await entitySourceContextLoader(syncEntityCommonTypeIdPair);
|
|
783
|
+
const relevantSources = loadSources(syncEntityCommonTypeIdPair, entitySourceContext);
|
|
784
|
+
return relevantSources;
|
|
785
|
+
};
|
|
786
|
+
let loadRelevantSources;
|
|
787
|
+
if (dynamicSources) {
|
|
788
|
+
// if dynamic, reload each time and do not cache
|
|
789
|
+
loadRelevantSources = _loadRelevantSources;
|
|
960
790
|
}
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
const replicaTaskResults = await performAsyncTasks(replicaSources, x => synchronizeInstance(x, primaryFlaggedDelete), {
|
|
965
|
-
sequential: false,
|
|
966
|
-
maxParallelTasks: 3
|
|
967
|
-
});
|
|
968
|
-
// add all the results
|
|
969
|
-
pushArrayItemsIntoArray(synchronizedEntityResults, replicaTaskResults.results.map(x => x[1]));
|
|
970
|
-
// compute final result
|
|
971
|
-
result = {
|
|
972
|
-
synchronizedEntityResults
|
|
973
|
-
};
|
|
791
|
+
else {
|
|
792
|
+
// if not dynamic, make a cached getter
|
|
793
|
+
loadRelevantSources = cachedGetter(_loadRelevantSources);
|
|
974
794
|
}
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
795
|
+
/**
|
|
796
|
+
* Performs the synchonization
|
|
797
|
+
*/
|
|
798
|
+
const synchronize = async (context) => {
|
|
799
|
+
const relevantSources = await loadRelevantSources();
|
|
800
|
+
const syncEntityInstances = await Promise.all(relevantSources.map((x) => x.source.syncEntityInstance(x).then((y) => [x, y])));
|
|
801
|
+
const sourcesByFlowType = makeValuesGroupMap(syncEntityInstances, (x) => x[0].flowType);
|
|
802
|
+
const primarySources = sourcesByFlowType.get('primary') ?? [];
|
|
803
|
+
const secondarySources = sourcesByFlowType.get('secondary') ?? [];
|
|
804
|
+
const replicaSources = sourcesByFlowType.get('replica') ?? [];
|
|
805
|
+
// assert primary sources count
|
|
806
|
+
switch (primarySources.length) {
|
|
807
|
+
case 0:
|
|
808
|
+
throw new NoPrimarySyncSourceError(syncEntityCommonTypeIdPair);
|
|
809
|
+
case 1:
|
|
810
|
+
break;
|
|
811
|
+
default:
|
|
812
|
+
throw new MultiplePrimarySyncSourceError(syncEntityCommonTypeIdPair);
|
|
813
|
+
}
|
|
814
|
+
function synchronizeInstance(source, deleted) {
|
|
815
|
+
const [input, sourceInstance] = source;
|
|
816
|
+
const promise = deleted ? sourceInstance.synchronizeDelete() : sourceInstance.synchronize();
|
|
817
|
+
return promise.catch((error) => {
|
|
818
|
+
const errorResult = {
|
|
819
|
+
type: 'error',
|
|
820
|
+
error,
|
|
821
|
+
entity: {
|
|
822
|
+
...syncEntityCommonTypeIdPair,
|
|
823
|
+
sourceInfo: input.source.info,
|
|
824
|
+
id: ''
|
|
825
|
+
}
|
|
826
|
+
};
|
|
827
|
+
return errorResult;
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
async function performSynchronizationOfSources(input) {
|
|
831
|
+
const { secondaryFlaggedDelete } = input;
|
|
832
|
+
let result;
|
|
833
|
+
// synchronize the primary source
|
|
834
|
+
const primarySource = primarySources[0];
|
|
835
|
+
const primarySyncResult = await synchronizeInstance(primarySource, secondaryFlaggedDelete ?? false);
|
|
836
|
+
const synchronizedEntityResults = [primarySyncResult];
|
|
837
|
+
let primaryFlaggedDelete = false;
|
|
838
|
+
switch (primarySyncResult.type) {
|
|
839
|
+
case 'deleted':
|
|
840
|
+
primaryFlaggedDelete = true;
|
|
841
|
+
break;
|
|
842
|
+
case 'failed':
|
|
843
|
+
case 'error':
|
|
844
|
+
throw new SynchronizationFailedError(syncEntityCommonTypeIdPair, primarySyncResult.error);
|
|
845
|
+
}
|
|
846
|
+
// synchronize all secondary sources, one after the other. If any secondary source returns deleted and the primary source was not flagged as deleted, then the synchronization will be restarted.
|
|
847
|
+
for (const secondarySource of secondarySources) {
|
|
848
|
+
const secondarySyncResult = await synchronizeInstance(secondarySource, primaryFlaggedDelete);
|
|
849
|
+
synchronizedEntityResults.push(secondarySyncResult);
|
|
850
|
+
switch (secondarySyncResult.type) {
|
|
851
|
+
case 'deleted':
|
|
852
|
+
if (primaryFlaggedDelete === false) {
|
|
853
|
+
break;
|
|
854
|
+
}
|
|
855
|
+
break;
|
|
856
|
+
case 'failed':
|
|
857
|
+
case 'error':
|
|
858
|
+
throw new SynchronizationFailedError(syncEntityCommonTypeIdPair, secondarySyncResult.error);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
// if result was already set, then it was completed in a recursive result
|
|
862
|
+
if (result == null) {
|
|
863
|
+
// synchronize all replica sources concurrently
|
|
864
|
+
const replicaTaskResults = await performAsyncTasks(replicaSources, (x) => synchronizeInstance(x, primaryFlaggedDelete), {
|
|
865
|
+
sequential: false,
|
|
866
|
+
maxParallelTasks: 3
|
|
867
|
+
});
|
|
868
|
+
// add all the results
|
|
869
|
+
pushArrayItemsIntoArray(synchronizedEntityResults, replicaTaskResults.results.map((x) => x[1]));
|
|
870
|
+
// compute final result
|
|
871
|
+
result = {
|
|
872
|
+
synchronizedEntityResults
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
return result;
|
|
876
|
+
}
|
|
877
|
+
const result = await performSynchronizationOfSources({ });
|
|
878
|
+
return {
|
|
879
|
+
targetPair: syncEntityCommonTypeIdPair,
|
|
880
|
+
entitiesSynchronized: result.synchronizedEntityResults
|
|
881
|
+
};
|
|
882
|
+
};
|
|
883
|
+
const instance = {
|
|
884
|
+
entityPair: syncEntityCommonTypeIdPair,
|
|
885
|
+
synchronize
|
|
886
|
+
};
|
|
887
|
+
return instance;
|
|
983
888
|
};
|
|
984
|
-
const
|
|
985
|
-
|
|
986
|
-
|
|
889
|
+
const result = {
|
|
890
|
+
commonType,
|
|
891
|
+
synchronizeInstance
|
|
987
892
|
};
|
|
988
|
-
return
|
|
989
|
-
};
|
|
990
|
-
const result = {
|
|
991
|
-
commonType,
|
|
992
|
-
synchronizeInstance
|
|
993
|
-
};
|
|
994
|
-
return result;
|
|
893
|
+
return result;
|
|
995
894
|
}
|
|
996
895
|
|
|
997
896
|
// MARK: String
|
|
998
897
|
function transformStringToBoolean(defaultValue) {
|
|
999
|
-
|
|
898
|
+
return (params) => stringToBoolean(params.value, defaultValue);
|
|
1000
899
|
}
|
|
1001
900
|
// MARK: Comma Separated Values
|
|
1002
901
|
function transformCommaSeparatedValueToArray(mapFn) {
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
902
|
+
return (params) => {
|
|
903
|
+
let result;
|
|
904
|
+
if (params.value) {
|
|
905
|
+
if (Array.isArray(params.value)) {
|
|
906
|
+
result = params.value;
|
|
907
|
+
}
|
|
908
|
+
else {
|
|
909
|
+
result = splitCommaSeparatedString(params.value, mapFn);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
return result;
|
|
913
|
+
};
|
|
1014
914
|
}
|
|
1015
|
-
const transformCommaSeparatedNumberValueToArray = transformCommaSeparatedValueToArray(x => Number(x));
|
|
1016
|
-
const transformCommaSeparatedStringValueToArray = transformCommaSeparatedValueToArray(x => x);
|
|
915
|
+
const transformCommaSeparatedNumberValueToArray = transformCommaSeparatedValueToArray((x) => Number(x));
|
|
916
|
+
const transformCommaSeparatedStringValueToArray = transformCommaSeparatedValueToArray((x) => x);
|
|
1017
917
|
|
|
1018
918
|
// MARK: Transform Annotations
|
|
1019
919
|
function TransformCommaSeparatedValueToArray(mapFn) {
|
|
1020
|
-
|
|
920
|
+
return Transform(transformCommaSeparatedValueToArray(mapFn));
|
|
1021
921
|
}
|
|
1022
922
|
const TransformCommaSeparatedStringValueToArray = () => Transform(transformCommaSeparatedStringValueToArray);
|
|
1023
923
|
const TransformCommaSeparatedNumberValueToArray = () => Transform(transformCommaSeparatedNumberValueToArray);
|
|
1024
924
|
const TransformStringValueToBoolean = () => Transform(transformStringToBoolean());
|
|
1025
925
|
|
|
1026
926
|
function transformAndValidateObject(config) {
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
};
|
|
1043
|
-
});
|
|
927
|
+
const transformToResult = transformAndValidateObjectResult(config);
|
|
928
|
+
const { handleValidationError } = config;
|
|
929
|
+
return (input, context) => transformToResult(input, context).then(async (x) => {
|
|
930
|
+
const object = x.object;
|
|
931
|
+
let result;
|
|
932
|
+
if (x.success) {
|
|
933
|
+
result = x.result;
|
|
934
|
+
}
|
|
935
|
+
else {
|
|
936
|
+
result = await handleValidationError(x.validationErrors);
|
|
937
|
+
}
|
|
938
|
+
return {
|
|
939
|
+
object,
|
|
940
|
+
result
|
|
941
|
+
};
|
|
942
|
+
});
|
|
1044
943
|
}
|
|
1045
944
|
/**
|
|
1046
945
|
* Creates a new TransformAndValidateObjectFactory.
|
|
@@ -1049,21 +948,17 @@ function transformAndValidateObject(config) {
|
|
|
1049
948
|
* @returns
|
|
1050
949
|
*/
|
|
1051
950
|
function transformAndValidateObjectFactory(defaults) {
|
|
1052
|
-
|
|
1053
|
-
handleValidationError
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
optionsForContext,
|
|
1063
|
-
defaultValidationOptions
|
|
951
|
+
const { handleValidationError: defaultHandleValidationError, optionsForContext, defaultValidationOptions } = defaults;
|
|
952
|
+
return (classType, fn, handleValidationError) => {
|
|
953
|
+
const config = {
|
|
954
|
+
classType,
|
|
955
|
+
fn,
|
|
956
|
+
handleValidationError: handleValidationError ?? defaultHandleValidationError,
|
|
957
|
+
optionsForContext,
|
|
958
|
+
defaultValidationOptions
|
|
959
|
+
};
|
|
960
|
+
return transformAndValidateObject(config);
|
|
1064
961
|
};
|
|
1065
|
-
return transformAndValidateObject(config);
|
|
1066
|
-
};
|
|
1067
962
|
}
|
|
1068
963
|
/**
|
|
1069
964
|
* 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.
|
|
@@ -1073,134 +968,113 @@ function transformAndValidateObjectFactory(defaults) {
|
|
|
1073
968
|
* @returns
|
|
1074
969
|
*/
|
|
1075
970
|
function transformAndValidateObjectResult(config) {
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
});
|
|
1099
|
-
if (validationErrors.length) {
|
|
1100
|
-
return {
|
|
1101
|
-
object,
|
|
1102
|
-
validationErrors,
|
|
1103
|
-
success: false
|
|
1104
|
-
};
|
|
1105
|
-
} else {
|
|
1106
|
-
const result = await fn(object);
|
|
1107
|
-
return {
|
|
1108
|
-
object,
|
|
1109
|
-
result,
|
|
1110
|
-
success: true
|
|
1111
|
-
};
|
|
1112
|
-
}
|
|
1113
|
-
};
|
|
971
|
+
const { defaultValidationOptions, classType, fn, optionsForContext: inputOptionsForContext } = config;
|
|
972
|
+
const optionsForContext = inputOptionsForContext ?? (() => ({}));
|
|
973
|
+
return async (input, context) => {
|
|
974
|
+
const { transform: transformOptions, validate: validateOptions } = optionsForContext(context);
|
|
975
|
+
const object = plainToInstance(classType, input, {
|
|
976
|
+
...transformOptions,
|
|
977
|
+
// Note: Each variable on the target class must be marked with the @Expose() annotation.
|
|
978
|
+
excludeExtraneousValues: true
|
|
979
|
+
});
|
|
980
|
+
const validationErrors = await validate(object, {
|
|
981
|
+
forbidUnknownValues: false, // allow classes without annotations by default
|
|
982
|
+
...defaultValidationOptions,
|
|
983
|
+
...validateOptions
|
|
984
|
+
});
|
|
985
|
+
if (validationErrors.length) {
|
|
986
|
+
return { object, validationErrors, success: false };
|
|
987
|
+
}
|
|
988
|
+
else {
|
|
989
|
+
const result = await fn(object);
|
|
990
|
+
return { object, result, success: true };
|
|
991
|
+
}
|
|
992
|
+
};
|
|
1114
993
|
}
|
|
1115
994
|
|
|
1116
995
|
function transformAndValidateFunctionResultFactory(defaults) {
|
|
1117
|
-
|
|
996
|
+
return toTransformAndValidateFunctionResultFactory(transformAndValidateObjectFactory(defaults));
|
|
1118
997
|
}
|
|
1119
998
|
function toTransformAndValidateFunctionResultFactory(transformAndValidateObjectFactory) {
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
999
|
+
return (classType, fn, handleValidationError) => {
|
|
1000
|
+
const transformAndValidateObjectFn = transformAndValidateObjectFactory(classType, fn, handleValidationError);
|
|
1001
|
+
return (input, context) => {
|
|
1002
|
+
return toTransformAndValidateFunctionResult(transformAndValidateObjectFn(input, context));
|
|
1003
|
+
};
|
|
1124
1004
|
};
|
|
1125
|
-
};
|
|
1126
1005
|
}
|
|
1127
1006
|
function toTransformAndValidateFunctionResult(objectOutput) {
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
fnResult.params = object;
|
|
1135
|
-
return fnResult;
|
|
1136
|
-
});
|
|
1007
|
+
return mapPromiseOrValue(objectOutput, (x) => {
|
|
1008
|
+
const { object, result } = x;
|
|
1009
|
+
const fnResult = result;
|
|
1010
|
+
fnResult.params = object;
|
|
1011
|
+
return fnResult;
|
|
1012
|
+
});
|
|
1137
1013
|
}
|
|
1138
1014
|
|
|
1139
1015
|
function transformAndValidateResultFactory(defaults) {
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
return result;
|
|
1016
|
+
const factory = transformAndValidateObjectFactory(defaults);
|
|
1017
|
+
return (classType, fn, handleValidationError) => {
|
|
1018
|
+
const transformAndValidateObjectFn = factory(classType, fn, handleValidationError);
|
|
1019
|
+
return async (input, context) => {
|
|
1020
|
+
const { result } = await transformAndValidateObjectFn(input, context);
|
|
1021
|
+
return result;
|
|
1022
|
+
};
|
|
1148
1023
|
};
|
|
1149
|
-
};
|
|
1150
1024
|
}
|
|
1151
1025
|
|
|
1152
1026
|
/**
|
|
1153
1027
|
* isISO8601DayString validator
|
|
1154
1028
|
*/
|
|
1155
1029
|
function IsISO8601DayString(validationOptions) {
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1030
|
+
return function (object, propertyName) {
|
|
1031
|
+
registerDecorator({
|
|
1032
|
+
name: 'isISO8601DayString',
|
|
1033
|
+
target: object.constructor,
|
|
1034
|
+
propertyName: propertyName,
|
|
1035
|
+
options: validationOptions,
|
|
1036
|
+
validator: {
|
|
1037
|
+
validate: isISO8601DayString,
|
|
1038
|
+
defaultMessage: buildMessage((eachPrefix, args) => eachPrefix + `$property value of "${args?.value}" is not a ISO8601DayString.`, validationOptions)
|
|
1039
|
+
}
|
|
1040
|
+
});
|
|
1041
|
+
};
|
|
1168
1042
|
}
|
|
1169
1043
|
|
|
1170
1044
|
/**
|
|
1171
1045
|
* isMinuteOfDay validator
|
|
1172
1046
|
*/
|
|
1173
1047
|
function IsMinuteOfDay(validationOptions) {
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1048
|
+
return function (object, propertyName) {
|
|
1049
|
+
registerDecorator({
|
|
1050
|
+
name: 'isMinuteOfDay',
|
|
1051
|
+
target: object.constructor,
|
|
1052
|
+
propertyName: propertyName,
|
|
1053
|
+
options: validationOptions,
|
|
1054
|
+
validator: {
|
|
1055
|
+
validate: isMinuteOfDay,
|
|
1056
|
+
defaultMessage: buildMessage((eachPrefix, args) => eachPrefix + `$property value of "${args?.value}" is not a valid minute of the day.`, validationOptions)
|
|
1057
|
+
}
|
|
1058
|
+
});
|
|
1059
|
+
};
|
|
1186
1060
|
}
|
|
1187
1061
|
|
|
1188
1062
|
/**
|
|
1189
1063
|
* isE164PhoneNumber validator that does not allowed extensions.
|
|
1190
1064
|
*/
|
|
1191
1065
|
function IsE164PhoneNumber(validationOptions) {
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1066
|
+
return function (object, propertyName) {
|
|
1067
|
+
registerDecorator({
|
|
1068
|
+
name: 'isE164PhoneNumber',
|
|
1069
|
+
target: object.constructor,
|
|
1070
|
+
propertyName: propertyName,
|
|
1071
|
+
options: validationOptions,
|
|
1072
|
+
validator: {
|
|
1073
|
+
validate: (x) => isE164PhoneNumber(x, false),
|
|
1074
|
+
defaultMessage: buildMessage((eachPrefix, args) => eachPrefix + `$property value of "${args?.value}" is not a E164PhoneNumber with no extension.`, validationOptions)
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
1077
|
+
};
|
|
1204
1078
|
}
|
|
1205
1079
|
/**
|
|
1206
1080
|
* isE164PhoneNumber validator that allows extensions.
|
|
@@ -1209,18 +1083,18 @@ function IsE164PhoneNumber(validationOptions) {
|
|
|
1209
1083
|
* @returns
|
|
1210
1084
|
*/
|
|
1211
1085
|
function IsE164PhoneNumberWithOptionalExtension(validationOptions) {
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1086
|
+
return function (object, propertyName) {
|
|
1087
|
+
registerDecorator({
|
|
1088
|
+
name: 'isE164PhoneNumber',
|
|
1089
|
+
target: object.constructor,
|
|
1090
|
+
propertyName: propertyName,
|
|
1091
|
+
options: validationOptions,
|
|
1092
|
+
validator: {
|
|
1093
|
+
validate: (x) => isE164PhoneNumber(x, true),
|
|
1094
|
+
defaultMessage: buildMessage((eachPrefix, args) => eachPrefix + `$property value of "${args?.value}" is not an E164PhoneNumber or has an invalid extension.`, validationOptions)
|
|
1095
|
+
}
|
|
1096
|
+
});
|
|
1097
|
+
};
|
|
1224
1098
|
}
|
|
1225
1099
|
/**
|
|
1226
1100
|
* isE164PhoneNumberWithExtension validator
|
|
@@ -1229,72 +1103,72 @@ function IsE164PhoneNumberWithOptionalExtension(validationOptions) {
|
|
|
1229
1103
|
* @returns
|
|
1230
1104
|
*/
|
|
1231
1105
|
function IsE164PhoneNumberWithExtension(validationOptions) {
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1106
|
+
return function (object, propertyName) {
|
|
1107
|
+
registerDecorator({
|
|
1108
|
+
name: 'isE164PhoneNumberWithExtension',
|
|
1109
|
+
target: object.constructor,
|
|
1110
|
+
propertyName: propertyName,
|
|
1111
|
+
options: validationOptions,
|
|
1112
|
+
validator: {
|
|
1113
|
+
validate: isE164PhoneNumberWithExtension,
|
|
1114
|
+
defaultMessage: buildMessage((eachPrefix, args) => eachPrefix + `$property value of "${args?.value}" is not a E164PhoneNumberWithExtension.`, validationOptions)
|
|
1115
|
+
}
|
|
1116
|
+
});
|
|
1117
|
+
};
|
|
1244
1118
|
}
|
|
1245
1119
|
|
|
1246
1120
|
/**
|
|
1247
1121
|
* isUniqueKeyedFunction validator
|
|
1248
1122
|
*/
|
|
1249
1123
|
function IsUniqueKeyed(readKey, validationOptions) {
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1124
|
+
const isUniqueKeyed = isUniqueKeyedFunction(readKey);
|
|
1125
|
+
return function (object, propertyName) {
|
|
1126
|
+
registerDecorator({
|
|
1127
|
+
name: 'isUniqueKeyed',
|
|
1128
|
+
target: object.constructor,
|
|
1129
|
+
propertyName: propertyName,
|
|
1130
|
+
options: validationOptions,
|
|
1131
|
+
validator: {
|
|
1132
|
+
validate: isUniqueKeyed,
|
|
1133
|
+
defaultMessage: buildMessage((eachPrefix, args) => eachPrefix + `$property value has one or more values with the same key. Keys must be unique.`, validationOptions)
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
};
|
|
1263
1137
|
}
|
|
1264
1138
|
|
|
1265
1139
|
/**
|
|
1266
1140
|
* isWebsiteUrl validator
|
|
1267
1141
|
*/
|
|
1268
1142
|
function IsWebsiteUrl(validationOptions) {
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1143
|
+
return function (object, propertyName) {
|
|
1144
|
+
registerDecorator({
|
|
1145
|
+
name: 'isWebsiteUrl',
|
|
1146
|
+
target: object.constructor,
|
|
1147
|
+
propertyName: propertyName,
|
|
1148
|
+
options: validationOptions,
|
|
1149
|
+
validator: {
|
|
1150
|
+
validate: isWebsiteUrl,
|
|
1151
|
+
defaultMessage: buildMessage((eachPrefix, args) => eachPrefix + `$property value of "${args?.value}" is not a valid website url.`, validationOptions)
|
|
1152
|
+
}
|
|
1153
|
+
});
|
|
1154
|
+
};
|
|
1281
1155
|
}
|
|
1282
1156
|
/**
|
|
1283
1157
|
* isWebsiteUrlWithPrefix validator
|
|
1284
1158
|
*/
|
|
1285
1159
|
function IsWebsiteUrlWithPrefix(validationOptions) {
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1160
|
+
return function (object, propertyName) {
|
|
1161
|
+
registerDecorator({
|
|
1162
|
+
name: 'isWebsiteUrlWithPrefix',
|
|
1163
|
+
target: object.constructor,
|
|
1164
|
+
propertyName: propertyName,
|
|
1165
|
+
options: validationOptions,
|
|
1166
|
+
validator: {
|
|
1167
|
+
validate: isWebsiteUrlWithPrefix,
|
|
1168
|
+
defaultMessage: buildMessage((eachPrefix, args) => eachPrefix + `$property value of "${args?.value}" is not a valid website url that starts with a http/https prefix.`, validationOptions)
|
|
1169
|
+
}
|
|
1170
|
+
});
|
|
1171
|
+
};
|
|
1298
1172
|
}
|
|
1299
1173
|
|
|
1300
1174
|
export { ADDRESS_CITY_MAX_LENGTH, ADDRESS_COUNTRY_MAX_LENGTH, ADDRESS_LINE_MAX_LENGTH, ADDRESS_STATE_CODE_MAX_LENGTH, ADDRESS_STATE_MAX_LENGTH, ADDRESS_ZIP_MAX_LENGTH, AbstractModelPermissionService, AbstractUnitedStatesAddressWithoutStateParams, CASHAPP_BASE_URL, CASHAPP_USERNAME_PREFIX, CASHAPP_WEBSITE_LINK_TYPE, EMAIL_URL_WEBSITE_LINK_TYPE, FACEBOOK_BASE_URL, FACEBOOK_WEBSITE_LINK_TYPE, FULL_ACCESS_ROLE_KEY, GRANTED_ADMIN_ROLE_KEY, GRANTED_DELETE_ROLE_KEY, GRANTED_OWNER_ROLE_KEY, GRANTED_READ_ROLE_KEY, GRANTED_SYS_ADMIN_ROLE_KEY, GRANTED_UPDATE_ROLE_KEY, GrantedRoleMapReaderInstance, INSTAGRAM_BASE_URL, INSTAGRAM_WEBSITE_LINK_TYPE, IsE164PhoneNumber, IsE164PhoneNumberWithExtension, IsE164PhoneNumberWithOptionalExtension, IsISO8601DayString, IsMinuteOfDay, IsUniqueKeyed, IsWebsiteUrl, IsWebsiteUrlWithPrefix, NO_ACCESS_ROLE_KEY, PAYPAL_BASE_URL, PAYPAL_WEBSITE_LINK_TYPE, PHONE_URL_WEBSITE_LINK_TYPE, SNAPCHAT_BASE_URL, SNAPCHAT_WEBSITE_LINK_ISOLATE_PROFILE_ID, SNAPCHAT_WEBSITE_LINK_TYPE, SPOTIFY_BASE_URL, SPOTIFY_WEBSITE_LINK_ISOLATE_PROFILE_ID, SPOTIFY_WEBSITE_LINK_TYPE, TIKTOK_BASE_URL, TIKTOK_USERNAME_PREFIX, TIKTOK_WEBSITE_LINK_TYPE, TWITTER_BASE_URL, TWITTER_WEBSITE_LINK_TYPE, TransformCommaSeparatedNumberValueToArray, TransformCommaSeparatedStringValueToArray, TransformCommaSeparatedValueToArray, TransformStringValueToBoolean, UNKNOWN_WEBSITE_LINK_TYPE, UnitedStatesAddressWithStateCodeParams, UnitedStatesAddressWithStateStringParams, VENMO_BASE_URL, VENMO_WEBSITE_LINK_ISOLATE_PROFILE_ID, VENMO_WEBSITE_LINK_TYPE, WEBSITE_FILE_LINK_DATA_MAX_LENGTH, WEBSITE_FILE_LINK_DATA_REGEX, WEBSITE_FILE_LINK_ENCODE_SEPARATOR, WEBSITE_FILE_LINK_MIME_TYPE_MAX_LENGTH, WEBSITE_FILE_LINK_MIME_TYPE_REGEX, WEBSITE_FILE_LINK_NAME_MAX_LENGTH, WEBSITE_FILE_LINK_TYPE_MAX_LENGTH, WEBSITE_FILE_LINK_TYPE_REGEX, WEBSITE_FILE_LINK_WEBSITE_LINK_TYPE, WEBSITE_LINK_ENCODED_DATA_MAX_LENGTH, WEBSITE_LINK_ISOLATE_BASE_URL_PROFILE_ID, WEBSITE_LINK_TYPE_MAX_LENGTH, WEBSITE_LINK_TYPE_REGEX, WEBSITE_URL_WEBSITE_LINK_TYPE, WebsiteFileLink, WebsiteLink, YOUTUBE_BASE_URL, YOUTUBE_WEBSITE_LINK_ISOLATE_PROFILE_ID, YOUTUBE_WEBSITE_LINK_TYPE, basicSyncEntityCommonTypeSynchronizerInstanceFactory, cashappProfileUrl, cashappProfileUrlToWebsiteLink, contextGrantedModelRoles, decodeWebsiteLinkEncodedDataToWebsiteFileLink, emailAddressToWebsiteLink, encodeWebsiteFileLinkToWebsiteLinkEncodedData, facebookProfileUrl, facebookProfileUrlToWebsiteLink, fullAccessGrantedModelRoles, fullAccessRoleMap, grantedRoleKeysMapFromArray, grantedRoleMapReader, instagramProfileUrl, instagramProfileUrlToWebsiteLink, isFullAccessRoleMap, isGrantedAdminLevelRole, isNoAccessRoleMap, isValidWebsiteLinkType, noAccessContextGrantedModelRoles, noAccessRoleMap, paypalProfileUrl, paypalProfileUrlToWebsiteLink, phoneNumberToWebsiteLink, snapchatProfileUrl, snapchatProfileUrlToWebsiteLink, spotifyProfileUrl, spotifyProfileUrlToWebsiteLink, syncEntityCommonTypeIdPairFactory, syncEntityFactory, syncEntitySynchronizer, tiktokProfileUrl, tiktokProfileUrlToWebsiteLink, toTransformAndValidateFunctionResult, toTransformAndValidateFunctionResultFactory, transformAndValidateFunctionResultFactory, transformAndValidateObject, transformAndValidateObjectFactory, transformAndValidateObjectResult, transformAndValidateResultFactory, transformCommaSeparatedNumberValueToArray, transformCommaSeparatedStringValueToArray, transformCommaSeparatedValueToArray, transformStringToBoolean, twitterProfileUrl, twitterProfileUrlToWebsiteLink, usernameFromUsernameOrWebsiteWithBaseUrlUsername, usernameFromUsernameOrWebsiteWithOneOffBaseUrlUsername, usernameOrWebsiteUrlToWebsiteUrl, venmoProfileUrl, venmoProfileUrlToWebsiteLink, websiteFileLinkToWebsiteLink, websiteLinkToWebsiteLinkFile, websiteUrlToWebsiteLink, youtubeProfileUrl, youtubeProfileUrlToWebsiteLink };
|