@echoxyz/sonar-core 0.0.3 → 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/CHANGELOG.md +6 -0
- package/README.md +139 -0
- package/package.json +8 -5
package/CHANGELOG.md
CHANGED
package/README.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# @echoxyz/sonar-core
|
|
2
|
+
|
|
3
|
+
Headless core client for interacting with Echo’s Sonar APIs. Router-agnostic, framework-agnostic.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @echoxyz/sonar-core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start (default settings)
|
|
12
|
+
|
|
13
|
+
The default client targets Echo’s hosted API and reads the auth token from `localStorage` under the `sonar:auth-token` key.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { createClient, buildAuthorizationUrl, generatePKCEParams, EntityType } from "@echoxyz/sonar-core";
|
|
17
|
+
|
|
18
|
+
// Configure once at app startup
|
|
19
|
+
const saleUUID = "<your-sale-uuid>";
|
|
20
|
+
const clientUUID = "<your-oauth-client-id>";
|
|
21
|
+
const redirectURI = window.location.origin + "/oauth/callback";
|
|
22
|
+
|
|
23
|
+
const client = createClient({ saleUUID });
|
|
24
|
+
|
|
25
|
+
// Start OAuth login (e.g. on a button click)
|
|
26
|
+
export async function login() {
|
|
27
|
+
const { codeVerifier, codeChallenge, state } = await generatePKCEParams();
|
|
28
|
+
|
|
29
|
+
sessionStorage.setItem("sonar:oauth:state", state);
|
|
30
|
+
sessionStorage.setItem("sonar:oauth:verifier", codeVerifier);
|
|
31
|
+
|
|
32
|
+
const url = buildAuthorizationUrl({
|
|
33
|
+
saleUUID,
|
|
34
|
+
clientUUID,
|
|
35
|
+
redirectURI,
|
|
36
|
+
state,
|
|
37
|
+
codeChallenge,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
window.location.href = url.toString();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Complete OAuth on your callback route/page
|
|
44
|
+
export async function completeOAuthFromCallback() {
|
|
45
|
+
const params = new URLSearchParams(window.location.search);
|
|
46
|
+
const code = params.get("code");
|
|
47
|
+
const state = params.get("state");
|
|
48
|
+
if (!code || !state) {
|
|
49
|
+
throw new Error("Missing OAuth params");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const expectedState = sessionStorage.getItem("sonar:oauth:state");
|
|
53
|
+
const codeVerifier = sessionStorage.getItem("sonar:oauth:verifier");
|
|
54
|
+
if (state !== expectedState || !codeVerifier) {
|
|
55
|
+
throw new Error("Invalid OAuth state or missing verifier");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const { token } = await client.exchangeAuthorizationCode({
|
|
59
|
+
code,
|
|
60
|
+
codeVerifier,
|
|
61
|
+
redirectURI,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Persist through the client (wired to default storage)
|
|
65
|
+
client.setToken(token);
|
|
66
|
+
|
|
67
|
+
// Clean up temp params
|
|
68
|
+
sessionStorage.removeItem("sonar:oauth:state");
|
|
69
|
+
sessionStorage.removeItem("sonar:oauth:verifier");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Call APIs (after token is set)
|
|
73
|
+
export async function exampleCalls() {
|
|
74
|
+
// List entities available to this user for the configured sale
|
|
75
|
+
const { Entities } = await client.listAvailableEntities({ saleUUID });
|
|
76
|
+
|
|
77
|
+
// Run a pre-purchase check
|
|
78
|
+
const pre = await client.prePurchaseCheck({
|
|
79
|
+
saleUUID,
|
|
80
|
+
entityUUID: Entities[0].EntityUUID,
|
|
81
|
+
entityType: EntityType.USER, // or EntityType.ORGANIZATION
|
|
82
|
+
walletAddress: "0x1234...abcd" as `0x${string}`,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
if (pre.ReadyToPurchase) {
|
|
86
|
+
// Generate a purchase permit
|
|
87
|
+
const permit = await client.generatePurchasePermit({
|
|
88
|
+
saleUUID,
|
|
89
|
+
entityUUID: Entities[0].EntityUUID,
|
|
90
|
+
entityType: EntityType.USER,
|
|
91
|
+
walletAddress: "0x1234...abcd" as `0x${string}`,
|
|
92
|
+
});
|
|
93
|
+
console.log(permit.Signature, permit.Permit);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Fetch allocation
|
|
97
|
+
const alloc = await client.fetchAllocation({ saleUUID, walletAddress: "0x1234...abcd" as `0x${string}` });
|
|
98
|
+
console.log(alloc);
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Customizing the client
|
|
103
|
+
|
|
104
|
+
`createClient` accepts options so you can swap out pieces as needed:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { AuthSession, buildAuthorizationUrl, createClient, createMemoryStorage } from "@echoxyz/sonar-core";
|
|
108
|
+
|
|
109
|
+
const client = createClient({
|
|
110
|
+
saleUUID: "<sale-uuid>",
|
|
111
|
+
apiURL: "https://api.echo.xyz",
|
|
112
|
+
fetch: customFetchImplementation,
|
|
113
|
+
auth: new AuthSession({
|
|
114
|
+
storage: createMemoryStorage(),
|
|
115
|
+
tokenKey: "custom-token-key",
|
|
116
|
+
}),
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// or let the factory create the session but tweak defaults
|
|
120
|
+
const clientWithCallbacks = createClient({
|
|
121
|
+
saleUUID: "<sale-uuid>",
|
|
122
|
+
onTokenChange: (token) => console.log("token updated", token),
|
|
123
|
+
onExpire: () => console.log("session expired"),
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const oauthURL = buildAuthorizationUrl({
|
|
127
|
+
saleUUID: "<sale-uuid>",
|
|
128
|
+
clientUUID: "<client-id>",
|
|
129
|
+
redirectURI: "https://example.com/oauth/callback",
|
|
130
|
+
state: "opaque-state",
|
|
131
|
+
codeChallenge: "pkce-challenge",
|
|
132
|
+
frontendURL: "https://custom.echo.xyz", // optional override
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Notes
|
|
137
|
+
|
|
138
|
+
- Tokens are not auto-refreshed. When they expire, clear `sonar:auth-token` and re-run the OAuth flow.
|
|
139
|
+
- This package is headless and router-agnostic. You can integrate with any router or framework.
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@echoxyz/sonar-core",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
|
-
"module": "./dist/index.
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
"README.md",
|
|
30
30
|
"package.json"
|
|
31
31
|
],
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"jose": "^6.1.0"
|
|
34
|
+
},
|
|
32
35
|
"scripts": {
|
|
33
36
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
34
37
|
"dev": "tsup src/index.ts --format esm,cjs --dts --watch",
|