@opendatalabs/vana-sdk 3.8.3 → 3.9.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 +31 -10
- package/dist/session-relay/client.cjs +215 -0
- package/dist/session-relay/client.cjs.map +1 -0
- package/dist/session-relay/client.d.ts +16 -0
- package/dist/session-relay/client.js +190 -0
- package/dist/session-relay/client.js.map +1 -0
- package/dist/session-relay/client.test.d.ts +1 -0
- package/dist/session-relay/endpoints.cjs +37 -0
- package/dist/session-relay/endpoints.cjs.map +1 -0
- package/dist/session-relay/endpoints.d.ts +7 -0
- package/dist/session-relay/endpoints.js +11 -0
- package/dist/session-relay/endpoints.js.map +1 -0
- package/dist/session-relay/errors.cjs +36 -0
- package/dist/session-relay/errors.cjs.map +1 -0
- package/dist/session-relay/errors.d.ts +13 -0
- package/dist/session-relay/errors.js +12 -0
- package/dist/session-relay/errors.js.map +1 -0
- package/dist/session-relay/index.cjs +46 -0
- package/dist/session-relay/index.cjs.map +1 -0
- package/dist/session-relay/index.d.ts +5 -0
- package/dist/session-relay/index.js +25 -0
- package/dist/session-relay/index.js.map +1 -0
- package/dist/session-relay/signing.cjs +62 -0
- package/dist/session-relay/signing.cjs.map +1 -0
- package/dist/session-relay/signing.d.ts +21 -0
- package/dist/session-relay/signing.js +39 -0
- package/dist/session-relay/signing.js.map +1 -0
- package/dist/session-relay/signing.test.d.ts +1 -0
- package/dist/session-relay/types.cjs +17 -0
- package/dist/session-relay/types.cjs.map +1 -0
- package/dist/session-relay/types.d.ts +119 -0
- package/dist/session-relay/types.js +1 -0
- package/dist/session-relay/types.js.map +1 -0
- package/dist/session-relay.cjs +46 -0
- package/dist/session-relay.cjs.map +1 -0
- package/dist/session-relay.d.ts +27 -0
- package/dist/session-relay.js +27 -0
- package/dist/session-relay.js.map +1 -0
- package/package.json +10 -1
package/README.md
CHANGED
|
@@ -29,6 +29,10 @@ encryption, storage providers, and a shared isomorphic platform layer.
|
|
|
29
29
|
- **Storage providers** — `VanaStorage` (default, talks to `storage.vana.org`),
|
|
30
30
|
`R2Storage`, `StorageManager`, `IpfsStorage`, `PinataStorage`,
|
|
31
31
|
`GoogleDriveStorage`, `DropboxStorage`, `CallbackStorage`.
|
|
32
|
+
- **Vana service integrations** — `@opendatalabs/vana-sdk/server`,
|
|
33
|
+
`@opendatalabs/vana-sdk/react`, and `@opendatalabs/vana-sdk/session-relay`
|
|
34
|
+
for Vana-operated app handoff flows. These are integration helpers, not
|
|
35
|
+
protocol-core modules.
|
|
32
36
|
- **Platform adapters** — `NodePlatformAdapter` and `BrowserPlatformAdapter`
|
|
33
37
|
with a shared `VanaPlatformAdapter` interface, plus detection helpers
|
|
34
38
|
(`detectPlatform`, `isPlatformSupported`, `createPlatformAdapter`,
|
|
@@ -104,12 +108,12 @@ const result = await storage.upload(myBlob, "report.json");
|
|
|
104
108
|
console.log(result.url);
|
|
105
109
|
```
|
|
106
110
|
|
|
107
|
-
## Build a
|
|
111
|
+
## Build a Vana app
|
|
108
112
|
|
|
109
113
|
Request user-approved data, read it from the user's Personal Server, and pay
|
|
110
114
|
for the read — without the browser ever seeing your app private key or choosing
|
|
111
|
-
scopes. Your **backend** owns the controller
|
|
112
|
-
your **frontend** drives a two-tab approval flow with a React hook
|
|
115
|
+
scopes. Your **backend** owns the Data Portability controller
|
|
116
|
+
(`@opendatalabs/vana-sdk/server`); your **frontend** drives a two-tab approval flow with a React hook
|
|
113
117
|
(`@opendatalabs/vana-sdk/react`).
|
|
114
118
|
|
|
115
119
|
> **How it fits together.** Access requests are created through the Vana Account
|
|
@@ -136,12 +140,12 @@ export const vana = createDirectDataController({
|
|
|
136
140
|
network: process.env.VANA_NETWORK === "moksha" ? "moksha" : "mainnet",
|
|
137
141
|
appPrivateKey: process.env.VANA_APP_PRIVATE_KEY!,
|
|
138
142
|
app: {
|
|
139
|
-
id: "
|
|
140
|
-
name: "
|
|
143
|
+
id: "spotify-taste",
|
|
144
|
+
name: "Spotify Taste",
|
|
141
145
|
homepageUrl: process.env.VANA_APP_URL!,
|
|
142
146
|
},
|
|
143
|
-
source: "
|
|
144
|
-
scopes: ["
|
|
147
|
+
source: "spotify",
|
|
148
|
+
scopes: ["spotify.savedTracks"],
|
|
145
149
|
// Settle paid reads through the DPv2 escrow gateway. The controller signs the
|
|
146
150
|
// GenericPayment with your app key; you supply the gateway client + contract.
|
|
147
151
|
escrow: {
|
|
@@ -172,7 +176,7 @@ const status = await vana.getAccessRequestStatus(requestId);
|
|
|
172
176
|
// GET /api/vana/data?requestId=...
|
|
173
177
|
const result = await vana.readApprovedData({ requestId });
|
|
174
178
|
// -> {
|
|
175
|
-
// scope: "
|
|
179
|
+
// scope: "spotify.savedTracks",
|
|
176
180
|
// data: ...,
|
|
177
181
|
// payment?: { // present only when this read settled a payment
|
|
178
182
|
// amount, asset, paymentNonce, paidAt,
|
|
@@ -194,7 +198,7 @@ amount and asset owed.
|
|
|
194
198
|
"use client";
|
|
195
199
|
import { useDirectVanaConnect } from "@opendatalabs/vana-sdk/react";
|
|
196
200
|
|
|
197
|
-
export function
|
|
201
|
+
export function ConnectSpotifyButton() {
|
|
198
202
|
const connect = useDirectVanaConnect({
|
|
199
203
|
createRequest: () =>
|
|
200
204
|
fetch("/api/vana/request", { method: "POST" }).then((r) => r.json()),
|
|
@@ -214,7 +218,7 @@ export function ConnectNotesButton() {
|
|
|
214
218
|
onClick={connect.start}
|
|
215
219
|
type="button"
|
|
216
220
|
>
|
|
217
|
-
{connect.state.type === "idle" ? "Connect
|
|
221
|
+
{connect.state.type === "idle" ? "Connect Spotify" : "Connecting..."}
|
|
218
222
|
</button>
|
|
219
223
|
);
|
|
220
224
|
}
|
|
@@ -225,6 +229,23 @@ until the request is approved, then calls `readResult`. `react` is an optional
|
|
|
225
229
|
peer dependency. The underlying `createDirectConnectFlow` store is also exported
|
|
226
230
|
for non-React frontends.
|
|
227
231
|
|
|
232
|
+
### Test with large sample data
|
|
233
|
+
|
|
234
|
+
When testing with realistic exports, use the public fixture catalog in
|
|
235
|
+
[`vana-com/data-connectors`](https://github.com/vana-com/data-connectors). Keep
|
|
236
|
+
the payload in a file or raw URL and point your app or agent at that location.
|
|
237
|
+
Do not paste large JSON into the terminal.
|
|
238
|
+
|
|
239
|
+
The controller can run against local test data by injecting an
|
|
240
|
+
`accessRequestClient` that returns an approved request and a
|
|
241
|
+
`personalServerFetch` that loads the sample payload, while the rest of your app
|
|
242
|
+
still calls `readApprovedData`.
|
|
243
|
+
|
|
244
|
+
See [`examples/vana-app`](../../examples/vana-app) for a runnable Next.js Vana
|
|
245
|
+
app. It includes the route handlers, return page, and React connect button from
|
|
246
|
+
this flow, defaults to sample-data mode using `vana-com/data-connectors`, and
|
|
247
|
+
can be switched to live protocol mode with environment variables.
|
|
248
|
+
|
|
228
249
|
## Networks
|
|
229
250
|
|
|
230
251
|
| Network | Chain ID | RPC URL |
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var client_exports = {};
|
|
20
|
+
__export(client_exports, {
|
|
21
|
+
createSessionRelayBuilderClient: () => createSessionRelayBuilderClient,
|
|
22
|
+
createSessionRelayClient: () => createSessionRelayClient
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(client_exports);
|
|
25
|
+
var import_endpoints = require("./endpoints");
|
|
26
|
+
var import_errors = require("./errors");
|
|
27
|
+
var import_signing = require("./signing");
|
|
28
|
+
const DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
29
|
+
const DEFAULT_POLL_TIMEOUT_MS = 15 * 6e4;
|
|
30
|
+
function stripTrailingSlash(url) {
|
|
31
|
+
return url.replace(/\/+$/, "");
|
|
32
|
+
}
|
|
33
|
+
function resolveFetch(fetchFn) {
|
|
34
|
+
const resolved = fetchFn ?? globalThis.fetch;
|
|
35
|
+
if (!resolved) {
|
|
36
|
+
throw new import_errors.SessionRelayError(
|
|
37
|
+
"No fetch implementation available. Pass `fetchFn` to the Session Relay client.",
|
|
38
|
+
{ relayErrorCode: "SESSION_RELAY_CONFIG_ERROR" }
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return resolved;
|
|
42
|
+
}
|
|
43
|
+
function endpoint(options) {
|
|
44
|
+
return stripTrailingSlash(options.baseUrl ?? (0, import_endpoints.getSessionRelayUrl)(options.env));
|
|
45
|
+
}
|
|
46
|
+
async function parseJson(res) {
|
|
47
|
+
if (res.status === 204) return void 0;
|
|
48
|
+
if (res.text) {
|
|
49
|
+
const text = await res.text();
|
|
50
|
+
if (text.length === 0) return void 0;
|
|
51
|
+
try {
|
|
52
|
+
return JSON.parse(text);
|
|
53
|
+
} catch {
|
|
54
|
+
throw new import_errors.SessionRelayError(
|
|
55
|
+
`Session Relay returned a non-JSON response (HTTP ${res.status})`,
|
|
56
|
+
{ status: res.status }
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
return await res.json();
|
|
62
|
+
} catch {
|
|
63
|
+
throw new import_errors.SessionRelayError(
|
|
64
|
+
`Session Relay returned a non-JSON response (HTTP ${res.status})`,
|
|
65
|
+
{ status: res.status }
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function relayErrorFromBody(body) {
|
|
70
|
+
if (body === null || typeof body !== "object" || !("error" in body)) {
|
|
71
|
+
return void 0;
|
|
72
|
+
}
|
|
73
|
+
const error = body.error;
|
|
74
|
+
if (error === null || typeof error !== "object") return void 0;
|
|
75
|
+
return error;
|
|
76
|
+
}
|
|
77
|
+
async function relayFetch(fetchFn, url, init) {
|
|
78
|
+
let res;
|
|
79
|
+
try {
|
|
80
|
+
res = await fetchFn(url, init);
|
|
81
|
+
} catch (err) {
|
|
82
|
+
throw new import_errors.SessionRelayError(
|
|
83
|
+
"Network error communicating with Session Relay",
|
|
84
|
+
{
|
|
85
|
+
body: err
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
const body = await parseJson(res);
|
|
90
|
+
if (!res.ok) {
|
|
91
|
+
const relayError = relayErrorFromBody(body);
|
|
92
|
+
throw new import_errors.SessionRelayError(
|
|
93
|
+
relayError?.message ?? `Session Relay request failed (HTTP ${res.status})`,
|
|
94
|
+
{
|
|
95
|
+
status: res.status,
|
|
96
|
+
relayCode: relayError?.code,
|
|
97
|
+
relayErrorCode: relayError?.errorCode,
|
|
98
|
+
body
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
return body;
|
|
103
|
+
}
|
|
104
|
+
async function pollSession(fetchFn, baseUrl, sessionId) {
|
|
105
|
+
return relayFetch(
|
|
106
|
+
fetchFn,
|
|
107
|
+
`${baseUrl}/v1/session/${encodeURIComponent(sessionId)}/poll`,
|
|
108
|
+
{ method: "GET" }
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
async function pollUntilComplete(fetchFn, baseUrl, sessionId, opts) {
|
|
112
|
+
const intervalMs = opts?.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
113
|
+
const timeoutMs = opts?.timeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;
|
|
114
|
+
const deadline = Date.now() + timeoutMs;
|
|
115
|
+
while (Date.now() < deadline) {
|
|
116
|
+
const result = await pollSession(fetchFn, baseUrl, sessionId);
|
|
117
|
+
if (result.status === "approved" || result.status === "denied" || result.status === "expired") {
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
121
|
+
}
|
|
122
|
+
throw new import_errors.SessionRelayError("Polling timed out", {
|
|
123
|
+
relayErrorCode: "SESSION_RELAY_POLL_TIMEOUT"
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function createSessionRelayClient(options = {}) {
|
|
127
|
+
const fetchFn = resolveFetch(options.fetchFn);
|
|
128
|
+
const baseUrl = endpoint(options);
|
|
129
|
+
return {
|
|
130
|
+
claimSession(request) {
|
|
131
|
+
return relayFetch(
|
|
132
|
+
fetchFn,
|
|
133
|
+
`${baseUrl}/v1/session/claim`,
|
|
134
|
+
{
|
|
135
|
+
method: "POST",
|
|
136
|
+
headers: { "Content-Type": "application/json" },
|
|
137
|
+
body: JSON.stringify(request)
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
},
|
|
141
|
+
async approveSession(sessionId, request) {
|
|
142
|
+
await relayFetch(
|
|
143
|
+
fetchFn,
|
|
144
|
+
`${baseUrl}/v1/session/${encodeURIComponent(sessionId)}/approve`,
|
|
145
|
+
{
|
|
146
|
+
method: "POST",
|
|
147
|
+
headers: { "Content-Type": "application/json" },
|
|
148
|
+
body: JSON.stringify(request)
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
},
|
|
152
|
+
async denySession(sessionId, request) {
|
|
153
|
+
await relayFetch(
|
|
154
|
+
fetchFn,
|
|
155
|
+
`${baseUrl}/v1/session/${encodeURIComponent(sessionId)}/deny`,
|
|
156
|
+
{
|
|
157
|
+
method: "POST",
|
|
158
|
+
headers: { "Content-Type": "application/json" },
|
|
159
|
+
body: JSON.stringify(request)
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
},
|
|
163
|
+
pollSession(sessionId) {
|
|
164
|
+
return pollSession(fetchFn, baseUrl, sessionId);
|
|
165
|
+
},
|
|
166
|
+
pollUntilComplete(sessionId, opts) {
|
|
167
|
+
return pollUntilComplete(fetchFn, baseUrl, sessionId, opts);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function createSessionRelayBuilderClient(options) {
|
|
172
|
+
const fetchFn = resolveFetch(options.fetchFn);
|
|
173
|
+
const baseUrl = endpoint(options);
|
|
174
|
+
return {
|
|
175
|
+
async initSession(params) {
|
|
176
|
+
const path = "/v1/session/init";
|
|
177
|
+
const body = JSON.stringify({
|
|
178
|
+
granteeAddress: options.granteeAddress,
|
|
179
|
+
scopes: params.scopes,
|
|
180
|
+
...params.webhookUrl && { webhookUrl: params.webhookUrl },
|
|
181
|
+
...params.appUserId && { appUserId: params.appUserId }
|
|
182
|
+
});
|
|
183
|
+
const iat = options.now?.() ?? Math.floor(Date.now() / 1e3);
|
|
184
|
+
const authHeader = await (0, import_signing.buildSessionRelayWeb3SignedHeader)({
|
|
185
|
+
signMessage: options.signMessage,
|
|
186
|
+
aud: baseUrl,
|
|
187
|
+
method: "POST",
|
|
188
|
+
uri: path,
|
|
189
|
+
body,
|
|
190
|
+
iat,
|
|
191
|
+
exp: iat + 300
|
|
192
|
+
});
|
|
193
|
+
return relayFetch(fetchFn, `${baseUrl}${path}`, {
|
|
194
|
+
method: "POST",
|
|
195
|
+
headers: {
|
|
196
|
+
"Content-Type": "application/json",
|
|
197
|
+
Authorization: authHeader
|
|
198
|
+
},
|
|
199
|
+
body
|
|
200
|
+
});
|
|
201
|
+
},
|
|
202
|
+
pollSession(sessionId) {
|
|
203
|
+
return pollSession(fetchFn, baseUrl, sessionId);
|
|
204
|
+
},
|
|
205
|
+
pollUntilComplete(sessionId, opts) {
|
|
206
|
+
return pollUntilComplete(fetchFn, baseUrl, sessionId, opts);
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
211
|
+
0 && (module.exports = {
|
|
212
|
+
createSessionRelayBuilderClient,
|
|
213
|
+
createSessionRelayClient
|
|
214
|
+
});
|
|
215
|
+
//# sourceMappingURL=client.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/session-relay/client.ts"],"sourcesContent":["import { getSessionRelayUrl } from \"./endpoints\";\nimport { SessionRelayError } from \"./errors\";\nimport { buildSessionRelayWeb3SignedHeader } from \"./signing\";\nimport type {\n SessionRelayApproveRequest,\n SessionRelayBuilderClient,\n SessionRelayBuilderClientOptions,\n SessionRelayClaimRequest,\n SessionRelayClaimResponse,\n SessionRelayClient,\n SessionRelayClientOptions,\n SessionRelayDenyRequest,\n SessionRelayFetch,\n SessionRelayInitParams,\n SessionRelayInitResult,\n SessionRelayPollResult,\n} from \"./types\";\n\nconst DEFAULT_POLL_INTERVAL_MS = 2_000;\nconst DEFAULT_POLL_TIMEOUT_MS = 15 * 60_000;\n\nfunction stripTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\nfunction resolveFetch(fetchFn?: SessionRelayFetch): SessionRelayFetch {\n const resolved = fetchFn ?? (globalThis.fetch as SessionRelayFetch);\n if (!resolved) {\n throw new SessionRelayError(\n \"No fetch implementation available. Pass `fetchFn` to the Session Relay client.\",\n { relayErrorCode: \"SESSION_RELAY_CONFIG_ERROR\" },\n );\n }\n return resolved;\n}\n\nfunction endpoint(options: SessionRelayClientOptions): string {\n return stripTrailingSlash(options.baseUrl ?? getSessionRelayUrl(options.env));\n}\n\nasync function parseJson(res: Awaited<ReturnType<SessionRelayFetch>>) {\n if (res.status === 204) return undefined;\n\n if (res.text) {\n const text = await res.text();\n if (text.length === 0) return undefined;\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw new SessionRelayError(\n `Session Relay returned a non-JSON response (HTTP ${res.status})`,\n { status: res.status },\n );\n }\n }\n\n try {\n return await res.json();\n } catch {\n throw new SessionRelayError(\n `Session Relay returned a non-JSON response (HTTP ${res.status})`,\n { status: res.status },\n );\n }\n}\n\nfunction relayErrorFromBody(\n body: unknown,\n):\n | { message?: string; code?: number; errorCode?: string; details?: unknown }\n | undefined {\n if (body === null || typeof body !== \"object\" || !(\"error\" in body)) {\n return undefined;\n }\n const error = (body as { error?: unknown }).error;\n if (error === null || typeof error !== \"object\") return undefined;\n return error as {\n message?: string;\n code?: number;\n errorCode?: string;\n details?: unknown;\n };\n}\n\nasync function relayFetch<T>(\n fetchFn: SessionRelayFetch,\n url: string,\n init: { method: string; headers?: Record<string, string>; body?: string },\n): Promise<T> {\n let res: Awaited<ReturnType<SessionRelayFetch>>;\n try {\n res = await fetchFn(url, init);\n } catch (err) {\n throw new SessionRelayError(\n \"Network error communicating with Session Relay\",\n {\n body: err,\n },\n );\n }\n\n const body = await parseJson(res);\n if (!res.ok) {\n const relayError = relayErrorFromBody(body);\n throw new SessionRelayError(\n relayError?.message ??\n `Session Relay request failed (HTTP ${res.status})`,\n {\n status: res.status,\n relayCode: relayError?.code,\n relayErrorCode: relayError?.errorCode,\n body,\n },\n );\n }\n\n return body as T;\n}\n\nasync function pollSession(\n fetchFn: SessionRelayFetch,\n baseUrl: string,\n sessionId: string,\n): Promise<SessionRelayPollResult> {\n return relayFetch<SessionRelayPollResult>(\n fetchFn,\n `${baseUrl}/v1/session/${encodeURIComponent(sessionId)}/poll`,\n { method: \"GET\" },\n );\n}\n\nasync function pollUntilComplete(\n fetchFn: SessionRelayFetch,\n baseUrl: string,\n sessionId: string,\n opts?: { intervalMs?: number; timeoutMs?: number },\n): Promise<SessionRelayPollResult> {\n const intervalMs = opts?.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n const timeoutMs = opts?.timeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() < deadline) {\n const result = await pollSession(fetchFn, baseUrl, sessionId);\n if (\n result.status === \"approved\" ||\n result.status === \"denied\" ||\n result.status === \"expired\"\n ) {\n return result;\n }\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n\n throw new SessionRelayError(\"Polling timed out\", {\n relayErrorCode: \"SESSION_RELAY_POLL_TIMEOUT\",\n });\n}\n\n/**\n * Create a Session Relay client for app-side claim/approve/deny calls and\n * unsigned polling.\n *\n * @remarks\n * This is a Vana service integration client, not a protocol-core primitive.\n * It intentionally models the current Session Relay HTTP API while leaving\n * user-facing grant orchestration to the app using it.\n */\nexport function createSessionRelayClient(\n options: SessionRelayClientOptions = {},\n): SessionRelayClient {\n const fetchFn = resolveFetch(options.fetchFn);\n const baseUrl = endpoint(options);\n\n return {\n claimSession(\n request: SessionRelayClaimRequest,\n ): Promise<SessionRelayClaimResponse> {\n return relayFetch<SessionRelayClaimResponse>(\n fetchFn,\n `${baseUrl}/v1/session/claim`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n },\n );\n },\n\n async approveSession(\n sessionId: string,\n request: SessionRelayApproveRequest,\n ): Promise<void> {\n await relayFetch<unknown>(\n fetchFn,\n `${baseUrl}/v1/session/${encodeURIComponent(sessionId)}/approve`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n },\n );\n },\n\n async denySession(\n sessionId: string,\n request: SessionRelayDenyRequest,\n ): Promise<void> {\n await relayFetch<unknown>(\n fetchFn,\n `${baseUrl}/v1/session/${encodeURIComponent(sessionId)}/deny`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n },\n );\n },\n\n pollSession(sessionId: string): Promise<SessionRelayPollResult> {\n return pollSession(fetchFn, baseUrl, sessionId);\n },\n\n pollUntilComplete(\n sessionId: string,\n opts?: { intervalMs?: number; timeoutMs?: number },\n ): Promise<SessionRelayPollResult> {\n return pollUntilComplete(fetchFn, baseUrl, sessionId, opts);\n },\n };\n}\n\n/**\n * Create a builder-side Session Relay client for signed session init and\n * unsigned polling.\n */\nexport function createSessionRelayBuilderClient(\n options: SessionRelayBuilderClientOptions,\n): SessionRelayBuilderClient {\n const fetchFn = resolveFetch(options.fetchFn);\n const baseUrl = endpoint(options);\n\n return {\n async initSession(\n params: SessionRelayInitParams,\n ): Promise<SessionRelayInitResult> {\n const path = \"/v1/session/init\";\n const body = JSON.stringify({\n granteeAddress: options.granteeAddress,\n scopes: params.scopes,\n ...(params.webhookUrl && { webhookUrl: params.webhookUrl }),\n ...(params.appUserId && { appUserId: params.appUserId }),\n });\n const iat = options.now?.() ?? Math.floor(Date.now() / 1000);\n const authHeader = await buildSessionRelayWeb3SignedHeader({\n signMessage: options.signMessage,\n aud: baseUrl,\n method: \"POST\",\n uri: path,\n body,\n iat,\n exp: iat + 300,\n });\n\n return relayFetch<SessionRelayInitResult>(fetchFn, `${baseUrl}${path}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: authHeader,\n },\n body,\n });\n },\n\n pollSession(sessionId: string): Promise<SessionRelayPollResult> {\n return pollSession(fetchFn, baseUrl, sessionId);\n },\n\n pollUntilComplete(\n sessionId: string,\n opts?: { intervalMs?: number; timeoutMs?: number },\n ): Promise<SessionRelayPollResult> {\n return pollUntilComplete(fetchFn, baseUrl, sessionId, opts);\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SessionRelayBuilderClient, SessionRelayBuilderClientOptions, SessionRelayClient, SessionRelayClientOptions } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Create a Session Relay client for app-side claim/approve/deny calls and
|
|
4
|
+
* unsigned polling.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* This is a Vana service integration client, not a protocol-core primitive.
|
|
8
|
+
* It intentionally models the current Session Relay HTTP API while leaving
|
|
9
|
+
* user-facing grant orchestration to the app using it.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createSessionRelayClient(options?: SessionRelayClientOptions): SessionRelayClient;
|
|
12
|
+
/**
|
|
13
|
+
* Create a builder-side Session Relay client for signed session init and
|
|
14
|
+
* unsigned polling.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createSessionRelayBuilderClient(options: SessionRelayBuilderClientOptions): SessionRelayBuilderClient;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { getSessionRelayUrl } from "./endpoints.js";
|
|
2
|
+
import { SessionRelayError } from "./errors.js";
|
|
3
|
+
import { buildSessionRelayWeb3SignedHeader } from "./signing.js";
|
|
4
|
+
const DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
5
|
+
const DEFAULT_POLL_TIMEOUT_MS = 15 * 6e4;
|
|
6
|
+
function stripTrailingSlash(url) {
|
|
7
|
+
return url.replace(/\/+$/, "");
|
|
8
|
+
}
|
|
9
|
+
function resolveFetch(fetchFn) {
|
|
10
|
+
const resolved = fetchFn ?? globalThis.fetch;
|
|
11
|
+
if (!resolved) {
|
|
12
|
+
throw new SessionRelayError(
|
|
13
|
+
"No fetch implementation available. Pass `fetchFn` to the Session Relay client.",
|
|
14
|
+
{ relayErrorCode: "SESSION_RELAY_CONFIG_ERROR" }
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
return resolved;
|
|
18
|
+
}
|
|
19
|
+
function endpoint(options) {
|
|
20
|
+
return stripTrailingSlash(options.baseUrl ?? getSessionRelayUrl(options.env));
|
|
21
|
+
}
|
|
22
|
+
async function parseJson(res) {
|
|
23
|
+
if (res.status === 204) return void 0;
|
|
24
|
+
if (res.text) {
|
|
25
|
+
const text = await res.text();
|
|
26
|
+
if (text.length === 0) return void 0;
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(text);
|
|
29
|
+
} catch {
|
|
30
|
+
throw new SessionRelayError(
|
|
31
|
+
`Session Relay returned a non-JSON response (HTTP ${res.status})`,
|
|
32
|
+
{ status: res.status }
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
return await res.json();
|
|
38
|
+
} catch {
|
|
39
|
+
throw new SessionRelayError(
|
|
40
|
+
`Session Relay returned a non-JSON response (HTTP ${res.status})`,
|
|
41
|
+
{ status: res.status }
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function relayErrorFromBody(body) {
|
|
46
|
+
if (body === null || typeof body !== "object" || !("error" in body)) {
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
49
|
+
const error = body.error;
|
|
50
|
+
if (error === null || typeof error !== "object") return void 0;
|
|
51
|
+
return error;
|
|
52
|
+
}
|
|
53
|
+
async function relayFetch(fetchFn, url, init) {
|
|
54
|
+
let res;
|
|
55
|
+
try {
|
|
56
|
+
res = await fetchFn(url, init);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
throw new SessionRelayError(
|
|
59
|
+
"Network error communicating with Session Relay",
|
|
60
|
+
{
|
|
61
|
+
body: err
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
const body = await parseJson(res);
|
|
66
|
+
if (!res.ok) {
|
|
67
|
+
const relayError = relayErrorFromBody(body);
|
|
68
|
+
throw new SessionRelayError(
|
|
69
|
+
relayError?.message ?? `Session Relay request failed (HTTP ${res.status})`,
|
|
70
|
+
{
|
|
71
|
+
status: res.status,
|
|
72
|
+
relayCode: relayError?.code,
|
|
73
|
+
relayErrorCode: relayError?.errorCode,
|
|
74
|
+
body
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return body;
|
|
79
|
+
}
|
|
80
|
+
async function pollSession(fetchFn, baseUrl, sessionId) {
|
|
81
|
+
return relayFetch(
|
|
82
|
+
fetchFn,
|
|
83
|
+
`${baseUrl}/v1/session/${encodeURIComponent(sessionId)}/poll`,
|
|
84
|
+
{ method: "GET" }
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
async function pollUntilComplete(fetchFn, baseUrl, sessionId, opts) {
|
|
88
|
+
const intervalMs = opts?.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
89
|
+
const timeoutMs = opts?.timeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;
|
|
90
|
+
const deadline = Date.now() + timeoutMs;
|
|
91
|
+
while (Date.now() < deadline) {
|
|
92
|
+
const result = await pollSession(fetchFn, baseUrl, sessionId);
|
|
93
|
+
if (result.status === "approved" || result.status === "denied" || result.status === "expired") {
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
97
|
+
}
|
|
98
|
+
throw new SessionRelayError("Polling timed out", {
|
|
99
|
+
relayErrorCode: "SESSION_RELAY_POLL_TIMEOUT"
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
function createSessionRelayClient(options = {}) {
|
|
103
|
+
const fetchFn = resolveFetch(options.fetchFn);
|
|
104
|
+
const baseUrl = endpoint(options);
|
|
105
|
+
return {
|
|
106
|
+
claimSession(request) {
|
|
107
|
+
return relayFetch(
|
|
108
|
+
fetchFn,
|
|
109
|
+
`${baseUrl}/v1/session/claim`,
|
|
110
|
+
{
|
|
111
|
+
method: "POST",
|
|
112
|
+
headers: { "Content-Type": "application/json" },
|
|
113
|
+
body: JSON.stringify(request)
|
|
114
|
+
}
|
|
115
|
+
);
|
|
116
|
+
},
|
|
117
|
+
async approveSession(sessionId, request) {
|
|
118
|
+
await relayFetch(
|
|
119
|
+
fetchFn,
|
|
120
|
+
`${baseUrl}/v1/session/${encodeURIComponent(sessionId)}/approve`,
|
|
121
|
+
{
|
|
122
|
+
method: "POST",
|
|
123
|
+
headers: { "Content-Type": "application/json" },
|
|
124
|
+
body: JSON.stringify(request)
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
},
|
|
128
|
+
async denySession(sessionId, request) {
|
|
129
|
+
await relayFetch(
|
|
130
|
+
fetchFn,
|
|
131
|
+
`${baseUrl}/v1/session/${encodeURIComponent(sessionId)}/deny`,
|
|
132
|
+
{
|
|
133
|
+
method: "POST",
|
|
134
|
+
headers: { "Content-Type": "application/json" },
|
|
135
|
+
body: JSON.stringify(request)
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
},
|
|
139
|
+
pollSession(sessionId) {
|
|
140
|
+
return pollSession(fetchFn, baseUrl, sessionId);
|
|
141
|
+
},
|
|
142
|
+
pollUntilComplete(sessionId, opts) {
|
|
143
|
+
return pollUntilComplete(fetchFn, baseUrl, sessionId, opts);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function createSessionRelayBuilderClient(options) {
|
|
148
|
+
const fetchFn = resolveFetch(options.fetchFn);
|
|
149
|
+
const baseUrl = endpoint(options);
|
|
150
|
+
return {
|
|
151
|
+
async initSession(params) {
|
|
152
|
+
const path = "/v1/session/init";
|
|
153
|
+
const body = JSON.stringify({
|
|
154
|
+
granteeAddress: options.granteeAddress,
|
|
155
|
+
scopes: params.scopes,
|
|
156
|
+
...params.webhookUrl && { webhookUrl: params.webhookUrl },
|
|
157
|
+
...params.appUserId && { appUserId: params.appUserId }
|
|
158
|
+
});
|
|
159
|
+
const iat = options.now?.() ?? Math.floor(Date.now() / 1e3);
|
|
160
|
+
const authHeader = await buildSessionRelayWeb3SignedHeader({
|
|
161
|
+
signMessage: options.signMessage,
|
|
162
|
+
aud: baseUrl,
|
|
163
|
+
method: "POST",
|
|
164
|
+
uri: path,
|
|
165
|
+
body,
|
|
166
|
+
iat,
|
|
167
|
+
exp: iat + 300
|
|
168
|
+
});
|
|
169
|
+
return relayFetch(fetchFn, `${baseUrl}${path}`, {
|
|
170
|
+
method: "POST",
|
|
171
|
+
headers: {
|
|
172
|
+
"Content-Type": "application/json",
|
|
173
|
+
Authorization: authHeader
|
|
174
|
+
},
|
|
175
|
+
body
|
|
176
|
+
});
|
|
177
|
+
},
|
|
178
|
+
pollSession(sessionId) {
|
|
179
|
+
return pollSession(fetchFn, baseUrl, sessionId);
|
|
180
|
+
},
|
|
181
|
+
pollUntilComplete(sessionId, opts) {
|
|
182
|
+
return pollUntilComplete(fetchFn, baseUrl, sessionId, opts);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
export {
|
|
187
|
+
createSessionRelayBuilderClient,
|
|
188
|
+
createSessionRelayClient
|
|
189
|
+
};
|
|
190
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/session-relay/client.ts"],"sourcesContent":["import { getSessionRelayUrl } from \"./endpoints\";\nimport { SessionRelayError } from \"./errors\";\nimport { buildSessionRelayWeb3SignedHeader } from \"./signing\";\nimport type {\n SessionRelayApproveRequest,\n SessionRelayBuilderClient,\n SessionRelayBuilderClientOptions,\n SessionRelayClaimRequest,\n SessionRelayClaimResponse,\n SessionRelayClient,\n SessionRelayClientOptions,\n SessionRelayDenyRequest,\n SessionRelayFetch,\n SessionRelayInitParams,\n SessionRelayInitResult,\n SessionRelayPollResult,\n} from \"./types\";\n\nconst DEFAULT_POLL_INTERVAL_MS = 2_000;\nconst DEFAULT_POLL_TIMEOUT_MS = 15 * 60_000;\n\nfunction stripTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\nfunction resolveFetch(fetchFn?: SessionRelayFetch): SessionRelayFetch {\n const resolved = fetchFn ?? (globalThis.fetch as SessionRelayFetch);\n if (!resolved) {\n throw new SessionRelayError(\n \"No fetch implementation available. Pass `fetchFn` to the Session Relay client.\",\n { relayErrorCode: \"SESSION_RELAY_CONFIG_ERROR\" },\n );\n }\n return resolved;\n}\n\nfunction endpoint(options: SessionRelayClientOptions): string {\n return stripTrailingSlash(options.baseUrl ?? getSessionRelayUrl(options.env));\n}\n\nasync function parseJson(res: Awaited<ReturnType<SessionRelayFetch>>) {\n if (res.status === 204) return undefined;\n\n if (res.text) {\n const text = await res.text();\n if (text.length === 0) return undefined;\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw new SessionRelayError(\n `Session Relay returned a non-JSON response (HTTP ${res.status})`,\n { status: res.status },\n );\n }\n }\n\n try {\n return await res.json();\n } catch {\n throw new SessionRelayError(\n `Session Relay returned a non-JSON response (HTTP ${res.status})`,\n { status: res.status },\n );\n }\n}\n\nfunction relayErrorFromBody(\n body: unknown,\n):\n | { message?: string; code?: number; errorCode?: string; details?: unknown }\n | undefined {\n if (body === null || typeof body !== \"object\" || !(\"error\" in body)) {\n return undefined;\n }\n const error = (body as { error?: unknown }).error;\n if (error === null || typeof error !== \"object\") return undefined;\n return error as {\n message?: string;\n code?: number;\n errorCode?: string;\n details?: unknown;\n };\n}\n\nasync function relayFetch<T>(\n fetchFn: SessionRelayFetch,\n url: string,\n init: { method: string; headers?: Record<string, string>; body?: string },\n): Promise<T> {\n let res: Awaited<ReturnType<SessionRelayFetch>>;\n try {\n res = await fetchFn(url, init);\n } catch (err) {\n throw new SessionRelayError(\n \"Network error communicating with Session Relay\",\n {\n body: err,\n },\n );\n }\n\n const body = await parseJson(res);\n if (!res.ok) {\n const relayError = relayErrorFromBody(body);\n throw new SessionRelayError(\n relayError?.message ??\n `Session Relay request failed (HTTP ${res.status})`,\n {\n status: res.status,\n relayCode: relayError?.code,\n relayErrorCode: relayError?.errorCode,\n body,\n },\n );\n }\n\n return body as T;\n}\n\nasync function pollSession(\n fetchFn: SessionRelayFetch,\n baseUrl: string,\n sessionId: string,\n): Promise<SessionRelayPollResult> {\n return relayFetch<SessionRelayPollResult>(\n fetchFn,\n `${baseUrl}/v1/session/${encodeURIComponent(sessionId)}/poll`,\n { method: \"GET\" },\n );\n}\n\nasync function pollUntilComplete(\n fetchFn: SessionRelayFetch,\n baseUrl: string,\n sessionId: string,\n opts?: { intervalMs?: number; timeoutMs?: number },\n): Promise<SessionRelayPollResult> {\n const intervalMs = opts?.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n const timeoutMs = opts?.timeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() < deadline) {\n const result = await pollSession(fetchFn, baseUrl, sessionId);\n if (\n result.status === \"approved\" ||\n result.status === \"denied\" ||\n result.status === \"expired\"\n ) {\n return result;\n }\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n\n throw new SessionRelayError(\"Polling timed out\", {\n relayErrorCode: \"SESSION_RELAY_POLL_TIMEOUT\",\n });\n}\n\n/**\n * Create a Session Relay client for app-side claim/approve/deny calls and\n * unsigned polling.\n *\n * @remarks\n * This is a Vana service integration client, not a protocol-core primitive.\n * It intentionally models the current Session Relay HTTP API while leaving\n * user-facing grant orchestration to the app using it.\n */\nexport function createSessionRelayClient(\n options: SessionRelayClientOptions = {},\n): SessionRelayClient {\n const fetchFn = resolveFetch(options.fetchFn);\n const baseUrl = endpoint(options);\n\n return {\n claimSession(\n request: SessionRelayClaimRequest,\n ): Promise<SessionRelayClaimResponse> {\n return relayFetch<SessionRelayClaimResponse>(\n fetchFn,\n `${baseUrl}/v1/session/claim`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n },\n );\n },\n\n async approveSession(\n sessionId: string,\n request: SessionRelayApproveRequest,\n ): Promise<void> {\n await relayFetch<unknown>(\n fetchFn,\n `${baseUrl}/v1/session/${encodeURIComponent(sessionId)}/approve`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n },\n );\n },\n\n async denySession(\n sessionId: string,\n request: SessionRelayDenyRequest,\n ): Promise<void> {\n await relayFetch<unknown>(\n fetchFn,\n `${baseUrl}/v1/session/${encodeURIComponent(sessionId)}/deny`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n },\n );\n },\n\n pollSession(sessionId: string): Promise<SessionRelayPollResult> {\n return pollSession(fetchFn, baseUrl, sessionId);\n },\n\n pollUntilComplete(\n sessionId: string,\n opts?: { intervalMs?: number; timeoutMs?: number },\n ): Promise<SessionRelayPollResult> {\n return pollUntilComplete(fetchFn, baseUrl, sessionId, opts);\n },\n };\n}\n\n/**\n * Create a builder-side Session Relay client for signed session init and\n * unsigned polling.\n */\nexport function createSessionRelayBuilderClient(\n options: SessionRelayBuilderClientOptions,\n): SessionRelayBuilderClient {\n const fetchFn = resolveFetch(options.fetchFn);\n const baseUrl = endpoint(options);\n\n return {\n async initSession(\n params: SessionRelayInitParams,\n ): Promise<SessionRelayInitResult> {\n const path = \"/v1/session/init\";\n const body = JSON.stringify({\n granteeAddress: options.granteeAddress,\n scopes: params.scopes,\n ...(params.webhookUrl && { webhookUrl: params.webhookUrl }),\n ...(params.appUserId && { appUserId: params.appUserId }),\n });\n const iat = options.now?.() ?? Math.floor(Date.now() / 1000);\n const authHeader = await buildSessionRelayWeb3SignedHeader({\n signMessage: options.signMessage,\n aud: baseUrl,\n method: \"POST\",\n uri: path,\n body,\n iat,\n exp: iat + 300,\n });\n\n return relayFetch<SessionRelayInitResult>(fetchFn, `${baseUrl}${path}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: authHeader,\n },\n body,\n });\n },\n\n pollSession(sessionId: string): Promise<SessionRelayPollResult> {\n return pollSession(fetchFn, baseUrl, sessionId);\n },\n\n pollUntilComplete(\n sessionId: string,\n opts?: { intervalMs?: number; timeoutMs?: number },\n ): Promise<SessionRelayPollResult> {\n return pollUntilComplete(fetchFn, baseUrl, sessionId, opts);\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var endpoints_exports = {};
|
|
20
|
+
__export(endpoints_exports, {
|
|
21
|
+
SESSION_RELAY_DEV_URL: () => SESSION_RELAY_DEV_URL,
|
|
22
|
+
SESSION_RELAY_PRODUCTION_URL: () => SESSION_RELAY_PRODUCTION_URL,
|
|
23
|
+
getSessionRelayUrl: () => getSessionRelayUrl
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(endpoints_exports);
|
|
26
|
+
const SESSION_RELAY_PRODUCTION_URL = "https://session-relay.vana.org";
|
|
27
|
+
const SESSION_RELAY_DEV_URL = "https://dev.session-relay.vana.org";
|
|
28
|
+
function getSessionRelayUrl(env = "production") {
|
|
29
|
+
return env === "dev" ? SESSION_RELAY_DEV_URL : SESSION_RELAY_PRODUCTION_URL;
|
|
30
|
+
}
|
|
31
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
32
|
+
0 && (module.exports = {
|
|
33
|
+
SESSION_RELAY_DEV_URL,
|
|
34
|
+
SESSION_RELAY_PRODUCTION_URL,
|
|
35
|
+
getSessionRelayUrl
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=endpoints.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/session-relay/endpoints.ts"],"sourcesContent":["import type { SessionRelayEnvironment } from \"./types\";\n\n/** Production Session Relay URL. */\nexport const SESSION_RELAY_PRODUCTION_URL = \"https://session-relay.vana.org\";\n\n/** Internal dev Session Relay URL. */\nexport const SESSION_RELAY_DEV_URL = \"https://dev.session-relay.vana.org\";\n\n/** Resolve the default Session Relay URL for a deployment environment. */\nexport function getSessionRelayUrl(\n env: SessionRelayEnvironment = \"production\",\n): string {\n return env === \"dev\" ? SESSION_RELAY_DEV_URL : SESSION_RELAY_PRODUCTION_URL;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,MAAM,+BAA+B;AAGrC,MAAM,wBAAwB;AAG9B,SAAS,mBACd,MAA+B,cACvB;AACR,SAAO,QAAQ,QAAQ,wBAAwB;AACjD;","names":[]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SessionRelayEnvironment } from "./types";
|
|
2
|
+
/** Production Session Relay URL. */
|
|
3
|
+
export declare const SESSION_RELAY_PRODUCTION_URL = "https://session-relay.vana.org";
|
|
4
|
+
/** Internal dev Session Relay URL. */
|
|
5
|
+
export declare const SESSION_RELAY_DEV_URL = "https://dev.session-relay.vana.org";
|
|
6
|
+
/** Resolve the default Session Relay URL for a deployment environment. */
|
|
7
|
+
export declare function getSessionRelayUrl(env?: SessionRelayEnvironment): string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const SESSION_RELAY_PRODUCTION_URL = "https://session-relay.vana.org";
|
|
2
|
+
const SESSION_RELAY_DEV_URL = "https://dev.session-relay.vana.org";
|
|
3
|
+
function getSessionRelayUrl(env = "production") {
|
|
4
|
+
return env === "dev" ? SESSION_RELAY_DEV_URL : SESSION_RELAY_PRODUCTION_URL;
|
|
5
|
+
}
|
|
6
|
+
export {
|
|
7
|
+
SESSION_RELAY_DEV_URL,
|
|
8
|
+
SESSION_RELAY_PRODUCTION_URL,
|
|
9
|
+
getSessionRelayUrl
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=endpoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/session-relay/endpoints.ts"],"sourcesContent":["import type { SessionRelayEnvironment } from \"./types\";\n\n/** Production Session Relay URL. */\nexport const SESSION_RELAY_PRODUCTION_URL = \"https://session-relay.vana.org\";\n\n/** Internal dev Session Relay URL. */\nexport const SESSION_RELAY_DEV_URL = \"https://dev.session-relay.vana.org\";\n\n/** Resolve the default Session Relay URL for a deployment environment. */\nexport function getSessionRelayUrl(\n env: SessionRelayEnvironment = \"production\",\n): string {\n return env === \"dev\" ? SESSION_RELAY_DEV_URL : SESSION_RELAY_PRODUCTION_URL;\n}\n"],"mappings":"AAGO,MAAM,+BAA+B;AAGrC,MAAM,wBAAwB;AAG9B,SAAS,mBACd,MAA+B,cACvB;AACR,SAAO,QAAQ,QAAQ,wBAAwB;AACjD;","names":[]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var errors_exports = {};
|
|
20
|
+
__export(errors_exports, {
|
|
21
|
+
SessionRelayError: () => SessionRelayError
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(errors_exports);
|
|
24
|
+
var import_errors = require("../errors");
|
|
25
|
+
class SessionRelayError extends import_errors.VanaError {
|
|
26
|
+
constructor(message, details = {}) {
|
|
27
|
+
super(message, details.relayErrorCode ?? "SESSION_RELAY_ERROR");
|
|
28
|
+
this.details = details;
|
|
29
|
+
}
|
|
30
|
+
details;
|
|
31
|
+
}
|
|
32
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
33
|
+
0 && (module.exports = {
|
|
34
|
+
SessionRelayError
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=errors.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/session-relay/errors.ts"],"sourcesContent":["import { VanaError } from \"../errors\";\n\n/** Error details returned by Session Relay. */\nexport interface SessionRelayErrorDetails {\n status?: number;\n relayCode?: number;\n relayErrorCode?: string;\n body?: unknown;\n}\n\n/** Error thrown by Session Relay client operations. */\nexport class SessionRelayError extends VanaError {\n constructor(\n message: string,\n public readonly details: SessionRelayErrorDetails = {},\n ) {\n super(message, details.relayErrorCode ?? \"SESSION_RELAY_ERROR\");\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA0B;AAWnB,MAAM,0BAA0B,wBAAU;AAAA,EAC/C,YACE,SACgB,UAAoC,CAAC,GACrD;AACA,UAAM,SAAS,QAAQ,kBAAkB,qBAAqB;AAF9C;AAAA,EAGlB;AAAA,EAHkB;AAIpB;","names":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { VanaError } from "../errors";
|
|
2
|
+
/** Error details returned by Session Relay. */
|
|
3
|
+
export interface SessionRelayErrorDetails {
|
|
4
|
+
status?: number;
|
|
5
|
+
relayCode?: number;
|
|
6
|
+
relayErrorCode?: string;
|
|
7
|
+
body?: unknown;
|
|
8
|
+
}
|
|
9
|
+
/** Error thrown by Session Relay client operations. */
|
|
10
|
+
export declare class SessionRelayError extends VanaError {
|
|
11
|
+
readonly details: SessionRelayErrorDetails;
|
|
12
|
+
constructor(message: string, details?: SessionRelayErrorDetails);
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { VanaError } from "../errors.js";
|
|
2
|
+
class SessionRelayError extends VanaError {
|
|
3
|
+
constructor(message, details = {}) {
|
|
4
|
+
super(message, details.relayErrorCode ?? "SESSION_RELAY_ERROR");
|
|
5
|
+
this.details = details;
|
|
6
|
+
}
|
|
7
|
+
details;
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
SessionRelayError
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/session-relay/errors.ts"],"sourcesContent":["import { VanaError } from \"../errors\";\n\n/** Error details returned by Session Relay. */\nexport interface SessionRelayErrorDetails {\n status?: number;\n relayCode?: number;\n relayErrorCode?: string;\n body?: unknown;\n}\n\n/** Error thrown by Session Relay client operations. */\nexport class SessionRelayError extends VanaError {\n constructor(\n message: string,\n public readonly details: SessionRelayErrorDetails = {},\n ) {\n super(message, details.relayErrorCode ?? \"SESSION_RELAY_ERROR\");\n }\n}\n"],"mappings":"AAAA,SAAS,iBAAiB;AAWnB,MAAM,0BAA0B,UAAU;AAAA,EAC/C,YACE,SACgB,UAAoC,CAAC,GACrD;AACA,UAAM,SAAS,QAAQ,kBAAkB,qBAAqB;AAF9C;AAAA,EAGlB;AAAA,EAHkB;AAIpB;","names":[]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var session_relay_exports = {};
|
|
20
|
+
__export(session_relay_exports, {
|
|
21
|
+
SESSION_RELAY_DEV_URL: () => import_endpoints.SESSION_RELAY_DEV_URL,
|
|
22
|
+
SESSION_RELAY_PRODUCTION_URL: () => import_endpoints.SESSION_RELAY_PRODUCTION_URL,
|
|
23
|
+
SessionRelayError: () => import_errors.SessionRelayError,
|
|
24
|
+
buildSessionRelayWeb3SignedHeader: () => import_signing.buildSessionRelayWeb3SignedHeader,
|
|
25
|
+
computeSessionRelayBodyHash: () => import_signing.computeSessionRelayBodyHash,
|
|
26
|
+
createSessionRelayBuilderClient: () => import_client.createSessionRelayBuilderClient,
|
|
27
|
+
createSessionRelayClient: () => import_client.createSessionRelayClient,
|
|
28
|
+
getSessionRelayUrl: () => import_endpoints.getSessionRelayUrl
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(session_relay_exports);
|
|
31
|
+
var import_endpoints = require("./endpoints");
|
|
32
|
+
var import_errors = require("./errors");
|
|
33
|
+
var import_signing = require("./signing");
|
|
34
|
+
var import_client = require("./client");
|
|
35
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
36
|
+
0 && (module.exports = {
|
|
37
|
+
SESSION_RELAY_DEV_URL,
|
|
38
|
+
SESSION_RELAY_PRODUCTION_URL,
|
|
39
|
+
SessionRelayError,
|
|
40
|
+
buildSessionRelayWeb3SignedHeader,
|
|
41
|
+
computeSessionRelayBodyHash,
|
|
42
|
+
createSessionRelayBuilderClient,
|
|
43
|
+
createSessionRelayClient,
|
|
44
|
+
getSessionRelayUrl
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/session-relay/index.ts"],"sourcesContent":["export {\n SESSION_RELAY_DEV_URL,\n SESSION_RELAY_PRODUCTION_URL,\n getSessionRelayUrl,\n} from \"./endpoints\";\nexport { SessionRelayError, type SessionRelayErrorDetails } from \"./errors\";\nexport {\n computeSessionRelayBodyHash,\n buildSessionRelayWeb3SignedHeader,\n} from \"./signing\";\nexport {\n createSessionRelayClient,\n createSessionRelayBuilderClient,\n} from \"./client\";\nexport type {\n SessionRelayEnvironment,\n SessionRelayFetch,\n SessionRelayClientOptions,\n SessionRelayBuilderClientOptions,\n SessionRelayInitParams,\n SessionRelayInitResult,\n SessionRelayGrantPayload,\n SessionRelayPollResult,\n SessionRelayClaimRequest,\n SessionRelayClaimResponse,\n SessionRelayApproveRequest,\n SessionRelayDenyRequest,\n SessionRelayClient,\n SessionRelayBuilderClient,\n} from \"./types\";\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAIO;AACP,oBAAiE;AACjE,qBAGO;AACP,oBAGO;","names":[]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { SESSION_RELAY_DEV_URL, SESSION_RELAY_PRODUCTION_URL, getSessionRelayUrl, } from "./endpoints";
|
|
2
|
+
export { SessionRelayError, type SessionRelayErrorDetails } from "./errors";
|
|
3
|
+
export { computeSessionRelayBodyHash, buildSessionRelayWeb3SignedHeader, } from "./signing";
|
|
4
|
+
export { createSessionRelayClient, createSessionRelayBuilderClient, } from "./client";
|
|
5
|
+
export type { SessionRelayEnvironment, SessionRelayFetch, SessionRelayClientOptions, SessionRelayBuilderClientOptions, SessionRelayInitParams, SessionRelayInitResult, SessionRelayGrantPayload, SessionRelayPollResult, SessionRelayClaimRequest, SessionRelayClaimResponse, SessionRelayApproveRequest, SessionRelayDenyRequest, SessionRelayClient, SessionRelayBuilderClient, } from "./types";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SESSION_RELAY_DEV_URL,
|
|
3
|
+
SESSION_RELAY_PRODUCTION_URL,
|
|
4
|
+
getSessionRelayUrl
|
|
5
|
+
} from "./endpoints.js";
|
|
6
|
+
import { SessionRelayError } from "./errors.js";
|
|
7
|
+
import {
|
|
8
|
+
computeSessionRelayBodyHash,
|
|
9
|
+
buildSessionRelayWeb3SignedHeader
|
|
10
|
+
} from "./signing.js";
|
|
11
|
+
import {
|
|
12
|
+
createSessionRelayClient,
|
|
13
|
+
createSessionRelayBuilderClient
|
|
14
|
+
} from "./client.js";
|
|
15
|
+
export {
|
|
16
|
+
SESSION_RELAY_DEV_URL,
|
|
17
|
+
SESSION_RELAY_PRODUCTION_URL,
|
|
18
|
+
SessionRelayError,
|
|
19
|
+
buildSessionRelayWeb3SignedHeader,
|
|
20
|
+
computeSessionRelayBodyHash,
|
|
21
|
+
createSessionRelayBuilderClient,
|
|
22
|
+
createSessionRelayClient,
|
|
23
|
+
getSessionRelayUrl
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/session-relay/index.ts"],"sourcesContent":["export {\n SESSION_RELAY_DEV_URL,\n SESSION_RELAY_PRODUCTION_URL,\n getSessionRelayUrl,\n} from \"./endpoints\";\nexport { SessionRelayError, type SessionRelayErrorDetails } from \"./errors\";\nexport {\n computeSessionRelayBodyHash,\n buildSessionRelayWeb3SignedHeader,\n} from \"./signing\";\nexport {\n createSessionRelayClient,\n createSessionRelayBuilderClient,\n} from \"./client\";\nexport type {\n SessionRelayEnvironment,\n SessionRelayFetch,\n SessionRelayClientOptions,\n SessionRelayBuilderClientOptions,\n SessionRelayInitParams,\n SessionRelayInitResult,\n SessionRelayGrantPayload,\n SessionRelayPollResult,\n SessionRelayClaimRequest,\n SessionRelayClaimResponse,\n SessionRelayApproveRequest,\n SessionRelayDenyRequest,\n SessionRelayClient,\n SessionRelayBuilderClient,\n} from \"./types\";\n"],"mappings":"AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,yBAAwD;AACjE;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;","names":[]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var signing_exports = {};
|
|
20
|
+
__export(signing_exports, {
|
|
21
|
+
buildSessionRelayWeb3SignedHeader: () => buildSessionRelayWeb3SignedHeader,
|
|
22
|
+
computeSessionRelayBodyHash: () => computeSessionRelayBodyHash
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(signing_exports);
|
|
25
|
+
var import_sha2 = require("@noble/hashes/sha2");
|
|
26
|
+
var import_viem = require("viem");
|
|
27
|
+
var import_web3_signed_builder = require("../auth/web3-signed-builder");
|
|
28
|
+
const textEncoder = new TextEncoder();
|
|
29
|
+
function canonicalizeJson(value) {
|
|
30
|
+
if (value === null || typeof value !== "object") return value;
|
|
31
|
+
if (Array.isArray(value)) return value.map(canonicalizeJson);
|
|
32
|
+
const sorted = {};
|
|
33
|
+
for (const key of Object.keys(value).sort()) {
|
|
34
|
+
if (key === "signature") continue;
|
|
35
|
+
sorted[key] = canonicalizeJson(value[key]);
|
|
36
|
+
}
|
|
37
|
+
return sorted;
|
|
38
|
+
}
|
|
39
|
+
function computeSessionRelayBodyHash(body) {
|
|
40
|
+
if (!body || body.length === 0) return "";
|
|
41
|
+
const parsed = JSON.parse(body);
|
|
42
|
+
const canonical = canonicalizeJson(parsed);
|
|
43
|
+
const digest = (0, import_sha2.sha256)(textEncoder.encode(JSON.stringify(canonical)));
|
|
44
|
+
return (0, import_viem.bytesToHex)(digest).slice(2);
|
|
45
|
+
}
|
|
46
|
+
function buildSessionRelayWeb3SignedHeader(params) {
|
|
47
|
+
return (0, import_web3_signed_builder.buildWeb3SignedHeader)({
|
|
48
|
+
signMessage: params.signMessage,
|
|
49
|
+
aud: params.aud,
|
|
50
|
+
method: params.method,
|
|
51
|
+
uri: params.uri,
|
|
52
|
+
bodyHash: computeSessionRelayBodyHash(params.body),
|
|
53
|
+
iat: params.iat,
|
|
54
|
+
exp: params.exp
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
58
|
+
0 && (module.exports = {
|
|
59
|
+
buildSessionRelayWeb3SignedHeader,
|
|
60
|
+
computeSessionRelayBodyHash
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=signing.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/session-relay/signing.ts"],"sourcesContent":["import { sha256 } from \"@noble/hashes/sha2\";\nimport { bytesToHex } from \"viem\";\nimport {\n buildWeb3SignedHeader,\n type Web3SignedSignFn,\n} from \"../auth/web3-signed-builder\";\n\nconst textEncoder = new TextEncoder();\n\nfunction canonicalizeJson(value: unknown): unknown {\n if (value === null || typeof value !== \"object\") return value;\n if (Array.isArray(value)) return value.map(canonicalizeJson);\n\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(value as Record<string, unknown>).sort()) {\n if (key === \"signature\") continue;\n sorted[key] = canonicalizeJson((value as Record<string, unknown>)[key]);\n }\n return sorted;\n}\n\n/**\n * Compute the legacy bodyHash shape currently accepted by Session Relay.\n *\n * @remarks\n * Personal Server Web3Signed requests use `sha256:<hex>`, including a canonical\n * empty-body hash. Session Relay's current signed init endpoint verifies a\n * legacy body hash: bare SHA-256 hex for non-empty JSON bodies and `\"\"` for\n * empty bodies. Keep this compatibility local to the Relay integration.\n */\nexport function computeSessionRelayBodyHash(body: string | undefined): string {\n if (!body || body.length === 0) return \"\";\n\n const parsed = JSON.parse(body);\n const canonical = canonicalizeJson(parsed);\n const digest = sha256(textEncoder.encode(JSON.stringify(canonical)));\n return bytesToHex(digest).slice(2);\n}\n\n/** Build a Web3Signed header compatible with Session Relay's signed endpoints. */\nexport function buildSessionRelayWeb3SignedHeader(params: {\n signMessage: Web3SignedSignFn;\n aud: string;\n method: string;\n uri: string;\n body?: string;\n iat?: number;\n exp?: number;\n}): Promise<string> {\n return buildWeb3SignedHeader({\n signMessage: params.signMessage,\n aud: params.aud,\n method: params.method,\n uri: params.uri,\n bodyHash: computeSessionRelayBodyHash(params.body),\n iat: params.iat,\n exp: params.exp,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAuB;AACvB,kBAA2B;AAC3B,iCAGO;AAEP,MAAM,cAAc,IAAI,YAAY;AAEpC,SAAS,iBAAiB,OAAyB;AACjD,MAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO;AACxD,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,gBAAgB;AAE3D,QAAM,SAAkC,CAAC;AACzC,aAAW,OAAO,OAAO,KAAK,KAAgC,EAAE,KAAK,GAAG;AACtE,QAAI,QAAQ,YAAa;AACzB,WAAO,GAAG,IAAI,iBAAkB,MAAkC,GAAG,CAAC;AAAA,EACxE;AACA,SAAO;AACT;AAWO,SAAS,4BAA4B,MAAkC;AAC5E,MAAI,CAAC,QAAQ,KAAK,WAAW,EAAG,QAAO;AAEvC,QAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAM,YAAY,iBAAiB,MAAM;AACzC,QAAM,aAAS,oBAAO,YAAY,OAAO,KAAK,UAAU,SAAS,CAAC,CAAC;AACnE,aAAO,wBAAW,MAAM,EAAE,MAAM,CAAC;AACnC;AAGO,SAAS,kCAAkC,QAQ9B;AAClB,aAAO,kDAAsB;AAAA,IAC3B,aAAa,OAAO;AAAA,IACpB,KAAK,OAAO;AAAA,IACZ,QAAQ,OAAO;AAAA,IACf,KAAK,OAAO;AAAA,IACZ,UAAU,4BAA4B,OAAO,IAAI;AAAA,IACjD,KAAK,OAAO;AAAA,IACZ,KAAK,OAAO;AAAA,EACd,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type Web3SignedSignFn } from "../auth/web3-signed-builder";
|
|
2
|
+
/**
|
|
3
|
+
* Compute the legacy bodyHash shape currently accepted by Session Relay.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Personal Server Web3Signed requests use `sha256:<hex>`, including a canonical
|
|
7
|
+
* empty-body hash. Session Relay's current signed init endpoint verifies a
|
|
8
|
+
* legacy body hash: bare SHA-256 hex for non-empty JSON bodies and `""` for
|
|
9
|
+
* empty bodies. Keep this compatibility local to the Relay integration.
|
|
10
|
+
*/
|
|
11
|
+
export declare function computeSessionRelayBodyHash(body: string | undefined): string;
|
|
12
|
+
/** Build a Web3Signed header compatible with Session Relay's signed endpoints. */
|
|
13
|
+
export declare function buildSessionRelayWeb3SignedHeader(params: {
|
|
14
|
+
signMessage: Web3SignedSignFn;
|
|
15
|
+
aud: string;
|
|
16
|
+
method: string;
|
|
17
|
+
uri: string;
|
|
18
|
+
body?: string;
|
|
19
|
+
iat?: number;
|
|
20
|
+
exp?: number;
|
|
21
|
+
}): Promise<string>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { sha256 } from "@noble/hashes/sha2";
|
|
2
|
+
import { bytesToHex } from "viem";
|
|
3
|
+
import {
|
|
4
|
+
buildWeb3SignedHeader
|
|
5
|
+
} from "../auth/web3-signed-builder.js";
|
|
6
|
+
const textEncoder = new TextEncoder();
|
|
7
|
+
function canonicalizeJson(value) {
|
|
8
|
+
if (value === null || typeof value !== "object") return value;
|
|
9
|
+
if (Array.isArray(value)) return value.map(canonicalizeJson);
|
|
10
|
+
const sorted = {};
|
|
11
|
+
for (const key of Object.keys(value).sort()) {
|
|
12
|
+
if (key === "signature") continue;
|
|
13
|
+
sorted[key] = canonicalizeJson(value[key]);
|
|
14
|
+
}
|
|
15
|
+
return sorted;
|
|
16
|
+
}
|
|
17
|
+
function computeSessionRelayBodyHash(body) {
|
|
18
|
+
if (!body || body.length === 0) return "";
|
|
19
|
+
const parsed = JSON.parse(body);
|
|
20
|
+
const canonical = canonicalizeJson(parsed);
|
|
21
|
+
const digest = sha256(textEncoder.encode(JSON.stringify(canonical)));
|
|
22
|
+
return bytesToHex(digest).slice(2);
|
|
23
|
+
}
|
|
24
|
+
function buildSessionRelayWeb3SignedHeader(params) {
|
|
25
|
+
return buildWeb3SignedHeader({
|
|
26
|
+
signMessage: params.signMessage,
|
|
27
|
+
aud: params.aud,
|
|
28
|
+
method: params.method,
|
|
29
|
+
uri: params.uri,
|
|
30
|
+
bodyHash: computeSessionRelayBodyHash(params.body),
|
|
31
|
+
iat: params.iat,
|
|
32
|
+
exp: params.exp
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
buildSessionRelayWeb3SignedHeader,
|
|
37
|
+
computeSessionRelayBodyHash
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=signing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/session-relay/signing.ts"],"sourcesContent":["import { sha256 } from \"@noble/hashes/sha2\";\nimport { bytesToHex } from \"viem\";\nimport {\n buildWeb3SignedHeader,\n type Web3SignedSignFn,\n} from \"../auth/web3-signed-builder\";\n\nconst textEncoder = new TextEncoder();\n\nfunction canonicalizeJson(value: unknown): unknown {\n if (value === null || typeof value !== \"object\") return value;\n if (Array.isArray(value)) return value.map(canonicalizeJson);\n\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(value as Record<string, unknown>).sort()) {\n if (key === \"signature\") continue;\n sorted[key] = canonicalizeJson((value as Record<string, unknown>)[key]);\n }\n return sorted;\n}\n\n/**\n * Compute the legacy bodyHash shape currently accepted by Session Relay.\n *\n * @remarks\n * Personal Server Web3Signed requests use `sha256:<hex>`, including a canonical\n * empty-body hash. Session Relay's current signed init endpoint verifies a\n * legacy body hash: bare SHA-256 hex for non-empty JSON bodies and `\"\"` for\n * empty bodies. Keep this compatibility local to the Relay integration.\n */\nexport function computeSessionRelayBodyHash(body: string | undefined): string {\n if (!body || body.length === 0) return \"\";\n\n const parsed = JSON.parse(body);\n const canonical = canonicalizeJson(parsed);\n const digest = sha256(textEncoder.encode(JSON.stringify(canonical)));\n return bytesToHex(digest).slice(2);\n}\n\n/** Build a Web3Signed header compatible with Session Relay's signed endpoints. */\nexport function buildSessionRelayWeb3SignedHeader(params: {\n signMessage: Web3SignedSignFn;\n aud: string;\n method: string;\n uri: string;\n body?: string;\n iat?: number;\n exp?: number;\n}): Promise<string> {\n return buildWeb3SignedHeader({\n signMessage: params.signMessage,\n aud: params.aud,\n method: params.method,\n uri: params.uri,\n bodyHash: computeSessionRelayBodyHash(params.body),\n iat: params.iat,\n exp: params.exp,\n });\n}\n"],"mappings":"AAAA,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAC3B;AAAA,EACE;AAAA,OAEK;AAEP,MAAM,cAAc,IAAI,YAAY;AAEpC,SAAS,iBAAiB,OAAyB;AACjD,MAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO;AACxD,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,gBAAgB;AAE3D,QAAM,SAAkC,CAAC;AACzC,aAAW,OAAO,OAAO,KAAK,KAAgC,EAAE,KAAK,GAAG;AACtE,QAAI,QAAQ,YAAa;AACzB,WAAO,GAAG,IAAI,iBAAkB,MAAkC,GAAG,CAAC;AAAA,EACxE;AACA,SAAO;AACT;AAWO,SAAS,4BAA4B,MAAkC;AAC5E,MAAI,CAAC,QAAQ,KAAK,WAAW,EAAG,QAAO;AAEvC,QAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAM,YAAY,iBAAiB,MAAM;AACzC,QAAM,SAAS,OAAO,YAAY,OAAO,KAAK,UAAU,SAAS,CAAC,CAAC;AACnE,SAAO,WAAW,MAAM,EAAE,MAAM,CAAC;AACnC;AAGO,SAAS,kCAAkC,QAQ9B;AAClB,SAAO,sBAAsB;AAAA,IAC3B,aAAa,OAAO;AAAA,IACpB,KAAK,OAAO;AAAA,IACZ,QAAQ,OAAO;AAAA,IACf,KAAK,OAAO;AAAA,IACZ,UAAU,4BAA4B,OAAO,IAAI;AAAA,IACjD,KAAK,OAAO;AAAA,IACZ,KAAK,OAAO;AAAA,EACd,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __copyProps = (to, from, except, desc) => {
|
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
+
for (let key of __getOwnPropNames(from))
|
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
+
}
|
|
12
|
+
return to;
|
|
13
|
+
};
|
|
14
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
|
+
var types_exports = {};
|
|
16
|
+
module.exports = __toCommonJS(types_exports);
|
|
17
|
+
//# sourceMappingURL=types.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/session-relay/types.ts"],"sourcesContent":["import type { Web3SignedSignFn } from \"../auth/web3-signed-builder\";\n\n/** Deployment environment for Vana's Session Relay service. */\nexport type SessionRelayEnvironment = \"production\" | \"dev\";\n\n/** Minimal fetch signature accepted by the Session Relay clients. */\nexport type SessionRelayFetch = (\n input: string,\n init?: {\n method?: string;\n headers?: Record<string, string>;\n body?: string;\n },\n) => Promise<{\n ok: boolean;\n status: number;\n statusText?: string;\n json(): Promise<unknown>;\n text?(): Promise<string>;\n}>;\n\n/** Shared Session Relay client options. */\nexport interface SessionRelayClientOptions {\n /** Session Relay base URL. Defaults from `env` when omitted. */\n baseUrl?: string;\n /** Vana deployment environment. Defaults to `\"production\"`. */\n env?: SessionRelayEnvironment;\n /** Fetch implementation. Defaults to `globalThis.fetch`. */\n fetchFn?: SessionRelayFetch;\n}\n\n/** Builder-side Session Relay options. */\nexport interface SessionRelayBuilderClientOptions extends SessionRelayClientOptions {\n /** Builder/app address registered with the Vana builder registry. */\n granteeAddress: `0x${string}`;\n /** EIP-191 signer for Web3Signed Relay requests. */\n signMessage: Web3SignedSignFn;\n /** Clock source used for signed request freshness claims. */\n now?: () => number;\n}\n\n/** Parameters for creating a Session Relay session. */\nexport interface SessionRelayInitParams {\n /** Data scopes requested from the user. */\n scopes: string[];\n /** Public HTTPS callback URL for grant notifications. */\n webhookUrl?: string;\n /** App-owned user id for correlating the approved grant. */\n appUserId?: string;\n}\n\n/** Raw Session Relay init result. */\nexport interface SessionRelayInitResult {\n sessionId: string;\n deepLinkUrl: string;\n expiresAt: string;\n}\n\n/** Grant payload returned after a Relay session is approved. */\nexport interface SessionRelayGrantPayload {\n grantId: string;\n userAddress: string;\n builderAddress: string;\n scopes: string[];\n serverAddress?: string;\n appUserId?: string;\n}\n\n/** Session Relay poll result. */\nexport interface SessionRelayPollResult {\n /**\n * Current session status.\n *\n * @remarks\n * Current Session Relay deployments may report expired sessions as a\n * structured `SESSION_EXPIRED` error instead of a JSON body with\n * `status: \"expired\"`. The `\"expired\"` status is accepted for deployments\n * that return expiry as a terminal poll body.\n */\n status: \"pending\" | \"claimed\" | \"approved\" | \"denied\" | \"expired\";\n grant?: SessionRelayGrantPayload;\n reason?: string;\n}\n\n/** Desktop/app-side claim request. */\nexport interface SessionRelayClaimRequest {\n sessionId: string;\n secret: string;\n}\n\n/** Claimed session data returned to the app that completes user consent. */\nexport interface SessionRelayClaimResponse {\n sessionId: string;\n granteeAddress: string;\n scopes: string[];\n expiresAt: string;\n webhookUrl?: string;\n appUserId?: string;\n}\n\n/** Desktop/app-side approval request. */\nexport interface SessionRelayApproveRequest {\n secret: string;\n grantId: string;\n userAddress: string;\n serverAddress?: string;\n scopes: string[];\n}\n\n/** Desktop/app-side denial request. */\nexport interface SessionRelayDenyRequest {\n secret: string;\n reason?: string;\n}\n\n/** Session Relay methods that do not require builder signing. */\nexport interface SessionRelayClient {\n claimSession(\n request: SessionRelayClaimRequest,\n ): Promise<SessionRelayClaimResponse>;\n approveSession(\n sessionId: string,\n request: SessionRelayApproveRequest,\n ): Promise<void>;\n denySession(\n sessionId: string,\n request: SessionRelayDenyRequest,\n ): Promise<void>;\n pollSession(sessionId: string): Promise<SessionRelayPollResult>;\n pollUntilComplete(\n sessionId: string,\n opts?: { intervalMs?: number; timeoutMs?: number },\n ): Promise<SessionRelayPollResult>;\n}\n\n/** Builder-side Session Relay methods. */\nexport interface SessionRelayBuilderClient {\n initSession(params: SessionRelayInitParams): Promise<SessionRelayInitResult>;\n pollSession(sessionId: string): Promise<SessionRelayPollResult>;\n pollUntilComplete(\n sessionId: string,\n opts?: { intervalMs?: number; timeoutMs?: number },\n ): Promise<SessionRelayPollResult>;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { Web3SignedSignFn } from "../auth/web3-signed-builder";
|
|
2
|
+
/** Deployment environment for Vana's Session Relay service. */
|
|
3
|
+
export type SessionRelayEnvironment = "production" | "dev";
|
|
4
|
+
/** Minimal fetch signature accepted by the Session Relay clients. */
|
|
5
|
+
export type SessionRelayFetch = (input: string, init?: {
|
|
6
|
+
method?: string;
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
body?: string;
|
|
9
|
+
}) => Promise<{
|
|
10
|
+
ok: boolean;
|
|
11
|
+
status: number;
|
|
12
|
+
statusText?: string;
|
|
13
|
+
json(): Promise<unknown>;
|
|
14
|
+
text?(): Promise<string>;
|
|
15
|
+
}>;
|
|
16
|
+
/** Shared Session Relay client options. */
|
|
17
|
+
export interface SessionRelayClientOptions {
|
|
18
|
+
/** Session Relay base URL. Defaults from `env` when omitted. */
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
/** Vana deployment environment. Defaults to `"production"`. */
|
|
21
|
+
env?: SessionRelayEnvironment;
|
|
22
|
+
/** Fetch implementation. Defaults to `globalThis.fetch`. */
|
|
23
|
+
fetchFn?: SessionRelayFetch;
|
|
24
|
+
}
|
|
25
|
+
/** Builder-side Session Relay options. */
|
|
26
|
+
export interface SessionRelayBuilderClientOptions extends SessionRelayClientOptions {
|
|
27
|
+
/** Builder/app address registered with the Vana builder registry. */
|
|
28
|
+
granteeAddress: `0x${string}`;
|
|
29
|
+
/** EIP-191 signer for Web3Signed Relay requests. */
|
|
30
|
+
signMessage: Web3SignedSignFn;
|
|
31
|
+
/** Clock source used for signed request freshness claims. */
|
|
32
|
+
now?: () => number;
|
|
33
|
+
}
|
|
34
|
+
/** Parameters for creating a Session Relay session. */
|
|
35
|
+
export interface SessionRelayInitParams {
|
|
36
|
+
/** Data scopes requested from the user. */
|
|
37
|
+
scopes: string[];
|
|
38
|
+
/** Public HTTPS callback URL for grant notifications. */
|
|
39
|
+
webhookUrl?: string;
|
|
40
|
+
/** App-owned user id for correlating the approved grant. */
|
|
41
|
+
appUserId?: string;
|
|
42
|
+
}
|
|
43
|
+
/** Raw Session Relay init result. */
|
|
44
|
+
export interface SessionRelayInitResult {
|
|
45
|
+
sessionId: string;
|
|
46
|
+
deepLinkUrl: string;
|
|
47
|
+
expiresAt: string;
|
|
48
|
+
}
|
|
49
|
+
/** Grant payload returned after a Relay session is approved. */
|
|
50
|
+
export interface SessionRelayGrantPayload {
|
|
51
|
+
grantId: string;
|
|
52
|
+
userAddress: string;
|
|
53
|
+
builderAddress: string;
|
|
54
|
+
scopes: string[];
|
|
55
|
+
serverAddress?: string;
|
|
56
|
+
appUserId?: string;
|
|
57
|
+
}
|
|
58
|
+
/** Session Relay poll result. */
|
|
59
|
+
export interface SessionRelayPollResult {
|
|
60
|
+
/**
|
|
61
|
+
* Current session status.
|
|
62
|
+
*
|
|
63
|
+
* @remarks
|
|
64
|
+
* Current Session Relay deployments may report expired sessions as a
|
|
65
|
+
* structured `SESSION_EXPIRED` error instead of a JSON body with
|
|
66
|
+
* `status: "expired"`. The `"expired"` status is accepted for deployments
|
|
67
|
+
* that return expiry as a terminal poll body.
|
|
68
|
+
*/
|
|
69
|
+
status: "pending" | "claimed" | "approved" | "denied" | "expired";
|
|
70
|
+
grant?: SessionRelayGrantPayload;
|
|
71
|
+
reason?: string;
|
|
72
|
+
}
|
|
73
|
+
/** Desktop/app-side claim request. */
|
|
74
|
+
export interface SessionRelayClaimRequest {
|
|
75
|
+
sessionId: string;
|
|
76
|
+
secret: string;
|
|
77
|
+
}
|
|
78
|
+
/** Claimed session data returned to the app that completes user consent. */
|
|
79
|
+
export interface SessionRelayClaimResponse {
|
|
80
|
+
sessionId: string;
|
|
81
|
+
granteeAddress: string;
|
|
82
|
+
scopes: string[];
|
|
83
|
+
expiresAt: string;
|
|
84
|
+
webhookUrl?: string;
|
|
85
|
+
appUserId?: string;
|
|
86
|
+
}
|
|
87
|
+
/** Desktop/app-side approval request. */
|
|
88
|
+
export interface SessionRelayApproveRequest {
|
|
89
|
+
secret: string;
|
|
90
|
+
grantId: string;
|
|
91
|
+
userAddress: string;
|
|
92
|
+
serverAddress?: string;
|
|
93
|
+
scopes: string[];
|
|
94
|
+
}
|
|
95
|
+
/** Desktop/app-side denial request. */
|
|
96
|
+
export interface SessionRelayDenyRequest {
|
|
97
|
+
secret: string;
|
|
98
|
+
reason?: string;
|
|
99
|
+
}
|
|
100
|
+
/** Session Relay methods that do not require builder signing. */
|
|
101
|
+
export interface SessionRelayClient {
|
|
102
|
+
claimSession(request: SessionRelayClaimRequest): Promise<SessionRelayClaimResponse>;
|
|
103
|
+
approveSession(sessionId: string, request: SessionRelayApproveRequest): Promise<void>;
|
|
104
|
+
denySession(sessionId: string, request: SessionRelayDenyRequest): Promise<void>;
|
|
105
|
+
pollSession(sessionId: string): Promise<SessionRelayPollResult>;
|
|
106
|
+
pollUntilComplete(sessionId: string, opts?: {
|
|
107
|
+
intervalMs?: number;
|
|
108
|
+
timeoutMs?: number;
|
|
109
|
+
}): Promise<SessionRelayPollResult>;
|
|
110
|
+
}
|
|
111
|
+
/** Builder-side Session Relay methods. */
|
|
112
|
+
export interface SessionRelayBuilderClient {
|
|
113
|
+
initSession(params: SessionRelayInitParams): Promise<SessionRelayInitResult>;
|
|
114
|
+
pollSession(sessionId: string): Promise<SessionRelayPollResult>;
|
|
115
|
+
pollUntilComplete(sessionId: string, opts?: {
|
|
116
|
+
intervalMs?: number;
|
|
117
|
+
timeoutMs?: number;
|
|
118
|
+
}): Promise<SessionRelayPollResult>;
|
|
119
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var session_relay_exports = {};
|
|
20
|
+
__export(session_relay_exports, {
|
|
21
|
+
SESSION_RELAY_DEV_URL: () => import_endpoints.SESSION_RELAY_DEV_URL,
|
|
22
|
+
SESSION_RELAY_PRODUCTION_URL: () => import_endpoints.SESSION_RELAY_PRODUCTION_URL,
|
|
23
|
+
SessionRelayError: () => import_errors.SessionRelayError,
|
|
24
|
+
buildSessionRelayWeb3SignedHeader: () => import_signing.buildSessionRelayWeb3SignedHeader,
|
|
25
|
+
computeSessionRelayBodyHash: () => import_signing.computeSessionRelayBodyHash,
|
|
26
|
+
createSessionRelayBuilderClient: () => import_client.createSessionRelayBuilderClient,
|
|
27
|
+
createSessionRelayClient: () => import_client.createSessionRelayClient,
|
|
28
|
+
getSessionRelayUrl: () => import_endpoints.getSessionRelayUrl
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(session_relay_exports);
|
|
31
|
+
var import_endpoints = require("./session-relay/endpoints");
|
|
32
|
+
var import_errors = require("./session-relay/errors");
|
|
33
|
+
var import_signing = require("./session-relay/signing");
|
|
34
|
+
var import_client = require("./session-relay/client");
|
|
35
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
36
|
+
0 && (module.exports = {
|
|
37
|
+
SESSION_RELAY_DEV_URL,
|
|
38
|
+
SESSION_RELAY_PRODUCTION_URL,
|
|
39
|
+
SessionRelayError,
|
|
40
|
+
buildSessionRelayWeb3SignedHeader,
|
|
41
|
+
computeSessionRelayBodyHash,
|
|
42
|
+
createSessionRelayBuilderClient,
|
|
43
|
+
createSessionRelayClient,
|
|
44
|
+
getSessionRelayUrl
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=session-relay.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/session-relay.ts"],"sourcesContent":["/**\n * Session Relay service integration for Vana app flows.\n *\n * @remarks\n * Session Relay coordinates the handoff between a builder app and the Vana app\n * that completes user consent. This entry point is intentionally separate from\n * `protocol/*`: it is a Vana-operated service integration, like Account or\n * Storage integrations, not a canonical on-chain protocol primitive.\n *\n * @example\n * ```typescript\n * import { createSessionRelayBuilderClient } from \"@opendatalabs/vana-sdk/session-relay\";\n *\n * const relay = createSessionRelayBuilderClient({\n * granteeAddress: appAddress,\n * signMessage,\n * });\n * ```\n *\n * @category Integrations\n * @module session-relay\n */\n\nexport {\n SESSION_RELAY_DEV_URL,\n SESSION_RELAY_PRODUCTION_URL,\n getSessionRelayUrl,\n} from \"./session-relay/endpoints\";\nexport {\n SessionRelayError,\n type SessionRelayErrorDetails,\n} from \"./session-relay/errors\";\nexport {\n computeSessionRelayBodyHash,\n buildSessionRelayWeb3SignedHeader,\n} from \"./session-relay/signing\";\nexport {\n createSessionRelayClient,\n createSessionRelayBuilderClient,\n} from \"./session-relay/client\";\nexport type {\n SessionRelayEnvironment,\n SessionRelayFetch,\n SessionRelayClientOptions,\n SessionRelayBuilderClientOptions,\n SessionRelayInitParams,\n SessionRelayInitResult,\n SessionRelayGrantPayload,\n SessionRelayPollResult,\n SessionRelayClaimRequest,\n SessionRelayClaimResponse,\n SessionRelayApproveRequest,\n SessionRelayDenyRequest,\n SessionRelayClient,\n SessionRelayBuilderClient,\n} from \"./session-relay/types\";\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBA,uBAIO;AACP,oBAGO;AACP,qBAGO;AACP,oBAGO;","names":[]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Relay service integration for Vana app flows.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Session Relay coordinates the handoff between a builder app and the Vana app
|
|
6
|
+
* that completes user consent. This entry point is intentionally separate from
|
|
7
|
+
* `protocol/*`: it is a Vana-operated service integration, like Account or
|
|
8
|
+
* Storage integrations, not a canonical on-chain protocol primitive.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { createSessionRelayBuilderClient } from "@opendatalabs/vana-sdk/session-relay";
|
|
13
|
+
*
|
|
14
|
+
* const relay = createSessionRelayBuilderClient({
|
|
15
|
+
* granteeAddress: appAddress,
|
|
16
|
+
* signMessage,
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @category Integrations
|
|
21
|
+
* @module session-relay
|
|
22
|
+
*/
|
|
23
|
+
export { SESSION_RELAY_DEV_URL, SESSION_RELAY_PRODUCTION_URL, getSessionRelayUrl, } from "./session-relay/endpoints";
|
|
24
|
+
export { SessionRelayError, type SessionRelayErrorDetails, } from "./session-relay/errors";
|
|
25
|
+
export { computeSessionRelayBodyHash, buildSessionRelayWeb3SignedHeader, } from "./session-relay/signing";
|
|
26
|
+
export { createSessionRelayClient, createSessionRelayBuilderClient, } from "./session-relay/client";
|
|
27
|
+
export type { SessionRelayEnvironment, SessionRelayFetch, SessionRelayClientOptions, SessionRelayBuilderClientOptions, SessionRelayInitParams, SessionRelayInitResult, SessionRelayGrantPayload, SessionRelayPollResult, SessionRelayClaimRequest, SessionRelayClaimResponse, SessionRelayApproveRequest, SessionRelayDenyRequest, SessionRelayClient, SessionRelayBuilderClient, } from "./session-relay/types";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SESSION_RELAY_DEV_URL,
|
|
3
|
+
SESSION_RELAY_PRODUCTION_URL,
|
|
4
|
+
getSessionRelayUrl
|
|
5
|
+
} from "./session-relay/endpoints.js";
|
|
6
|
+
import {
|
|
7
|
+
SessionRelayError
|
|
8
|
+
} from "./session-relay/errors.js";
|
|
9
|
+
import {
|
|
10
|
+
computeSessionRelayBodyHash,
|
|
11
|
+
buildSessionRelayWeb3SignedHeader
|
|
12
|
+
} from "./session-relay/signing.js";
|
|
13
|
+
import {
|
|
14
|
+
createSessionRelayClient,
|
|
15
|
+
createSessionRelayBuilderClient
|
|
16
|
+
} from "./session-relay/client.js";
|
|
17
|
+
export {
|
|
18
|
+
SESSION_RELAY_DEV_URL,
|
|
19
|
+
SESSION_RELAY_PRODUCTION_URL,
|
|
20
|
+
SessionRelayError,
|
|
21
|
+
buildSessionRelayWeb3SignedHeader,
|
|
22
|
+
computeSessionRelayBodyHash,
|
|
23
|
+
createSessionRelayBuilderClient,
|
|
24
|
+
createSessionRelayClient,
|
|
25
|
+
getSessionRelayUrl
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=session-relay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/session-relay.ts"],"sourcesContent":["/**\n * Session Relay service integration for Vana app flows.\n *\n * @remarks\n * Session Relay coordinates the handoff between a builder app and the Vana app\n * that completes user consent. This entry point is intentionally separate from\n * `protocol/*`: it is a Vana-operated service integration, like Account or\n * Storage integrations, not a canonical on-chain protocol primitive.\n *\n * @example\n * ```typescript\n * import { createSessionRelayBuilderClient } from \"@opendatalabs/vana-sdk/session-relay\";\n *\n * const relay = createSessionRelayBuilderClient({\n * granteeAddress: appAddress,\n * signMessage,\n * });\n * ```\n *\n * @category Integrations\n * @module session-relay\n */\n\nexport {\n SESSION_RELAY_DEV_URL,\n SESSION_RELAY_PRODUCTION_URL,\n getSessionRelayUrl,\n} from \"./session-relay/endpoints\";\nexport {\n SessionRelayError,\n type SessionRelayErrorDetails,\n} from \"./session-relay/errors\";\nexport {\n computeSessionRelayBodyHash,\n buildSessionRelayWeb3SignedHeader,\n} from \"./session-relay/signing\";\nexport {\n createSessionRelayClient,\n createSessionRelayBuilderClient,\n} from \"./session-relay/client\";\nexport type {\n SessionRelayEnvironment,\n SessionRelayFetch,\n SessionRelayClientOptions,\n SessionRelayBuilderClientOptions,\n SessionRelayInitParams,\n SessionRelayInitResult,\n SessionRelayGrantPayload,\n SessionRelayPollResult,\n SessionRelayClaimRequest,\n SessionRelayClaimResponse,\n SessionRelayApproveRequest,\n SessionRelayDenyRequest,\n SessionRelayClient,\n SessionRelayBuilderClient,\n} from \"./session-relay/types\";\n"],"mappings":"AAuBA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opendatalabs/vana-sdk",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"description": "A TypeScript library for interacting with Vana Network smart contracts.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -37,6 +37,15 @@
|
|
|
37
37
|
"types": "./dist/react.d.ts",
|
|
38
38
|
"import": "./dist/react.js"
|
|
39
39
|
},
|
|
40
|
+
"./session-relay": {
|
|
41
|
+
"browser": {
|
|
42
|
+
"types": "./dist/session-relay.d.ts",
|
|
43
|
+
"import": "./dist/session-relay.js"
|
|
44
|
+
},
|
|
45
|
+
"types": "./dist/session-relay.d.ts",
|
|
46
|
+
"import": "./dist/session-relay.js",
|
|
47
|
+
"require": "./dist/session-relay.cjs"
|
|
48
|
+
},
|
|
40
49
|
"./chains": {
|
|
41
50
|
"browser": {
|
|
42
51
|
"types": "./dist/chains.browser.d.ts",
|