@renown/sdk 6.2.2-dev.9 → 6.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.
Files changed (75) hide show
  1. package/README.md +162 -1
  2. package/dist/{browser-key-storage-v4O-fjz0.js → browser-key-storage-e3RQsnLS.js} +1 -1
  3. package/dist/{browser-key-storage-v4O-fjz0.js.map → browser-key-storage-e3RQsnLS.js.map} +1 -1
  4. package/dist/constants-BexAR53F.js +82 -0
  5. package/dist/constants-BexAR53F.js.map +1 -0
  6. package/dist/crypto.d.ts +2 -2
  7. package/dist/crypto.js +2 -2
  8. package/dist/index-BLIpkdF7.d.ts +131 -0
  9. package/dist/index-BLIpkdF7.d.ts.map +1 -0
  10. package/dist/index.d.ts +11 -8
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +21 -9
  13. package/dist/index.js.map +1 -1
  14. package/dist/local-credential-verifier-CU8hmFlR.js +907 -0
  15. package/dist/local-credential-verifier-CU8hmFlR.js.map +1 -0
  16. package/dist/meta-BesJP74N.d.ts +19 -0
  17. package/dist/meta-BesJP74N.d.ts.map +1 -0
  18. package/dist/meta-CHgd9Qd0.js +31 -0
  19. package/dist/meta-CHgd9Qd0.js.map +1 -0
  20. package/dist/meta-D-5kvwx8.js +27 -0
  21. package/dist/meta-D-5kvwx8.js.map +1 -0
  22. package/dist/meta-bV7L-1yb.d.ts +19 -0
  23. package/dist/meta-bV7L-1yb.d.ts.map +1 -0
  24. package/dist/node.d.ts +11 -11
  25. package/dist/node.d.ts.map +1 -1
  26. package/dist/node.js +104 -12
  27. package/dist/node.js.map +1 -1
  28. package/dist/{signer-CgYhXTV7.js → signer-DrjINLqt.js} +13 -6
  29. package/dist/signer-DrjINLqt.js.map +1 -0
  30. package/dist/{signer-DYKGoYHB.d.ts → types-BGQKPoUr.d.ts} +170 -118
  31. package/dist/types-BGQKPoUr.d.ts.map +1 -0
  32. package/dist/types-C-hJrsQg.d.ts +59 -0
  33. package/dist/types-C-hJrsQg.d.ts.map +1 -0
  34. package/dist/types-C_qc_62W.js +20 -0
  35. package/dist/types-C_qc_62W.js.map +1 -0
  36. package/dist/types-DInveFLz.d.ts +63 -0
  37. package/dist/types-DInveFLz.d.ts.map +1 -0
  38. package/dist/{utils-C9ZgMs_C.d.ts → utils-DtWREYeO.d.ts} +81 -94
  39. package/dist/utils-DtWREYeO.d.ts.map +1 -0
  40. package/dist/wallet/index.d.ts +8 -0
  41. package/dist/wallet/index.d.ts.map +1 -0
  42. package/dist/wallet/index.js +30 -0
  43. package/dist/wallet/index.js.map +1 -0
  44. package/dist/wallet/mock/factory.d.ts +9 -0
  45. package/dist/wallet/mock/factory.d.ts.map +1 -0
  46. package/dist/wallet/mock/factory.js +35 -0
  47. package/dist/wallet/mock/factory.js.map +1 -0
  48. package/dist/wallet/mock/index.d.ts +9 -0
  49. package/dist/wallet/mock/index.d.ts.map +1 -0
  50. package/dist/wallet/mock/index.js +16 -0
  51. package/dist/wallet/mock/index.js.map +1 -0
  52. package/dist/wallet/privy/factory.d.ts +79 -0
  53. package/dist/wallet/privy/factory.d.ts.map +1 -0
  54. package/dist/wallet/privy/factory.js +382 -0
  55. package/dist/wallet/privy/factory.js.map +1 -0
  56. package/dist/wallet/privy/index.d.ts +9 -0
  57. package/dist/wallet/privy/index.d.ts.map +1 -0
  58. package/dist/wallet/privy/index.js +16 -0
  59. package/dist/wallet/privy/index.js.map +1 -0
  60. package/dist/wallet/rainbow/factory.d.ts +7 -0
  61. package/dist/wallet/rainbow/factory.d.ts.map +1 -0
  62. package/dist/wallet/rainbow/factory.js +219 -0
  63. package/dist/wallet/rainbow/factory.js.map +1 -0
  64. package/dist/wallet/rainbow/index.d.ts +9 -0
  65. package/dist/wallet/rainbow/index.d.ts.map +1 -0
  66. package/dist/wallet/rainbow/index.js +21 -0
  67. package/dist/wallet/rainbow/index.js.map +1 -0
  68. package/package.json +77 -4
  69. package/dist/browser-key-storage-DSkDBAhU.d.ts +0 -14
  70. package/dist/browser-key-storage-DSkDBAhU.d.ts.map +0 -1
  71. package/dist/renown-builder-Sn_Y2Cb2.js +0 -496
  72. package/dist/renown-builder-Sn_Y2Cb2.js.map +0 -1
  73. package/dist/signer-CgYhXTV7.js.map +0 -1
  74. package/dist/signer-DYKGoYHB.d.ts.map +0 -1
  75. package/dist/utils-C9ZgMs_C.d.ts.map +0 -1
