@verii/data-loader 1.1.0-pre.1775646065 → 1.1.0-pre.1775953178

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verii/data-loader",
3
- "version": "1.1.0-pre.1775646065",
3
+ "version": "1.1.0-pre.1775953178",
4
4
  "description": "A tool for uploading data to the different target systems.",
5
5
  "repository": "https://github.com/LFDT-Verii/core",
6
6
  "main": "src/index.js",
@@ -29,20 +29,20 @@
29
29
  "eslint-watch": "8.0.0",
30
30
  "expect": "30.3.0",
31
31
  "globals": "17.4.0",
32
- "nock": "15.0.0",
32
+ "nock": "15.0.0-beta.10",
33
33
  "prettier": "3.8.1"
34
34
  },
35
35
  "dependencies": {
36
+ "@verii/http-client": "1.1.0-pre.1775953178",
36
37
  "chalk": "~4.1.2",
37
38
  "commander": "~14.0.0",
38
39
  "csv-parser": "~3.2.0",
39
40
  "date-fns": "4.1.0",
40
- "got": "11.8.6",
41
41
  "handlebars": "^4.7.7",
42
42
  "inquirer": "^8.0.0",
43
43
  "lodash": "^4.17.21",
44
44
  "nanoid": "5.1.6",
45
45
  "strip-bom-stream": "^4.0.0"
46
46
  },
47
- "gitHead": "c90142b444d418223ac72994f14bfd0ccd336444"
47
+ "gitHead": "05090118369e202d7c77fc4a420b14f94338a3e5"
48
48
  }
@@ -1,78 +1,77 @@
1
1
  const { env } = require('node:process');
2
- const got = require('got');
2
+ const { initHttpClient } = require('@verii/http-client');
3
3
  const { map, isEmpty } = require('lodash/fp');
4
4
  const { printInfo } = require('../helpers/common');
5
5
 
