Skip to content

Commit d9fc9ce

Browse files
committed
fix: pr feedback
1 parent 466d6b9 commit d9fc9ce

File tree

3 files changed

+114
-23
lines changed

3 files changed

+114
-23
lines changed

packages/services/src/__tests__/verifiableCredential.test.ts

Lines changed: 98 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ describe('verifiableCredential', () => {
3838

3939
describe('sign', () => {
4040
const mockEnvelopedVerifiableCredential = {
41-
'@context': ['https://www.w3.org/ns/credentials/v2'],
42-
type: 'EnvelopedVerifiableCredential',
43-
id: 'data:application/vc-ld+jwt,eyJhbGciOiJFZERTQSIsImlzcyI6ImRpZDp3ZWIvcmcvMjAxOC9jcmVkZWyMDIyIn1dfQ.8pUt1rZktWKGBGyJ6GH3io6f7fliAg8IWsEqTWCYvKm0fQkIlPnqqTobxgR3qmtMd_jJXc8IHwbVVOBUEvpcCg',
44-
issuer: 'did:web:uncefact.github.io:project-vckit:test-and-development'
41+
verifiableCredential: {
42+
'@context': ['https://www.w3.org/ns/credentials/v2'],
43+
type: 'EnvelopedVerifiableCredential',
44+
id: 'data:application/vc-ld+jwt,eyJhbGciOiJFZERTQSIsImlzcyI6ImRpZDp3ZWIvcmcvMjAxOC9jcmVkZWyMDIyIn1dfQ.8pUt1rZktWKGBGyJ6GH3io6f7fliAg8IWsEqTWCYvKm0fQkIlPnqqTobxgR3qmtMd_jJXc8IHwbVVOBUEvpcCg',
45+
issuer: 'did:web:uncefact.github.io:project-vckit:test-and-development'
46+
}
4547
};
4648

4749
it('should call issue API endpoint with credential status', async () => {
@@ -61,7 +63,7 @@ describe('verifiableCredential', () => {
6163
// Verify call to credential status endpoint
6264
expect(privateAPI.post).toHaveBeenNthCalledWith(
6365
1,
64-
`https://api.vc.example.com/agent/issueBitstringStatusList`,
66+
`${mockAPIUrl}/agent/issueBitstringStatusList`,
6567
expect.objectContaining({
6668
statusPurpose: 'revocation',
6769
bitstringStatusIssuer: mockIssuer,
@@ -106,7 +108,7 @@ describe('verifiableCredential', () => {
106108
// Verify headers in credential status call
107109
expect(privateAPI.post).toHaveBeenNthCalledWith(
108110
1,
109-
`https://api.vc.example.com/agent/issueBitstringStatusList`,
111+
`${mockAPIUrl}/agent/issueBitstringStatusList`,
110112
expect.any(Object),
111113
{ headers: customHeaders },
112114
);
@@ -168,6 +170,33 @@ describe('verifiableCredential', () => {
168170

169171
const result = await service.sign(vc);
170172

173+
// Verify call to credential status endpoint with default issuer
174+
expect(privateAPI.post).toHaveBeenNthCalledWith(
175+
1,
176+
`${mockAPIUrl}/agent/issueBitstringStatusList`,
177+
expect.objectContaining({
178+
statusPurpose: 'revocation',
179+
bitstringStatusIssuer: 'did:web:uncefact.github.io:project-vckit:test-and-development',
180+
}),
181+
{ headers: {} },
182+
);
183+
184+
// Verify call to issue endpoint with default context, type, and issuer
185+
expect(privateAPI.post).toHaveBeenNthCalledWith(
186+
2,
187+
`${mockAPIUrl}/credentials/issue`,
188+
expect.objectContaining({
189+
credential: {
190+
'@context': ['https://www.w3.org/ns/credentials/v2'],
191+
type: ['VerifiableCredential'],
192+
issuer: 'did:web:uncefact.github.io:project-vckit:test-and-development',
193+
credentialSubject: mockCredentialSubject,
194+
credentialStatus: mockCredentialStatus,
195+
}
196+
}),
197+
{ headers: {} },
198+
);
199+
171200
expect(result).toEqual(mockEnvelopedVerifiableCredential);
172201
});
173202

@@ -179,8 +208,10 @@ describe('verifiableCredential', () => {
179208
} as CredentialPayload;
180209

181210
const mockIssueResponse = {
182-
...mockEnvelopedVerifiableCredential,
183-
"@context": ['https://www.w3.org/ns/credentials/v2', 'https://test.uncefact.org/vocabulary/untp/dia/0.6.0/']
211+
verifiableCredential: {
212+
...mockEnvelopedVerifiableCredential.verifiableCredential,
213+
"@context": ['https://www.w3.org/ns/credentials/v2', 'https://test.uncefact.org/vocabulary/untp/dia/0.6.0/']
214+
}
184215
};
185216

186217
(privateAPI.post as jest.Mock)
@@ -189,19 +220,48 @@ describe('verifiableCredential', () => {
189220

190221
const result = await service.sign(vc);
191222

223+
// Verify call to credential status endpoint with default issuer
224+
expect(privateAPI.post).toHaveBeenNthCalledWith(
225+
1,
226+
`${mockAPIUrl}/agent/issueBitstringStatusList`,
227+
expect.objectContaining({
228+
statusPurpose: 'revocation',
229+
bitstringStatusIssuer: 'did:web:uncefact.github.io:project-vckit:test-and-development',
230+
}),
231+
{ headers: {} },
232+
);
233+
234+
// Verify call to issue endpoint with merged context (default + custom)
235+
expect(privateAPI.post).toHaveBeenNthCalledWith(
236+
2,
237+
`${mockAPIUrl}/credentials/issue`,
238+
expect.objectContaining({
239+
credential: expect.objectContaining({
240+
'@context': ['https://www.w3.org/ns/credentials/v2', 'https://test.uncefact.org/vocabulary/untp/dia/0.6.0/'],
241+
type: ['VerifiableCredential'],
242+
issuer: 'did:web:uncefact.github.io:project-vckit:test-and-development',
243+
credentialSubject: mockCredentialSubject,
244+
credentialStatus: mockCredentialStatus,
245+
})
246+
}),
247+
{ headers: {} },
248+
);
249+
192250
expect(result).toEqual(mockIssueResponse);
193251
});
194252

195253
it('should issue VC with added type', async () => {
196254
const service = new VerifiableCredentialService(mockAPIUrl);
197255
const vc = {
198-
type: ['Custom Type'],
256+
type: 'CustomType',
199257
credentialSubject: mockCredentialSubject
200258
} as CredentialPayload;
201259

202260
const mockIssueResponse = {
203-
...mockEnvelopedVerifiableCredential,
204-
type: ['Custom Type', 'VerifiableCredential']
261+
verifiableCredential: {
262+
...mockEnvelopedVerifiableCredential.verifiableCredential,
263+
type: ['VerifiableCredential', 'CustomType']
264+
}
205265
};
206266

207267
(privateAPI.post as jest.Mock)
@@ -210,6 +270,33 @@ describe('verifiableCredential', () => {
210270

211271
const result = await service.sign(vc);
212272

273+
// Verify call to credential status endpoint with default issuer
274+
expect(privateAPI.post).toHaveBeenNthCalledWith(
275+
1,
276+
`${mockAPIUrl}/agent/issueBitstringStatusList`,
277+
expect.objectContaining({
278+
statusPurpose: 'revocation',
279+
bitstringStatusIssuer: 'did:web:uncefact.github.io:project-vckit:test-and-development',
280+
}),
281+
{ headers: {} },
282+
);
283+
284+
// Verify call to issue endpoint with merged type (custom + default)
285+
expect(privateAPI.post).toHaveBeenNthCalledWith(
286+
2,
287+
`${mockAPIUrl}/credentials/issue`,
288+
expect.objectContaining({
289+
credential: expect.objectContaining({
290+
'@context': ['https://www.w3.org/ns/credentials/v2'],
291+
type: ['VerifiableCredential', 'CustomType'],
292+
issuer: 'did:web:uncefact.github.io:project-vckit:test-and-development',
293+
credentialSubject: mockCredentialSubject,
294+
credentialStatus: mockCredentialStatus,
295+
})
296+
}),
297+
{ headers: {} },
298+
);
299+
213300
expect(result).toEqual(mockIssueResponse);
214301
});
215302

packages/services/src/interfaces/verifiableCredentialService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ export type CredentialPayload = {
111111
issuer?: Issuer;
112112
credentialSubject: OneOrMany<CredentialSubject>;
113113
credentialStatus?: OneOrMany<CredentialStatus>;
114-
} & Extensible;
114+
};
115115

116116
export type Error = {
117117
message?: string;

packages/services/src/verifiableCredential.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,17 @@ export class VerifiableCredentialService implements IVerifiableCredentialService
5757
}
5858

5959
// Issue credential status if not provided
60-
if (!credentialPayload.credentialStatus) {
61-
const credentialStatus = await this.issueCredentialStatus({
62-
host: new URL(this.baseURL).origin,
63-
headers,
64-
bitstringStatusIssuer: credentialPayload.issuer || issuerDefault,
65-
});
66-
credentialPayload.credentialStatus = credentialStatus as CredentialStatus;
67-
}
60+
const credentialStatus = credentialPayload.credentialStatus ?? await this.issueCredentialStatus({
61+
host: new URL(this.baseURL).origin,
62+
headers,
63+
bitstringStatusIssuer: credentialPayload.issuer || issuerDefault,
64+
});
6865

6966
// construct verifiable credential
70-
const vc = this.constructVerifiableCredential(credentialPayload);
67+
const vc = this.constructVerifiableCredential({
68+
...credentialPayload,
69+
credentialStatus
70+
});
7171

7272
// issue credential
7373
const signedCredential = await this.issueVerifiableCredential(vc, headers);
@@ -85,8 +85,12 @@ export class VerifiableCredentialService implements IVerifiableCredentialService
8585
credentialPayload: CredentialPayload
8686
): W3CVerifiableCredential {
8787
// add or merge context from credentialPayload
88-
const context = [...contextDefault, ...(credentialPayload.context || [])]
89-
const type = [...(credentialPayload.type || []), ...typeDefault];
88+
const context = [...new Set([...contextDefault, ...(credentialPayload.context || [])])]
89+
const additionalTypes = credentialPayload.type
90+
? (Array.isArray(credentialPayload.type) ? credentialPayload.type : [credentialPayload.type])
91+
: [];
92+
93+
const type = [...typeDefault, ...additionalTypes];
9094

9195
const issuer = credentialPayload.issuer || issuerDefault;
9296

0 commit comments

Comments
 (0)