@renown/sdk 0.1.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 +3 -0
- package/package.json +46 -0
- package/src/common.ts +136 -0
- package/src/constants.ts +45 -0
- package/src/event/event.browser.ts +34 -0
- package/src/event/event.node.ts +26 -0
- package/src/event/types.ts +19 -0
- package/src/index.browser.ts +2 -0
- package/src/index.node.ts +2 -0
- package/src/init.browser.ts +12 -0
- package/src/init.node.ts +13 -0
- package/src/storage/common.ts +18 -0
- package/src/storage/storage.browser.ts +30 -0
- package/src/storage/storage.node.ts +53 -0
- package/src/types.ts +96 -0
- package/src/utils.ts +28 -0
- package/tsconfig.base.json +10 -0
- package/tsconfig.browser.json +9 -0
- package/tsconfig.node.json +9 -0
package/README.md
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@renown/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"license": "AGPL-3.0-only",
|
|
6
|
+
"private": false,
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./src/index.browser.ts",
|
|
9
|
+
"types": "./src/index.browser.ts",
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"node": "./src/index.node.ts",
|
|
16
|
+
"default": "./src/index.browser.ts"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"/src",
|
|
21
|
+
"tsconfig.base.json",
|
|
22
|
+
"tsconfig.browser.json",
|
|
23
|
+
"tsconfig.node.json"
|
|
24
|
+
],
|
|
25
|
+
"nx-release-publish": {
|
|
26
|
+
"options": {
|
|
27
|
+
"packageRoot": "dist/{projectRoot}"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"document-model": "2.14.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"document-model": "2.14.0"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"check-types": "tsc -p tsconfig.node.json --noEmit && tsc -p tsconfig.browser.json --noEmit",
|
|
38
|
+
"check-types:node": "tsc -p tsconfig.node.json --noEmit",
|
|
39
|
+
"check-types:brower": "tsc -p tsconfig.browser.json --noEmit",
|
|
40
|
+
"build": "tsc -p tsconfig.node.json && tsc -p tsconfig.browser.json",
|
|
41
|
+
"build:browser": "tsc -p tsconfig.browser.json",
|
|
42
|
+
"build:node": "tsc -p tsconfig.node.json",
|
|
43
|
+
"clean": "rimraf dist/",
|
|
44
|
+
"clean:node_modules": "rimraf node_modules"
|
|
45
|
+
}
|
|
46
|
+
}
|
package/src/common.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IRenown,
|
|
3
|
+
PowerhouseVerifiableCredential,
|
|
4
|
+
RenownEventEmitter,
|
|
5
|
+
RenownEvents,
|
|
6
|
+
RenownStorage,
|
|
7
|
+
User,
|
|
8
|
+
} from "./types";
|
|
9
|
+
import { DEFAULT_RENOWN_URL } from "./constants";
|
|
10
|
+
import { parsePkhDid } from "./utils";
|
|
11
|
+
|
|
12
|
+
export class Renown implements IRenown {
|
|
13
|
+
#baseUrl: string;
|
|
14
|
+
#store: RenownStorage;
|
|
15
|
+
#connectId: string;
|
|
16
|
+
#eventEmitter: RenownEventEmitter;
|
|
17
|
+
|
|
18
|
+
constructor(
|
|
19
|
+
store: RenownStorage,
|
|
20
|
+
eventEmitter: RenownEventEmitter,
|
|
21
|
+
connectId: string,
|
|
22
|
+
baseUrl = DEFAULT_RENOWN_URL,
|
|
23
|
+
) {
|
|
24
|
+
this.#store = store;
|
|
25
|
+
this.#eventEmitter = eventEmitter;
|
|
26
|
+
this.#connectId = connectId;
|
|
27
|
+
this.#baseUrl = baseUrl;
|
|
28
|
+
|
|
29
|
+
if (this.user) {
|
|
30
|
+
this.login(this.user.did).catch(() => void 0);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get user() {
|
|
35
|
+
return this.#store.get("user");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#updateUser(user: User | undefined) {
|
|
39
|
+
if (user) {
|
|
40
|
+
this.#store.set("user", user);
|
|
41
|
+
} else {
|
|
42
|
+
this.#store.delete("user");
|
|
43
|
+
}
|
|
44
|
+
this.#eventEmitter.emit("user", user);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
set connectId(connectId: string) {
|
|
48
|
+
this.#connectId = connectId;
|
|
49
|
+
const user = this.user;
|
|
50
|
+
|
|
51
|
+
this.#updateUser(undefined);
|
|
52
|
+
|
|
53
|
+
// tries to login with new connectId
|
|
54
|
+
if (user) {
|
|
55
|
+
this.login(user.did).catch((e: unknown) => {
|
|
56
|
+
console.log("User no longer authenticated:", e);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async login(did: string): Promise<User> {
|
|
62
|
+
try {
|
|
63
|
+
const result = parsePkhDid(did);
|
|
64
|
+
|
|
65
|
+
const credential = await this.#getCredential(
|
|
66
|
+
result.address,
|
|
67
|
+
result.chainId,
|
|
68
|
+
this.#connectId,
|
|
69
|
+
);
|
|
70
|
+
if (!credential) {
|
|
71
|
+
this.#updateUser(undefined);
|
|
72
|
+
throw new Error("Credential not found");
|
|
73
|
+
}
|
|
74
|
+
const user: User = {
|
|
75
|
+
...result,
|
|
76
|
+
did,
|
|
77
|
+
credential,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// TODO
|
|
81
|
+
// getEnsInfo(user.address, user.chainId)
|
|
82
|
+
// .then((ens) => {
|
|
83
|
+
// if (
|
|
84
|
+
// this.user?.address === user.address &&
|
|
85
|
+
// this.user.chainId === user.chainId
|
|
86
|
+
// ) {
|
|
87
|
+
// this.#updateUser({ ...this.user, ens });
|
|
88
|
+
// }
|
|
89
|
+
// })
|
|
90
|
+
// .catch(logger.error);
|
|
91
|
+
|
|
92
|
+
this.#updateUser(user);
|
|
93
|
+
return user;
|
|
94
|
+
} catch (error) {
|
|
95
|
+
this.#updateUser(undefined);
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
logout() {
|
|
101
|
+
this.#updateUser(undefined);
|
|
102
|
+
return Promise.resolve();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
on<K extends keyof RenownEvents>(
|
|
106
|
+
event: K,
|
|
107
|
+
listener: (data: RenownEvents[K]) => void,
|
|
108
|
+
): () => void {
|
|
109
|
+
return this.#eventEmitter.on(event, listener);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async #getCredential(
|
|
113
|
+
address: string,
|
|
114
|
+
chainId: number,
|
|
115
|
+
connectId: string,
|
|
116
|
+
): Promise<PowerhouseVerifiableCredential | undefined> {
|
|
117
|
+
if (!this.#baseUrl) {
|
|
118
|
+
throw new Error("RENOWN_URL is not set");
|
|
119
|
+
}
|
|
120
|
+
const url = new URL(
|
|
121
|
+
`/api/auth/credential?address=${encodeURIComponent(address)}&chainId=${encodeURIComponent(chainId)}&connectId=${encodeURIComponent(connectId)}`,
|
|
122
|
+
this.#baseUrl,
|
|
123
|
+
);
|
|
124
|
+
const response = await fetch(url, {
|
|
125
|
+
method: "GET",
|
|
126
|
+
});
|
|
127
|
+
if (response.ok) {
|
|
128
|
+
const result = (await response.json()) as {
|
|
129
|
+
credential: PowerhouseVerifiableCredential;
|
|
130
|
+
};
|
|
131
|
+
return result.credential;
|
|
132
|
+
} else {
|
|
133
|
+
throw new Error("Failed to get credential");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export const DEFAULT_RENOWN_URL = "https://www.renown.id";
|
|
2
|
+
export const DEFAULT_RENOWN_NETWORK_ID = "eip155";
|
|
3
|
+
export const DEFAULT_RENOWN_CHAIN_ID = "1";
|
|
4
|
+
|
|
5
|
+
export const DOMAIN_TYPE = [
|
|
6
|
+
{ name: "name", type: "string" },
|
|
7
|
+
{ name: "version", type: "string" },
|
|
8
|
+
{ name: "chainId", type: "uint256" },
|
|
9
|
+
{ name: "verifyingContract", type: "address" },
|
|
10
|
+
] as const;
|
|
11
|
+
|
|
12
|
+
export const VERIFIABLE_CREDENTIAL_EIP712_TYPE = [
|
|
13
|
+
{ name: "@context", type: "string[]" },
|
|
14
|
+
{ name: "type", type: "string[]" },
|
|
15
|
+
{ name: "id", type: "string" },
|
|
16
|
+
{ name: "issuer", type: "Issuer" },
|
|
17
|
+
{ name: "credentialSubject", type: "CredentialSubject" },
|
|
18
|
+
{ name: "credentialSchema", type: "CredentialSchema" },
|
|
19
|
+
{ name: "issuanceDate", type: "string" },
|
|
20
|
+
{ name: "expirationDate", type: "string" },
|
|
21
|
+
] as const;
|
|
22
|
+
|
|
23
|
+
export const CREDENTIAL_SCHEMA_EIP712_TYPE = [
|
|
24
|
+
{ name: "id", type: "string" },
|
|
25
|
+
{ name: "type", type: "string" },
|
|
26
|
+
] as const;
|
|
27
|
+
|
|
28
|
+
export const CREDENTIAL_SUBJECT_TYPE = [
|
|
29
|
+
{ name: "app", type: "string" },
|
|
30
|
+
{ name: "id", type: "string" },
|
|
31
|
+
{ name: "name", type: "string" },
|
|
32
|
+
] as const;
|
|
33
|
+
|
|
34
|
+
export const ISSUER_TYPE = [
|
|
35
|
+
{ name: "id", type: "string" },
|
|
36
|
+
{ name: "ethereumAddress", type: "string" },
|
|
37
|
+
] as const;
|
|
38
|
+
|
|
39
|
+
export const CREDENTIAL_TYPES = {
|
|
40
|
+
EIP712Domain: DOMAIN_TYPE,
|
|
41
|
+
VerifiableCredential: VERIFIABLE_CREDENTIAL_EIP712_TYPE,
|
|
42
|
+
CredentialSchema: CREDENTIAL_SCHEMA_EIP712_TYPE,
|
|
43
|
+
CredentialSubject: CREDENTIAL_SUBJECT_TYPE,
|
|
44
|
+
Issuer: ISSUER_TYPE,
|
|
45
|
+
} as const;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { IEventEmitter } from "./types";
|
|
2
|
+
|
|
3
|
+
export class TypedCustomEvent<T> extends CustomEvent<T> {
|
|
4
|
+
constructor(type: string, detail?: T) {
|
|
5
|
+
super(type, { detail });
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class BrowserEventEmitter<Events extends Record<string, unknown>>
|
|
10
|
+
implements IEventEmitter<Events>
|
|
11
|
+
{
|
|
12
|
+
#eventTarget = new EventTarget();
|
|
13
|
+
|
|
14
|
+
on<K extends keyof Events>(
|
|
15
|
+
event: K,
|
|
16
|
+
listener: (data: Events[K]) => void,
|
|
17
|
+
): () => void {
|
|
18
|
+
const wrappedListener = (e: Event) => {
|
|
19
|
+
if (e instanceof TypedCustomEvent) {
|
|
20
|
+
listener(e.detail as Events[K]);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
this.#eventTarget.addEventListener(event.toString(), wrappedListener);
|
|
25
|
+
return () => {
|
|
26
|
+
this.#eventTarget.removeEventListener(event.toString(), wrappedListener);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
emit<K extends keyof Events>(event: K, data: Events[K]): void {
|
|
31
|
+
const customEvent = new TypedCustomEvent(event.toString(), data);
|
|
32
|
+
this.#eventTarget.dispatchEvent(customEvent);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { IEventEmitter } from "./types.js";
|
|
3
|
+
|
|
4
|
+
export class NodeEventEmitter<Events extends Record<string, unknown>>
|
|
5
|
+
implements IEventEmitter<Events>
|
|
6
|
+
{
|
|
7
|
+
#emitter = new EventEmitter();
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
this.#emitter.setMaxListeners(0);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
on<K extends keyof Events>(
|
|
14
|
+
event: K,
|
|
15
|
+
listener: (data: Events[K]) => void,
|
|
16
|
+
): () => void {
|
|
17
|
+
this.#emitter.on(event as string, listener);
|
|
18
|
+
return () => {
|
|
19
|
+
this.#emitter.removeListener(event.toString(), listener);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
emit<K extends keyof Events>(event: K, data: Events[K]): void {
|
|
24
|
+
this.#emitter.emit(event.toString(), data);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface IEventEmitter<Events extends Record<string, unknown>> {
|
|
2
|
+
/**
|
|
3
|
+
* Registers a listener for the specified event.
|
|
4
|
+
* @param event - The event name.
|
|
5
|
+
* @param listener - The listener function for the event.
|
|
6
|
+
* @returns A function to remove the listener.
|
|
7
|
+
*/
|
|
8
|
+
on<K extends keyof Events>(
|
|
9
|
+
event: K,
|
|
10
|
+
listener: (data: Events[K]) => void,
|
|
11
|
+
): () => void;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Emits an event with the specified data.
|
|
15
|
+
* @param event - The event name.
|
|
16
|
+
* @param data - The data to pass to listeners.
|
|
17
|
+
*/
|
|
18
|
+
emit<K extends keyof Events>(event: K, data: Events[K]): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Renown } from "./common";
|
|
2
|
+
import { RenownEvents, RenownStorageMap } from "./types";
|
|
3
|
+
import { BrowserEventEmitter } from "./event/event.browser";
|
|
4
|
+
import { BrowserStorage } from "./storage/storage.browser";
|
|
5
|
+
|
|
6
|
+
export function initRenown(connectId: string, basename: string | undefined) {
|
|
7
|
+
return new Renown(
|
|
8
|
+
new BrowserStorage<RenownStorageMap>("renown", basename),
|
|
9
|
+
new BrowserEventEmitter<RenownEvents>(),
|
|
10
|
+
connectId,
|
|
11
|
+
);
|
|
12
|
+
}
|
package/src/init.node.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Renown } from "./common";
|
|
2
|
+
import { NodeEventEmitter } from "./event/event.node";
|
|
3
|
+
import { NodeStorage } from "./storage/storage.node";
|
|
4
|
+
import { RenownEvents, RenownStorageMap } from "./types";
|
|
5
|
+
|
|
6
|
+
export function initRenown(
|
|
7
|
+
connectId: string,
|
|
8
|
+
filePath: string,
|
|
9
|
+
namespace: string,
|
|
10
|
+
) {
|
|
11
|
+
const storage = new NodeStorage<RenownStorageMap>(filePath, namespace);
|
|
12
|
+
return new Renown(storage, new NodeEventEmitter<RenownEvents>(), connectId);
|
|
13
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface IStorage<
|
|
2
|
+
T extends Record<string, unknown> = Record<string, unknown>,
|
|
3
|
+
> {
|
|
4
|
+
get<Key extends keyof T>(key: Key): T[Key] | undefined;
|
|
5
|
+
set<Key extends keyof T>(key: Key, value?: T[Key]): void;
|
|
6
|
+
delete(key: keyof T): void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export abstract class BaseStorage<
|
|
10
|
+
T extends Record<string, unknown> = Record<string, unknown>,
|
|
11
|
+
> implements IStorage<T>
|
|
12
|
+
{
|
|
13
|
+
protected constructor(protected namespace: string) {}
|
|
14
|
+
|
|
15
|
+
abstract get<Key extends keyof T>(key: Key): T[Key] | undefined;
|
|
16
|
+
abstract set<Key extends keyof T>(key: Key, value?: T[Key]): void;
|
|
17
|
+
abstract delete(key: keyof T): void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { BaseStorage } from "./common";
|
|
2
|
+
|
|
3
|
+
export class BrowserStorage<
|
|
4
|
+
T extends Record<string, unknown> = Record<string, unknown>,
|
|
5
|
+
> extends BaseStorage<T> {
|
|
6
|
+
constructor(namespace: string, basename: string | undefined) {
|
|
7
|
+
super(`${basename}:${namespace}`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
#buildKey(key: keyof T): string {
|
|
11
|
+
return `${this.namespace}:${key.toString()}`;
|
|
12
|
+
}
|
|
13
|
+
get<Key extends keyof T>(key: Key): T[Key] | undefined {
|
|
14
|
+
const value = localStorage.getItem(this.#buildKey(key));
|
|
15
|
+
if (value) {
|
|
16
|
+
return JSON.parse(value) as T[Key];
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
set<Key extends keyof T>(key: Key, value?: T[Key] | undefined): void {
|
|
22
|
+
return value
|
|
23
|
+
? localStorage.setItem(this.#buildKey(key), JSON.stringify(value))
|
|
24
|
+
: localStorage.removeItem(this.#buildKey(key));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
delete(key: keyof T): void {
|
|
28
|
+
return localStorage.removeItem(this.#buildKey(key));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { writeFileSync, readFileSync, existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { BaseStorage } from "./common";
|
|
4
|
+
|
|
5
|
+
export class NodeStorage<
|
|
6
|
+
T extends Record<string, unknown> = Record<string, unknown>,
|
|
7
|
+
> extends BaseStorage<T> {
|
|
8
|
+
private readonly filePath: string;
|
|
9
|
+
|
|
10
|
+
constructor(filePath: string, namespace: string) {
|
|
11
|
+
super(namespace);
|
|
12
|
+
this.filePath = filePath;
|
|
13
|
+
|
|
14
|
+
if (!existsSync(this.filePath)) {
|
|
15
|
+
writeFileSync(this.filePath, JSON.stringify({}));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private readData(): T {
|
|
20
|
+
const data = readFileSync(this.filePath, "utf-8");
|
|
21
|
+
return JSON.parse(data) as T;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private writeData(data: T): void {
|
|
25
|
+
writeFileSync(
|
|
26
|
+
join(this.filePath, `$this.namespace}.json`),
|
|
27
|
+
JSON.stringify(data, null, 2),
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get<Key extends keyof T>(key: Key): T[Key] | undefined {
|
|
32
|
+
const data = this.readData();
|
|
33
|
+
return data[key];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
set<Key extends keyof T>(key: Key, value?: T[Key]): void {
|
|
37
|
+
const data = this.readData();
|
|
38
|
+
if (value === undefined) {
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
40
|
+
delete data[key];
|
|
41
|
+
} else {
|
|
42
|
+
data[key] = value;
|
|
43
|
+
}
|
|
44
|
+
this.writeData(data);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
delete(key: keyof T): void {
|
|
48
|
+
const data = this.readData();
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
50
|
+
delete data[key];
|
|
51
|
+
this.writeData(data);
|
|
52
|
+
}
|
|
53
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { User as EditorUser } from "document-model/document";
|
|
2
|
+
import { CREDENTIAL_TYPES } from "./constants";
|
|
3
|
+
import { IStorage } from "./storage/common";
|
|
4
|
+
import { IEventEmitter } from "./event/types";
|
|
5
|
+
|
|
6
|
+
export type User = EditorUser & {
|
|
7
|
+
did: string;
|
|
8
|
+
credential: PowerhouseVerifiableCredential | undefined;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type Unsubscribe = () => void;
|
|
12
|
+
|
|
13
|
+
export type RenownStorageMap = { user: User | undefined };
|
|
14
|
+
|
|
15
|
+
export type RenownStorage = IStorage<RenownStorageMap>;
|
|
16
|
+
|
|
17
|
+
export type RenownEvents = {
|
|
18
|
+
user: User | undefined;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type RenownEventEmitter = IEventEmitter<RenownEvents>;
|
|
22
|
+
|
|
23
|
+
export interface IRenown extends Pick<RenownEventEmitter, "on"> {
|
|
24
|
+
user: User | undefined;
|
|
25
|
+
login: (did: string) => Promise<User | undefined>;
|
|
26
|
+
logout: () => Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type IssuerType<T> = {
|
|
30
|
+
id: string;
|
|
31
|
+
} & T;
|
|
32
|
+
|
|
33
|
+
type CredentialSubjecType<T> = {
|
|
34
|
+
id?: string;
|
|
35
|
+
} & T;
|
|
36
|
+
|
|
37
|
+
interface CredentialStatus {
|
|
38
|
+
id: string;
|
|
39
|
+
type: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface CredentialSchema {
|
|
43
|
+
id: string;
|
|
44
|
+
type: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface IVerifiableCredentialPayload<Subject, Issuer> {
|
|
48
|
+
"@context": string[];
|
|
49
|
+
id: string;
|
|
50
|
+
type: string[];
|
|
51
|
+
issuer: IssuerType<Issuer>;
|
|
52
|
+
issuanceDate: string;
|
|
53
|
+
expirationDate?: string;
|
|
54
|
+
credentialSubject: CredentialSubjecType<Subject>;
|
|
55
|
+
credentialStatus?: CredentialStatus;
|
|
56
|
+
credentialSchema: CredentialSchema;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface IProof {
|
|
60
|
+
verificationMethod: string;
|
|
61
|
+
ethereumAddress: `0x${string}`;
|
|
62
|
+
created: string;
|
|
63
|
+
proofPurpose: string;
|
|
64
|
+
type: string;
|
|
65
|
+
proofValue: string;
|
|
66
|
+
eip712: {
|
|
67
|
+
domain: {
|
|
68
|
+
name: string;
|
|
69
|
+
version: string;
|
|
70
|
+
chainId: number;
|
|
71
|
+
verifyingContract: string;
|
|
72
|
+
};
|
|
73
|
+
types: typeof CREDENTIAL_TYPES;
|
|
74
|
+
primaryType: "VerifiableCredential";
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface IVerifiableCredential<Subject, Issuer>
|
|
79
|
+
extends IVerifiableCredentialPayload<Subject, Issuer> {
|
|
80
|
+
proof: IProof;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface IPowerhouseCredentialSubject {
|
|
84
|
+
id: string;
|
|
85
|
+
app: string;
|
|
86
|
+
name?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface IPowerhouseIssuerType {
|
|
90
|
+
ethereumAddress: `0x${string}`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export type PowerhouseVerifiableCredential = IVerifiableCredential<
|
|
94
|
+
IPowerhouseCredentialSubject,
|
|
95
|
+
IPowerhouseIssuerType
|
|
96
|
+
>;
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type PKHDid = {
|
|
2
|
+
networkId: string;
|
|
3
|
+
chainId: number;
|
|
4
|
+
address: `0x${string}`;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export function parsePkhDid(did: string): PKHDid {
|
|
8
|
+
const parts = did.split(":");
|
|
9
|
+
if (!did.startsWith("did:pkh:") || parts.length !== 5) {
|
|
10
|
+
throw new Error("Invalid pkh did");
|
|
11
|
+
}
|
|
12
|
+
const [, , networkId, chainIdStr, address] = parts;
|
|
13
|
+
|
|
14
|
+
if (!address.startsWith("0x")) {
|
|
15
|
+
throw new Error(`Invalid address: ${address}`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const chainId = Number(chainIdStr);
|
|
19
|
+
if (isNaN(chainId)) {
|
|
20
|
+
throw new Error(`Invalid chain id: ${chainIdStr}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
chainId,
|
|
25
|
+
networkId,
|
|
26
|
+
address: address as PKHDid["address"],
|
|
27
|
+
};
|
|
28
|
+
}
|