grm-shared-library 1.1.246 → 1.1.247
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.
|
@@ -61,7 +61,7 @@ export interface AccountAnalyticsKindRow {
|
|
|
61
61
|
/** Of the accounts created in the period, how far each got - as they stand now. */
|
|
62
62
|
export interface AccountAnalyticsFunnel {
|
|
63
63
|
created: number;
|
|
64
|
-
/**
|
|
64
|
+
/** Proved their phone or e-mail: a sign-in code, Google or Apple (the older app: its one-time code). */
|
|
65
65
|
verified: number;
|
|
66
66
|
acceptedTerms: number;
|
|
67
67
|
/** Signed in at least once. */
|
|
@@ -84,7 +84,7 @@ export interface AccountAnalyticsAccounts {
|
|
|
84
84
|
/** Active accounts that were created in an earlier period. */
|
|
85
85
|
returning: number;
|
|
86
86
|
funnel: AccountAnalyticsFunnel;
|
|
87
|
-
/** Now: never
|
|
87
|
+
/** Now: never proved their phone or e-mail (see `AccountAnalyticsFunnel.verified`). */
|
|
88
88
|
pendingNow: number;
|
|
89
89
|
/** Now: never signed in. */
|
|
90
90
|
neverSignedIn: number;
|
|
@@ -104,12 +104,16 @@ export interface AccountAnalyticsAccounts {
|
|
|
104
104
|
recency: AccountAnalyticsCount<AccountRecencyBand>[];
|
|
105
105
|
}
|
|
106
106
|
/**
|
|
107
|
-
* How somebody signed in:
|
|
108
|
-
* - PASSWORD
|
|
109
|
-
* - OTP
|
|
110
|
-
* -
|
|
107
|
+
* How somebody signed in - or, for a sign-up, made their account:
|
|
108
|
+
* - PASSWORD e-mail and password (the admin and the web);
|
|
109
|
+
* - OTP the older app (before 1.0.18): phone number and one code sent by SMS and e-mail together;
|
|
110
|
+
* - PHONE_CODE a code to the phone by SMS or a call, or a WhatsApp message from it - proves the number;
|
|
111
|
+
* - EMAIL_CODE a code to the e-mail - proves the e-mail only;
|
|
112
|
+
* - GOOGLE Google vouches for the e-mail;
|
|
113
|
+
* - APPLE Apple vouches for the e-mail (possibly a private relay address);
|
|
114
|
+
* - REVIEWER the app-store reviewers' account.
|
|
111
115
|
*/
|
|
112
|
-
export type AccountSignInMethod = 'PASSWORD' | 'OTP' | 'REVIEWER';
|
|
116
|
+
export type AccountSignInMethod = 'PASSWORD' | 'OTP' | 'PHONE_CODE' | 'EMAIL_CODE' | 'GOOGLE' | 'APPLE' | 'REVIEWER';
|
|
113
117
|
export interface AccountAnalyticsMethodRow {
|
|
114
118
|
method: string;
|
|
115
119
|
succeeded: number;
|
|
@@ -127,8 +131,13 @@ export interface AccountAnalyticsSignIns {
|
|
|
127
131
|
firstSignIns: number;
|
|
128
132
|
/** Failed for an e-mail or a code that matches no account (counted, never stored). */
|
|
129
133
|
unknownAccount: number;
|
|
134
|
+
/**
|
|
135
|
+
* By AccountSignInMethod. A wrong phone or e-mail code is not a failed sign-in - it is
|
|
136
|
+
* counted with the codes (`AccountAnalyticsVerificationCodes`) - so PHONE_CODE and
|
|
137
|
+
* EMAIL_CODE fail only for a switched-off account.
|
|
138
|
+
*/
|
|
130
139
|
byMethod: AccountAnalyticsMethodRow[];
|
|
131
|
-
/** INVALID_CREDENTIALS, UNVERIFIED, UNKNOWN_ACCOUNT, INVALID_TOKEN, ERROR... */
|
|
140
|
+
/** INVALID_CREDENTIALS, UNVERIFIED, UNKNOWN_ACCOUNT, INVALID_TOKEN, INVALID_ID_TOKEN, DISABLED, EMAIL_IN_USE, EMAIL_REQUIRED, ERROR... */
|
|
132
141
|
failureReasons: AccountAnalyticsCount[];
|
|
133
142
|
averageDailyUsers: number;
|
|
134
143
|
peakDailyUsers: number;
|
|
@@ -141,6 +150,11 @@ export interface AccountAnalyticsOtpActionRow {
|
|
|
141
150
|
sent: number;
|
|
142
151
|
verified: number;
|
|
143
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* The older app's one-time codes (before 1.0.18): one code to the e-mail and the phone
|
|
155
|
+
* together, for signing up, in and confirming. The current app's codes are in
|
|
156
|
+
* `AccountAnalyticsSignInOptions.codes`.
|
|
157
|
+
*/
|
|
144
158
|
export interface AccountAnalyticsOtp {
|
|
145
159
|
/** First sends and resends. */
|
|
146
160
|
sent: number;
|
|
@@ -237,6 +251,166 @@ export interface AccountAnalyticsPrevious {
|
|
|
237
251
|
deletionRequests: number;
|
|
238
252
|
guardianLinks: number;
|
|
239
253
|
}
|
|
254
|
+
/** How a code travels. SMS and VOICE carry it to the phone; WHATSAPP is the person messaging us FROM the phone; EMAIL. */
|
|
255
|
+
export type AccountVerificationChannel = 'SMS' | 'VOICE' | 'WHATSAPP' | 'EMAIL';
|
|
256
|
+
/** What a code is for: signing in (or up), or proving the phone number of an account already signed in. */
|
|
257
|
+
export type AccountVerificationPurpose = 'SIGN_IN' | 'VERIFY_PHONE';
|
|
258
|
+
/** One channel's codes for one purpose, in the period. */
|
|
259
|
+
export interface AccountAnalyticsCodeChannelRow {
|
|
260
|
+
purpose: AccountVerificationPurpose | string;
|
|
261
|
+
channel: AccountVerificationChannel | string;
|
|
262
|
+
/** Codes sent - for WhatsApp, the message the person was asked to send us. */
|
|
263
|
+
sent: number;
|
|
264
|
+
/** Refused before anything was sent: asked for too often, a number already on another account, a channel that cannot reach it. */
|
|
265
|
+
refused: number;
|
|
266
|
+
/** The SMS or call provider could not take it. The app offers the other channels. */
|
|
267
|
+
notDelivered: number;
|
|
268
|
+
confirmed: number;
|
|
269
|
+
wrongCode: number;
|
|
270
|
+
expired: number;
|
|
271
|
+
/** WhatsApp: the message came from a number other than the one being proven. */
|
|
272
|
+
wrongNumber: number;
|
|
273
|
+
/** confirmed / sent; null with none sent. */
|
|
274
|
+
confirmationRate: number | null;
|
|
275
|
+
}
|
|
276
|
+
/** Codes by the country of the number (or of the app, for an e-mail code) and channel, in the period. */
|
|
277
|
+
export interface AccountAnalyticsCodeCountryRow {
|
|
278
|
+
/** KE, UG, TZ - or UNKNOWN. */
|
|
279
|
+
country: string;
|
|
280
|
+
channel: AccountVerificationChannel | string;
|
|
281
|
+
sent: number;
|
|
282
|
+
notDelivered: number;
|
|
283
|
+
confirmed: number;
|
|
284
|
+
}
|
|
285
|
+
/** The current app's codes (1.0.18 on): to the phone only, or to the e-mail only - never both. */
|
|
286
|
+
export interface AccountAnalyticsVerificationCodes {
|
|
287
|
+
sent: number;
|
|
288
|
+
refused: number;
|
|
289
|
+
notDelivered: number;
|
|
290
|
+
confirmed: number;
|
|
291
|
+
wrongCode: number;
|
|
292
|
+
expired: number;
|
|
293
|
+
wrongNumber: number;
|
|
294
|
+
confirmationRate: number | null;
|
|
295
|
+
/** Biggest first. */
|
|
296
|
+
byChannel: AccountAnalyticsCodeChannelRow[];
|
|
297
|
+
byCountry: AccountAnalyticsCodeCountryRow[];
|
|
298
|
+
/** Why codes were refused: RATE_LIMITED, PHONE_IN_USE, CHANNEL_UNAVAILABLE. */
|
|
299
|
+
refusals: AccountAnalyticsCount[];
|
|
300
|
+
}
|
|
301
|
+
/** App users making their own account, in the period. */
|
|
302
|
+
export interface AccountAnalyticsSignUps {
|
|
303
|
+
/** A phone or e-mail code confirmed that matched no account: the app showed the short sign-up form. */
|
|
304
|
+
formsStarted: number;
|
|
305
|
+
/** Accounts made from that form. Google and Apple make the account straight away, with no form. */
|
|
306
|
+
formsCompleted: number;
|
|
307
|
+
/** formsCompleted / formsStarted; null with none started. */
|
|
308
|
+
completionRate: number | null;
|
|
309
|
+
/** Sign-ups refused - the e-mail or number already has an account, the form came back too late. */
|
|
310
|
+
refused: number;
|
|
311
|
+
/** EMAIL_IN_USE, PHONE_IN_USE, EMAIL_REQUIRED, REGISTRATION_EXPIRED. */
|
|
312
|
+
failureReasons: AccountAnalyticsCount[];
|
|
313
|
+
/**
|
|
314
|
+
* App (Mobile-User) accounts created in the period, by how: PHONE_CODE, EMAIL_CODE,
|
|
315
|
+
* GOOGLE, APPLE, OTP (the older app) - and OTHER: made for the person (a corporate
|
|
316
|
+
* member, a partner's caller) or before sign-ups were recorded.
|
|
317
|
+
*/
|
|
318
|
+
byMethod: AccountAnalyticsCount[];
|
|
319
|
+
}
|
|
320
|
+
export interface AccountAnalyticsPhoneCountryRow {
|
|
321
|
+
country: string;
|
|
322
|
+
appUsers: number;
|
|
323
|
+
verified: number;
|
|
324
|
+
unverified: number;
|
|
325
|
+
noNumber: number;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* App users' phone numbers - the number a responder calls - as they stand now. A number
|
|
329
|
+
* is verified only when a code to it, or a WhatsApp message from it, proved it; a number
|
|
330
|
+
* saved with "Verify later" is shown to the dispatcher as not verified.
|
|
331
|
+
*/
|
|
332
|
+
export interface AccountAnalyticsPhoneNumbers {
|
|
333
|
+
appUsers: number;
|
|
334
|
+
withNumber: number;
|
|
335
|
+
verified: number;
|
|
336
|
+
unverified: number;
|
|
337
|
+
noNumber: number;
|
|
338
|
+
/** verified / appUsers; null with none. */
|
|
339
|
+
verifiedRate: number | null;
|
|
340
|
+
/**
|
|
341
|
+
* Every app user once: how the number was proven - SMS, VOICE, WHATSAPP, LEGACY_OTP (the
|
|
342
|
+
* older app's code, counted where its SMS always arrived) - or UNVERIFIED, or NONE.
|
|
343
|
+
*/
|
|
344
|
+
byState: AccountAnalyticsCount[];
|
|
345
|
+
byCountry: AccountAnalyticsPhoneCountryRow[];
|
|
346
|
+
/** In the period: numbers proven by somebody already signed in (after Google, Apple or an e-mail code), by channel. */
|
|
347
|
+
verifiedInPeriod: AccountAnalyticsCount[];
|
|
348
|
+
/** In the period: "Verify later" - a number saved without proving it. */
|
|
349
|
+
deferred: number;
|
|
350
|
+
/** Now: app users whose e-mail is proven (an e-mail code, Google or Apple). */
|
|
351
|
+
emailVerified: number;
|
|
352
|
+
}
|
|
353
|
+
/** Google or Apple. */
|
|
354
|
+
export interface AccountAnalyticsProviderRow {
|
|
355
|
+
provider: 'GOOGLE' | 'APPLE' | string;
|
|
356
|
+
/** Accounts linked to it now. */
|
|
357
|
+
linkedAccounts: number;
|
|
358
|
+
/** In the period. */
|
|
359
|
+
signIns: number;
|
|
360
|
+
/** Accounts it created, in the period. */
|
|
361
|
+
newAccounts: number;
|
|
362
|
+
/** Linked to an account that already had the same proven e-mail, in the period. */
|
|
363
|
+
linkedExisting: number;
|
|
364
|
+
/** The provider's token did not check out, or the account could not be used (switched off, e-mail taken or missing). */
|
|
365
|
+
failed: number;
|
|
366
|
+
}
|
|
367
|
+
/** Sign-ins in one country by one way in, in the period. */
|
|
368
|
+
export interface AccountAnalyticsMethodCountryRow {
|
|
369
|
+
/** The account's country (KE, UG, TZ), or UNKNOWN. */
|
|
370
|
+
country: string;
|
|
371
|
+
method: AccountSignInMethod | string;
|
|
372
|
+
signIns: number;
|
|
373
|
+
}
|
|
374
|
+
export interface AccountAnalyticsSignInOptionsPoint {
|
|
375
|
+
/** As `AccountAnalyticsPoint.bucket`. */
|
|
376
|
+
bucket: string;
|
|
377
|
+
/** Successful sign-ins in the bucket by AccountSignInMethod; methods with none are left out. */
|
|
378
|
+
byMethod: Record<string, number>;
|
|
379
|
+
/** The current app's codes. */
|
|
380
|
+
codesSent: number;
|
|
381
|
+
codesConfirmed: number;
|
|
382
|
+
}
|
|
383
|
+
/** The same figures for the previous period of the same length. */
|
|
384
|
+
export interface AccountAnalyticsSignInOptionsPrevious {
|
|
385
|
+
/** Sign-ins by PHONE_CODE, EMAIL_CODE, GOOGLE or APPLE. */
|
|
386
|
+
currentAppSignIns: number;
|
|
387
|
+
/** Sign-ins by the older app's code (OTP). */
|
|
388
|
+
olderAppSignIns: number;
|
|
389
|
+
codesSent: number;
|
|
390
|
+
codesConfirmed: number;
|
|
391
|
+
phonesVerified: number;
|
|
392
|
+
deferred: number;
|
|
393
|
+
formsCompleted: number;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* The ways into the app since 1.0.18 - a code to the phone (SMS, a call, WhatsApp), a code
|
|
397
|
+
* to the e-mail, Google, Apple - next to the older app's SMS-and-e-mail code, and whether
|
|
398
|
+
* the phone numbers responders call are proven.
|
|
399
|
+
*/
|
|
400
|
+
export interface AccountAnalyticsSignInOptions {
|
|
401
|
+
/** People who signed in during the period, each by the way they signed in LAST. */
|
|
402
|
+
lastMethodUsed: AccountAnalyticsCount[];
|
|
403
|
+
byCountry: AccountAnalyticsMethodCountryRow[];
|
|
404
|
+
/** One point per bucket, as `AccountAnalytics.timeline`. */
|
|
405
|
+
timeline: AccountAnalyticsSignInOptionsPoint[];
|
|
406
|
+
codes: AccountAnalyticsVerificationCodes;
|
|
407
|
+
signUps: AccountAnalyticsSignUps;
|
|
408
|
+
phones: AccountAnalyticsPhoneNumbers;
|
|
409
|
+
/** GOOGLE and APPLE, always both. */
|
|
410
|
+
providers: AccountAnalyticsProviderRow[];
|
|
411
|
+
/** Absent for "forever". */
|
|
412
|
+
previous: AccountAnalyticsSignInOptionsPrevious | null;
|
|
413
|
+
}
|
|
240
414
|
/** A Super-Admin's view of every organization: one row each, biggest first. */
|
|
241
415
|
export interface AccountAnalyticsOrganizationRow {
|
|
242
416
|
organizationId: number;
|
|
@@ -266,6 +440,8 @@ export interface AccountAnalytics {
|
|
|
266
440
|
passwords: AccountAnalyticsPasswords;
|
|
267
441
|
guardians: AccountAnalyticsGuardians;
|
|
268
442
|
deletions: AccountAnalyticsDeletions;
|
|
443
|
+
/** The ways into the app, codes by channel and proven phone numbers. Absent only from a clarion-authentication older than this field. */
|
|
444
|
+
signInOptions?: AccountAnalyticsSignInOptions;
|
|
269
445
|
/** A Super-Admin looking at every organization only. */
|
|
270
446
|
byOrganization?: AccountAnalyticsOrganizationRow[];
|
|
271
447
|
}
|
package/package.json
CHANGED
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "grm-shared-library",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"main": "dist/cjs/index.js",
|
|
5
|
-
"module": "dist/esm/index.js",
|
|
6
|
-
"types": "dist/types/index.d.ts",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": {
|
|
9
|
-
"types": "./dist/types/index.d.ts",
|
|
10
|
-
"import": "./dist/esm/index.js",
|
|
11
|
-
"require": "./dist/cjs/index.js"
|
|
12
|
-
},
|
|
13
|
-
"./dist/modules/*": {
|
|
14
|
-
"types": "./dist/types/modules/*.d.ts",
|
|
15
|
-
"import": "./dist/esm/modules/*.js",
|
|
16
|
-
"require": "./dist/cjs/modules/*.js"
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
"files": [
|
|
20
|
-
"dist/**/*"
|
|
21
|
-
],
|
|
22
|
-
"scripts": {
|
|
23
|
-
"clean": "rimraf dist dist-test",
|
|
24
|
-
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
25
|
-
"build:esm": "tsc -p tsconfig.esm.json",
|
|
26
|
-
"build:types": "tsc -p tsconfig.types.json",
|
|
27
|
-
"build": "npm run clean && npm run build:types && npm run build:cjs && npm run build:esm",
|
|
28
|
-
"prepublishOnly": "npm run build",
|
|
29
|
-
"pretest": "rimraf dist-test",
|
|
30
|
-
"test": "tsc -p tsconfig.spec.json && node --test \"dist-test/**/*.spec.js\""
|
|
31
|
-
},
|
|
32
|
-
"keywords": [],
|
|
33
|
-
"author": "",
|
|
34
|
-
"license": "ISC",
|
|
35
|
-
"description": "",
|
|
36
|
-
"publishConfig": {
|
|
37
|
-
"access": "public"
|
|
38
|
-
},
|
|
39
|
-
"devDependencies": {
|
|
40
|
-
"@types/express": "^5.0.3",
|
|
41
|
-
"@types/geojson": "^7946.0.14",
|
|
42
|
-
"@types/node": "^22.10.5",
|
|
43
|
-
"rimraf": "^5.0.5",
|
|
44
|
-
"typescript": "^5.7.3"
|
|
45
|
-
},
|
|
46
|
-
"dependencies": {
|
|
47
|
-
"@nestjs/common": "^11.0.0",
|
|
48
|
-
"@nestjs/core": "^11.0.0",
|
|
49
|
-
"@nestjs/mapped-types": "^2.0.6",
|
|
50
|
-
"@nestjs/microservices": "^11.0.0",
|
|
51
|
-
"@nestjs/swagger": "^11.2.0",
|
|
52
|
-
"@sentry/node": "^8.0.0",
|
|
53
|
-
"class-transformer": "^0.5.0",
|
|
54
|
-
"class-validator": "^0.14.0",
|
|
55
|
-
"express": "^5.1.0",
|
|
56
|
-
"geojson": "^0.5.0",
|
|
57
|
-
"grm-shared-library": "^1.1.101",
|
|
58
|
-
"libphonenumber-js": "^1.13.8",
|
|
59
|
-
"rxjs": "^7.8.2",
|
|
60
|
-
"swagger-ui-express": "^5.0.1",
|
|
61
|
-
"@nestjs/config": "^4.0.0"
|
|
62
|
-
},
|
|
63
|
-
"peerDependencies": {
|
|
64
|
-
"@nestjs/common": "^11.0.0",
|
|
65
|
-
"@nestjs/core": "^11.0.0",
|
|
66
|
-
"@nestjs/microservices": "^11.0.0",
|
|
67
|
-
"@sentry/node": "^8.0.0",
|
|
68
|
-
"class-transformer": "^0.5.0",
|
|
69
|
-
"class-validator": "^0.14.0",
|
|
70
|
-
"@nestjs/config": "^4.0.0"
|
|
71
|
-
}
|
|
72
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "grm-shared-library",
|
|
3
|
+
"version": "1.1.247",
|
|
4
|
+
"main": "dist/cjs/index.js",
|
|
5
|
+
"module": "dist/esm/index.js",
|
|
6
|
+
"types": "dist/types/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/types/index.d.ts",
|
|
10
|
+
"import": "./dist/esm/index.js",
|
|
11
|
+
"require": "./dist/cjs/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./dist/modules/*": {
|
|
14
|
+
"types": "./dist/types/modules/*.d.ts",
|
|
15
|
+
"import": "./dist/esm/modules/*.js",
|
|
16
|
+
"require": "./dist/cjs/modules/*.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist/**/*"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"clean": "rimraf dist dist-test",
|
|
24
|
+
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
25
|
+
"build:esm": "tsc -p tsconfig.esm.json",
|
|
26
|
+
"build:types": "tsc -p tsconfig.types.json",
|
|
27
|
+
"build": "npm run clean && npm run build:types && npm run build:cjs && npm run build:esm",
|
|
28
|
+
"prepublishOnly": "npm run build",
|
|
29
|
+
"pretest": "rimraf dist-test",
|
|
30
|
+
"test": "tsc -p tsconfig.spec.json && node --test \"dist-test/**/*.spec.js\""
|
|
31
|
+
},
|
|
32
|
+
"keywords": [],
|
|
33
|
+
"author": "",
|
|
34
|
+
"license": "ISC",
|
|
35
|
+
"description": "",
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/express": "^5.0.3",
|
|
41
|
+
"@types/geojson": "^7946.0.14",
|
|
42
|
+
"@types/node": "^22.10.5",
|
|
43
|
+
"rimraf": "^5.0.5",
|
|
44
|
+
"typescript": "^5.7.3"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@nestjs/common": "^11.0.0",
|
|
48
|
+
"@nestjs/core": "^11.0.0",
|
|
49
|
+
"@nestjs/mapped-types": "^2.0.6",
|
|
50
|
+
"@nestjs/microservices": "^11.0.0",
|
|
51
|
+
"@nestjs/swagger": "^11.2.0",
|
|
52
|
+
"@sentry/node": "^8.0.0",
|
|
53
|
+
"class-transformer": "^0.5.0",
|
|
54
|
+
"class-validator": "^0.14.0",
|
|
55
|
+
"express": "^5.1.0",
|
|
56
|
+
"geojson": "^0.5.0",
|
|
57
|
+
"grm-shared-library": "^1.1.101",
|
|
58
|
+
"libphonenumber-js": "^1.13.8",
|
|
59
|
+
"rxjs": "^7.8.2",
|
|
60
|
+
"swagger-ui-express": "^5.0.1",
|
|
61
|
+
"@nestjs/config": "^4.0.0"
|
|
62
|
+
},
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"@nestjs/common": "^11.0.0",
|
|
65
|
+
"@nestjs/core": "^11.0.0",
|
|
66
|
+
"@nestjs/microservices": "^11.0.0",
|
|
67
|
+
"@sentry/node": "^8.0.0",
|
|
68
|
+
"class-transformer": "^0.5.0",
|
|
69
|
+
"class-validator": "^0.14.0",
|
|
70
|
+
"@nestjs/config": "^4.0.0"
|
|
71
|
+
}
|
|
72
|
+
}
|