@idos-network/client 1.5.0 → 2.2.2
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 +15 -9
- package/dist/index.d.ts +51 -26
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -464
- package/dist/index.js.map +1 -1
- package/package.json +13 -9
- package/src/enclave/helpers.ts +10 -6
- package/src/enclave/iframe-enclave.test.ts +26 -0
- package/src/enclave/iframe-enclave.ts +6 -3
- package/src/index.test.ts +521 -0
- package/src/index.ts +513 -98
package/src/index.ts
CHANGED
|
@@ -3,28 +3,38 @@ import type {
|
|
|
3
3
|
EncryptionPasswordStore,
|
|
4
4
|
PublicEncryptionProfile,
|
|
5
5
|
} from "@idos-network/enclave";
|
|
6
|
-
import type { KwilSigner } from "@idos-network/kwil-js";
|
|
7
6
|
|
|
8
7
|
import {
|
|
9
|
-
|
|
8
|
+
buildEphemeralSignedCredentialContentReference,
|
|
9
|
+
buildPreliminaryIDOSCredential,
|
|
10
|
+
mapPreliminaryToIDOSCredential,
|
|
10
11
|
matchLevelOrHigher,
|
|
12
|
+
type PreliminaryIDOSCredential,
|
|
11
13
|
recordFilter,
|
|
14
|
+
type BaseLevel,
|
|
15
|
+
type Addon,
|
|
12
16
|
} from "@idos-network/credentials/utils";
|
|
13
17
|
import {
|
|
14
18
|
createClientKwilSigner,
|
|
19
|
+
createKgwAuthenticatedBlobGateway,
|
|
20
|
+
createNodeKwilClient,
|
|
15
21
|
createWebKwilClient,
|
|
22
|
+
isMmTokenAuth,
|
|
16
23
|
type KwilActionClient,
|
|
24
|
+
mmTokenCredentialContentUri,
|
|
17
25
|
signNearMessage,
|
|
18
26
|
type Wallet,
|
|
19
27
|
} from "@idos-network/kwil-infra";
|
|
20
28
|
import {
|
|
21
29
|
type AddAttributeInput,
|
|
22
30
|
type AddWalletInput,
|
|
31
|
+
type AddWalletMessageInput,
|
|
23
32
|
addWallet,
|
|
33
|
+
addWalletMessage as requestAddWalletMessage,
|
|
24
34
|
addWallets,
|
|
25
35
|
addAttribute as createAttribute,
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
createPreliminaryCredential,
|
|
37
|
+
type CreatePreliminaryCredentialInput,
|
|
28
38
|
dwgMessage,
|
|
29
39
|
type GetAccessGrantsGrantedInput,
|
|
30
40
|
type GetWalletsOutput,
|
|
@@ -41,6 +51,8 @@ import {
|
|
|
41
51
|
type idOSCredential,
|
|
42
52
|
type idOSCredentialListItem,
|
|
43
53
|
type idOSDelegatedWriteGrant,
|
|
54
|
+
type DelegatedWriteGrantBaseParams,
|
|
55
|
+
toDelegatedWriteGrantBaseParams,
|
|
44
56
|
type idOSGrant,
|
|
45
57
|
type idOSUser,
|
|
46
58
|
type idOSUserAttribute,
|
|
@@ -48,18 +60,24 @@ import {
|
|
|
48
60
|
removeCredential,
|
|
49
61
|
removeWallet,
|
|
50
62
|
revokeAccessGrant,
|
|
51
|
-
type
|
|
52
|
-
|
|
63
|
+
type SharePreliminaryCredentialInput,
|
|
64
|
+
sharePreliminaryCredential,
|
|
53
65
|
type WalletType,
|
|
54
66
|
} from "@idos-network/kwil-infra/actions";
|
|
67
|
+
import { NodeKwil, type KwilSigner } from "@idos-network/kwil-js";
|
|
68
|
+
import {
|
|
69
|
+
BlobGateway,
|
|
70
|
+
createBlobContentReference,
|
|
71
|
+
requireAccessTokenForUkycContent,
|
|
72
|
+
resolveCredentialEncryptedContent,
|
|
73
|
+
} from "@idos-network/utils/blob-gateway";
|
|
55
74
|
import {
|
|
56
75
|
base64Decode,
|
|
57
76
|
base64Encode,
|
|
58
77
|
hexEncodeSha256Hash,
|
|
59
78
|
utf8Decode,
|
|
60
|
-
utf8Encode,
|
|
61
79
|
} from "@idos-network/utils/codecs";
|
|
62
|
-
import { LocalStorageStore, type Store } from "@idos-network/utils/store";
|
|
80
|
+
import { LocalStorageStore, MemoryStore, type Store } from "@idos-network/utils/store";
|
|
63
81
|
import invariant from "tiny-invariant";
|
|
64
82
|
|
|
65
83
|
import { IframeEnclave } from "./enclave/iframe-enclave";
|
|
@@ -70,6 +88,226 @@ type Properties<T> = {
|
|
|
70
88
|
[K in keyof T as Exclude<T[K], Function> extends never ? never : K]: T[K];
|
|
71
89
|
};
|
|
72
90
|
|
|
91
|
+
function isBrowserRuntime(): boolean {
|
|
92
|
+
return typeof window !== "undefined";
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function usesNodeKwil(kwilClient: KwilActionClient): boolean {
|
|
96
|
+
return kwilClient.client instanceof NodeKwil;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function idleBlobGateway(url: string): BlobGateway {
|
|
100
|
+
if (!isBrowserRuntime()) {
|
|
101
|
+
return new BlobGateway({ url });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return new BlobGateway({
|
|
105
|
+
url,
|
|
106
|
+
// Browser blob reads need the KGW HttpOnly session cookie. That only works if the
|
|
107
|
+
// blob gateway is covered by the cookie's Domain (typically same host as nodeUrl/KGW).
|
|
108
|
+
fetchFn: (input, init) => fetch(input, { ...init, credentials: "include" }),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function blobGatewayForSigner(idle: idOSClientIdle, kwilSigner: KwilSigner): BlobGateway {
|
|
113
|
+
if (usesNodeKwil(idle.kwilClient)) {
|
|
114
|
+
return createKgwAuthenticatedBlobGateway({
|
|
115
|
+
url: idle.blobGateway.url,
|
|
116
|
+
kwilClient: idle.kwilClient,
|
|
117
|
+
signer: kwilSigner,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return isMmTokenAuth(kwilSigner)
|
|
122
|
+
? idle.blobGateway.withAccessToken(kwilSigner.accessToken)
|
|
123
|
+
: idle.blobGateway;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function contentUriForWallet(
|
|
127
|
+
walletType: WalletType,
|
|
128
|
+
kwilSigner: KwilSigner,
|
|
129
|
+
credentialId: string,
|
|
130
|
+
): string | undefined {
|
|
131
|
+
if (walletType !== "MM") {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
return mmTokenCredentialContentUri(kwilSigner, credentialId);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const STALE_CLIENT =
|
|
138
|
+
"This idOS client is stale: another signer was set or it was logged out. Use the client returned by the latest `withUserSigner()`.";
|
|
139
|
+
|
|
140
|
+
// Wrappers from one idle client share its Kwil client and enclave. `rawOf` unwraps the
|
|
141
|
+
// guard below; `turns` keeps signer replacement and enclave reconfiguration from interleaving.
|
|
142
|
+
const rawOf = new WeakMap<KwilActionClient, KwilActionClient>();
|
|
143
|
+
const boundOf = new WeakMap<KwilActionClient, WeakMap<KwilSigner, KwilActionClient>>();
|
|
144
|
+
const rawEnclaveOf = new WeakMap<BaseProvider, BaseProvider>();
|
|
145
|
+
const boundEnclaveOf = new WeakMap<BaseProvider, WeakMap<KwilSigner, BaseProvider>>();
|
|
146
|
+
const turns = new WeakMap<KwilActionClient, Promise<void>>();
|
|
147
|
+
const resetPending = new WeakSet<KwilActionClient>();
|
|
148
|
+
|
|
149
|
+
function sharedKwilClient(kwilClient: KwilActionClient): KwilActionClient {
|
|
150
|
+
return rawOf.get(kwilClient) ?? kwilClient;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function assertSigner(kwilClient: KwilActionClient, kwilSigner: KwilSigner): void {
|
|
154
|
+
if (kwilClient.signer !== kwilSigner) throw new Error(STALE_CLIENT);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// shortcut: guards call/execute/waitForTx/setSigner only; wrap any new KwilActionClient method here.
|
|
158
|
+
function boundKwilClient(kwilClient: KwilActionClient, kwilSigner: KwilSigner): KwilActionClient {
|
|
159
|
+
const raw = sharedKwilClient(kwilClient);
|
|
160
|
+
const cached = kwilSigner ? boundOf.get(raw)?.get(kwilSigner) : undefined;
|
|
161
|
+
if (cached) return cached;
|
|
162
|
+
|
|
163
|
+
const guard = (): void => assertSigner(raw, kwilSigner);
|
|
164
|
+
const bound = {
|
|
165
|
+
get signer() {
|
|
166
|
+
guard();
|
|
167
|
+
return raw.signer;
|
|
168
|
+
},
|
|
169
|
+
get client() {
|
|
170
|
+
guard();
|
|
171
|
+
return raw.client;
|
|
172
|
+
},
|
|
173
|
+
call: async (...args: Parameters<KwilActionClient["call"]>) => {
|
|
174
|
+
guard();
|
|
175
|
+
return raw.call(...args);
|
|
176
|
+
},
|
|
177
|
+
execute: async (...args: Parameters<KwilActionClient["execute"]>) => {
|
|
178
|
+
guard();
|
|
179
|
+
return raw.execute(...args);
|
|
180
|
+
},
|
|
181
|
+
waitForTx: async (txHash: string) => {
|
|
182
|
+
guard();
|
|
183
|
+
return raw.waitForTx(txHash);
|
|
184
|
+
},
|
|
185
|
+
setSigner: (signer: KwilSigner | undefined) => {
|
|
186
|
+
guard();
|
|
187
|
+
raw.setSigner(signer);
|
|
188
|
+
},
|
|
189
|
+
} as KwilActionClient;
|
|
190
|
+
|
|
191
|
+
rawOf.set(bound, raw);
|
|
192
|
+
if (kwilSigner) {
|
|
193
|
+
const bySigner = boundOf.get(raw) ?? new WeakMap<KwilSigner, KwilActionClient>();
|
|
194
|
+
bySigner.set(kwilSigner, bound);
|
|
195
|
+
boundOf.set(raw, bySigner);
|
|
196
|
+
}
|
|
197
|
+
return bound;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function sharedEnclave(enclave: BaseProvider): BaseProvider {
|
|
201
|
+
return (enclave && rawEnclaveOf.get(enclave)) || enclave;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function boundEnclave(
|
|
205
|
+
enclave: BaseProvider,
|
|
206
|
+
kwilClient: KwilActionClient,
|
|
207
|
+
kwilSigner: KwilSigner,
|
|
208
|
+
): BaseProvider {
|
|
209
|
+
const raw = sharedEnclave(enclave);
|
|
210
|
+
const cached = kwilSigner ? boundEnclaveOf.get(raw)?.get(kwilSigner) : undefined;
|
|
211
|
+
if (cached) return cached;
|
|
212
|
+
|
|
213
|
+
const bound = new Proxy(raw, {
|
|
214
|
+
get(target, prop) {
|
|
215
|
+
if (prop === "then" || typeof prop === "symbol") return undefined;
|
|
216
|
+
const value = Reflect.get(target, prop, target);
|
|
217
|
+
if (typeof value !== "function") {
|
|
218
|
+
assertSigner(kwilClient, kwilSigner);
|
|
219
|
+
return value;
|
|
220
|
+
}
|
|
221
|
+
return (...args: unknown[]) => {
|
|
222
|
+
assertSigner(kwilClient, kwilSigner);
|
|
223
|
+
return value.apply(target, args);
|
|
224
|
+
};
|
|
225
|
+
},
|
|
226
|
+
}) as BaseProvider;
|
|
227
|
+
|
|
228
|
+
rawEnclaveOf.set(bound, raw);
|
|
229
|
+
if (kwilSigner) {
|
|
230
|
+
const bySigner = boundEnclaveOf.get(raw) ?? new WeakMap<KwilSigner, BaseProvider>();
|
|
231
|
+
bySigner.set(kwilSigner, bound);
|
|
232
|
+
boundEnclaveOf.set(raw, bySigner);
|
|
233
|
+
}
|
|
234
|
+
return bound;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function exclusive<T>(kwilClient: KwilActionClient, run: () => Promise<T>): Promise<T> {
|
|
238
|
+
const raw = sharedKwilClient(kwilClient);
|
|
239
|
+
const previous = turns.get(raw) ?? Promise.resolve();
|
|
240
|
+
const result = previous.then(run, run);
|
|
241
|
+
turns.set(
|
|
242
|
+
raw,
|
|
243
|
+
result.then(
|
|
244
|
+
() => undefined,
|
|
245
|
+
() => undefined,
|
|
246
|
+
),
|
|
247
|
+
);
|
|
248
|
+
return result;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// `setSigner` is synchronous on the real clients. A rejected promise here is not awaited
|
|
252
|
+
// by `withUserSigner` or the enclave constructor, and Node can terminate on it.
|
|
253
|
+
function detachedSurface<T extends object>(): T {
|
|
254
|
+
return new Proxy({} as T, {
|
|
255
|
+
get(_target, prop) {
|
|
256
|
+
if (prop === "signer") return undefined;
|
|
257
|
+
if (prop === "then" || typeof prop === "symbol") return undefined;
|
|
258
|
+
if (prop === "client") throw new Error(STALE_CLIENT);
|
|
259
|
+
if (prop === "setSigner") {
|
|
260
|
+
return () => {
|
|
261
|
+
throw new Error(STALE_CLIENT);
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
return async () => {
|
|
265
|
+
throw new Error(STALE_CLIENT);
|
|
266
|
+
};
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function staleIdle(store: Store, blobUrl: string): idOSClientIdle {
|
|
272
|
+
return new idOSClientIdle(
|
|
273
|
+
store,
|
|
274
|
+
detachedSurface<KwilActionClient>(),
|
|
275
|
+
detachedSurface<BaseProvider>(),
|
|
276
|
+
idleBlobGateway(blobUrl),
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// A replaced signer keeps the session. The signer that actually logged out must finish
|
|
281
|
+
// `reset` on a later attempt; success is only returned once that reset completes.
|
|
282
|
+
function finishLogOut(
|
|
283
|
+
store: Store,
|
|
284
|
+
kwilClient: KwilActionClient,
|
|
285
|
+
kwilSigner: KwilSigner,
|
|
286
|
+
enclaveProvider: BaseProvider,
|
|
287
|
+
blobUrl: string,
|
|
288
|
+
): Promise<idOSClientIdle> {
|
|
289
|
+
const raw = sharedKwilClient(kwilClient);
|
|
290
|
+
return exclusive(raw, async () => {
|
|
291
|
+
const current = raw.signer;
|
|
292
|
+
if (current !== undefined && current !== kwilSigner) return staleIdle(store, blobUrl);
|
|
293
|
+
|
|
294
|
+
if (current === kwilSigner) {
|
|
295
|
+
raw.setSigner(undefined);
|
|
296
|
+
resetPending.add(raw);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (resetPending.has(raw)) {
|
|
300
|
+
await enclaveProvider.reset();
|
|
301
|
+
resetPending.delete(raw);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// A signer installed while `reset` was in progress must not ride back on this idle client.
|
|
305
|
+
if (raw.signer !== undefined && raw.signer !== kwilSigner) return staleIdle(store, blobUrl);
|
|
306
|
+
|
|
307
|
+
return new idOSClientIdle(store, raw, enclaveProvider, idleBlobGateway(blobUrl));
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
73
311
|
export type idOSClient =
|
|
74
312
|
| idOSClientConfiguration
|
|
75
313
|
| idOSClientIdle
|
|
@@ -80,6 +318,7 @@ export class idOSClientConfiguration<Provider extends BaseProvider = IframeEncla
|
|
|
80
318
|
readonly state: "configuration";
|
|
81
319
|
readonly chainId?: string;
|
|
82
320
|
readonly nodeUrl: string;
|
|
321
|
+
readonly blobGatewayUrl?: string;
|
|
83
322
|
readonly enclaveOptions: Omit<Provider["options"], "mode">;
|
|
84
323
|
readonly store: Store;
|
|
85
324
|
readonly enclaveProvider: BaseProvider;
|
|
@@ -87,6 +326,12 @@ export class idOSClientConfiguration<Provider extends BaseProvider = IframeEncla
|
|
|
87
326
|
constructor(params: {
|
|
88
327
|
chainId?: string;
|
|
89
328
|
nodeUrl: string;
|
|
329
|
+
/**
|
|
330
|
+
* Optional blob gateway base URL. Defaults to `nodeUrl`.
|
|
331
|
+
* In the browser this must share KGW's session-cookie Domain
|
|
332
|
+
* (typically the same host), because reads use `credentials: "include"`.
|
|
333
|
+
*/
|
|
334
|
+
blobGatewayUrl?: string;
|
|
90
335
|
enclaveOptions: Omit<Provider["options"], "mode">;
|
|
91
336
|
enclaveProvider?: new (options: Omit<Provider["options"], "mode">) => Provider;
|
|
92
337
|
store?: Store;
|
|
@@ -94,8 +339,9 @@ export class idOSClientConfiguration<Provider extends BaseProvider = IframeEncla
|
|
|
94
339
|
this.state = "configuration";
|
|
95
340
|
this.chainId = params.chainId;
|
|
96
341
|
this.nodeUrl = params.nodeUrl;
|
|
342
|
+
this.blobGatewayUrl = params.blobGatewayUrl;
|
|
97
343
|
this.enclaveOptions = params.enclaveOptions;
|
|
98
|
-
this.store = params.store ?? new LocalStorageStore();
|
|
344
|
+
this.store = params.store ?? (isBrowserRuntime() ? new LocalStorageStore() : new MemoryStore());
|
|
99
345
|
|
|
100
346
|
// TODO: This is a mess because of types...
|
|
101
347
|
if (params.enclaveProvider) {
|
|
@@ -120,23 +366,37 @@ export class idOSClientIdle {
|
|
|
120
366
|
readonly store: Store;
|
|
121
367
|
readonly kwilClient: KwilActionClient;
|
|
122
368
|
readonly enclaveProvider: BaseProvider;
|
|
369
|
+
readonly blobGateway: BlobGateway;
|
|
123
370
|
|
|
124
|
-
constructor(
|
|
371
|
+
constructor(
|
|
372
|
+
store: Store,
|
|
373
|
+
kwilClient: KwilActionClient,
|
|
374
|
+
enclaveProvider: BaseProvider,
|
|
375
|
+
blobGateway: BlobGateway,
|
|
376
|
+
) {
|
|
125
377
|
this.state = "idle";
|
|
126
378
|
this.store = store;
|
|
127
379
|
this.kwilClient = kwilClient;
|
|
128
380
|
this.enclaveProvider = enclaveProvider;
|
|
381
|
+
this.blobGateway = blobGateway;
|
|
129
382
|
}
|
|
130
383
|
|
|
131
384
|
static async fromConfig(params: idOSClientConfiguration<BaseProvider>): Promise<idOSClientIdle> {
|
|
132
|
-
const
|
|
385
|
+
const createKwilClient = isBrowserRuntime() ? createWebKwilClient : createNodeKwilClient;
|
|
386
|
+
const kwilClient = await createKwilClient({
|
|
133
387
|
nodeUrl: params.nodeUrl,
|
|
134
388
|
chainId: params.chainId,
|
|
135
389
|
});
|
|
136
390
|
|
|
137
391
|
await params.enclaveProvider.load();
|
|
138
392
|
|
|
139
|
-
|
|
393
|
+
const blobGatewayUrl = params.blobGatewayUrl ?? params.nodeUrl;
|
|
394
|
+
return new idOSClientIdle(
|
|
395
|
+
params.store,
|
|
396
|
+
kwilClient,
|
|
397
|
+
params.enclaveProvider,
|
|
398
|
+
idleBlobGateway(blobGatewayUrl),
|
|
399
|
+
);
|
|
140
400
|
}
|
|
141
401
|
|
|
142
402
|
async addressHasProfile(address: string): Promise<boolean> {
|
|
@@ -148,8 +408,6 @@ export class idOSClientIdle {
|
|
|
148
408
|
const [kwilSigner, walletIdentifier, walletPublicKey, walletType] =
|
|
149
409
|
await createClientKwilSigner(this.store, this.kwilClient, signer);
|
|
150
410
|
|
|
151
|
-
this.kwilClient.setSigner(kwilSigner);
|
|
152
|
-
|
|
153
411
|
if (walletType === "NEAR") {
|
|
154
412
|
const originalSigner = signer;
|
|
155
413
|
signer = {
|
|
@@ -163,14 +421,18 @@ export class idOSClientIdle {
|
|
|
163
421
|
} as unknown as Wallet;
|
|
164
422
|
}
|
|
165
423
|
|
|
166
|
-
return
|
|
167
|
-
this
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
424
|
+
return exclusive(this.kwilClient, async () => {
|
|
425
|
+
this.kwilClient.setSigner(kwilSigner);
|
|
426
|
+
return new idOSClientWithUserSigner(
|
|
427
|
+
this,
|
|
428
|
+
signer,
|
|
429
|
+
kwilSigner,
|
|
430
|
+
walletIdentifier,
|
|
431
|
+
walletPublicKey,
|
|
432
|
+
walletType,
|
|
433
|
+
blobGatewayForSigner(this, kwilSigner),
|
|
434
|
+
);
|
|
435
|
+
});
|
|
174
436
|
}
|
|
175
437
|
|
|
176
438
|
async logOut(): Promise<idOSClientIdle> {
|
|
@@ -181,13 +443,14 @@ export class idOSClientIdle {
|
|
|
181
443
|
export class idOSClientWithUserSigner implements Omit<Properties<idOSClientIdle>, "state"> {
|
|
182
444
|
readonly state: "with-user-signer";
|
|
183
445
|
readonly store: Store;
|
|
184
|
-
readonly kwilClient: KwilActionClient;
|
|
185
|
-
readonly enclaveProvider: BaseProvider;
|
|
446
|
+
readonly #kwilClient: KwilActionClient;
|
|
447
|
+
readonly #enclaveProvider: BaseProvider;
|
|
186
448
|
readonly signer: Wallet;
|
|
187
449
|
readonly kwilSigner: KwilSigner;
|
|
188
450
|
readonly walletIdentifier: string;
|
|
189
451
|
readonly walletPublicKey: string | undefined;
|
|
190
452
|
readonly walletType: WalletType;
|
|
453
|
+
readonly blobGateway: BlobGateway;
|
|
191
454
|
|
|
192
455
|
constructor(
|
|
193
456
|
idOSClientIdle: idOSClientIdle,
|
|
@@ -196,23 +459,38 @@ export class idOSClientWithUserSigner implements Omit<Properties<idOSClientIdle>
|
|
|
196
459
|
walletIdentifier: string,
|
|
197
460
|
walletPublicKey: string | undefined,
|
|
198
461
|
walletType: WalletType,
|
|
462
|
+
blobGateway: BlobGateway,
|
|
199
463
|
) {
|
|
200
464
|
this.state = "with-user-signer";
|
|
201
465
|
this.store = idOSClientIdle.store;
|
|
202
|
-
this
|
|
203
|
-
this
|
|
466
|
+
this.#kwilClient = idOSClientIdle.kwilClient;
|
|
467
|
+
this.#enclaveProvider = idOSClientIdle.enclaveProvider;
|
|
204
468
|
this.signer = signer;
|
|
205
469
|
this.kwilSigner = kwilSigner;
|
|
206
470
|
this.walletIdentifier = walletIdentifier;
|
|
207
471
|
this.walletPublicKey = walletPublicKey;
|
|
208
472
|
this.walletType = walletType;
|
|
473
|
+
this.blobGateway = blobGateway;
|
|
209
474
|
// @ts-expect-error - TODO: Fix this
|
|
210
|
-
this
|
|
475
|
+
this.#enclaveProvider.setSigner(this.signer);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
get kwilClient(): KwilActionClient {
|
|
479
|
+
return boundKwilClient(this.#kwilClient, this.kwilSigner);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
get enclaveProvider(): BaseProvider {
|
|
483
|
+
return boundEnclave(this.#enclaveProvider, this.#kwilClient, this.kwilSigner);
|
|
211
484
|
}
|
|
212
485
|
|
|
213
486
|
async logOut(): Promise<idOSClientIdle> {
|
|
214
|
-
|
|
215
|
-
|
|
487
|
+
return finishLogOut(
|
|
488
|
+
this.store,
|
|
489
|
+
this.#kwilClient,
|
|
490
|
+
this.kwilSigner,
|
|
491
|
+
this.#enclaveProvider,
|
|
492
|
+
this.blobGateway.url,
|
|
493
|
+
);
|
|
216
494
|
}
|
|
217
495
|
|
|
218
496
|
async hasProfile(): Promise<boolean> {
|
|
@@ -225,16 +503,20 @@ export class idOSClientWithUserSigner implements Omit<Properties<idOSClientIdle>
|
|
|
225
503
|
userId: string,
|
|
226
504
|
forceEncryptionPasswordStore?: EncryptionPasswordStore,
|
|
227
505
|
): Promise<PublicEncryptionProfile> {
|
|
228
|
-
await this
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
506
|
+
await exclusive(this.#kwilClient, async () => {
|
|
507
|
+
assertSigner(this.#kwilClient, this.kwilSigner);
|
|
508
|
+
await this.enclaveProvider.reconfigure({
|
|
509
|
+
mode: "new",
|
|
510
|
+
userId,
|
|
511
|
+
walletAddress: this.walletIdentifier,
|
|
512
|
+
walletPublicKey: this.walletPublicKey,
|
|
513
|
+
walletType: this.walletType,
|
|
514
|
+
encryptionPasswordStore: forceEncryptionPasswordStore,
|
|
515
|
+
expectedUserEncryptionPublicKey: undefined,
|
|
516
|
+
});
|
|
517
|
+
assertSigner(this.#kwilClient, this.kwilSigner);
|
|
236
518
|
});
|
|
237
|
-
|
|
519
|
+
assertSigner(this.#kwilClient, this.kwilSigner);
|
|
238
520
|
return this.enclaveProvider.ensureUserEncryptionProfile();
|
|
239
521
|
}
|
|
240
522
|
|
|
@@ -243,56 +525,133 @@ export class idOSClientWithUserSigner implements Omit<Properties<idOSClientIdle>
|
|
|
243
525
|
|
|
244
526
|
const kwilUser = await getUser(this.kwilClient);
|
|
245
527
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
528
|
+
return exclusive(this.#kwilClient, async () => {
|
|
529
|
+
assertSigner(this.#kwilClient, this.kwilSigner);
|
|
530
|
+
await this.enclaveProvider.reconfigure({
|
|
531
|
+
mode: "existing",
|
|
532
|
+
userId: kwilUser.id,
|
|
533
|
+
expectedUserEncryptionPublicKey: kwilUser.recipient_encryption_public_key,
|
|
534
|
+
walletAddress: this.walletIdentifier,
|
|
535
|
+
walletType: this.walletType,
|
|
536
|
+
encryptionPasswordStore: kwilUser.encryption_password_store,
|
|
537
|
+
walletPublicKey: this.walletPublicKey,
|
|
538
|
+
});
|
|
539
|
+
assertSigner(this.#kwilClient, this.kwilSigner);
|
|
540
|
+
return new idOSClientLoggedIn(this, kwilUser);
|
|
254
541
|
});
|
|
255
|
-
|
|
256
|
-
return new idOSClientLoggedIn(this, kwilUser);
|
|
257
542
|
}
|
|
258
543
|
}
|
|
259
544
|
|
|
260
545
|
export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSigner>, "state"> {
|
|
261
546
|
readonly state: "logged-in";
|
|
262
547
|
readonly store: Store;
|
|
263
|
-
readonly kwilClient: KwilActionClient;
|
|
264
|
-
readonly enclaveProvider: BaseProvider;
|
|
548
|
+
readonly #kwilClient: KwilActionClient;
|
|
549
|
+
readonly #enclaveProvider: BaseProvider;
|
|
265
550
|
readonly signer: Wallet;
|
|
266
551
|
readonly kwilSigner: KwilSigner;
|
|
267
552
|
readonly walletIdentifier: string;
|
|
268
553
|
readonly walletPublicKey: string | undefined;
|
|
269
554
|
readonly walletType: WalletType;
|
|
270
555
|
readonly user: idOSUser;
|
|
556
|
+
readonly blobGateway: BlobGateway;
|
|
271
557
|
|
|
272
558
|
constructor(idOSClientWithUserSigner: idOSClientWithUserSigner, user: idOSUser) {
|
|
273
559
|
this.state = "logged-in";
|
|
274
560
|
this.store = idOSClientWithUserSigner.store;
|
|
275
|
-
this
|
|
276
|
-
this
|
|
561
|
+
this.#kwilClient = sharedKwilClient(idOSClientWithUserSigner.kwilClient);
|
|
562
|
+
this.#enclaveProvider = sharedEnclave(idOSClientWithUserSigner.enclaveProvider);
|
|
277
563
|
this.signer = idOSClientWithUserSigner.signer;
|
|
278
564
|
this.kwilSigner = idOSClientWithUserSigner.kwilSigner;
|
|
279
565
|
this.walletIdentifier = idOSClientWithUserSigner.walletIdentifier;
|
|
280
566
|
this.walletPublicKey = idOSClientWithUserSigner.walletPublicKey;
|
|
281
567
|
this.walletType = idOSClientWithUserSigner.walletType;
|
|
282
568
|
this.user = user;
|
|
569
|
+
this.blobGateway = idOSClientWithUserSigner.blobGateway;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
get kwilClient(): KwilActionClient {
|
|
573
|
+
return boundKwilClient(this.#kwilClient, this.kwilSigner);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
get enclaveProvider(): BaseProvider {
|
|
577
|
+
return boundEnclave(this.#enclaveProvider, this.#kwilClient, this.kwilSigner);
|
|
283
578
|
}
|
|
284
579
|
|
|
285
580
|
async logOut(): Promise<idOSClientIdle> {
|
|
286
|
-
|
|
287
|
-
|
|
581
|
+
return finishLogOut(
|
|
582
|
+
this.store,
|
|
583
|
+
this.#kwilClient,
|
|
584
|
+
this.kwilSigner,
|
|
585
|
+
this.#enclaveProvider,
|
|
586
|
+
this.blobGateway.url,
|
|
587
|
+
);
|
|
288
588
|
}
|
|
289
589
|
|
|
290
590
|
async requestDWGMessage(params: idOSDelegatedWriteGrant): Promise<string> {
|
|
291
591
|
return dwgMessage(this.kwilClient, params).then((res) => res.message);
|
|
292
592
|
}
|
|
293
593
|
|
|
594
|
+
async createCredential(
|
|
595
|
+
publicNotes: string,
|
|
596
|
+
plaintextContent: Uint8Array<ArrayBufferLike>,
|
|
597
|
+
// In case of credential creation on users behalf, this would be a issuer key
|
|
598
|
+
issuerSigningSecretKey?: Uint8Array,
|
|
599
|
+
): Promise<Omit<idOSCredential, "user_id" | "content" | "inserter_type" | "inserter_id">> {
|
|
600
|
+
const credentialId = crypto.randomUUID();
|
|
601
|
+
const preliminaryCredential: PreliminaryIDOSCredential = {
|
|
602
|
+
...(await buildPreliminaryIDOSCredential({
|
|
603
|
+
publicNotes,
|
|
604
|
+
plaintextContent,
|
|
605
|
+
recipientEncryptionPublicKey: base64Decode(this.user.recipient_encryption_public_key),
|
|
606
|
+
issuerSigningSecretKey,
|
|
607
|
+
contentUri: contentUriForWallet(this.walletType, this.kwilSigner, credentialId),
|
|
608
|
+
})),
|
|
609
|
+
id: credentialId,
|
|
610
|
+
};
|
|
611
|
+
requireAccessTokenForUkycContent(
|
|
612
|
+
preliminaryCredential.contentUri,
|
|
613
|
+
this.blobGateway.hasAccessToken,
|
|
614
|
+
);
|
|
615
|
+
|
|
616
|
+
const requestId = crypto.randomUUID();
|
|
617
|
+
|
|
618
|
+
const payload: CreatePreliminaryCredentialInput = {
|
|
619
|
+
request_id: requestId,
|
|
620
|
+
credential_id: preliminaryCredential.id,
|
|
621
|
+
issuer_auth_public_key: preliminaryCredential.issuerAuthPublicKey,
|
|
622
|
+
encryptor_public_key: preliminaryCredential.encryptorPublicKey,
|
|
623
|
+
content_uri: preliminaryCredential.contentUri,
|
|
624
|
+
content_size: preliminaryCredential.contentSize,
|
|
625
|
+
content_hash: hexEncodeSha256Hash(plaintextContent),
|
|
626
|
+
public_notes: preliminaryCredential.publicNotes,
|
|
627
|
+
public_notes_signature: preliminaryCredential.publicNotesSignature,
|
|
628
|
+
broader_signature: preliminaryCredential.broaderSignature,
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
await createPreliminaryCredential(this.kwilClient, payload);
|
|
632
|
+
|
|
633
|
+
await this.blobGateway.uploadCredentialBlobs({
|
|
634
|
+
requestId,
|
|
635
|
+
original: preliminaryCredential.encryptedContent,
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
return mapPreliminaryToIDOSCredential(preliminaryCredential);
|
|
639
|
+
}
|
|
640
|
+
|
|
294
641
|
async removeCredential(id: string): Promise<{ id: string }> {
|
|
642
|
+
const credential = await this.getCredentialById(id);
|
|
643
|
+
invariant(credential, `"idOSCredential" with id ${id} not found`);
|
|
644
|
+
|
|
645
|
+
const contentUri = credential.content_uri ?? null;
|
|
646
|
+
requireAccessTokenForUkycContent(contentUri, this.blobGateway.hasAccessToken);
|
|
647
|
+
|
|
295
648
|
await removeCredential(this.kwilClient, { id });
|
|
649
|
+
|
|
650
|
+
if (!contentUri) {
|
|
651
|
+
return { id };
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
await this.blobGateway.deleteCredentialBlob({ credentialId: id });
|
|
296
655
|
return { id };
|
|
297
656
|
}
|
|
298
657
|
|
|
@@ -300,8 +659,10 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
|
|
|
300
659
|
return getCredentialOwned(this.kwilClient, { id }).then((res) => res[0]);
|
|
301
660
|
}
|
|
302
661
|
|
|
303
|
-
async shareCredential(
|
|
304
|
-
|
|
662
|
+
async shareCredential(
|
|
663
|
+
credential: SharePreliminaryCredentialInput,
|
|
664
|
+
): Promise<SharePreliminaryCredentialInput> {
|
|
665
|
+
await sharePreliminaryCredential(this.kwilClient, credential);
|
|
305
666
|
return credential;
|
|
306
667
|
}
|
|
307
668
|
|
|
@@ -326,13 +687,7 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
|
|
|
326
687
|
const credential = await this.getCredentialById(id);
|
|
327
688
|
|
|
328
689
|
invariant(credential, `"idOSCredential" with id ${id} not found`);
|
|
329
|
-
|
|
330
|
-
await this.enclaveProvider.ensureUserEncryptionProfile();
|
|
331
|
-
|
|
332
|
-
const plaintext = await this.enclaveProvider.decrypt(
|
|
333
|
-
base64Decode(credential.content),
|
|
334
|
-
base64Decode(credential.encryptor_public_key),
|
|
335
|
-
);
|
|
690
|
+
const plaintext = await this.#decryptCredentialContent(credential);
|
|
336
691
|
|
|
337
692
|
return hexEncodeSha256Hash(plaintext);
|
|
338
693
|
}
|
|
@@ -341,19 +696,24 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
|
|
|
341
696
|
const credential = await this.getCredentialById(id);
|
|
342
697
|
|
|
343
698
|
invariant(credential, `"idOSCredential" with id ${id} not found`);
|
|
344
|
-
|
|
345
|
-
await this.enclaveProvider.ensureUserEncryptionProfile();
|
|
346
|
-
|
|
347
|
-
const plaintext = await this.enclaveProvider.decrypt(
|
|
348
|
-
base64Decode(credential.content),
|
|
349
|
-
base64Decode(credential.encryptor_public_key),
|
|
350
|
-
);
|
|
699
|
+
const plaintext = await this.#decryptCredentialContent(credential);
|
|
351
700
|
|
|
352
701
|
return utf8Decode(plaintext);
|
|
353
702
|
}
|
|
354
703
|
|
|
355
|
-
async
|
|
356
|
-
|
|
704
|
+
async getCredentialWithEncryptedContent(id: string): Promise<idOSCredential> {
|
|
705
|
+
const credential = await this.getCredentialById(id);
|
|
706
|
+
invariant(credential, `"idOSCredential" with id ${id} not found`);
|
|
707
|
+
return this.#credentialWithInlineContent(credential);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
async getCredentialSharedContent(id: string): Promise<string> {
|
|
711
|
+
const credential = await this.getCredentialShared(id);
|
|
712
|
+
|
|
713
|
+
invariant(credential, `Shared credential with id ${id} not found`);
|
|
714
|
+
const plaintext = await this.#decryptCredentialContent(credential);
|
|
715
|
+
|
|
716
|
+
return utf8Decode(plaintext);
|
|
357
717
|
}
|
|
358
718
|
|
|
359
719
|
async getGrants(
|
|
@@ -385,6 +745,11 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
|
|
|
385
745
|
return { id };
|
|
386
746
|
}
|
|
387
747
|
|
|
748
|
+
async addWalletMessage(params: AddWalletMessageInput): Promise<string> {
|
|
749
|
+
const result = await requestAddWalletMessage(this.kwilClient, params);
|
|
750
|
+
return result.message;
|
|
751
|
+
}
|
|
752
|
+
|
|
388
753
|
async addWallet(params: AddWalletInput): Promise<AddWalletInput> {
|
|
389
754
|
await addWallet(this.kwilClient, params);
|
|
390
755
|
|
|
@@ -485,8 +850,8 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
|
|
|
485
850
|
omit: Parameters<typeof recordFilter>[2];
|
|
486
851
|
};
|
|
487
852
|
credentialLevelOrHigherFilter?: {
|
|
488
|
-
userLevel:
|
|
489
|
-
requiredAddons:
|
|
853
|
+
userLevel: BaseLevel;
|
|
854
|
+
requiredAddons: Addon[];
|
|
490
855
|
};
|
|
491
856
|
}): Promise<idOSCredentialListItem[]> {
|
|
492
857
|
const credentials = await this.getAllCredentials();
|
|
@@ -563,7 +928,9 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
|
|
|
563
928
|
);
|
|
564
929
|
|
|
565
930
|
const matches = await this.enclaveProvider.filterCredentials(
|
|
566
|
-
|
|
931
|
+
await Promise.all(
|
|
932
|
+
fullCredentials.map((credential) => this.#credentialWithInlineContent(credential)),
|
|
933
|
+
),
|
|
567
934
|
privateFieldFilters,
|
|
568
935
|
);
|
|
569
936
|
|
|
@@ -586,49 +953,90 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
|
|
|
586
953
|
consumerAuthPublicKey: string;
|
|
587
954
|
lockedUntil?: number;
|
|
588
955
|
},
|
|
589
|
-
): Promise<
|
|
956
|
+
): Promise<SharePreliminaryCredentialInput> {
|
|
590
957
|
const credential = await this.getCredentialById(credentialId);
|
|
591
|
-
const contentHash = await this.getCredentialContentSha256Hash(credentialId);
|
|
592
958
|
|
|
593
959
|
invariant(credential, `"idOSCredential" with id ${credentialId} not found`);
|
|
594
960
|
|
|
595
|
-
const plaintextContent =
|
|
596
|
-
|
|
597
|
-
base64Decode(credential.content),
|
|
598
|
-
base64Decode(credential.encryptor_public_key),
|
|
599
|
-
),
|
|
600
|
-
);
|
|
961
|
+
const plaintextContent = await this.#decryptCredentialContent(credential);
|
|
962
|
+
const contentHash = hexEncodeSha256Hash(plaintextContent);
|
|
601
963
|
|
|
602
964
|
await this.enclaveProvider.ensureUserEncryptionProfile();
|
|
603
965
|
|
|
604
966
|
const { content, encryptorPublicKey } = await this.enclaveProvider.encrypt(
|
|
605
|
-
|
|
967
|
+
plaintextContent,
|
|
606
968
|
base64Decode(consumerEncryptionPublicKey),
|
|
607
969
|
);
|
|
608
970
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
)
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
971
|
+
// User issues the shared copy: sign content_uri with an ephemeral user-side key.
|
|
972
|
+
// Copy issuer_auth_public_key need not match the original credential's issuer.
|
|
973
|
+
const copyId = crypto.randomUUID();
|
|
974
|
+
const ukycContentUri = contentUriForWallet(this.walletType, this.kwilSigner, copyId);
|
|
975
|
+
requireAccessTokenForUkycContent(ukycContentUri, this.blobGateway.hasAccessToken);
|
|
976
|
+
const copyReference = ukycContentUri
|
|
977
|
+
? { uri: ukycContentUri, size: content.byteLength }
|
|
978
|
+
: await createBlobContentReference(content);
|
|
979
|
+
const signedReference = buildEphemeralSignedCredentialContentReference("", copyReference.uri);
|
|
980
|
+
|
|
981
|
+
// Integrator-supplied. ed25519 @caller is lowercase hex; after exact grantee
|
|
982
|
+
// matching, uppercase hex would store a grant the consumer cannot read. Other
|
|
983
|
+
// identifier encodings (NEAR, XRPL, Stellar, MM) are case-sensitive, so leave them.
|
|
984
|
+
const granteeWalletIdentifier = /^[0-9a-fA-F]{64}$/.test(consumerAuthPublicKey)
|
|
985
|
+
? consumerAuthPublicKey.toLowerCase()
|
|
986
|
+
: consumerAuthPublicKey;
|
|
987
|
+
|
|
988
|
+
const preliminaryCredential: SharePreliminaryCredentialInput = {
|
|
989
|
+
...signedReference,
|
|
990
|
+
request_id: crypto.randomUUID(),
|
|
991
|
+
copy_id: copyId,
|
|
992
|
+
original_id: credential.id,
|
|
993
|
+
content_uri: copyReference.uri,
|
|
994
|
+
content_size: copyReference.size,
|
|
995
|
+
encryptor_public_key: base64Encode(encryptorPublicKey),
|
|
996
|
+
grantee_wallet_identifier: granteeWalletIdentifier,
|
|
620
997
|
locked_until: lockedUntil,
|
|
621
998
|
content_hash: contentHash,
|
|
622
999
|
};
|
|
623
1000
|
|
|
624
|
-
await this.shareCredential(
|
|
1001
|
+
await this.shareCredential(preliminaryCredential);
|
|
1002
|
+
await this.blobGateway.uploadCredentialBlobs({
|
|
1003
|
+
requestId: preliminaryCredential.request_id,
|
|
1004
|
+
copy: content,
|
|
1005
|
+
});
|
|
1006
|
+
|
|
1007
|
+
return preliminaryCredential;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
async #credentialWithInlineContent(credential: idOSCredential): Promise<idOSCredential> {
|
|
1011
|
+
if (credential.content) {
|
|
1012
|
+
return credential;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
return {
|
|
1016
|
+
...credential,
|
|
1017
|
+
content: base64Encode(await this.#getCredentialEncryptedContent(credential)),
|
|
1018
|
+
content_uri: null,
|
|
1019
|
+
content_size: null,
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
async #decryptCredentialContent(credential: idOSCredential): Promise<Uint8Array> {
|
|
1024
|
+
await this.enclaveProvider.ensureUserEncryptionProfile();
|
|
1025
|
+
|
|
1026
|
+
return this.enclaveProvider.decrypt(
|
|
1027
|
+
await this.#getCredentialEncryptedContent(credential),
|
|
1028
|
+
base64Decode(credential.encryptor_public_key),
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
625
1031
|
|
|
626
|
-
|
|
1032
|
+
async #getCredentialEncryptedContent(credential: idOSCredential): Promise<Uint8Array> {
|
|
1033
|
+
return resolveCredentialEncryptedContent(credential, this.blobGateway);
|
|
627
1034
|
}
|
|
628
1035
|
}
|
|
629
1036
|
|
|
630
1037
|
export type {
|
|
631
1038
|
idOSDelegatedWriteGrant,
|
|
1039
|
+
DelegatedWriteGrantBaseParams,
|
|
632
1040
|
idOSCredential,
|
|
633
1041
|
idOSCredentialListItem,
|
|
634
1042
|
idOSGrant,
|
|
@@ -637,14 +1045,21 @@ export type {
|
|
|
637
1045
|
idOSWallet,
|
|
638
1046
|
};
|
|
639
1047
|
|
|
640
|
-
export { signNearMessage };
|
|
1048
|
+
export { signNearMessage, toDelegatedWriteGrantBaseParams };
|
|
641
1049
|
|
|
642
1050
|
export function createIDOSClient(params: {
|
|
643
1051
|
nodeUrl: string;
|
|
1052
|
+
/**
|
|
1053
|
+
* Optional blob gateway base URL. Defaults to `nodeUrl`.
|
|
1054
|
+
* In the browser this must share KGW's session-cookie Domain
|
|
1055
|
+
* (typically the same host), because reads use `credentials: "include"`.
|
|
1056
|
+
*/
|
|
1057
|
+
blobGatewayUrl?: string;
|
|
644
1058
|
enclaveOptions: Omit<IframeEnclave["options"], "mode">;
|
|
645
1059
|
}): idOSClientConfiguration<IframeEnclave> {
|
|
646
1060
|
return new idOSClientConfiguration({
|
|
647
1061
|
nodeUrl: params.nodeUrl,
|
|
1062
|
+
blobGatewayUrl: params.blobGatewayUrl,
|
|
648
1063
|
enclaveOptions: params.enclaveOptions,
|
|
649
1064
|
});
|
|
650
1065
|
}
|