@opencrvs/mosip 1.7.0-alpha.9 → 1.8.0-alpha.1

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/src/forms.ts CHANGED
@@ -1,5 +1,3 @@
1
- // @TODO: Yet to be implemented! Placeholders for NPM publish.
2
-
3
1
  /**
4
2
  * E-Signet popup button and hidden field form definitions
5
3
  * @example
@@ -17,220 +15,400 @@
17
15
  *
18
16
  */
19
17
  export const esignet = (
20
- event: string,
21
- sectionId: string,
22
18
  esignetAuthUrl: string,
23
19
  openIdProviderClientId: string,
24
- openIdProviderClaims: string = 'name,family_name,given_name,middle_name,birthdate,address',
20
+ openIdProviderClaims: string = "name,family_name,given_name,middle_name,birthdate,address",
25
21
  fieldName: string,
26
- callbackFieldName: string
22
+ callbackFieldName: string,
27
23
  ) => {
28
24
  const url = new URL(esignetAuthUrl);
29
25
 
30
26
  url.searchParams.append(
31
- 'client_id',
32
- openIdProviderClientId || 'mock-client_id'
33
- );
34
- url.searchParams.append('response_type', 'code');
35
- url.searchParams.append('scope', 'openid profile');
36
- url.searchParams.append('acr_values', 'mosip:idp:acr:static-code');
37
- url.searchParams.append('claims', openIdProviderClaims);
38
- url.searchParams.append('state', 'fetch-on-mount');
39
- url.searchParams.append(
40
- 'redirect_uri',
41
- '${window.location.origin}/drafts/${window.location.pathname.split("/")[2]}/events/${event}/${sectionId}/group/${sectionId}'
27
+ "client_id",
28
+ openIdProviderClientId || "mock-client_id",
42
29
  );
30
+ url.searchParams.append("response_type", "code");
31
+ url.searchParams.append("scope", "openid profile");
32
+ url.searchParams.append("acr_values", "mosip:idp:acr:static-code");
33
+ url.searchParams.append("claims", openIdProviderClaims);
34
+ url.searchParams.append("state", "fetch-on-mount");
35
+ url.searchParams.append("redirect_uri", "${window.location.href}");
43
36
 
44
37
  return {
45
38
  name: fieldName,
46
39
  validator: [],
47
40
  icon: {
48
- desktop: 'Globe',
49
- mobile: 'Fingerprint'
41
+ desktop: "Globe",
42
+ mobile: "Fingerprint",
50
43
  },
51
- type: 'LINK_BUTTON',
44
+ type: "LINK_BUTTON",
52
45
  custom: true,
53
46
  label: {
54
- id: 'views.idReader.label.eSignet',
55
- defaultMessage: 'E-signet'
47
+ id: "views.idReader.label.eSignet",
48
+ defaultMessage: "E-signet",
56
49
  },
57
50
  hideInPreview: true,
58
51
  conditionals: [
59
52
  {
60
- action: 'disable',
61
- expression: '!!$form.redirectCallbackFetch'
62
- }
53
+ action: "disable",
54
+ expression: "!!$form.redirectCallbackFetch",
55
+ },
63
56
  ],
57
+ mapping: {
58
+ mutation: {
59
+ operation: "ignoreFieldTransformer",
60
+ },
61
+ },
64
62
  options: {
65
63
  url: url.toString(),
66
64
  callback: {
67
65
  params: {
68
- state: 'fetch-on-mount'
66
+ state: "fetch-on-mount",
69
67
  },
70
- trigger: callbackFieldName
71
- }
72
- }
68
+ trigger: callbackFieldName,
69
+ },
70
+ },
73
71
  };
74
72
  };
75
73
 
76
74
  export const popupButton = ({
77
75
  /** URL to OpenCRVS-MOSIP gateway (e.g. https://opencrvs-mosip-gateway.farajaland.opencrvs.org) */
78
- url
76
+ url,
79
77
  }: {
80
78
  url: string;
81
79
  }) => {
82
80
  return {
83
- name: 'INFORMANT_AUTHENTICATION_POPUP_BUTTON',
84
- type: 'POPUP_BUTTON',
85
- url
81
+ name: "INFORMANT_AUTHENTICATION_POPUP_BUTTON",
82
+ type: "POPUP_BUTTON",
83
+ url,
86
84
  };
87
85
  };
