@learncard/network-plugin 2.14.0 → 3.0.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/README.md +12 -0
- package/dist/inbox-batch.d.ts +5 -0
- package/dist/inbox-batch.d.ts.map +1 -0
- package/dist/inbox-batch.test.d.ts +2 -0
- package/dist/inbox-batch.test.d.ts.map +1 -0
- package/dist/lcn-plugin.cjs.development.cjs +670 -246
- package/dist/lcn-plugin.cjs.development.cjs.map +4 -4
- package/dist/lcn-plugin.cjs.production.min.cjs +36 -36
- package/dist/lcn-plugin.cjs.production.min.cjs.map +4 -4
- package/dist/lcn-plugin.esm.js +672 -246
- package/dist/lcn-plugin.esm.js.map +4 -4
- package/dist/plugin.d.ts +11 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/test/act-as.test.d.ts +2 -0
- package/dist/test/act-as.test.d.ts.map +1 -0
- package/dist/test/refresh-send.test-d.d.ts +2 -0
- package/dist/test/refresh-send.test-d.d.ts.map +1 -0
- package/dist/test/refresh-send.test.d.ts +2 -0
- package/dist/test/refresh-send.test.d.ts.map +1 -0
- package/dist/test/verify-boost-regression.test.d.ts +2 -0
- package/dist/test/verify-boost-regression.test.d.ts.map +1 -0
- package/dist/types.d.ts +93 -19
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/inbox-batch.test.ts +105 -0
- package/src/inbox-batch.ts +66 -0
- package/src/plugin.ts +377 -63
- package/src/test/act-as.test.ts +323 -0
- package/src/test/index.test.ts +161 -10
- package/src/test/refresh-send.test-d.ts +152 -0
- package/src/test/refresh-send.test.ts +646 -0
- package/src/test/verify-boost-regression.test.ts +167 -0
- package/src/types.ts +118 -22
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import type { VC } from '@learncard/types';
|
|
3
|
+
|
|
4
|
+
import { getVerifyBoostPlugin } from '../plugin';
|
|
5
|
+
|
|
6
|
+
const trustedIssuer = 'did:web:network.learncard.com';
|
|
7
|
+
const boostId = 'lc:network:network.learncard.com/trpc:boost:test';
|
|
8
|
+
const result = (errors: string[] = []) => ({ errors, warnings: [], checks: ['proof', 'status'] });
|
|
9
|
+
|
|
10
|
+
describe('VerifyBoost wrapper transition', () => {
|
|
11
|
+
it.each([
|
|
12
|
+
['lc:network:localhost%3A4000/trpc:boost:test', 'did:web:localhost%3A4000'],
|
|
13
|
+
['lc:network:preview.example/brain/trpc:boost:test', 'did:web:preview.example:brain'],
|
|
14
|
+
['lc:network:preview.example/trpc/trpc:boost:test', 'did:web:preview.example:trpc'],
|
|
15
|
+
['lc:network:network.learncard.com/boost:test', trustedIssuer],
|
|
16
|
+
])('resolves the registry network from %s', async (boostId, did) => {
|
|
17
|
+
const card = {
|
|
18
|
+
invoke: { verifyCredential: vi.fn().mockResolvedValue(result()) },
|
|
19
|
+
} as unknown as Parameters<typeof getVerifyBoostPlugin>[0];
|
|
20
|
+
const registryUrl = `data:application/json,${encodeURIComponent(
|
|
21
|
+
JSON.stringify([{ id: 'Test Network', did, url: 'https://registry.example' }])
|
|
22
|
+
)}`;
|
|
23
|
+
const plugin = await getVerifyBoostPlugin(card, registryUrl);
|
|
24
|
+
const verified = await plugin.methods.verifyCredential(card, {
|
|
25
|
+
issuer: 'did:key:z6MkSigningAuthority',
|
|
26
|
+
boostId,
|
|
27
|
+
type: ['BoostCredential'],
|
|
28
|
+
} as unknown as VC);
|
|
29
|
+
expect(verified.checks).toContain('Boost is Authentic. Verified by Test Network.');
|
|
30
|
+
expect(verified.errors).toEqual([]);
|
|
31
|
+
expect(verified.warnings).toEqual([]);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('does not infer authenticity for a pre-signed Boost without a signed association', async () => {
|
|
35
|
+
const card = {
|
|
36
|
+
invoke: { verifyCredential: vi.fn().mockResolvedValue(result()) },
|
|
37
|
+
} as unknown as Parameters<typeof getVerifyBoostPlugin>[0];
|
|
38
|
+
const plugin = await getVerifyBoostPlugin(card);
|
|
39
|
+
const verified = await plugin.methods.verifyCredential(card, {
|
|
40
|
+
issuer: trustedIssuer,
|
|
41
|
+
type: ['BoostCredential'],
|
|
42
|
+
} as unknown as VC);
|
|
43
|
+
expect(verified.errors).toEqual([]);
|
|
44
|
+
expect(verified.checks).toContain('proof');
|
|
45
|
+
expect(verified.checks.some(check => check.includes('Boost is Authentic'))).toBe(false);
|
|
46
|
+
expect(verified.warnings).toEqual([
|
|
47
|
+
'Boost Authenticity could not be verified: Boost ID metadata is missing.',
|
|
48
|
+
]);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it.each([
|
|
52
|
+
'did:key:z6MkSigningAuthority',
|
|
53
|
+
'did:web:network.learncard.com:users:issuer',
|
|
54
|
+
{ id: 'did:web:network.learncard.com:users:issuer' },
|
|
55
|
+
])('verifies a direct SA credential using its signed Boost network (%j)', async issuer => {
|
|
56
|
+
const verifyCredential = vi.fn().mockResolvedValue(result());
|
|
57
|
+
const card = { invoke: { verifyCredential } } as unknown as Parameters<
|
|
58
|
+
typeof getVerifyBoostPlugin
|
|
59
|
+
>[0];
|
|
60
|
+
const plugin = await getVerifyBoostPlugin(card);
|
|
61
|
+
const vc = { issuer, boostId, type: ['BoostCredential'] } as unknown as VC;
|
|
62
|
+
const verified = await plugin.methods.verifyCredential(card, vc);
|
|
63
|
+
expect(verifyCredential).toHaveBeenCalledTimes(1);
|
|
64
|
+
expect(verified.errors).toEqual([]);
|
|
65
|
+
expect(verified.checks).toContain('Boost is Authentic. Verified by LearnCard Network.');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it.each([
|
|
69
|
+
'lc:network:untrusted.example/boost:test',
|
|
70
|
+
'lc:network:network.learncard.com.evil.example/boost:test',
|
|
71
|
+
'lc:network:network.learncard.com@evil.example/boost:test',
|
|
72
|
+
'lc:network:network.learncard.com/credential:test',
|
|
73
|
+
'lc:network:network.learncard.com/boost:',
|
|
74
|
+
'lc:network:network.learncard.com/boost:test?network=trusted',
|
|
75
|
+
'not-a-boost-uri',
|
|
76
|
+
])(
|
|
77
|
+
'does not mark a direct credential with an untrusted or invalid Boost URI authentic (%s)',
|
|
78
|
+
async boostId => {
|
|
79
|
+
const card = {
|
|
80
|
+
invoke: { verifyCredential: vi.fn().mockResolvedValue(result()) },
|
|
81
|
+
} as unknown as Parameters<typeof getVerifyBoostPlugin>[0];
|
|
82
|
+
const plugin = await getVerifyBoostPlugin(card);
|
|
83
|
+
const verified = await plugin.methods.verifyCredential(card, {
|
|
84
|
+
issuer: trustedIssuer,
|
|
85
|
+
boostId,
|
|
86
|
+
type: ['BoostCredential'],
|
|
87
|
+
} as unknown as VC);
|
|
88
|
+
expect(verified.checks.some(check => check.includes('Boost is Authentic'))).toBe(false);
|
|
89
|
+
expect(verified.warnings).toEqual([
|
|
90
|
+
`Boost Authenticity could not be verified. Boost ID does not identify a trusted network: ${boostId}`,
|
|
91
|
+
]);
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
it.each(['Invalid signature', 'Credential revoked'])(
|
|
96
|
+
'explains why a direct credential with %s cannot establish Boost authenticity',
|
|
97
|
+
async error => {
|
|
98
|
+
const card = {
|
|
99
|
+
invoke: { verifyCredential: vi.fn().mockResolvedValue(result([error])) },
|
|
100
|
+
} as unknown as Parameters<typeof getVerifyBoostPlugin>[0];
|
|
101
|
+
const plugin = await getVerifyBoostPlugin(card);
|
|
102
|
+
const verified = await plugin.methods.verifyCredential(card, {
|
|
103
|
+
issuer: trustedIssuer,
|
|
104
|
+
boostId,
|
|
105
|
+
type: ['BoostCredential'],
|
|
106
|
+
} as unknown as VC);
|
|
107
|
+
expect(verified.errors).toEqual([error]);
|
|
108
|
+
expect(verified.warnings).toContain(
|
|
109
|
+
'Boost Authenticity could not be verified: Credential verification failed.'
|
|
110
|
+
);
|
|
111
|
+
expect(verified.checks.some(check => check.includes('Boost is Authentic'))).toBe(false);
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
it('preserves legacy inner verification failures even when both boost IDs are missing', async () => {
|
|
116
|
+
const verifyCredential = vi
|
|
117
|
+
.fn()
|
|
118
|
+
.mockResolvedValueOnce(result())
|
|
119
|
+
.mockResolvedValueOnce(result(['Credential revoked']));
|
|
120
|
+
const card = { invoke: { verifyCredential } } as unknown as Parameters<
|
|
121
|
+
typeof getVerifyBoostPlugin
|
|
122
|
+
>[0];
|
|
123
|
+
const plugin = await getVerifyBoostPlugin(card);
|
|
124
|
+
const verified = await plugin.methods.verifyCredential(card, {
|
|
125
|
+
issuer: trustedIssuer,
|
|
126
|
+
type: ['CertifiedBoostCredential'],
|
|
127
|
+
boostCredential: { issuer: 'did:example:issuer', type: ['BoostCredential'] },
|
|
128
|
+
} as unknown as VC);
|
|
129
|
+
expect(verifyCredential).toHaveBeenCalledTimes(2);
|
|
130
|
+
expect(verified.errors).toContain('Credential revoked');
|
|
131
|
+
expect(verified.checks).not.toContain('status');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('continues to verify matching legacy wrappers', async () => {
|
|
135
|
+
const verifyCredential = vi.fn().mockImplementation(async () => result());
|
|
136
|
+
const card = { invoke: { verifyCredential } } as unknown as Parameters<
|
|
137
|
+
typeof getVerifyBoostPlugin
|
|
138
|
+
>[0];
|
|
139
|
+
const plugin = await getVerifyBoostPlugin(card);
|
|
140
|
+
const verified = await plugin.methods.verifyCredential(card, {
|
|
141
|
+
issuer: trustedIssuer,
|
|
142
|
+
boostId,
|
|
143
|
+
type: ['CertifiedBoostCredential'],
|
|
144
|
+
boostCredential: { issuer: 'did:example:issuer', boostId, type: ['BoostCredential'] },
|
|
145
|
+
} as unknown as VC);
|
|
146
|
+
expect(verifyCredential).toHaveBeenCalledTimes(2);
|
|
147
|
+
expect(verified.errors).toEqual([]);
|
|
148
|
+
expect(verified.checks).toContain('Boost is Authentic. Verified by LearnCard Network.');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('identifies the issuer when a legacy wrapper is outside the trust network', async () => {
|
|
152
|
+
const card = {
|
|
153
|
+
invoke: { verifyCredential: vi.fn().mockImplementation(async () => result()) },
|
|
154
|
+
} as unknown as Parameters<typeof getVerifyBoostPlugin>[0];
|
|
155
|
+
const plugin = await getVerifyBoostPlugin(card);
|
|
156
|
+
const verified = await plugin.methods.verifyCredential(card, {
|
|
157
|
+
issuer: 'did:example:untrusted',
|
|
158
|
+
boostId,
|
|
159
|
+
type: ['CertifiedBoostCredential'],
|
|
160
|
+
boostCredential: { issuer: 'did:example:issuer', boostId, type: ['BoostCredential'] },
|
|
161
|
+
} as unknown as VC);
|
|
162
|
+
expect(verified.checks.some(check => check.includes('Boost is Authentic'))).toBe(false);
|
|
163
|
+
expect(verified.warnings).toEqual([
|
|
164
|
+
'Boost Authenticity could not be verified. Issuer is outside of trust network: did:example:untrusted',
|
|
165
|
+
]);
|
|
166
|
+
});
|
|
167
|
+
});
|
package/src/types.ts
CHANGED
|
@@ -53,6 +53,9 @@ import {
|
|
|
53
53
|
AuthGrantType,
|
|
54
54
|
AuthGrantQuery,
|
|
55
55
|
IssueInboxCredentialType,
|
|
56
|
+
IssueInboxCredentialBatch,
|
|
57
|
+
InboxBatchReceipt,
|
|
58
|
+
InboxBatchStatus,
|
|
56
59
|
InboxCredentialType,
|
|
57
60
|
PaginatedInboxCredentialsType,
|
|
58
61
|
PaginatedSkillFrameworksType,
|
|
@@ -113,17 +116,68 @@ import {
|
|
|
113
116
|
BitstringCredentialStatusEntry,
|
|
114
117
|
AllocateCredentialRefreshInput,
|
|
115
118
|
AllocateCredentialRefreshResult,
|
|
119
|
+
ManagedCredentialRefreshReceipt,
|
|
116
120
|
PublishCredentialRefreshInput,
|
|
117
121
|
PublishCredentialRefreshResult,
|
|
118
122
|
GetCredentialRefreshHistoryInput,
|
|
119
123
|
GetCredentialRefreshHistoryResult,
|
|
120
124
|
} from '@learncard/types';
|
|
121
|
-
import { Plugin } from '@learncard/core';
|
|
125
|
+
import { LearnCard, Plugin } from '@learncard/core';
|
|
122
126
|
import { ProofOptions } from '@learncard/didkit-plugin';
|
|
123
127
|
import { VerifyExtension } from '@learncard/vc-plugin';
|
|
124
128
|
|
|
125
129
|
export type { BitstringCredentialStatusPurpose, BitstringCredentialStatusEntry };
|
|
126
130
|
|
|
131
|
+
/** Object-form options for the network plugin's `sendBoost` */
|
|
132
|
+
export type SendBoostNetworkOptions = {
|
|
133
|
+
encrypt?: boolean;
|
|
134
|
+
overideFn?: (boost: UnsignedVC) => UnsignedVC;
|
|
135
|
+
skipNotification?: boolean;
|
|
136
|
+
templateData?: Record<string, unknown>;
|
|
137
|
+
statusPurposes?: BitstringCredentialStatusPurpose[];
|
|
138
|
+
/**
|
|
139
|
+
* Opt into a managed refresh service. When true, a stable UUID credential ID is
|
|
140
|
+
* generated if the boost template has none, a refresh service is allocated BEFORE
|
|
141
|
+
* signing and injected into the signed credential, and the credential is sent via
|
|
142
|
+
* the dedicated managed-send procedure (holder-encrypted storage only) instead of
|
|
143
|
+
* legacy credential storage. The `encrypt` option is ignored in this mode —
|
|
144
|
+
* managed storage is always holder-only.
|
|
145
|
+
*/
|
|
146
|
+
enableRefresh?: boolean;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/** Result of a refresh-enabled `sendBoost` call (opt-in via `enableRefresh: true`) */
|
|
150
|
+
export type SendBoostRefreshResult = {
|
|
151
|
+
/** URI of the issued (managed, holder-encrypted) credential */
|
|
152
|
+
credentialUri: string;
|
|
153
|
+
/** Issuance metadata the issuer keeps in order to publish future updates */
|
|
154
|
+
refresh: ManagedCredentialRefreshReceipt;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/** The `enableRefresh` type carried by `sendBoost` options (`undefined` when absent). */
|
|
158
|
+
type EnableRefreshOf<Options> = Options extends object
|
|
159
|
+
? 'enableRefresh' extends keyof Options
|
|
160
|
+
? Options extends { enableRefresh?: infer Enabled }
|
|
161
|
+
? Enabled
|
|
162
|
+
: undefined
|
|
163
|
+
: undefined
|
|
164
|
+
: undefined;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Resolves the `sendBoost` return type from the (const-inferred) options type.
|
|
168
|
+
*
|
|
169
|
+
* - legacy `boolean` options, omitted options, and object options without
|
|
170
|
+
* `enableRefresh` keep the historical `string` result.
|
|
171
|
+
* - literal `enableRefresh: true` returns the refreshable-issuance result.
|
|
172
|
+
* - anything that may be `true` at runtime (a `boolean`, an optional property, or a
|
|
173
|
+
* union of option shapes) degrades to the union of both shapes.
|
|
174
|
+
*/
|
|
175
|
+
export type SendBoostResultFor<Options> = [EnableRefreshOf<Options>] extends [true]
|
|
176
|
+
? SendBoostRefreshResult
|
|
177
|
+
: true extends EnableRefreshOf<Options>
|
|
178
|
+
? string | SendBoostRefreshResult
|
|
179
|
+
: string;
|
|
180
|
+
|
|
127
181
|
/** @group LearnCardNetwork Plugin */
|
|
128
182
|
export type LearnCardNetworkPluginDependentMethods = {
|
|
129
183
|
getDidAuthVp: (options?: ProofOptions) => Promise<VP | string>;
|
|
@@ -160,6 +214,14 @@ export type LearnCardNetworkPluginMethods = {
|
|
|
160
214
|
getManagedProfiles: (
|
|
161
215
|
options?: Partial<PaginationOptionsType> & { query?: LCNProfileQuery }
|
|
162
216
|
) => Promise<PaginatedLCNProfiles>;
|
|
217
|
+
/**
|
|
218
|
+
* Returns a new LearnCard instance whose network plugin sends every request with the
|
|
219
|
+
* `X-LearnCard-Act-As` header set to `profileId`, asking the server to swap the acting
|
|
220
|
+
* profile for the duration of each request. Token scope is unchanged; the server responds
|
|
221
|
+
* `403` if the caller doesn't manage `profileId`, or if an API token's grant doesn't cover
|
|
222
|
+
* it. The original instance (and its headers) is left untouched.
|
|
223
|
+
*/
|
|
224
|
+
actAs: (profileId: string) => Promise<ActingLearnCard>;
|
|
163
225
|
claimPendingGuardianLinks: () => Promise<
|
|
164
226
|
Array<{ childProfileId: string; childDisplayName: string; managerId: string | null }>
|
|
165
227
|
>;
|
|
@@ -473,29 +535,23 @@ export type LearnCardNetworkPluginMethods = {
|
|
|
473
535
|
recipientProfileId: string,
|
|
474
536
|
credentialUri?: string
|
|
475
537
|
) => Promise<boolean>;
|
|
476
|
-
|
|
538
|
+
/**
|
|
539
|
+
* Sends a boost credential to a recipient profile.
|
|
540
|
+
*
|
|
541
|
+
* **Return shape (opt-in):** legacy callers (boolean options, omitted options, or
|
|
542
|
+
* object options without `enableRefresh`) receive the issued credential URI as a
|
|
543
|
+
* `string`, exactly as before. Passing literal `{ enableRefresh: true }` opts into
|
|
544
|
+
* managed refresh and returns `{ credentialUri, refresh }` instead, where `refresh`
|
|
545
|
+
* is the issuance receipt needed to publish future versions (see
|
|
546
|
+
* `publishCredentialRefresh`). Options whose `enableRefresh` may be `true` at runtime
|
|
547
|
+
* (a `boolean`, or a variable typed `SendBoostNetworkOptions`) degrade the result to
|
|
548
|
+
* `string | { credentialUri, refresh }`.
|
|
549
|
+
*/
|
|
550
|
+
sendBoost: <const Options extends boolean | SendBoostNetworkOptions | undefined = undefined>(
|
|
477
551
|
profileId: string,
|
|
478
552
|
boostUri: string,
|
|
479
|
-
options?:
|
|
480
|
-
|
|
481
|
-
| {
|
|
482
|
-
encrypt?: boolean;
|
|
483
|
-
overideFn?: (boost: UnsignedVC) => UnsignedVC;
|
|
484
|
-
skipNotification?: boolean;
|
|
485
|
-
templateData?: Record<string, unknown>;
|
|
486
|
-
statusPurposes?: BitstringCredentialStatusPurpose[];
|
|
487
|
-
/**
|
|
488
|
-
* Opt into a managed refresh service. When true, a stable UUID
|
|
489
|
-
* credential ID is generated if the boost template has none, a
|
|
490
|
-
* refresh service is allocated BEFORE signing and injected into the
|
|
491
|
-
* signed credential, and the credential is sent via the dedicated
|
|
492
|
-
* managed-send procedure (holder-encrypted storage only) instead of
|
|
493
|
-
* legacy credential storage. The `encrypt` option is ignored in this
|
|
494
|
-
* mode — managed storage is always holder-only.
|
|
495
|
-
*/
|
|
496
|
-
enableRefresh?: boolean;
|
|
497
|
-
}
|
|
498
|
-
) => Promise<string>;
|
|
553
|
+
options?: Options
|
|
554
|
+
) => Promise<SendBoostResultFor<Options>>;
|
|
499
555
|
|
|
500
556
|
registerSigningAuthority: (endpoint: string, name: string, did: string) => Promise<boolean>;
|
|
501
557
|
getRegisteredSigningAuthorities: () => Promise<LCNSigningAuthorityForUserType[]>;
|
|
@@ -679,6 +735,27 @@ export type LearnCardNetworkPluginMethods = {
|
|
|
679
735
|
revokeAuthGrant: (id: string) => Promise<boolean>;
|
|
680
736
|
getAPITokenForAuthGrant: (id: string) => Promise<string>;
|
|
681
737
|
|
|
738
|
+
/** Queue 1–100 credentials; workers may start up to a minute later. Use sendCredentialViaInbox for immediate single issuance. */
|
|
739
|
+
sendCredentialsViaInbox: (batch: IssueInboxCredentialBatch) => Promise<InboxBatchReceipt>;
|
|
740
|
+
/** Explicit batch alias for sendCredentialsViaInbox. Returns a durable receipt. */
|
|
741
|
+
sendCredentialBatchViaInbox: (batch: IssueInboxCredentialBatch) => Promise<InboxBatchReceipt>;
|
|
742
|
+
/** Ordered results and disjoint success/failure/unconfirmed counts. `done` includes unconfirmed outcomes.
|
|
743
|
+
* @see https://docs.learncard.com/sdks/learncard-network/universal-inbox-api
|
|
744
|
+
*/
|
|
745
|
+
getInboxCredentialBatch: (batchId: string) => Promise<InboxBatchStatus>;
|
|
746
|
+
/** Poll until done with bounded backoff. Abort/timeout stops waiting, not processing. */
|
|
747
|
+
waitForInboxCredentialBatch: (
|
|
748
|
+
batchId: string,
|
|
749
|
+
options?: WaitForInboxCredentialBatchOptions
|
|
750
|
+
) => Promise<InboxBatchStatus>;
|
|
751
|
+
/** Submit once and wait; persist the receipt with onSubmitted for recovery after timeout. */
|
|
752
|
+
sendCredentialsViaInboxAndWait: (
|
|
753
|
+
batch: IssueInboxCredentialBatch,
|
|
754
|
+
options?: WaitForInboxCredentialBatchOptions & {
|
|
755
|
+
onSubmitted?: (receipt: InboxBatchReceipt) => void | Promise<void>;
|
|
756
|
+
}
|
|
757
|
+
) => Promise<InboxBatchStatus>;
|
|
758
|
+
/** Issue one credential synchronously, without waiting for the batch dispatcher. */
|
|
682
759
|
sendCredentialViaInbox: (
|
|
683
760
|
issueInboxCredential: IssueInboxCredentialType
|
|
684
761
|
) => Promise<IssueInboxCredentialResponseType>;
|
|
@@ -971,6 +1048,16 @@ export type LearnCardNetworkPluginMethods = {
|
|
|
971
1048
|
};
|
|
972
1049
|
|
|
973
1050
|
/** @group LearnCardNetwork Plugin */
|
|
1051
|
+
/**
|
|
1052
|
+
* The wallet returned by `invoke.actAs`: the caller's existing plugins with a network
|
|
1053
|
+
* plugin bound to the target profile appended. The caller's plugin list cannot be named
|
|
1054
|
+
* from inside the plugin's own method map, hence the open tuple.
|
|
1055
|
+
*/
|
|
1056
|
+
export type ActingLearnCard = LearnCard<
|
|
1057
|
+
[...Plugin[], LearnCardNetworkPlugin],
|
|
1058
|
+
'id' | 'read' | 'store'
|
|
1059
|
+
>;
|
|
1060
|
+
|
|
974
1061
|
export type LearnCardNetworkPlugin = Plugin<
|
|
975
1062
|
'LearnCard Network',
|
|
976
1063
|
'id' | 'read' | 'store',
|
|
@@ -988,3 +1075,12 @@ export type TrustedBoostRegistryEntry = {
|
|
|
988
1075
|
url: string;
|
|
989
1076
|
did: string;
|
|
990
1077
|
};
|
|
1078
|
+
|
|
1079
|
+
export interface WaitForInboxCredentialBatchOptions {
|
|
1080
|
+
/** Overall polling deadline; defaults to ten minutes. */
|
|
1081
|
+
timeoutMs?: number;
|
|
1082
|
+
/** Initial interval; increases by 1.5x up to ten seconds (or this interval if larger). */
|
|
1083
|
+
intervalMs?: number;
|
|
1084
|
+
signal?: AbortSignal;
|
|
1085
|
+
onProgress?: (status: InboxBatchStatus) => void;
|
|
1086
|
+
}
|