@@ -0,0 +1,907 @@
1
+ import { a as DEFAULT_RENOWN_NETWORK_ID, o as DEFAULT_RENOWN_URL, r as CREDENTIAL_TYPES } from "./constants-BexAR53F.js";
2
+ import { m as verifyAuthBearerToken, p as parsePkhDid, s as RenownCryptoBuilder, t as RenownCryptoSigner } from "./signer-DrjINLqt.js";
3
+ import { recoverTypedDataAddress } from "viem";
4
+ import { createAction } from "@powerhousedao/shared/document-model";
5
+ //#region src/discovery.ts
6
+ const DEFAULT_DISCOVERY_TIMEOUT_MS = 3e3;
7
+ async function resolveSwitchboardEndpoint(options) {
8
+ const { switchboardUrl, baseUrl, timeoutMs } = options;
9
+ if (switchboardUrl) return switchboardUrl;
10
+ if (!baseUrl) return;
11
+ const controller = new AbortController();
12
+ const timeout = setTimeout(() => controller.abort(), timeoutMs ?? DEFAULT_DISCOVERY_TIMEOUT_MS);
13
+ try {
14
+ const url = new URL("/api/switchboard", baseUrl);
15
+ const response = await fetch(url, {
16
+ method: "GET",
17
+ signal: controller.signal
18
+ });
19
+ if (!response.ok) return;
20
+ return (await response.json()).endpoint || void 0;
21
+ } catch {
22
+ return;
23
+ } finally {
24
+ clearTimeout(timeout);
25
+ }
26
+ }
27
+ //#endregion
28
+ //#region src/switchboard.ts
29
+ /** Thrown by `signIn` when the instance has no switchboard to write the
30
+ * credential to, so a host can fall back to the Renown redirect flow. */
31
+ var MissingSwitchboardError = class MissingSwitchboardError extends Error {
32
+ constructor() {
33
+ super("signIn requires a switchboard endpoint. Set switchboardUrl or a discoverable baseUrl.");
34
+ this.name = "MissingSwitchboardError";
35
+ }
36
+ /** `instanceof` fails across duplicate SDK copies, so match by name too. */
37
+ static is(error) {
38
+ return error instanceof MissingSwitchboardError || error instanceof Error && error.name === "MissingSwitchboardError";
39
+ }
40
+ };
41
+ function userDriveId(address) {
42
+ return `renown-${address.toLowerCase()}`;
43
+ }
44
+ const CREDENTIALS_QUERY = `
45
+ query RenownCredentials($input: RenownCredentialsInput!) {
46
+ renownCredentials(input: $input) {
47
+ documentId
48
+ credentialId
49
+ context
50
+ type
51
+ issuerId
52
+ issuerEthereumAddress
53
+ issuanceDate
54
+ expirationDate
55
+ credentialSubjectId
56
+ credentialSubjectApp
57
+ credentialStatusId
58
+ credentialStatusType
59
+ credentialSchemaId
60
+ credentialSchemaType
61
+ proofVerificationMethod
62
+ proofEthereumAddress
63
+ proofCreated
64
+ proofPurpose
65
+ proofType
66
+ proofValue
67
+ proofEip712Domain
68
+ proofEip712PrimaryType
69
+ revoked
70
+ }
71
+ }
72
+ `;
73
+ const USERS_QUERY = `
74
+ query RenownUsers($input: RenownUsersInput!) {
75
+ renownUsers(input: $input) {
76
+ documentId
77
+ username
78
+ ethAddress
79
+ userImage
80
+ createdAt
81
+ updatedAt
82
+ }
83
+ }
84
+ `;
85
+ const CREATE_EMPTY_DOCUMENT_MUTATION = `
86
+ mutation CreateEmptyDocument(
87
+ $documentType: String!
88
+ $parentIdentifier: String
89
+ ) {
90
+ createEmptyDocument(
91
+ documentType: $documentType
92
+ parentIdentifier: $parentIdentifier
93
+ ) {
94
+ id
95
+ }
96
+ }
97
+ `;
98
+ const MUTATE_DOCUMENT_MUTATION = `
99
+ mutation MutateDocument(
100
+ $documentIdentifier: String!
101
+ $actions: [ActionInput!]!
102
+ ) {
103
+ mutateDocument: execute(
104
+ documentIdentifier: $documentIdentifier
105
+ actions: $actions
106
+ ) {
107
+ id
108
+ }
109
+ }
110
+ `;
111
+ const LEGACY_MUTATE_DOCUMENT_MUTATION = `
112
+ mutation MutateDocument(
113
+ $documentIdentifier: String!
114
+ $actions: [JSONObject!]!
115
+ ) {
116
+ mutateDocument(documentIdentifier: $documentIdentifier, actions: $actions) {
117
+ id
118
+ }
119
+ }
120
+ `;
121
+ function isUnknownExecuteField(error) {
122
+ return error instanceof Error && /Cannot query field "execute" on type "Mutation"/.test(error.message);
123
+ }
124
+ const RENOWN_CREDENTIAL_DOC_TYPE = "powerhouse/renown-credential";
125
+ const RENOWN_USER_DOC_TYPE = "powerhouse/renown-user";
126
+ function reshapeCredential(row) {
127
+ const domain = JSON.parse(row.proofEip712Domain);
128
+ return {
129
+ "@context": row.context,
130
+ type: row.type,
131
+ id: row.credentialId,
132
+ issuer: {
133
+ id: row.issuerId,
134
+ ethereumAddress: row.issuerEthereumAddress
135
+ },
136
+ credentialSubject: {
137
+ id: row.credentialSubjectId ?? "",
138
+ app: row.credentialSubjectApp
139
+ },
140
+ credentialSchema: {
141
+ id: row.credentialSchemaId,
142
+ type: row.credentialSchemaType
143
+ },
144
+ ...row.credentialStatusId ? { credentialStatus: {
145
+ id: row.credentialStatusId,
146
+ type: row.credentialStatusType ?? ""
147
+ } } : {},
148
+ issuanceDate: row.issuanceDate,
149
+ expirationDate: row.expirationDate ?? "",
150
+ proof: {
151
+ type: row.proofType,
152
+ created: row.proofCreated,
153
+ verificationMethod: row.proofVerificationMethod,
154
+ proofPurpose: row.proofPurpose,
155
+ proofValue: row.proofValue,
156
+ ethereumAddress: row.proofEthereumAddress,
157
+ eip712: {
158
+ domain,
159
+ types: CREDENTIAL_TYPES,
160
+ primaryType: "VerifiableCredential"
161
+ }
162
+ }
163
+ };
164
+ }
165
+ function issuerChainId(issuerId) {
166
+ return issuerId.split(":")[3];
167
+ }
168
+ function issuerDidAddress(issuerId) {
169
+ return issuerId.split(":")[4];
170
+ }
171
+ function bindsTo(row, address, chainId, appDid) {
172
+ const expected = address.toLowerCase();
173
+ return !row.revoked && row.credentialSubjectId === appDid && issuerChainId(row.issuerId) === String(chainId) && issuerDidAddress(row.issuerId)?.toLowerCase() === expected && row.issuerEthereumAddress.toLowerCase() === expected;
174
+ }
175
+ var SwitchboardClient = class {
176
+ #endpoint;
177
+ #transport;
178
+ #legacyMutate = false;
179
+ constructor(source) {
180
+ if (typeof source === "string") {
181
+ this.#endpoint = source;
182
+ this.#transport = (query, variables) => this.#post(source, query, variables);
183
+ } else this.#transport = source;
184
+ }
185
+ /** The HTTP endpoint, or undefined when reading through a local executor. */
186
+ get endpoint() {
187
+ return this.#endpoint;
188
+ }
189
+ async #post(endpoint, query, variables) {
190
+ const response = await fetch(endpoint, {
191
+ method: "POST",
192
+ headers: { "Content-Type": "application/json" },
193
+ body: JSON.stringify({
194
+ query,
195
+ variables
196
+ })
197
+ });
198
+ const body = await response.json().catch(() => void 0);
199
+ if (body?.errors?.length) throw new Error(body.errors.map((e) => e.message).join("; "));
200
+ if (!response.ok || !body) throw new Error(`Switchboard request failed: ${response.status}`);
201
+ return body.data;
202
+ }
203
+ async #request(query, variables) {
204
+ const data = await this.#transport(query, variables);
205
+ if (!data) throw new Error("Switchboard returned no data");
206
+ return data;
207
+ }
208
+ async getCredential(params) {
209
+ const { address, chainId, appDid } = params;
210
+ const { renownCredentials } = await this.#request(CREDENTIALS_QUERY, { input: {
211
+ driveId: userDriveId(address),
212
+ ethAddress: address.toLowerCase(),
213
+ did: appDid,
214
+ includeRevoked: false
215
+ } });
216
+ const now = Date.now();
217
+ const mostRecent = renownCredentials.filter((row) => bindsTo(row, address, chainId, appDid)).filter((row) => {
218
+ if (!row.expirationDate) return true;
219
+ const expiresAt = Date.parse(row.expirationDate);
220
+ return !Number.isNaN(expiresAt) && expiresAt > now;
221
+ }).sort((a, b) => Date.parse(b.issuanceDate) - Date.parse(a.issuanceDate)).at(0);
222
+ return mostRecent ? reshapeCredential(mostRecent) : void 0;
223
+ }
224
+ async getProfileByAddress(address) {
225
+ const { renownUsers } = await this.#request(USERS_QUERY, { input: {
226
+ driveId: userDriveId(address),
227
+ ethAddresses: [address.toLowerCase()]
228
+ } });
229
+ const user = renownUsers.at(0);
230
+ if (!user) return void 0;
231
+ return {
232
+ documentId: user.documentId,
233
+ username: user.username,
234
+ ethAddress: user.ethAddress,
235
+ userImage: user.userImage,
236
+ createdAt: user.createdAt,
237
+ updatedAt: user.updatedAt
238
+ };
239
+ }
240
+ async createEmptyDocument(documentType, parentIdentifier) {
241
+ const { createEmptyDocument } = await this.#request(CREATE_EMPTY_DOCUMENT_MUTATION, {
242
+ documentType,
243
+ parentIdentifier
244
+ });
245
+ return createEmptyDocument.id;
246
+ }
247
+ async mutateDocument(documentIdentifier, actions) {
248
+ const variables = {
249
+ documentIdentifier,
250
+ actions
251
+ };
252
+ if (!this.#legacyMutate) try {
253
+ const { mutateDocument } = await this.#request(MUTATE_DOCUMENT_MUTATION, variables);
254
+ return mutateDocument.id;
255
+ } catch (error) {
256
+ if (!isUnknownExecuteField(error)) throw error;
257
+ this.#legacyMutate = true;
258
+ }
259
+ const { mutateDocument } = await this.#request(LEGACY_MUTATE_DOCUMENT_MUTATION, variables);
260
+ return mutateDocument.id;
261
+ }
262
+ async issueCredential(credential, parentIdentifier) {
263
+ const documentId = await this.createEmptyDocument(RENOWN_CREDENTIAL_DOC_TYPE, parentIdentifier);
264
+ const input = {
265
+ id: credential.id,
266
+ context: credential["@context"],
267
+ type: credential.type,
268
+ issuer: {
269
+ id: credential.issuer.id,
270
+ ethereumAddress: credential.issuer.ethereumAddress
271
+ },
272
+ credentialSubject: {
273
+ id: credential.credentialSubject.id,
274
+ app: credential.credentialSubject.app
275
+ },
276
+ credentialSchema: {
277
+ id: credential.credentialSchema.id,
278
+ type: credential.credentialSchema.type
279
+ },
280
+ issuanceDate: credential.issuanceDate,
281
+ expirationDate: credential.expirationDate || void 0,
282
+ proof: {
283
+ type: credential.proof.type,
284
+ created: credential.proof.created,
285
+ verificationMethod: credential.proof.verificationMethod,
286
+ proofPurpose: credential.proof.proofPurpose,
287
+ proofValue: credential.proof.proofValue,
288
+ ethereumAddress: credential.proof.ethereumAddress,
289
+ eip712: {
290
+ domain: {
291
+ version: credential.proof.eip712.domain.version,
292
+ chainId: credential.proof.eip712.domain.chainId
293
+ },
294
+ primaryType: credential.proof.eip712.primaryType
295
+ }
296
+ }
297
+ };
298
+ await this.mutateDocument(documentId, [createAction("INIT", input)]);
299
+ return documentId;
300
+ }
301
+ async findOrCreateUser(address, profile = {}) {
302
+ const updates = [];
303
+ if (profile.username !== void 0) updates.push(createAction("SET_USERNAME", { username: profile.username }));
304
+ if (profile.userImage !== void 0) updates.push(createAction("SET_USER_IMAGE", { userImage: profile.userImage }));
305
+ const existing = await this.getProfileByAddress(address);
306
+ if (existing) {
307
+ if (updates.length) await this.mutateDocument(existing.documentId, updates);
308
+ return existing.documentId;
309
+ }
310
+ const documentId = await this.createEmptyDocument(RENOWN_USER_DOC_TYPE);
311
+ await this.mutateDocument(documentId, [createAction("SET_ETH_ADDRESS", { ethAddress: address }), ...updates]);
312
+ return documentId;
313
+ }
314
+ async revokeCredential(documentId, reason) {
315
+ await this.mutateDocument(documentId, [createAction("REVOKE", {
316
+ revokedAt: (/* @__PURE__ */ new Date()).toISOString(),
317
+ reason: reason ?? null
318
+ })]);
319
+ }
320
+ profileFetcher = (user) => this.getProfileByAddress(user.address).catch(() => void 0);
321
+ };
322
+ //#endregion
323
+ //#region src/credential.ts
324
+ /** Assemble a Renown delegation VC and sign it with the provided signer. */
325
+ async function buildAndSignCredential(params) {
326
+ const { signTypedData, address, chainId, app, appId, expiresInDays = 7 } = params;
327
+ const issuerId = `did:pkh:${DEFAULT_RENOWN_NETWORK_ID}:${chainId}:${address.toLowerCase()}`;
328
+ const credentialId = `urn:uuid:${globalThis.crypto.randomUUID()}`;
329
+ const now = /* @__PURE__ */ new Date();
330
+ const expirationDate = new Date(now.getTime() + expiresInDays * 24 * 60 * 60 * 1e3);
331
+ const message = {
332
+ "@context": ["https://www.w3.org/2018/credentials/v1"],
333
+ type: ["VerifiableCredential", "RenownCredential"],
334
+ id: credentialId,
335
+ issuer: {
336
+ id: issuerId,
337
+ ethereumAddress: address
338
+ },
339
+ credentialSubject: {
340
+ id: appId,
341
+ app
342
+ },
343
+ credentialSchema: {
344
+ id: "https://renown.id/schemas/renown-credential/v1",
345
+ type: "JsonSchemaValidator2018"
346
+ },
347
+ issuanceDate: now.toISOString(),
348
+ expirationDate: expirationDate.toISOString()
349
+ };
350
+ const domain = {
351
+ version: "1",
352
+ chainId
353
+ };
354
+ const { EIP712Domain, ...signTypes } = CREDENTIAL_TYPES;
355
+ const signature = await signTypedData({
356
+ domain,
357
+ types: signTypes,
358
+ primaryType: "VerifiableCredential",
359
+ message
360
+ });
361
+ return {
362
+ ...message,
363
+ proof: {
364
+ type: "EthereumEip712Signature2021",
365
+ created: message.issuanceDate,
366
+ verificationMethod: issuerId,
367
+ proofPurpose: "assertionMethod",
368
+ proofValue: signature,
369
+ ethereumAddress: address,
370
+ eip712: {
371
+ domain,
372
+ types: CREDENTIAL_TYPES,
373
+ primaryType: "VerifiableCredential"
374
+ }
375
+ }
376
+ };
377
+ }
378
+ /** Recover the address that signed a credential's EIP-712 proof. */
379
+ async function recoverCredentialSigner(credential) {
380
+ const { proof, ...message } = credential;
381
+ const { EIP712Domain, ...types } = CREDENTIAL_TYPES;
382
+ return recoverTypedDataAddress({
383
+ domain: proof.eip712.domain,
384
+ types,
385
+ primaryType: "VerifiableCredential",
386
+ message,
387
+ signature: proof.proofValue
388
+ });
389
+ }
390
+ /** True when the proof was signed by the credential's declared issuer address. */
391
+ async function verifyCredentialSignature(credential) {
392
+ try {
393
+ return (await recoverCredentialSigner(credential)).toLowerCase() === credential.issuer.ethereumAddress.toLowerCase();
394
+ } catch {
395
+ return false;
396
+ }
397
+ }
398
+ function withEip712Domain(credential, chainId) {
399
+ if (credential.proof.eip712?.domain) return credential;
400
+ return {
401
+ ...credential,
402
+ proof: {
403
+ ...credential.proof,
404
+ eip712: {
405
+ domain: {
406
+ version: "1",
407
+ chainId
408
+ },
409
+ types: CREDENTIAL_TYPES,
410
+ primaryType: "VerifiableCredential"
411
+ }
412
+ }
413
+ };
414
+ }
415
+ async function fetchDelegationCredentialRest(params) {
416
+ const { address, chainId, appDid, baseUrl } = params;
417
+ const url = new URL(`/api/auth/credential?address=${encodeURIComponent(address)}&chainId=${encodeURIComponent(chainId)}&connectId=${encodeURIComponent(appDid)}&appId=${encodeURIComponent(appDid)}`, baseUrl);
418
+ const response = await fetch(url, { method: "GET" });
419
+ if (!response.ok) return void 0;
420
+ const { credential } = await response.json();
421
+ if (!credential) return void 0;
422
+ const [, , , issuerChainId, issuerAddress] = credential.issuer.id.split(":");
423
+ if (credential.credentialSubject.id !== appDid || issuerChainId !== String(chainId) || issuerAddress.toLowerCase() !== address.toLowerCase() || credential.issuer.ethereumAddress.toLowerCase() !== address.toLowerCase()) return;
424
+ if (credential.expirationDate) {
425
+ const expiresAt = Date.parse(credential.expirationDate);
426
+ if (Number.isNaN(expiresAt) || expiresAt <= Date.now()) return;
427
+ }
428
+ return credential;
429
+ }
430
+ async function finalizeCredential(credential, chainId, verifySignature) {
431
+ if (!verifySignature) return credential;
432
+ const withDomain = withEip712Domain(credential, chainId);
433
+ if (withDomain.proof.eip712.domain.chainId !== chainId || !await verifyCredentialSignature(withDomain)) return;
434
+ return withDomain;
435
+ }
436
+ async function fetchDelegationCredential(options) {
437
+ const { address, chainId, appDid, switchboardUrl, switchboardRequest, discover = true, verifySignature = true } = options;
438
+ const explicitBaseUrl = options.baseUrl;
439
+ const baseUrl = explicitBaseUrl ?? "https://www.renown.id";
440
+ try {
441
+ const source = switchboardRequest ?? (switchboardUrl ? switchboardUrl : discover && explicitBaseUrl ? await resolveSwitchboardEndpoint({ baseUrl }) : void 0);
442
+ const credential = source ? await new SwitchboardClient(source).getCredential({
443
+ address,
444
+ chainId,
445
+ appDid
446
+ }) : await fetchDelegationCredentialRest({
447
+ address,
448
+ chainId,
449
+ appDid,
450
+ baseUrl
451
+ });
452
+ if (!credential) return void 0;
453
+ return await finalizeCredential(credential, chainId, verifySignature);
454
+ } catch {
455
+ return;
456
+ }
457
+ }
458
+ async function verifyAuthCredential(jwt, options = {}) {
459
+ const verified = await verifyAuthBearerToken(jwt, { audience: options.audience });
460
+ if (!verified) return void 0;
461
+ const { address, chainId, networkId } = verified.verifiableCredential.credentialSubject;
462
+ const appDid = verified.issuer;
463
+ const credential = await fetchDelegationCredential({
464
+ address,
465
+ chainId,
466
+ appDid,
467
+ baseUrl: options.renownUrl,
468
+ switchboardUrl: options.switchboardUrl,
469
+ switchboardRequest: options.switchboardRequest,
470
+ verifySignature: options.verifySignature
471
+ });
472
+ if (!credential) return void 0;
473
+ return {
474
+ address,
475
+ chainId,
476
+ networkId,
477
+ did: credential.issuer.id,
478
+ appDid,
479
+ credential
480
+ };
481
+ }
482
+ //#endregion
483
+ //#region src/storage/common.ts
484
+ var BaseStorage = class {};
485
+ var MemoryStorage = class extends BaseStorage {
486
+ data = /* @__PURE__ */ new Map();
487
+ get(key) {
488
+ return this.data.get(key);
489
+ }
490
+ set(key, value) {
491
+ if (value === void 0) this.data.delete(key);
492
+ else this.data.set(key, value);
493
+ }
494
+ delete(key) {
495
+ this.data.delete(key);
496
+ }
497
+ };
498
+ //#endregion
499
+ //#region src/common.ts
500
+ var RenownMemoryStorage = class extends MemoryStorage {};
501
+ /**
502
+ * The acting identity an action's signature carries.
503
+ *
504
+ * `User` here is the whole session record — it also holds the DID, the
505
+ * credential, the fetched profile and ENS info — while `UserActionSigner` is
506
+ * what travels on a signed action, and it is deliberately just an address on a
507
+ * chain. The reactor's `ReactorSignerUserInput` declares exactly these three
508
+ * fields, and a GraphQL input object refuses a field it does not declare by
509
+ * rejecting the WHOLE request, so handing the session record to the signer
510
+ * makes every signed push fail before it reaches the reactor.
511
+ *
512
+ * Narrowed here rather than at the transport, because the session record has no
513
+ * business being on an operation in the first place: it is stored on every
514
+ * operation a local reactor writes, not only on the ones that go over a wire.
515
+ *
516
+ * The compiler cannot catch the difference — excess-property checks apply to
517
+ * fresh object literals, never to a variable of a wider type — which is why
518
+ * this is a function rather than a type annotation.
519
+ */
520
+ function toActionSigner(user) {
521
+ if (!user) return void 0;
522
+ return {
523
+ address: user.address,
524
+ networkId: user.networkId,
525
+ chainId: user.chainId
526
+ };
527
+ }
528
+ var Renown = class {
529
+ #baseUrl;
530
+ #store;
531
+ #eventEmitter;
532
+ #appName;
533
+ #crypto;
534
+ #signer;
535
+ #profileFetcher;
536
+ #switchboard;
537
+ #chainId;
538
+ #status = "initial";
539
+ constructor(store, eventEmitter, crypto, appName, baseUrl = DEFAULT_RENOWN_URL, profileFetcher, switchboard, chainId = 1) {
540
+ this.#store = store;
541
+ this.#eventEmitter = eventEmitter;
542
+ this.#baseUrl = baseUrl;
543
+ this.#crypto = crypto;
544
+ this.#appName = appName;
545
+ this.#profileFetcher = profileFetcher;
546
+ this.#switchboard = switchboard;
547
+ this.#chainId = chainId;
548
+ const restoredUser = this.user;
549
+ this.#signer = new RenownCryptoSigner(crypto, this.#appName, toActionSigner(restoredUser));
550
+ if (restoredUser) this.#status = "authorized";
551
+ this.on("user", (user) => {
552
+ this.#signer.user = toActionSigner(user);
553
+ });
554
+ }
555
+ get baseUrl() {
556
+ return this.#baseUrl;
557
+ }
558
+ /** Chain id this app issues credentials on; a session from another chain is rejected by {@link signIn}. */
559
+ get chainId() {
560
+ return this.#chainId;
561
+ }
562
+ get user() {
563
+ return this.#store.get("user");
564
+ }
565
+ get status() {
566
+ return this.#status;
567
+ }
568
+ get signer() {
569
+ return this.#signer;
570
+ }
571
+ get crypto() {
572
+ return this.#crypto;
573
+ }
574
+ get did() {
575
+ return this.#crypto.did;
576
+ }
577
+ get profileFetcher() {
578
+ return this.#profileFetcher;
579
+ }
580
+ #updateStatus(status) {
581
+ this.#status = status;
582
+ this.#eventEmitter.emit("status", status);
583
+ }
584
+ #updateUser(user) {
585
+ if (user) this.#store.set("user", user);
586
+ else this.#store.delete("user");
587
+ this.#eventEmitter.emit("user", user);
588
+ }
589
+ async login(userDid) {
590
+ this.#updateStatus("checking");
591
+ try {
592
+ const result = parsePkhDid(userDid);
593
+ const credential = await this.#getCredential(result.address, result.chainId, this.#crypto.did);
594
+ if (!credential) {
595
+ this.#updateUser(void 0);
596
+ throw new Error("Credential not found");
597
+ }
598
+ return await this.#completeLogin(userDid, result, credential);
599
+ } catch (error) {
600
+ this.#updateUser(void 0);
601
+ this.#updateStatus("not-authorized");
602
+ throw error;
603
+ }
604
+ }
605
+ async signIn(params) {
606
+ if (!this.#switchboard) throw new MissingSwitchboardError();
607
+ const { address, chainId, signTypedData, username, userImage, expiresInDays } = params;
608
+ if (chainId !== this.#chainId) throw new Error(`Renown signIn: wallet is on chain ${chainId}, but this app issues credentials on chain ${this.#chainId}. Switch networks and retry — signing here would create a separate identity for the same address.`);
609
+ this.#updateStatus("checking");
610
+ try {
611
+ const credential = await buildAndSignCredential({
612
+ signTypedData,
613
+ address,
614
+ chainId,
615
+ app: this.#appName,
616
+ appId: this.did,
617
+ expiresInDays
618
+ });
619
+ await this.#switchboard.issueCredential(credential);
620
+ await this.#switchboard.findOrCreateUser(address, {
621
+ username,
622
+ userImage
623
+ });
624
+ const userDid = `did:pkh:${DEFAULT_RENOWN_NETWORK_ID}:${chainId}:${address.toLowerCase()}`;
625
+ return await this.#completeLogin(userDid, parsePkhDid(userDid), credential);
626
+ } catch (error) {
627
+ this.#updateUser(void 0);
628
+ this.#updateStatus("not-authorized");
629
+ throw error;
630
+ }
631
+ }
632
+ async #completeLogin(userDid, result, credential) {
633
+ if (!(credential.issuer.id === userDid && credential.credentialSubject.id === this.did)) throw new Error("Invalid credential");
634
+ const verifiableCredential = credential.proof.eip712?.domain ? credential : {
635
+ ...credential,
636
+ proof: {
637
+ ...credential.proof,
638
+ eip712: {
639
+ domain: {
640
+ version: "1",
641
+ chainId: result.chainId
642
+ },
643
+ types: CREDENTIAL_TYPES,
644
+ primaryType: "VerifiableCredential"
645
+ }
646
+ }
647
+ };
648
+ if (credential.issuer.ethereumAddress.toLowerCase() !== result.address.toLowerCase() || verifiableCredential.proof.eip712.domain.chainId !== result.chainId || !await verifyCredentialSignature(verifiableCredential)) throw new Error("Invalid credential signature");
649
+ const user = {
650
+ ...result,
651
+ address: credential.issuer.ethereumAddress,
652
+ did: userDid,
653
+ credential: verifiableCredential
654
+ };
655
+ this.#updateUser(user);
656
+ this.#updateStatus("authorized");
657
+ if (this.#profileFetcher) this.#profileFetcher(user, this.#baseUrl).then((profile) => {
658
+ if (profile && this.user?.address === user.address && this.user.chainId === user.chainId) this.#updateUser({
659
+ ...this.user,
660
+ profile,
661
+ ens: {
662
+ name: profile.username ?? void 0,
663
+ avatarUrl: profile.userImage ?? void 0
664
+ }
665
+ });
666
+ }).catch(console.error);
667
+ return user;
668
+ }
669
+ logout() {
670
+ this.#updateUser(void 0);
671
+ this.#updateStatus("initial");
672
+ return Promise.resolve();
673
+ }
674
+ async revalidate() {
675
+ const user = this.user;
676
+ if (!user) return false;
677
+ try {
678
+ if (!await this.#getCredential(user.address, user.chainId, this.#crypto.did)) {
679
+ await this.logout();
680
+ return false;
681
+ }
682
+ await this.refreshProfile();
683
+ return true;
684
+ } catch {
685
+ return true;
686
+ }
687
+ }
688
+ async refreshProfile() {
689
+ const user = this.user;
690
+ if (!user || !this.#profileFetcher) return false;
691
+ try {
692
+ const profile = await this.#profileFetcher(user, this.#baseUrl);
693
+ if (!profile) return false;
694
+ const current = this.user;
695
+ if (!current || current.address !== user.address || current.chainId !== user.chainId) return false;
696
+ if (current.profile !== void 0 && current.profile.documentId === profile.documentId && current.profile.username === profile.username && current.profile.userImage === profile.userImage) return false;
697
+ this.#updateUser({
698
+ ...current,
699
+ profile,
700
+ ens: {
701
+ name: profile.username ?? void 0,
702
+ avatarUrl: profile.userImage ?? void 0
703
+ }
704
+ });
705
+ return true;
706
+ } catch {
707
+ return false;
708
+ }
709
+ }
710
+ on(event, listener) {
711
+ return this.#eventEmitter.on(event, listener);
712
+ }
713
+ async #getCredential(address, chainId, appDid) {
714
+ if (this.#switchboard) return this.#switchboard.getCredential({
715
+ address,
716
+ chainId,
717
+ appDid
718
+ });
719
+ if (!this.#baseUrl) throw new Error("RENOWN_URL is not set");
720
+ const url = new URL(`/api/auth/credential?address=${encodeURIComponent(address)}&chainId=${encodeURIComponent(chainId)}&connectId=${encodeURIComponent(appDid)}&appId=${encodeURIComponent(appDid)}`, this.#baseUrl);
721
+ const response = await fetch(url, { method: "GET" });
722
+ if (response.ok) return (await response.json()).credential;
723
+ else throw new Error(`Failed to get credential: ${response.status}`);
724
+ }
725
+ async verifyBearerToken(token) {
726
+ return verifyAuthBearerToken(token);
727
+ }
728
+ async getBearerToken(options) {
729
+ if (!this.user) throw new Error("User not found");
730
+ return this.#crypto.getBearerToken(this.user.address, options);
731
+ }
732
+ };
733
+ //#endregion
734
+ //#region src/event/memory.ts
735
+ var MemoryEventEmitter = class {
736
+ #listeners = /* @__PURE__ */ new Map();
737
+ on(event, listener) {
738
+ if (!this.#listeners.has(event)) this.#listeners.set(event, /* @__PURE__ */ new Set());
739
+ this.#listeners.get(event).add(listener);
740
+ return () => {
741
+ this.#listeners.get(event)?.delete(listener);
742
+ };
743
+ }
744
+ emit(event, data) {
745
+ this.#listeners.get(event)?.forEach((listener) => listener(data));
746
+ }
747
+ };
748
+ //#endregion
749
+ //#region src/profile.ts
750
+ const fetchRenownProfile = async (user, baseUrl) => {
751
+ try {
752
+ const response = await fetch(`${baseUrl.replace(/\/+$/, "")}/api/profile`, {
753
+ method: "POST",
754
+ headers: { "Content-Type": "application/json" },
755
+ body: JSON.stringify({ ethAddress: user.address })
756
+ });
757
+ if (!response.ok) return;
758
+ return (await response.json()).profile ?? void 0;
759
+ } catch {
760
+ return;
761
+ }
762
+ };
763
+ //#endregion
764
+ //#region src/renown-builder.ts
765
+ /**
766
+ * Base builder for creating Renown instances.
767
+ * Use platform-specific builders (RenownBuilder from init.browser.js or init.node.js)
768
+ * for pre-configured defaults.
769
+ */
770
+ var BaseRenownBuilder = class BaseRenownBuilder {
771
+ #appName;
772
+ #storage;
773
+ #eventEmitter;
774
+ #crypto;
775
+ #keyPairStorage;
776
+ #baseUrl;
777
+ #switchboardUrl;
778
+ #profileFetcher;
779
+ #chainId;
780
+ /**
781
+ * @param appName - Application name used for signing context
782
+ */
783
+ constructor(appName) {
784
+ this.#appName = appName;
785
+ }
786
+ /**
787
+ * Set custom storage for user data persistence.
788
+ * Defaults to in-memory storage if not set.
789
+ */
790
+ withStorage(storage) {
791
+ this.#storage = storage;
792
+ return this;
793
+ }
794
+ /**
795
+ * Set custom event emitter for user state changes.
796
+ * Defaults to in-memory event emitter if not set.
797
+ */
798
+ withEventEmitter(eventEmitter) {
799
+ this.#eventEmitter = eventEmitter;
800
+ return this;
801
+ }
802
+ /**
803
+ * Set a pre-built crypto instance.
804
+ * Either crypto or keyPairStorage must be provided.
805
+ */
806
+ withCrypto(crypto) {
807
+ this.#crypto = crypto;
808
+ return this;
809
+ }
810
+ /**
811
+ * Set key pair storage for cryptographic keys.
812
+ * A crypto instance will be built from this storage.
813
+ * Either crypto or keyPairStorage must be provided.
814
+ */
815
+ withKeyPairStorage(keyPairStorage) {
816
+ this.#keyPairStorage = keyPairStorage;
817
+ return this;
818
+ }
819
+ /**
820
+ * Set the Renown server URL for credential verification.
821
+ * Defaults to https://www.renown.id
822
+ */
823
+ withBaseUrl(baseUrl) {
824
+ this.#baseUrl = baseUrl;
825
+ return this;
826
+ }
827
+ withSwitchboardUrl(switchboardUrl) {
828
+ this.#switchboardUrl = switchboardUrl;
829
+ return this;
830
+ }
831
+ withChainId(chainId) {
832
+ this.#chainId = chainId;
833
+ return this;
834
+ }
835
+ /**
836
+ * Set a profile fetcher strategy for enriching user data after login.
837
+ * The fetcher receives the authenticated user and the base URL,
838
+ * and returns a RenownProfile. Called in the background after each login.
839
+ * Defaults to fetchRenownProfile which calls the Renown API.
840
+ */
841
+ withProfileFetcher(profileFetcher) {
842
+ this.#profileFetcher = profileFetcher;
843
+ return this;
844
+ }
845
+ /**
846
+ * Build and initialize the Renown instance.
847
+ * If a user is stored, attempts to re-authenticate them.
848
+ * @throws Error if neither crypto nor keyPairStorage is provided
849
+ */
850
+ async build() {
851
+ if (!this.#crypto && !this.#keyPairStorage) throw new Error("Either crypto or keyPairStorage is required. Use withCrypto() or withKeyPairStorage() to set one.");
852
+ const chainId = this.#chainId ?? 1;
853
+ const crypto = this.#crypto ?? await new RenownCryptoBuilder().withKeyPairStorage(this.#keyPairStorage).withChainId(chainId).build();
854
+ if (crypto.chainId !== void 0 && crypto.chainId !== chainId) console.warn(`Renown: the supplied crypto signs bearer tokens for chain ${crypto.chainId}, but credentials are issued on chain ${chainId}.`);
855
+ const storage = this.#storage ?? new RenownMemoryStorage();
856
+ const eventEmitter = this.#eventEmitter ?? new MemoryEventEmitter();
857
+ const baseUrl = this.#baseUrl ?? "https://www.renown.id";
858
+ const switchboardEndpoint = await resolveSwitchboardEndpoint({
859
+ switchboardUrl: this.#switchboardUrl,
860
+ baseUrl
861
+ });
862
+ const switchboard = switchboardEndpoint ? new SwitchboardClient(switchboardEndpoint) : void 0;
863
+ const profileFetcher = this.#profileFetcher ?? (switchboard ? switchboard.profileFetcher : fetchRenownProfile);
864
+ return new Renown(storage, eventEmitter, crypto, this.#appName, baseUrl, profileFetcher, switchboard, chainId);
865
+ }
866
+ /**
867
+ * Create a BaseRenownBuilder from options object for a more concise API
868
+ */
869
+ static from(options) {
870
+ const builder = new BaseRenownBuilder(options.appName);
871
+ if (options.storage) builder.withStorage(options.storage);
872
+ if (options.eventEmitter) builder.withEventEmitter(options.eventEmitter);
873
+ if (options.crypto) builder.withCrypto(options.crypto);
874
+ if (options.keyPairStorage) builder.withKeyPairStorage(options.keyPairStorage);
875
+ if (options.baseUrl) builder.withBaseUrl(options.baseUrl);
876
+ if (options.switchboardUrl) builder.withSwitchboardUrl(options.switchboardUrl);
877
+ if (options.profileFetcher) builder.withProfileFetcher(options.profileFetcher);
878
+ if (options.chainId !== void 0) builder.withChainId(options.chainId);
879
+ return builder;
880
+ }
881
+ };
882
+ //#endregion
883
+ //#region src/local-credential-verifier.ts
884
+ /** A credential check that reads a Switchboard's own renown read model through
885
+ * `execute`, rather than any Renown or Switchboard over HTTP. */
886
+ function createLocalCredentialVerifier(execute, options = {}) {
887
+ const request = async (query, variables) => {
888
+ try {
889
+ return await execute(query, variables);
890
+ } catch (error) {
891
+ options.onError?.(error);
892
+ throw error;
893
+ }
894
+ };
895
+ return async ({ address, chainId, appId }) => {
896
+ return await fetchDelegationCredential({
897
+ address,
898
+ chainId,
899
+ appDid: appId,
900
+ switchboardRequest: request
901
+ }) !== void 0;
902
+ };
903
+ }
904
+ //#endregion
905
+ export { RenownMemoryStorage as a, fetchDelegationCredential as c, verifyCredentialSignature as d, MissingSwitchboardError as f, Renown as i, recoverCredentialSigner as l, resolveSwitchboardEndpoint as m, BaseRenownBuilder as n, BaseStorage as o, SwitchboardClient as p, fetchRenownProfile as r, buildAndSignCredential as s, createLocalCredentialVerifier as t, verifyAuthCredential as u };
906
+
907
+ //# sourceMappingURL=local-credential-verifier-CU8hmFlR.js.map