88
86
 
89
87
  /**
90
88
  *
91
- * @description esignet callback button form definition. Calls mosip-api/esignet-api /esignet/get-oidp-user-info (this field may not be supported in the latest release of OpenCRVS yet)
89
+ * @description esignet callback button form definition. Calls https://mosip-api.{{hostname}}/esignet/get-oidp-user-info
92
90
  *
93
91
  */
94
92
 
95
93
  export const esignetCallback = ({
96
94
  fieldName,
97
- event,
98
- sectionId,
99
- getOIDPUserInfoUrl,
100
- openIdProviderClientId
95
+ mosipAPIUserInfoUrl,
96
+ openIdProviderClientId,
101
97
  }: {
102
98
  fieldName: string;
103
- event: string;
104
- sectionId: string;
105
- getOIDPUserInfoUrl: string;
99
+ mosipAPIUserInfoUrl: string;
106
100
  openIdProviderClientId: string;
107
101
  }) => ({
108
102
  name: fieldName,
109
- type: 'HTTP',
103
+ type: "HTTP",
110
104
  custom: true,
111
105
  label: {
112
- id: 'form.field.label.empty',
113
- defaultMessage: ''
106
+ id: "form.field.label.empty",
107
+ defaultMessage: "",
114
108
  },
115
109
  validator: [],
110
+ hideInPreview: true,
111
+ mapping: {
112
+ mutation: {
113
+ operation: "ignoreFieldTransformer",
114
+ },
115
+ },
116
116
  options: {
117
- getOIDPUserInfoUrl,
117
+ url: mosipAPIUserInfoUrl,
118
118
  headers: {
119
- 'Content-type': 'application/json'
119
+ "Content-type": "application/json",
120
120
  },
121
121
  body: {
122
122
  clientId: openIdProviderClientId,
123
- redirectUri:
124
- '${window.location.origin}/drafts/${window.location.pathname.split("/")[2]}/events/${event}/${sectionId}/group/${sectionId}'
123
+ redirectUri: "${window.location.href}",
125
124
  },
126
125
 
127
- method: 'POST'
128
- }
126
+ method: "POST",
127
+ },
129
128
  });
130
129
 
131
130
  export const esignetHidden = () => {
132
131
  return {
133
- name: 'INFORMANT_PSUT_TOKEN',
134
- type: 'HIDDEN'
132
+ name: "INFORMANT_PSUT_TOKEN",
133
+ type: "HIDDEN",
135
134
  };
136
135
  };
137
136
 
138
- /**
139
- *
140
- * @description QR reader type definition (this field may not be supported in the latest release of OpenCRVS yet)
141
- *
142
- */
143
-
144
137
  export const idReader = (
145
138
  event: string,
146
139
  sectionId: string,
147
140
  conditionals: any[],
148
- readers: any[]
141
+ readers: any[],
149
142
  ) => {
150
- const fieldName: string = 'idReader';
143
+ const fieldName: string = "idReader";
151
144
  const fieldId: string = `${event}.${sectionId}.${sectionId}-view-group.${fieldName}`;
152
145
  return {
153
146
  name: fieldName,
154
147
  customQuestionMappingId: fieldId,
155
148
  custom: true,
156
149
  required: false,
157
- type: 'ID_READER',
150
+ type: "ID_READER",
158
151
  label: {
159
- id: 'form.field.label.empty',
160
- defaultMessage: ''
152
+ id: "form.field.label.idReader",
153
+ defaultMessage: "ID verification",
161
154
  },
162
155
  hideInPreview: true,
163
- initialValue: '',
156
+ initialValue: "",
164
157
  validator: [],
165
158
  conditionals,
166
159
  dividerLabel: {
167
- id: 'views.idReader.label.or',
168
- defaultMessage: 'Or'
160
+ id: "views.idReader.label.or",
161
+ defaultMessage: "Or",
169
162
  },
170
163
  manualInputInstructionLabel: {
171
- id: 'views.idReader.label.manualInput',
172
- defaultMessage: 'Complete fields below'
164
+ id: "views.idReader.label.manualInput",
165
+ defaultMessage: "Complete fields below",
166
+ },
167
+ mapping: {
168
+ mutation: {
169
+ operation: "ignoreFieldTransformer",
170
+ },
173
171
  },
174
- readers
172
+ readers,
175
173
  };
176
174
  };
