@kubun/service-credential-api 0.17.2 → 0.18.0
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/lib/adapter.d.ts +2 -2
- package/lib/adapter.js +81 -1
- package/lib/errors.d.ts +7 -0
- package/lib/errors.js +12 -0
- package/lib/index.d.ts +107 -1
- package/lib/index.js +134 -2
- package/package.json +5 -5
package/lib/adapter.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Client } from '@enkaku/client';
|
|
2
|
-
import type { AliasBindingCredentialProvider, CredentialProvider, ProviderAccount } from '@kubun/credential-types';
|
|
2
|
+
import type { AdoptGrantAPI, AliasBindingCredentialProvider, CredentialProvider, EntryPairedCredentialProvider, ProviderAccount, VersionedEntryCredentialProvider } from '@kubun/credential-types';
|
|
3
3
|
import type { CredentialServiceProtocol } from './index.js';
|
|
4
4
|
/**
|
|
5
5
|
* What a storage-only account peek discloses: the provider account and the
|
|
@@ -22,4 +22,4 @@ export type CredentialProviderWithProvenance = CredentialProvider & {
|
|
|
22
22
|
writerDID: string | null;
|
|
23
23
|
} | null>;
|
|
24
24
|
};
|
|
25
|
-
export declare function toCredentialProvider(client: Client<CredentialServiceProtocol>): CredentialProviderWithProvenance & AliasBindingCredentialProvider & Required<Pick<CredentialProviderWithProvenance, 'peekAccount'>>;
|
|
25
|
+
export declare function toCredentialProvider(client: Client<CredentialServiceProtocol>): CredentialProviderWithProvenance & AliasBindingCredentialProvider & EntryPairedCredentialProvider & VersionedEntryCredentialProvider & AdoptGrantAPI & Required<Pick<CredentialProviderWithProvenance, 'peekAccount'>>;
|
package/lib/adapter.js
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
import { RequestError } from '@enkaku/client';
|
|
7
7
|
import { ErrorCodes } from '@enkaku/protocol';
|
|
8
8
|
import { deserializeCredential, serializeCredential } from '@kubun/credential';
|
|
9
|
-
import {
|
|
9
|
+
import { CredentialUpdateUnavailableError } from '@kubun/credential-types';
|
|
10
|
+
import { CredentialPeekUnsupportedError, CredentialUnexpectedSupersededError } from './errors.js';
|
|
10
11
|
export function toCredentialProvider(client) {
|
|
11
12
|
return {
|
|
12
13
|
async get (providerName, ownerDID) {
|
|
@@ -18,6 +19,80 @@ export function toCredentialProvider(client) {
|
|
|
18
19
|
});
|
|
19
20
|
return raw == null ? null : deserializeCredential(raw);
|
|
20
21
|
},
|
|
22
|
+
async getCredentialRef (providerName, ownerDID) {
|
|
23
|
+
const ref = await client.request('credential/get-ref', {
|
|
24
|
+
param: {
|
|
25
|
+
providerName,
|
|
26
|
+
ownerDID
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return ref == null ? null : {
|
|
30
|
+
credential: deserializeCredential(ref.credential),
|
|
31
|
+
entryID: ref.entryID
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
async getVersionedCredentialRef (providerName, ownerDID) {
|
|
35
|
+
const ref = await client.request('credential/get-ref', {
|
|
36
|
+
param: {
|
|
37
|
+
providerName,
|
|
38
|
+
ownerDID
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
return ref == null ? null : {
|
|
42
|
+
credential: deserializeCredential(ref.credential),
|
|
43
|
+
entryID: ref.entryID,
|
|
44
|
+
...ref.version == null ? {} : {
|
|
45
|
+
version: ref.version
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
setCredentialForEntryIfUnchanged ({ providerName, ownerDID, entryID, credential, expectedVersion }) {
|
|
50
|
+
return client.request('credential/refresh-entry', {
|
|
51
|
+
param: {
|
|
52
|
+
providerName,
|
|
53
|
+
ownerDID,
|
|
54
|
+
entryID,
|
|
55
|
+
credential: serializeCredential(credential),
|
|
56
|
+
expectedVersion
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
async update (address, change) {
|
|
61
|
+
for(;;){
|
|
62
|
+
const ref = await client.request('credential/get-ref', {
|
|
63
|
+
param: {
|
|
64
|
+
providerName: address.providerName,
|
|
65
|
+
ownerDID: address.ownerDID,
|
|
66
|
+
deviceDID: address.deviceDID
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
if (ref == null || ref.version == null) throw new CredentialUpdateUnavailableError();
|
|
70
|
+
const result = await client.request('credential/refresh-entry', {
|
|
71
|
+
param: {
|
|
72
|
+
providerName: address.providerName,
|
|
73
|
+
ownerDID: address.ownerDID,
|
|
74
|
+
deviceDID: address.deviceDID,
|
|
75
|
+
entryID: ref.entryID,
|
|
76
|
+
credential: serializeCredential(change(deserializeCredential(ref.credential))),
|
|
77
|
+
expectedVersion: ref.version
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
if (result === 'updated') return;
|
|
81
|
+
if (result === 'absent') throw new CredentialUpdateUnavailableError();
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
async setCredentialForEntry ({ providerName, ownerDID, entryID, credential }) {
|
|
85
|
+
const result = await client.request('credential/refresh-entry', {
|
|
86
|
+
param: {
|
|
87
|
+
providerName,
|
|
88
|
+
ownerDID,
|
|
89
|
+
entryID,
|
|
90
|
+
credential: serializeCredential(credential)
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
if (result === 'superseded') throw new CredentialUnexpectedSupersededError();
|
|
94
|
+
return result;
|
|
95
|
+
},
|
|
21
96
|
async peekAccount (providerName, ownerDID) {
|
|
22
97
|
let peeked;
|
|
23
98
|
try {
|
|
@@ -97,6 +172,11 @@ export function toCredentialProvider(client) {
|
|
|
97
172
|
entryID
|
|
98
173
|
}
|
|
99
174
|
});
|
|
175
|
+
},
|
|
176
|
+
async adoptCredentialGrant (params) {
|
|
177
|
+
await client.request('credential/adopt-grant', {
|
|
178
|
+
param: params
|
|
179
|
+
});
|
|
100
180
|
}
|
|
101
181
|
};
|
|
102
182
|
}
|
package/lib/errors.d.ts
CHANGED
|
@@ -16,3 +16,10 @@ export declare class CredentialPeekUnsupportedError extends Error {
|
|
|
16
16
|
constructor(options?: ErrorOptions);
|
|
17
17
|
get code(): typeof CREDENTIAL_PEEK_UNSUPPORTED;
|
|
18
18
|
}
|
|
19
|
+
/** An unconditional entry write received a result reserved for versioned writes. */
|
|
20
|
+
export declare const CREDENTIAL_UNEXPECTED_SUPERSEDED = "CREDENTIAL_UNEXPECTED_SUPERSEDED";
|
|
21
|
+
export declare class CredentialUnexpectedSupersededError extends Error {
|
|
22
|
+
#private;
|
|
23
|
+
constructor();
|
|
24
|
+
get code(): typeof CREDENTIAL_UNEXPECTED_SUPERSEDED;
|
|
25
|
+
}
|
package/lib/errors.js
CHANGED
|
@@ -20,3 +20,15 @@
|
|
|
20
20
|
return this.#code;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
/** An unconditional entry write received a result reserved for versioned writes. */ export const CREDENTIAL_UNEXPECTED_SUPERSEDED = 'CREDENTIAL_UNEXPECTED_SUPERSEDED';
|
|
24
|
+
export class CredentialUnexpectedSupersededError extends Error {
|
|
25
|
+
#code;
|
|
26
|
+
constructor(){
|
|
27
|
+
super('The credential service superseded an unconditional entry write');
|
|
28
|
+
this.name = 'CredentialUnexpectedSupersededError';
|
|
29
|
+
this.#code = CREDENTIAL_UNEXPECTED_SUPERSEDED;
|
|
30
|
+
}
|
|
31
|
+
get code() {
|
|
32
|
+
return this.#code;
|
|
33
|
+
}
|
|
34
|
+
}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { type CredentialAccountPeek, type CredentialProviderWithProvenance, toCredentialProvider, } from './adapter.js';
|
|
2
|
-
export { CREDENTIAL_PEEK_UNSUPPORTED, CredentialPeekUnsupportedError } from './errors.js';
|
|
2
|
+
export { CREDENTIAL_PEEK_UNSUPPORTED, CREDENTIAL_UNEXPECTED_SUPERSEDED, CredentialPeekUnsupportedError, CredentialUnexpectedSupersededError, } from './errors.js';
|
|
3
3
|
export declare const credentialServiceProtocol: {
|
|
4
4
|
readonly 'credential/get': {
|
|
5
5
|
readonly type: "request";
|
|
@@ -24,6 +24,45 @@ export declare const credentialServiceProtocol: {
|
|
|
24
24
|
}];
|
|
25
25
|
};
|
|
26
26
|
};
|
|
27
|
+
readonly 'credential/get-ref': {
|
|
28
|
+
readonly type: "request";
|
|
29
|
+
readonly param: {
|
|
30
|
+
readonly type: "object";
|
|
31
|
+
readonly properties: {
|
|
32
|
+
readonly providerName: {
|
|
33
|
+
readonly type: "string";
|
|
34
|
+
};
|
|
35
|
+
readonly ownerDID: {
|
|
36
|
+
readonly type: "string";
|
|
37
|
+
};
|
|
38
|
+
readonly deviceDID: {
|
|
39
|
+
readonly type: "string";
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
readonly required: readonly ["providerName", "ownerDID"];
|
|
43
|
+
readonly additionalProperties: false;
|
|
44
|
+
};
|
|
45
|
+
readonly result: {
|
|
46
|
+
readonly anyOf: [{
|
|
47
|
+
readonly type: "object";
|
|
48
|
+
readonly properties: {
|
|
49
|
+
readonly credential: {
|
|
50
|
+
readonly type: "string";
|
|
51
|
+
};
|
|
52
|
+
readonly entryID: {
|
|
53
|
+
readonly type: "string";
|
|
54
|
+
};
|
|
55
|
+
readonly version: {
|
|
56
|
+
readonly type: "string";
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
readonly required: readonly ["credential", "entryID"];
|
|
60
|
+
readonly additionalProperties: false;
|
|
61
|
+
}, {
|
|
62
|
+
readonly type: "null";
|
|
63
|
+
}];
|
|
64
|
+
};
|
|
65
|
+
};
|
|
27
66
|
readonly 'credential/peek': {
|
|
28
67
|
readonly type: "request";
|
|
29
68
|
readonly param: {
|
|
@@ -165,6 +204,73 @@ export declare const credentialServiceProtocol: {
|
|
|
165
204
|
readonly type: "null";
|
|
166
205
|
};
|
|
167
206
|
};
|
|
207
|
+
readonly 'credential/refresh-entry': {
|
|
208
|
+
readonly type: "request";
|
|
209
|
+
readonly param: {
|
|
210
|
+
readonly type: "object";
|
|
211
|
+
readonly properties: {
|
|
212
|
+
readonly providerName: {
|
|
213
|
+
readonly type: "string";
|
|
214
|
+
};
|
|
215
|
+
readonly ownerDID: {
|
|
216
|
+
readonly type: "string";
|
|
217
|
+
};
|
|
218
|
+
readonly deviceDID: {
|
|
219
|
+
readonly type: "string";
|
|
220
|
+
};
|
|
221
|
+
readonly entryID: {
|
|
222
|
+
readonly type: "string";
|
|
223
|
+
};
|
|
224
|
+
readonly credential: {
|
|
225
|
+
readonly type: "string";
|
|
226
|
+
};
|
|
227
|
+
readonly expectedVersion: {
|
|
228
|
+
readonly type: "string";
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
readonly required: readonly ["providerName", "ownerDID", "entryID", "credential"];
|
|
232
|
+
readonly additionalProperties: false;
|
|
233
|
+
};
|
|
234
|
+
readonly result: {
|
|
235
|
+
readonly type: "string";
|
|
236
|
+
readonly enum: readonly ["updated", "absent", "superseded"];
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
readonly 'credential/adopt-grant': {
|
|
240
|
+
readonly type: "request";
|
|
241
|
+
readonly param: {
|
|
242
|
+
readonly type: "object";
|
|
243
|
+
readonly properties: {
|
|
244
|
+
readonly providerName: {
|
|
245
|
+
readonly type: "string";
|
|
246
|
+
};
|
|
247
|
+
readonly ownerDID: {
|
|
248
|
+
readonly type: "string";
|
|
249
|
+
};
|
|
250
|
+
readonly fromDeviceDID: {
|
|
251
|
+
readonly type: "string";
|
|
252
|
+
};
|
|
253
|
+
readonly toDeviceDID: {
|
|
254
|
+
readonly type: "string";
|
|
255
|
+
};
|
|
256
|
+
readonly sourceKeyOwnerDID: {
|
|
257
|
+
readonly type: "string";
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
readonly required: readonly ["providerName", "ownerDID", "fromDeviceDID", "toDeviceDID"];
|
|
261
|
+
readonly additionalProperties: false;
|
|
262
|
+
};
|
|
263
|
+
readonly result: {
|
|
264
|
+
readonly type: "object";
|
|
265
|
+
readonly properties: {
|
|
266
|
+
readonly adopted: {
|
|
267
|
+
readonly type: "boolean";
|
|
268
|
+
};
|
|
269
|
+
};
|
|
270
|
+
readonly required: readonly ["adopted"];
|
|
271
|
+
readonly additionalProperties: false;
|
|
272
|
+
};
|
|
273
|
+
};
|
|
168
274
|
readonly 'credential/delete': {
|
|
169
275
|
readonly type: "request";
|
|
170
276
|
readonly param: {
|
package/lib/index.js
CHANGED
|
@@ -5,14 +5,15 @@
|
|
|
5
5
|
// authenticated client into the `credential-provider` the connector registers, so
|
|
6
6
|
// this package is no longer type-only.
|
|
7
7
|
export { toCredentialProvider } from './adapter.js';
|
|
8
|
-
export { CREDENTIAL_PEEK_UNSUPPORTED, CredentialPeekUnsupportedError } from './errors.js';
|
|
8
|
+
export { CREDENTIAL_PEEK_UNSUPPORTED, CREDENTIAL_UNEXPECTED_SUPERSEDED, CredentialPeekUnsupportedError, CredentialUnexpectedSupersededError } from './errors.js';
|
|
9
9
|
// Param↔seam mapping. `providerName`/`ownerDID` are the alias key the seam
|
|
10
10
|
// resolves. `ownerDID` is ALSO the authorization subject: each handler passes it
|
|
11
11
|
// to `context.authorize(ownerDID)` (the per-serve `callerMayActFor`), NOT the
|
|
12
12
|
// Enkaku message `sub` — the host rejects a `sub` that differs from `iss`, so a
|
|
13
13
|
// caller acting for another owner carries that owner in the param, not the
|
|
14
14
|
// envelope. Serialized credential bytes cross as a UTF string; the vault stores
|
|
15
|
-
// the ciphertext, never the plaintext.
|
|
15
|
+
// the ciphertext, never the plaintext. Entry-scoped writes report their outcome;
|
|
16
|
+
// the other writes ack with `null`.
|
|
16
17
|
export const credentialServiceProtocol = {
|
|
17
18
|
'credential/get': {
|
|
18
19
|
type: 'request',
|
|
@@ -43,6 +44,54 @@ export const credentialServiceProtocol = {
|
|
|
43
44
|
]
|
|
44
45
|
}
|
|
45
46
|
},
|
|
47
|
+
'credential/get-ref': {
|
|
48
|
+
type: 'request',
|
|
49
|
+
param: {
|
|
50
|
+
type: 'object',
|
|
51
|
+
properties: {
|
|
52
|
+
providerName: {
|
|
53
|
+
type: 'string'
|
|
54
|
+
},
|
|
55
|
+
ownerDID: {
|
|
56
|
+
type: 'string'
|
|
57
|
+
},
|
|
58
|
+
deviceDID: {
|
|
59
|
+
type: 'string'
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
required: [
|
|
63
|
+
'providerName',
|
|
64
|
+
'ownerDID'
|
|
65
|
+
],
|
|
66
|
+
additionalProperties: false
|
|
67
|
+
},
|
|
68
|
+
result: {
|
|
69
|
+
anyOf: [
|
|
70
|
+
{
|
|
71
|
+
type: 'object',
|
|
72
|
+
properties: {
|
|
73
|
+
credential: {
|
|
74
|
+
type: 'string'
|
|
75
|
+
},
|
|
76
|
+
entryID: {
|
|
77
|
+
type: 'string'
|
|
78
|
+
},
|
|
79
|
+
version: {
|
|
80
|
+
type: 'string'
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
required: [
|
|
84
|
+
'credential',
|
|
85
|
+
'entryID'
|
|
86
|
+
],
|
|
87
|
+
additionalProperties: false
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
type: 'null'
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
},
|
|
46
95
|
// Storage-only, non-refreshing read of the stored credential's provider
|
|
47
96
|
// account and the scopes it was granted — and nothing else: no token
|
|
48
97
|
// material crosses the wire. The server
|
|
@@ -234,6 +283,89 @@ export const credentialServiceProtocol = {
|
|
|
234
283
|
type: 'null'
|
|
235
284
|
}
|
|
236
285
|
},
|
|
286
|
+
'credential/refresh-entry': {
|
|
287
|
+
type: 'request',
|
|
288
|
+
param: {
|
|
289
|
+
type: 'object',
|
|
290
|
+
properties: {
|
|
291
|
+
providerName: {
|
|
292
|
+
type: 'string'
|
|
293
|
+
},
|
|
294
|
+
ownerDID: {
|
|
295
|
+
type: 'string'
|
|
296
|
+
},
|
|
297
|
+
deviceDID: {
|
|
298
|
+
type: 'string'
|
|
299
|
+
},
|
|
300
|
+
entryID: {
|
|
301
|
+
type: 'string'
|
|
302
|
+
},
|
|
303
|
+
credential: {
|
|
304
|
+
type: 'string'
|
|
305
|
+
},
|
|
306
|
+
expectedVersion: {
|
|
307
|
+
type: 'string'
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
required: [
|
|
311
|
+
'providerName',
|
|
312
|
+
'ownerDID',
|
|
313
|
+
'entryID',
|
|
314
|
+
'credential'
|
|
315
|
+
],
|
|
316
|
+
additionalProperties: false
|
|
317
|
+
},
|
|
318
|
+
result: {
|
|
319
|
+
type: 'string',
|
|
320
|
+
enum: [
|
|
321
|
+
'updated',
|
|
322
|
+
'absent',
|
|
323
|
+
'superseded'
|
|
324
|
+
]
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
'credential/adopt-grant': {
|
|
328
|
+
type: 'request',
|
|
329
|
+
param: {
|
|
330
|
+
type: 'object',
|
|
331
|
+
properties: {
|
|
332
|
+
providerName: {
|
|
333
|
+
type: 'string'
|
|
334
|
+
},
|
|
335
|
+
ownerDID: {
|
|
336
|
+
type: 'string'
|
|
337
|
+
},
|
|
338
|
+
fromDeviceDID: {
|
|
339
|
+
type: 'string'
|
|
340
|
+
},
|
|
341
|
+
toDeviceDID: {
|
|
342
|
+
type: 'string'
|
|
343
|
+
},
|
|
344
|
+
sourceKeyOwnerDID: {
|
|
345
|
+
type: 'string'
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
required: [
|
|
349
|
+
'providerName',
|
|
350
|
+
'ownerDID',
|
|
351
|
+
'fromDeviceDID',
|
|
352
|
+
'toDeviceDID'
|
|
353
|
+
],
|
|
354
|
+
additionalProperties: false
|
|
355
|
+
},
|
|
356
|
+
result: {
|
|
357
|
+
type: 'object',
|
|
358
|
+
properties: {
|
|
359
|
+
adopted: {
|
|
360
|
+
type: 'boolean'
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
required: [
|
|
364
|
+
'adopted'
|
|
365
|
+
],
|
|
366
|
+
additionalProperties: false
|
|
367
|
+
}
|
|
368
|
+
},
|
|
237
369
|
'credential/delete': {
|
|
238
370
|
type: 'request',
|
|
239
371
|
param: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubun/service-credential-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"keywords": [],
|
|
5
5
|
"license": "see LICENSE.md",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
"LICENSE.md"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@enkaku/client": "^0.21.
|
|
19
|
-
"@enkaku/protocol": "^0.21.
|
|
20
|
-
"@kubun/credential": "^0.
|
|
21
|
-
"@kubun/credential-types": "^0.
|
|
18
|
+
"@enkaku/client": "^0.21.5",
|
|
19
|
+
"@enkaku/protocol": "^0.21.5",
|
|
20
|
+
"@kubun/credential": "^0.18.0",
|
|
21
|
+
"@kubun/credential-types": "^0.18.0"
|
|
22
22
|
},
|
|
23
23
|
"publishConfig": {
|
|
24
24
|
"access": "public"
|