6
- const setupGot = ({ endpoint, authToken }) => {
6
+ const setupHttpClient = ({ endpoint, authToken }) => {
7
7
  const options = {};
8
8
  if (endpoint != null) {
9
9
  options.prefixUrl = `${endpoint}/operator-api/v0.8`;
10
10
  }
11
11
  if (authToken != null) {
12
- options.headers = { Authorization: `Bearer ${authToken}` };
12
+ options.bearerToken = authToken;
13
13
  }
14
14
  if (env.NODE_TLS_REJECT_UNAUTHORIZED === '0') {
15
- options.https = {
16
- rejectUnauthorized: false,
17
- };
15
+ options.tlsRejectUnauthorized = false;
18
16
  }
19
- return got.extend(options);
17
+ if (env.NODE_ENV === 'test') {
18
+ options.isTest = true;
19
+ }
20
+
21
+ return initHttpClient(options)({
22
+ log: console,
23
+ traceId: 'TRACE-ID',
24
+ });
20
25
  };
21
26
 
22
27
  const initFetchers = (options) => {
23
- const credentialAgentTenantGot = setupGot(options);
28
+ const credentialAgentTenantClient = setupHttpClient(options);
24
29
  const param = getTenantsRouteParam(options);
25
30
  return {
26
31
  getTenant: async () => {
27
32
  printInfo('Retrieving tenant');
28
- return credentialAgentTenantGot.get(`tenants/${param}`).json();
33
+ return credentialAgentTenantClient
34
+ .get(`tenants/${param}`)
35
+ .then((res) => res.json());
29
36
  },
30
37
  createDisclosure: async (disclosureRequest) => {
31
38
  printInfo('Creating disclosure');
32
- return credentialAgentTenantGot
33
- .post(`tenants/${param}/disclosures`, {
34
- json: disclosureRequest,
35
- })
36
- .json();
39
+ return credentialAgentTenantClient
40
+ .post(`tenants/${param}/disclosures`, disclosureRequest)
41
+ .then((res) => res.json());
37
42
  },
38
43
  getDisclosureList: async (vendorEndpoints) => {
39
44
  printInfo('Retrieving disclosure list');
40
- const url = new URL(
41
- `tenants/${param}/disclosures`,
42
- credentialAgentTenantGot.defaults.options.prefixUrl,
43
- );
44
-
45
+ const searchParams = new URLSearchParams();
45
46
  if (!isEmpty(vendorEndpoints)) {
46
47
  vendorEndpoints.forEach((vendorEndpoint) => {
47
- url.searchParams.append('vendorEndpoint', vendorEndpoint);
48
+ searchParams.append('vendorEndpoint', vendorEndpoint);
48
49
  });
49
50
  }
50
51
 
51
- return credentialAgentTenantGot.get(url).json();
52
+ return credentialAgentTenantClient
53
+ .get(`tenants/${param}/disclosures`, { searchParams })
54
+ .then((res) => res.json());
52
55
  },
53
56
  getDisclosure: async (disclosureId) => {
54
57
  printInfo('Retrieving disclosure');
55
- return credentialAgentTenantGot
58
+ return credentialAgentTenantClient
56
59
  .get(`tenants/${param}/disclosures/${disclosureId}`)
57
- .json();
60
+ .then((res) => res.json());
58
61
  },
59
62
  createOfferExchange: async (newExchange) => {
60
63
  printInfo('Creating exchange');
61
- return credentialAgentTenantGot
62
- .post(`tenants/${param}/exchanges`, {
63
- json: newExchange,
64
- })
65
- .json();
64
+ return credentialAgentTenantClient
65
+ .post(`tenants/${param}/exchanges`, newExchange)
66
+ .then((res) => res.json());
66
67
  },
67
68
  createOffer: async (exchange, newOffer) => {
68
69
  printInfo(
69
70
  `Adding offer ${newOffer.offerId} to exchange id: ${exchange.id}`,
70
71
  );
71
- return credentialAgentTenantGot
72
- .post(`tenants/${param}/exchanges/${exchange.id}/offers`, {
73
- json: newOffer,
74
- })
75
- .json();
72
+ return credentialAgentTenantClient
73
+ .post(`tenants/${param}/exchanges/${exchange.id}/offers`, newOffer)
74
+ .then((res) => res.json());
76
75
  },
77
76
  submitCompleteOffer: async (exchange, offers) => {
78
77
  printInfo(
@@ -81,30 +80,34 @@ const initFetchers = (options) => {
81
80
  offers,
82
81
  )}`,
83
82
  );
84
- return credentialAgentTenantGot
83
+ return credentialAgentTenantClient
85
84
  .post(`tenants/${param}/exchanges/${exchange.id}/offers/complete`)
86
- .json();
85
+ .then((res) => res.json());
87
86
  },
88
87
  loadExchangeQrcode: async (exchange) =>
89
- (
90
- await credentialAgentTenantGot.get(
91
- `tenants/${param}/exchanges/${exchange.id}/qrcode.png`,
92
- )
93
- ).rawBody,
88
+ Buffer.from(
89
+ await (
90
+ await credentialAgentTenantClient.get(
91
+ `tenants/${param}/exchanges/${exchange.id}/qrcode.png`,
92
+ )
93
+ ).rawBody.arrayBuffer(),
94
+ ),
94
95
  loadExchangeDeeplink: async (exchange) =>
95
- credentialAgentTenantGot
96
+ credentialAgentTenantClient
96
97
  .get(`tenants/${param}/exchanges/${exchange.id}/qrcode.uri`)
97
- .text(),
98
+ .then((res) => res.text()),
98
99
  loadDisclosureQrcode: async (disclosure) =>
99
- (
100
- await credentialAgentTenantGot.get(
101
- `tenants/${param}/disclosures/${disclosure.id}/qrcode.png`,
102
- )
103
- ).rawBody,
100
+ Buffer.from(
101
+ await (
102
+ await credentialAgentTenantClient.get(
103
+ `tenants/${param}/disclosures/${disclosure.id}/qrcode.png`,
104
+ )
105
+ ).rawBody.arrayBuffer(),
106
+ ),
104
107
  loadDisclosureDeeplink: async (disclosure) =>
105
- credentialAgentTenantGot
108
+ credentialAgentTenantClient
106
109
  .get(`tenants/${param}/disclosures/${disclosure.id}/qrcode.uri`)
107
- .text(),
110
+ .then((res) => res.text()),
108
111
  };
109
112
  };
110
113
 
@@ -1,28 +1,35 @@
1
- const got = require('got');
1
+ const { initHttpClient } = require('@verii/http-client');
2
2
  const { printInfo } = require('../helpers/common');
3
3
 
4
- const setupGot = ({ endpoint, authToken }) => {
5
- const options = {
6
- prefixUrl: endpoint,
7
- };
4
+ const setupHttpClient = ({ endpoint, authToken }) => {
5
+ const options = { prefixUrl: endpoint };
8
6
  if (authToken != null) {
9
- options.headers = { Authorization: `Bearer ${authToken}` };
7
+ options.bearerToken = authToken;
8
+ }
9
+ if (process.env.NODE_ENV === 'test') {
10
+ options.isTest = true;
10
11
  }
11
- return got.extend(options);
12
+
13
+ return initHttpClient(options)({
14
+ log: console,
15
+ traceId: 'TRACE-ID',
16
+ });
12
17
  };
13
18
 
14
19
  const initExecuteUpdate = (options) => {
15
- const vendorGot = setupGot(options);
20
+ const vendorHttpClient = setupHttpClient(options);
16
21
  return async ({ person, offer }) => {
17
22
  if (person) {
18
23
  printInfo({
19
- createdPerson: await vendorGot
20
- .post('api/users', { json: person })
21
- .json(),
24
+ createdPerson: await vendorHttpClient
25
+ .post('api/users', person)
26
+ .then((res) => res.json()),
22
27
  });
23
28
  }
24
29
  printInfo({
25
- createdOffer: await vendorGot.post('api/offers', { json: offer }).json(),
30
+ createdOffer: await vendorHttpClient
31
+ .post('api/offers', offer)
32
+ .then((res) => res.json()),
26
33
  });
27
34
  };
28
35
  };
@@ -1,6 +1,8 @@
1
1
  const { after, before, describe, it } = require('node:test');
2
2
  const { expect } = require('expect');
3
3
 
4
+ const fs = require('fs');
5
+ const os = require('os');
4
6
  const path = require('path');
5
7
  const nock = require('nock');
6
8
 
@@ -1465,4 +1467,151 @@ describe('batch issuing test', () => {
1465
1467
  });
1466
1468
  });
1467
1469
  });
1470
+
1471
+ it('should create disclosure and exchange payloads through the full issuing flow', async () => {
1472
+ const agentUrl = 'https://exampleUrl';
1473
+ const tempDir = fs.mkdtempSync(
1474
+ path.join(os.tmpdir(), 'data-loader-batch-issuing-'),
1475
+ );
1476
+ const expectedDisclosure = {
1477
+ configurationType: 'issuing',
1478
+ vendorEndpoint: 'integrated-issuing-identification',
1479
+ types: [{ type: 'EmailV1.0' }],
1480
+ identityMatchers: {
1481
+ rules: [
1482
+ {
1483
+ valueIndex: 0,
1484
+ path: ['$.emails'],
1485
+ rule: 'pick',
1486
+ },
1487
+ ],
1488
+ vendorUserIdIndex: 2,
1489
+ },
1490
+ setIssuingDefault: true,
1491
+ duration: '1h',
1492
+ purpose: 'Issuing Career Credential',
1493
+ authTokenExpiresIn: 525600,
1494
+ termsUrl: 'http://example.com/terms.html',
1495
+ };
1496
+ const expectedFirstExchange = {
1497
+ type: 'ISSUING',
1498
+ identityMatcherValues: ['joan.lee@sap.com'],
1499
+ disclosureId: 'disclosure-id',
1500
+ };
1501
+ const expectedSecondExchange = {
1502
+ type: 'ISSUING',
1503
+ identityMatcherValues: ['john.smith@sap.com'],
1504
+ disclosureId: 'disclosure-id',
1505
+ };
1506
+ const expectedFirstOffer = {
1507
+ type: ['EmailV1.0'],
1508
+ issuer: { id: 'did:sap:123' },
1509
+ credentialSubject: {
1510
+ vendorUserId: 'joan.lee@sap.com',
1511
+ email: 'joan.lee@sap.com',
1512
+ },
1513
+ };
1514
+ const expectedSecondOffer = {
1515
+ type: ['EmailV1.0'],
1516
+ issuer: { id: 'did:sap:123' },
1517
+ credentialSubject: {
1518
+ vendorUserId: 'john.smith@sap.com',
1519
+ email: 'john.smith@sap.com',
1520
+ },
1521
+ };
1522
+
1523
+ const disclosureScope = nock(agentUrl, {
1524
+ reqheaders: { Authorization: 'Bearer fakeToken' },
1525
+ })
1526
+ .post('/operator-api/v0.8/tenants/tenant-id/disclosures', (body) => {
1527
+ expect(body).toMatchObject(expectedDisclosure);
1528
+ expect(body.vendorDisclosureId).toEqual(expect.any(Number));
1529
+ expect(body.activationDate).toEqual(
1530
+ expect.stringMatching(ISO_DATETIME_TZ_FORMAT),
1531
+ );
1532
+ return true;
1533
+ })
1534
+ .reply(200, { id: 'disclosure-id' });
1535
+
1536
+ const exchangeOfferScope = nock(agentUrl, {
1537
+ reqheaders: { Authorization: 'Bearer fakeToken' },
1538
+ })
1539
+ .post(
1540
+ '/operator-api/v0.8/tenants/tenant-id/exchanges',
1541
+ expectedFirstExchange,
1542
+ )
1543
+ .reply(200, { id: 'exchange-1' })
1544
+ .post(
1545
+ '/operator-api/v0.8/tenants/tenant-id/exchanges/exchange-1/offers',
1546
+ (body) => {
1547
+ expect(body).toMatchObject(expectedFirstOffer);
1548
+ expect(body.offerId).toEqual(expect.any(String));
1549
+ return true;
1550
+ },
1551
+ )
1552
+ .reply(200, { id: 'offer-1' })
1553
+ .post(
1554
+ '/operator-api/v0.8/tenants/tenant-id/exchanges/exchange-1/offers/complete',
1555
+ )
1556
+ .reply(200, {})
1557
+ .post(
1558
+ '/operator-api/v0.8/tenants/tenant-id/exchanges',
1559
+ expectedSecondExchange,
1560
+ )
1561
+ .reply(200, { id: 'exchange-2' })
1562
+ .post(
1563
+ '/operator-api/v0.8/tenants/tenant-id/exchanges/exchange-2/offers',
1564
+ (body) => {
1565
+ expect(body).toMatchObject(expectedSecondOffer);
1566
+ expect(body.offerId).toEqual(expect.any(String));
1567
+ return true;
1568
+ },
1569
+ )
1570
+ .reply(200, { id: 'offer-2' })
1571
+ .post(
1572
+ '/operator-api/v0.8/tenants/tenant-id/exchanges/exchange-2/offers/complete',
1573
+ )
1574
+ .reply(200, {})
1575
+ .get(
1576
+ '/operator-api/v0.8/tenants/tenant-id/disclosures/disclosure-id/qrcode.uri',
1577
+ )
1578
+ .reply(200, 'https://example.com/disclosure')
1579
+ .get(
1580
+ '/operator-api/v0.8/tenants/tenant-id/disclosures/disclosure-id/qrcode.png',
1581
+ )
1582
+ .reply(200, Buffer.from('fake-png'));
1583
+
1584
+ const options = {
1585
+ csvFilename: path.join(__dirname, 'data/variables.csv'),
1586
+ offerTemplateFilename: path.join(
1587
+ __dirname,
1588
+ 'data/email-offer.template.json',
1589
+ ),
1590
+ tenant: 'tenant-id',
1591
+ did: 'did:sap:123',
1592
+ termsUrl: 'http://example.com/terms.html',
1593
+ idCredentialType: 'EmailV1.0',
1594
+ vendorUseridColumn: 'email',
1595
+ new: true,
1596
+ endpoint: agentUrl,
1597
+ authToken: 'fakeToken',
1598
+ path: tempDir,
1599
+ };
1600
+
1601
+ try {
1602
+ await expect(runBatchIssuing(options)).resolves.toBeUndefined();
1603
+
1604
+ disclosureScope.done();
1605
+ exchangeOfferScope.done();
1606
+ expect(
1607
+ fs.existsSync(path.join(tempDir, 'disclosure-disclosure-id.json')),
1608
+ ).toBe(true);
1609
+ expect(fs.existsSync(path.join(tempDir, 'lastrun.json'))).toBe(true);
1610
+ expect(fs.existsSync(path.join(tempDir, 'qrcode-generic.png'))).toBe(
1611
+ true,
1612
+ );
1613
+ } finally {
1614
+ fs.rmSync(tempDir, { recursive: true, force: true });
1615
+ }
1616
+ });
1468
1617
  });
@@ -1,5 +1,6 @@
1
- const { describe, it } = require('node:test');
1
+ const { after, before, describe, it } = require('node:test');
2
2
  const { expect } = require('expect');
3
+ const nock = require('nock');
3
4
 
4
5
  const path = require('path');
5
6
  const {
@@ -7,6 +8,15 @@ const {
7
8
  } = require('../src/vendor-credentials/orchestrator');
8
9
 
9
10
  describe('vendor credentials test', () => {
11
+ before(() => {
12
+ nock.cleanAll();
13
+ });
14
+
15
+ after(() => {
16
+ nock.cleanAll();
17
+ nock.restore();
18
+ });
19
+
10
20
  it('should load the templates and csv', async () => {
11
21
  const options = {
12
22
  csvFilename: path.join(__dirname, 'data/variables.csv'),
@@ -227,4 +237,88 @@ describe('vendor credentials test', () => {
227
237
  },
228
238
  ]);
229
239
  });
240
+
241
+ it('should post prepared person and offer payloads when endpoint is provided', async () => {
242
+ const endpoint = 'https://vendor.example';
243
+ const firstPerson = {
244
+ emails: [{ email: 'joan.lee@sap.com' }],
245
+ firstName: { localized: { en: 'Joan' } },
246
+ lastName: { localized: { en: 'Lee' } },
247
+ };
248
+ const secondPerson = {
249
+ emails: [{ email: 'john.smith@sap.com' }],
250
+ firstName: { localized: { en: 'John' } },
251
+ lastName: { localized: { en: 'Smith' } },
252
+ };
253
+ const firstOffer = {
254
+ type: ['OpenBadgeV1.0'],
255
+ issuer: {
256
+ id: 'did:ion:sap123',
257
+ },
258
+ credentialSubject: {
259
+ vendorUserId: 'joan.lee@sap.com',
260
+ holds: {
261
+ name: 'SAP Sapphire Attendance',
262
+ description:
263
+ 'Digital Badge for the Conference Attendees of SAPs Sapphire Conference',
264
+ type: 'BadgeClass',
265
+ issuer: {
266
+ type: 'Profile',
267
+ id: 'did:ion:sap123',
268
+ name: 'SAP',
269
+ uri: 'https://sap.com',
270
+ },
271
+ image: 'https://example.com/badge-image.png',
272
+ criteria: 'https://example.com/sap/criteria.html',
273
+ },
274
+ },
275
+ };
276
+ const secondOffer = {
277
+ type: ['OpenBadgeV1.0'],
278
+ issuer: {
279
+ id: 'did:ion:sap123',
280
+ },
281
+ credentialSubject: {
282
+ vendorUserId: 'john.smith@sap.com',
283
+ holds: {
284
+ name: 'SAP Sapphire Attendance',
285
+ description:
286
+ 'Digital Badge for the Conference Attendees of SAPs Sapphire Conference',
287
+ type: 'BadgeClass',
288
+ issuer: {
289
+ type: 'Profile',
290
+ id: 'did:ion:sap123',
291
+ name: 'SAP',
292
+ uri: 'https://sap.com',
293
+ },
294
+ image: 'https://example.com/badge-image.png',
295
+ criteria: 'https://example.com/sap/criteria.html',
296
+ },
297
+ },
298
+ };
299
+
300
+ const scope = nock(endpoint, {
301
+ reqheaders: { Authorization: 'Bearer fakeToken' },
302
+ })
303
+ .post('/api/users', firstPerson)
304
+ .reply(200, { id: 'person-id-1' })
305
+ .post('/api/offers', firstOffer)
306
+ .reply(200, { id: 'offer-id-1' })
307
+ .post('/api/users', secondPerson)
308
+ .reply(200, { id: 'person-id-2' })
309
+ .post('/api/offers', secondOffer)
310
+ .reply(200, { id: 'offer-id-2' });
311
+
312
+ const options = {
313
+ csvFilename: path.join(__dirname, 'data/variables.csv'),
314
+ offerTemplateFilename: path.join(__dirname, 'data/offer.template.json'),
315
+ personTemplateFilename: path.join(__dirname, 'data/person.template.json'),
316
+ endpoint,
317
+ authToken: 'fakeToken',
318
+ };
319
+
320
+ await expect(executeVendorCredentials(options)).resolves.toBeUndefined();
321
+
322
+ scope.done();
323
+ });
230
324
  });