177
175
 
178
- export const qr = () => ({
179
- type: 'QR'
176
+ type MessageDescriptor = {
177
+ id: string;
178
+ defaultMessage: string;
179
+ description?: string;
180
+ };
181
+
182
+ interface QRValidation {
183
+ rule: Record<string, unknown>;
184
+ errorMessage: MessageDescriptor;
185
+ }
186
+
187
+ interface QRConfig {
188
+ validation: QRValidation;
189
+ }
190
+
191
+ export const qr = ({ validation }: QRConfig) => ({
192
+ type: "QR",
193
+ validation,
180
194
  });
181
195
 
182
- export const verified = (event: string, sectionId: string) => {
183
- const fieldName = 'verified';
196
+ interface ESignetConfig {
197
+ esignetAuthUrl: string;
198
+ openIdProviderClientId: string;
199
+ openIdProviderClaims: string | undefined;
200
+ fieldName: string;
201
+ callback: {
202
+ fieldName: string;
203
+ mosipAPIUserInfoUrl: string;
204
+ };
205
+ loaderFieldName?: string;
206
+ }
207
+
208
+ export const verified = (
209
+ event: string,
210
+ sectionId: string,
211
+ mapping: any,
212
+ esignetConfig?: ESignetConfig,
213
+ ) => {
214
+ const fieldName = "verified";
184
215
  const fieldId = `${event}.${sectionId}.${sectionId}-view-group.${fieldName}`;
185
216
  return {
186
- name: 'verified',
217
+ name: "verified",
187
218
  fieldId,
188
219
  customQuestionMappingId: fieldId,
189
- type: 'HIDDEN',
220
+ type: "HIDDEN",
190
221
  custom: true,
191
222
  label: {
192
- id: 'messages.empty',
193
- defaultMessage: ''
194
- },
195
- initialValue: {
196
- dependsOn: ['idReader'],
197
- expression: 'Boolean($form?.idReader)? "pending":""'
223
+ id: "form.field.label.empty",
224
+ defaultMessage: "",
198
225
  },
199
- validator: []
226
+ initialValue: esignetConfig
227
+ ? {
228
+ dependsOn: ["idReader", esignetConfig.callback.fieldName],
229
+ expression: `Boolean($form?.idReader)? "pending"
230
+ : Boolean($form?.${esignetConfig.callback.fieldName}?.data)? "authenticated"
231
+ : Boolean($form?.${esignetConfig.callback.fieldName}?.error)? "failedFetchIdDetails"
232
+ : ""`,
233
+ }
234
+ : {
235
+ dependsOn: ["idReader"],
236
+ expression: 'Boolean($form?.idReader)? "pending":""',
237
+ },
238
+ validator: [],
239
+ mapping,
200
240
  };
201
241
  };
202
242
 
203
- export const idPendingVerificationBanner = (
243
+ function capitalize(str: string) {
244
+ return str.charAt(0).toUpperCase() + str.slice(1);
245
+ }
246
+
247
+ type VerificationStatus =
248
+ | "verified"
249
+ | "failed"
250
+ | "authenticated"
251
+ | "failedFetchIdDetails";
252
+
253
+ export const idVerificationBanner = (
204
254
  event: string,
205
- sectionId: string
255
+ sectionId: string,
256
+ status: VerificationStatus,
257
+ conditionals: any[] = [],
206
258
  ) => {
207
- const fieldName = 'verified';
259
+ const fieldName = "verified";
208
260
  const fieldId = `${event}.${sectionId}.${sectionId}-view-group.${fieldName}`;
209
261
  return {
210
- name: 'idPending',
211
- type: 'ID_VERIFICATION_BANNER',
262
+ name: `id${capitalize(status)}.`,
263
+ type: "ID_VERIFICATION_BANNER",
212
264
  fieldId,
213
265
  hideInPreview: true,
214
266
  custom: true,
215
- bannerType: 'pending',
216
- idFieldName: 'idReader',
267
+ bannerType: status,
268
+ idFieldName:
269
+ status === "authenticated" || "failedFetchIdDetails"
270
+ ? "esignetCallback"
271
+ : "idReader",
217
272
  label: {
218
- id: 'messages.empty',
219
- defaultMessage: ''
273
+ id: "form.field.label.empty",
274
+ defaultMessage: "",
220
275
  },
221
276
  validator: [],
222
- conditionals: [
277
+ conditionals: conditionals.concat([
223
278
  {
224
- action: 'hide',
225
- expression: '$form?.verified !== "pending"'
226
- }
227
- ]
279
+ action: "hide",
280
+ expression: `$form?.verified !== "${status}"`,
281
+ },
282
+ ]),
228
283
  };
229
284
  };
230
285
 
231
- export const idVerificationFields = (event: string, sectionId: string) => {
286
+ export function esignetLoaderField({
287
+ event,
288
+ section,
289
+ fieldName,
290
+ esignetCallbackFieldName,
291
+ }: {
292
+ event: "birth" | "death";
293
+ section: "informant" | "mother" | "father" | "spouse" | "deceased";
294
+ fieldName: string;
295
+ esignetCallbackFieldName: string;
296
+ }) {
297
+ const fieldId = `${event}.${section}.${section}-view-group.${fieldName}`;
298
+ return {
299
+ name: fieldName,
300
+ type: "LOADER",
301
+ fieldId,
302
+ hideInPreview: true,
303
+ custom: true,
304
+ label: {
305
+ id: "form.field.label.idReader",
306
+ defaultMessage: "ID verification",
307
+ },
308
+ loadingText: {
309
+ id: "form.field.label.authenticating.nid",
310
+ defaultMessage: "Fetching the person's data from E-Signet",
311
+ },
312
+ conditionals: [
313
+ {
314
+ action: "hide",
315
+ expression: `!$form?.${esignetCallbackFieldName}?.loading`,
316
+ },
317
+ ],
318
+ };
319
+ }
320
+
321
+ export const getInitialValueFromIDReader = (fieldNameInReader: string) => ({
322
+ dependsOn: ["idReader", "esignetCallback"],
323
+ expression: `$form?.idReader?.${fieldNameInReader} || $form?.esignetCallback?.data?.${fieldNameInReader} || ""`,
324
+ });
325
+
326
+ export const idReaderFields = (
327
+ event: "birth" | "death",
328
+ section: "informant" | "mother" | "father" | "spouse" | "deceased",
329
+ qrConfig: QRConfig,
330
+ esignetConfig: ESignetConfig | undefined,
331
+ verifiedCustomFieldMapping: any,
332
+ conditionals: any[] = [],
333
+ ) => {
334
+ const readers: any[] = [qr(qrConfig)];
335
+ const fields: any[] = [
336
+ idReader(
337
+ event,
338
+ section,
339
+ conditionals.concat({
340
+ action: "hide",
341
+ expression:
342
+ "$form?.verified === 'verified' || $form?.verified === 'authenticated' || $form?.verified === 'failed' || $form?.verified === 'failedFetchIdDetails' || !!$form?.esignetCallback?.loading",
343
+ }),
344
+ readers,
345
+ ),
346
+ ];
347
+ if (esignetConfig) {
348
+ readers.push(
349
+ esignet(
350
+ esignetConfig.esignetAuthUrl,
351
+ esignetConfig.openIdProviderClientId,
352
+ esignetConfig.openIdProviderClaims,
353
+ esignetConfig.fieldName,
354
+ esignetConfig.callback.fieldName,
355
+ ),
356
+ );
357
+ fields.push(
358
+ esignetCallback({
359
+ fieldName: esignetConfig.callback.fieldName,
360
+ mosipAPIUserInfoUrl: esignetConfig.callback.mosipAPIUserInfoUrl,
361
+ openIdProviderClientId: esignetConfig.openIdProviderClientId,
362
+ }),
363
+ );
364
+ if (esignetConfig.loaderFieldName) {
365
+ fields.push(
366
+ esignetLoaderField({
367
+ event,
368
+ section,
369
+ fieldName: esignetConfig.loaderFieldName,
370
+ esignetCallbackFieldName: esignetConfig.callback.fieldName,
371
+ }),
372
+ );
373
+ }
374
+ return [
375
+ ...fields,
376
+ ...idVerificationFields(
377
+ event,
378
+ section,
379
+ verifiedCustomFieldMapping,
380
+ conditionals,
381
+ esignetConfig,
382
+ ),
383
+ ];
384
+ }
385
+ return [
386
+ ...fields,
387
+ ...idVerificationFields(
388
+ event,
389
+ section,
390
+ verifiedCustomFieldMapping,
391
+ conditionals,
392
+ ),
393
+ ];
394
+ };
395
+ export const idVerificationFields = (
396
+ event: string,
397
+ sectionId: string,
398
+ mapping: any,
399
+ conditionals: any[] = [],
400
+ esignetConfig?: ESignetConfig,
401
+ ) => {
232
402
  return [
233
- verified(event, sectionId),
234
- idPendingVerificationBanner(event, sectionId)
403
+ verified(event, sectionId, mapping, esignetConfig),
404
+ idVerificationBanner(event, sectionId, "verified", conditionals),
405
+ idVerificationBanner(event, sectionId, "failed", conditionals),
406
+ idVerificationBanner(event, sectionId, "authenticated", conditionals),
407
+ idVerificationBanner(
408
+ event,
409
+ sectionId,
410
+ "failedFetchIdDetails",
411
+ conditionals,
412
+ ),
235
413
  ];
236
414
  };
package/src/index.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from "./forms";
2
2
  export * from "./events";
3
+ export * from "./transform";
@@ -0,0 +1,92 @@
1
+ type IdentityInfo = { value: string; language: string };
2
+
3
+ export interface MOSIPPayload {
4
+ compositionId: string;
5
+ trackingId: string;
6
+ notification: {
7
+ recipientFullName: string;
8
+ recipientEmail: string;
9
+ recipientPhone: string;
10
+ };
11
+ requestFields: {
12
+ fullName: string;
13
+ dateOfBirth: string;
14
+ gender: string;
15
+ guardianOrParentName: string;
16
+ nationalIdNumber: string;
17
+ passportNumber: string;
18
+ drivingLicenseNumber: string;
19
+ deceasedStatus: boolean;
20
+ residenceStatus: string;
21
+ vid: string;
22
+ email: string;
23
+ phone: string;
24
+ guardianOrParentBirthCertificateNumber: string;
25
+ birthCertificateNumber: string;
26
+ addressLine1: string;
27
+ addressLine2: string;
28
+ addressLine3: string;
29
+ district: string;
30
+ village: string;
31
+ birthRegistrationCertificate: string;
32
+ passportId: string;
33
+ nationalId: string;
34
+ drivingLicenseId: string;
35
+ addressProof: string;
36
+ selectedHandles: string;
37
+ UIN: string;
38
+ deathDeclared: string;
39
+ dateOfDeath: string;
40
+ };
41
+ audit: {
42
+ uuid: string;
43
+ createdAt: string;
44
+ eventId: string;
45
+ eventName: string;
46
+ eventType: string;
47
+ hostName: string;
48
+ hostIp: string;
49
+ applicationId: string;
50
+ applicationName: string;
51
+ sessionUserId: string;
52
+ sessionUserName: string;
53
+ id: string;
54
+ idType: string;
55
+ createdBy: string;
56
+ moduleName: string;
57
+ moduleId: string;
58
+ description: string;
59
+ actionTimeStamp: string;
60
+ };
61
+ }
62
+
63
+ type Resolver<T> = (bundle: fhir3.Bundle) => T;
64
+
65
+ type ResolverMap<T> = {
66
+ [K in keyof T]?: T[K] extends IdentityInfo[] | string | boolean | number
67
+ ? Resolver<T[K]>
68
+ : ResolverMap<T[K]>;
69
+ };
70
+
71
+ export function fhirBundleToMOSIPPayload(
72
+ bundle: fhir3.Bundle,
73
+ resolverMap: ResolverMap<MOSIPPayload>,
74
+ ): MOSIPPayload {
75
+ const assignResolvers = <T extends object>(resolvers: ResolverMap<T>): T => {
76
+ const result = {} as T;
77
+
78
+ for (const key in resolvers) {
79
+ const resolver = resolvers[key];
80
+
81
+ if (typeof resolver === "function") {
82
+ result[key] = resolver(bundle);
83
+ } else if (resolver && typeof resolver === "object") {
84
+ result[key] = assignResolvers(resolver) as T[Extract<keyof T, string>];
85
+ }
86
+ }
87
+
88
+ return result;
89
+ };
90
+
91
+ return assignResolvers(resolverMap);
92
+ }
package/tsconfig.json CHANGED
@@ -8,4 +8,4 @@
8
8
  "declaration": true,
9
9
  "outDir": "./build"
10
10
  }
11
- }
11
+ }