@opendatalabs/vana-sdk 3.5.1 → 3.6.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 +116 -0
- package/dist/direct/access-request-client.cjs +104 -0
- package/dist/direct/access-request-client.cjs.map +1 -0
- package/dist/direct/access-request-client.d.ts +51 -0
- package/dist/direct/access-request-client.js +79 -0
- package/dist/direct/access-request-client.js.map +1 -0
- package/dist/direct/access-request-client.test.d.ts +1 -0
- package/dist/direct/connect-flow.cjs +152 -0
- package/dist/direct/connect-flow.cjs.map +1 -0
- package/dist/direct/connect-flow.d.ts +85 -0
- package/dist/direct/connect-flow.js +128 -0
- package/dist/direct/connect-flow.js.map +1 -0
- package/dist/direct/connect-flow.test.d.ts +1 -0
- package/dist/direct/controller.cjs +129 -0
- package/dist/direct/controller.cjs.map +1 -0
- package/dist/direct/controller.d.ts +152 -0
- package/dist/direct/controller.js +109 -0
- package/dist/direct/controller.js.map +1 -0
- package/dist/direct/controller.test.d.ts +1 -0
- package/dist/direct/endpoints.cjs +45 -0
- package/dist/direct/endpoints.cjs.map +1 -0
- package/dist/direct/endpoints.d.ts +22 -0
- package/dist/direct/endpoints.js +19 -0
- package/dist/direct/endpoints.js.map +1 -0
- package/dist/direct/errors.cjs +65 -0
- package/dist/direct/errors.cjs.map +1 -0
- package/dist/direct/errors.d.ts +44 -0
- package/dist/direct/errors.js +38 -0
- package/dist/direct/errors.js.map +1 -0
- package/dist/direct/escrow-payment.cjs +96 -0
- package/dist/direct/escrow-payment.cjs.map +1 -0
- package/dist/direct/escrow-payment.d.ts +81 -0
- package/dist/direct/escrow-payment.js +72 -0
- package/dist/direct/escrow-payment.js.map +1 -0
- package/dist/direct/escrow-payment.test.d.ts +1 -0
- package/dist/direct/personal-server-read.cjs +149 -0
- package/dist/direct/personal-server-read.cjs.map +1 -0
- package/dist/direct/personal-server-read.d.ts +103 -0
- package/dist/direct/personal-server-read.js +124 -0
- package/dist/direct/personal-server-read.js.map +1 -0
- package/dist/direct/personal-server-read.test.d.ts +1 -0
- package/dist/direct/types.cjs +35 -0
- package/dist/direct/types.cjs.map +1 -0
- package/dist/direct/types.d.ts +205 -0
- package/dist/direct/types.js +11 -0
- package/dist/direct/types.js.map +1 -0
- package/dist/direct/use-direct-vana-connect.cjs +68 -0
- package/dist/direct/use-direct-vana-connect.cjs.map +1 -0
- package/dist/direct/use-direct-vana-connect.d.ts +45 -0
- package/dist/direct/use-direct-vana-connect.js +46 -0
- package/dist/direct/use-direct-vana-connect.js.map +1 -0
- package/dist/index.browser.d.ts +7 -3
- package/dist/index.browser.js +438 -157
- package/dist/index.browser.js.map +4 -4
- package/dist/index.node.cjs +461 -162
- package/dist/index.node.cjs.map +4 -4
- package/dist/index.node.d.ts +7 -3
- package/dist/index.node.js +438 -157
- package/dist/index.node.js.map +4 -4
- package/dist/protocol/data-point-status.cjs +80 -0
- package/dist/protocol/data-point-status.cjs.map +1 -0
- package/dist/protocol/data-point-status.d.ts +34 -0
- package/dist/protocol/data-point-status.js +51 -0
- package/dist/protocol/data-point-status.js.map +1 -0
- package/dist/protocol/data-point-status.test.d.ts +1 -0
- package/dist/protocol/eip712.cjs +53 -31
- package/dist/protocol/eip712.cjs.map +1 -1
- package/dist/protocol/eip712.d.ts +98 -43
- package/dist/protocol/eip712.js +47 -27
- package/dist/protocol/eip712.js.map +1 -1
- package/dist/protocol/escrow-deposit.cjs +89 -0
- package/dist/protocol/escrow-deposit.cjs.map +1 -0
- package/dist/protocol/escrow-deposit.d.ts +47 -0
- package/dist/protocol/escrow-deposit.js +60 -0
- package/dist/protocol/escrow-deposit.js.map +1 -0
- package/dist/protocol/escrow-deposit.test.d.ts +1 -0
- package/dist/protocol/escrow-flow.test.d.ts +21 -0
- package/dist/protocol/fee-registry.cjs +116 -0
- package/dist/protocol/fee-registry.cjs.map +1 -0
- package/dist/protocol/fee-registry.d.ts +151 -0
- package/dist/protocol/fee-registry.js +89 -0
- package/dist/protocol/fee-registry.js.map +1 -0
- package/dist/protocol/fee-registry.test.d.ts +1 -0
- package/dist/protocol/gateway.cjs +107 -37
- package/dist/protocol/gateway.cjs.map +1 -1
- package/dist/protocol/gateway.d.ts +223 -57
- package/dist/protocol/gateway.js +107 -37
- package/dist/protocol/gateway.js.map +1 -1
- package/dist/protocol/grants.cjs +27 -64
- package/dist/protocol/grants.cjs.map +1 -1
- package/dist/protocol/grants.d.ts +6 -13
- package/dist/protocol/grants.js +27 -63
- package/dist/protocol/grants.js.map +1 -1
- package/dist/protocol/personal-server-data.cjs +71 -0
- package/dist/protocol/personal-server-data.cjs.map +1 -0
- package/dist/protocol/personal-server-data.d.ts +16 -0
- package/dist/protocol/personal-server-data.js +47 -0
- package/dist/protocol/personal-server-data.js.map +1 -0
- package/dist/protocol/personal-server-data.test.d.ts +1 -0
- package/dist/protocol/personal-server-lite-owner-binding.cjs +93 -0
- package/dist/protocol/personal-server-lite-owner-binding.cjs.map +1 -0
- package/dist/protocol/personal-server-lite-owner-binding.d.ts +44 -0
- package/dist/protocol/personal-server-lite-owner-binding.js +65 -0
- package/dist/protocol/personal-server-lite-owner-binding.js.map +1 -0
- package/dist/protocol/personal-server-lite-owner-binding.test.d.ts +1 -0
- package/dist/react.cjs +32 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.ts +33 -0
- package/dist/react.js +11 -0
- package/dist/react.js.map +1 -0
- package/dist/server.cjs +73 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.ts +32 -0
- package/dist/server.js +55 -0
- package/dist/server.js.map +1 -0
- package/package.json +20 -1
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
2
|
+
const DEFAULT_TIMEOUT_MS = 3e5;
|
|
3
|
+
function toError(value) {
|
|
4
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
5
|
+
}
|
|
6
|
+
function createDirectConnectFlow(transports, options = {}) {
|
|
7
|
+
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
8
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
9
|
+
const openWindow = options.openWindow ?? ((url) => {
|
|
10
|
+
if (typeof window !== "undefined" && window.open) {
|
|
11
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
const setTimeoutFn = options.setTimeoutFn ?? ((cb, ms) => globalThis.setTimeout(cb, ms));
|
|
15
|
+
const clearTimeoutFn = options.clearTimeoutFn ?? ((handle) => {
|
|
16
|
+
globalThis.clearTimeout(handle);
|
|
17
|
+
});
|
|
18
|
+
const now = options.now ?? (() => Date.now());
|
|
19
|
+
let state = { type: "idle" };
|
|
20
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
21
|
+
let pollHandle = null;
|
|
22
|
+
let running = false;
|
|
23
|
+
function emit() {
|
|
24
|
+
for (const listener of listeners) listener();
|
|
25
|
+
}
|
|
26
|
+
function setState(next) {
|
|
27
|
+
state = next;
|
|
28
|
+
emit();
|
|
29
|
+
}
|
|
30
|
+
function clearPoll() {
|
|
31
|
+
if (pollHandle !== null) {
|
|
32
|
+
clearTimeoutFn(pollHandle);
|
|
33
|
+
pollHandle = null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function isRunningPhase() {
|
|
37
|
+
return state.type === "creating" || state.type === "awaiting_approval" || state.type === "reading";
|
|
38
|
+
}
|
|
39
|
+
async function readAndFinish(request) {
|
|
40
|
+
setState({ type: "reading", request });
|
|
41
|
+
try {
|
|
42
|
+
const result = await transports.readResult(request.requestId);
|
|
43
|
+
if (!running) return;
|
|
44
|
+
setState({ type: "done", result });
|
|
45
|
+
} catch (err) {
|
|
46
|
+
if (!running) return;
|
|
47
|
+
setState({ type: "error", error: toError(err) });
|
|
48
|
+
} finally {
|
|
49
|
+
running = false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function scheduleNextPoll(request, deadline) {
|
|
53
|
+
pollHandle = setTimeoutFn(() => {
|
|
54
|
+
void poll(request, deadline);
|
|
55
|
+
}, pollIntervalMs);
|
|
56
|
+
}
|
|
57
|
+
async function poll(request, deadline) {
|
|
58
|
+
if (!running) return;
|
|
59
|
+
if (now() >= deadline) {
|
|
60
|
+
running = false;
|
|
61
|
+
setState({
|
|
62
|
+
type: "error",
|
|
63
|
+
error: new Error("Timed out waiting for approval")
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
let status;
|
|
68
|
+
try {
|
|
69
|
+
status = await transports.getStatus(request.requestId);
|
|
70
|
+
} catch (err) {
|
|
71
|
+
if (!running) return;
|
|
72
|
+
running = false;
|
|
73
|
+
setState({ type: "error", error: toError(err) });
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (!running) return;
|
|
77
|
+
if (status.status === "approved") {
|
|
78
|
+
clearPoll();
|
|
79
|
+
await readAndFinish(request);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (status.status === "denied" || status.status === "expired") {
|
|
83
|
+
running = false;
|
|
84
|
+
setState({
|
|
85
|
+
type: "error",
|
|
86
|
+
error: new Error(`Access request ${status.status}`)
|
|
87
|
+
});
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
scheduleNextPoll(request, deadline);
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
getState() {
|
|
94
|
+
return state;
|
|
95
|
+
},
|
|
96
|
+
subscribe(listener) {
|
|
97
|
+
listeners.add(listener);
|
|
98
|
+
return () => listeners.delete(listener);
|
|
99
|
+
},
|
|
100
|
+
async start() {
|
|
101
|
+
if (running || isRunningPhase()) return;
|
|
102
|
+
running = true;
|
|
103
|
+
setState({ type: "creating" });
|
|
104
|
+
let request;
|
|
105
|
+
try {
|
|
106
|
+
request = await transports.createRequest();
|
|
107
|
+
} catch (err) {
|
|
108
|
+
running = false;
|
|
109
|
+
setState({ type: "error", error: toError(err) });
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (!running) return;
|
|
113
|
+
setState({ type: "awaiting_approval", request });
|
|
114
|
+
openWindow(request.approvalUrl);
|
|
115
|
+
const deadline = now() + timeoutMs;
|
|
116
|
+
scheduleNextPoll(request, deadline);
|
|
117
|
+
},
|
|
118
|
+
reset() {
|
|
119
|
+
running = false;
|
|
120
|
+
clearPoll();
|
|
121
|
+
setState({ type: "idle" });
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
export {
|
|
126
|
+
createDirectConnectFlow
|
|
127
|
+
};
|
|
128
|
+
//# sourceMappingURL=connect-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/direct/connect-flow.ts"],"sourcesContent":["/**\n * Framework-agnostic connect-flow state machine for the browser two-tab helper.\n *\n * @remarks\n * This is the testable core behind {@link useDirectVanaConnect}. It is pure\n * TypeScript (no React, no DOM-only APIs beyond an injectable window opener and\n * timers) so the full flow — create request, open Vana, poll status, read data —\n * can be exercised in a Node test environment.\n *\n * The React hook is a thin `useSyncExternalStore` binding over this store.\n *\n * @category Direct\n * @module direct/connect-flow\n */\n\nimport type {\n AccessRequest,\n AccessRequestStatus,\n ApprovedDataResult,\n} from \"./types\";\n\n/**\n * Caller-supplied transports. These typically `fetch` the app's own backend\n * routes, which in turn delegate to a {@link DirectDataController}.\n */\nexport interface DirectConnectTransports<T = unknown> {\n /** Ask the backend to create an access request. */\n createRequest: () => Promise<AccessRequest>;\n /** Ask the backend for the current status of a request. */\n getStatus: (requestId: string) => Promise<AccessRequestStatus>;\n /** Ask the backend to read the approved data. */\n readResult: (requestId: string) => Promise<ApprovedDataResult<T>>;\n}\n\n/** Tunables for the connect flow. */\nexport interface DirectConnectOptions {\n /** Status poll interval in ms. Defaults to 1500. */\n pollIntervalMs?: number;\n /** Overall timeout in ms before giving up. Defaults to 300000 (5 min). */\n timeoutMs?: number;\n /** Opens the approval URL. Defaults to `window.open`. Injectable for tests. */\n openWindow?: (url: string) => void;\n /** `setTimeout`. Injectable for tests. Defaults to `globalThis.setTimeout`. */\n setTimeoutFn?: (cb: () => void, ms: number) => unknown;\n /** `clearTimeout`. Injectable for tests. Defaults to `globalThis.clearTimeout`. */\n clearTimeoutFn?: (handle: unknown) => void;\n /** Clock source in ms. Injectable for tests. Defaults to `Date.now`. */\n now?: () => number;\n}\n\n/**\n * Discriminated connect-flow state.\n *\n * @remarks\n * `type` matches the builder guide: it starts at `\"idle\"` and is non-idle while\n * connecting. The intermediate phases give richer UIs something to render.\n */\nexport type DirectConnectState<T = unknown> =\n | { type: \"idle\" }\n | { type: \"creating\" }\n | { type: \"awaiting_approval\"; request: AccessRequest }\n | { type: \"reading\"; request: AccessRequest }\n | { type: \"done\"; result: ApprovedDataResult<T> }\n | { type: \"error\"; error: Error };\n\n/** The store returned by {@link createDirectConnectFlow}. */\nexport interface DirectConnectFlow<T = unknown> {\n /** Current state. */\n getState(): DirectConnectState<T>;\n /** Subscribe to state changes; returns an unsubscribe function. */\n subscribe(listener: () => void): () => void;\n /** Begin the flow. No-op if already running. */\n start(): Promise<void>;\n /** Reset to `idle` and stop any in-flight polling. */\n reset(): void;\n}\n\nconst DEFAULT_POLL_INTERVAL_MS = 1500;\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\nfunction toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value));\n}\n\n/**\n * Create a connect-flow store.\n *\n * @param transports - Backend transports (`createRequest`, `getStatus`, `readResult`).\n * @param options - Polling/timeout tunables and injectable side effects.\n * @returns A {@link DirectConnectFlow} store.\n */\nexport function createDirectConnectFlow<T = unknown>(\n transports: DirectConnectTransports<T>,\n options: DirectConnectOptions = {},\n): DirectConnectFlow<T> {\n const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const openWindow =\n options.openWindow ??\n ((url: string) => {\n if (typeof window !== \"undefined\" && window.open) {\n window.open(url, \"_blank\", \"noopener,noreferrer\");\n }\n });\n const setTimeoutFn =\n options.setTimeoutFn ??\n ((cb: () => void, ms: number) => globalThis.setTimeout(cb, ms));\n const clearTimeoutFn =\n options.clearTimeoutFn ??\n ((handle: unknown) => {\n globalThis.clearTimeout(handle as never);\n });\n const now = options.now ?? (() => Date.now());\n\n let state: DirectConnectState<T> = { type: \"idle\" };\n const listeners = new Set<() => void>();\n let pollHandle: unknown = null;\n let running = false;\n\n function emit(): void {\n for (const listener of listeners) listener();\n }\n\n function setState(next: DirectConnectState<T>): void {\n state = next;\n emit();\n }\n\n function clearPoll(): void {\n if (pollHandle !== null) {\n clearTimeoutFn(pollHandle);\n pollHandle = null;\n }\n }\n\n function isRunningPhase(): boolean {\n return (\n state.type === \"creating\" ||\n state.type === \"awaiting_approval\" ||\n state.type === \"reading\"\n );\n }\n\n async function readAndFinish(request: AccessRequest): Promise<void> {\n setState({ type: \"reading\", request });\n try {\n const result = await transports.readResult(request.requestId);\n if (!running) return;\n setState({ type: \"done\", result });\n } catch (err) {\n if (!running) return;\n setState({ type: \"error\", error: toError(err) });\n } finally {\n running = false;\n }\n }\n\n function scheduleNextPoll(request: AccessRequest, deadline: number): void {\n pollHandle = setTimeoutFn(() => {\n void poll(request, deadline);\n }, pollIntervalMs);\n }\n\n async function poll(request: AccessRequest, deadline: number): Promise<void> {\n if (!running) return;\n if (now() >= deadline) {\n running = false;\n setState({\n type: \"error\",\n error: new Error(\"Timed out waiting for approval\"),\n });\n return;\n }\n let status: AccessRequestStatus;\n try {\n status = await transports.getStatus(request.requestId);\n } catch (err) {\n if (!running) return;\n running = false;\n setState({ type: \"error\", error: toError(err) });\n return;\n }\n if (!running) return;\n\n if (status.status === \"approved\") {\n clearPoll();\n await readAndFinish(request);\n return;\n }\n if (status.status === \"denied\" || status.status === \"expired\") {\n running = false;\n setState({\n type: \"error\",\n error: new Error(`Access request ${status.status}`),\n });\n return;\n }\n scheduleNextPoll(request, deadline);\n }\n\n return {\n getState() {\n return state;\n },\n\n subscribe(listener: () => void) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n\n async start(): Promise<void> {\n if (running || isRunningPhase()) return;\n running = true;\n setState({ type: \"creating\" });\n\n let request: AccessRequest;\n try {\n request = await transports.createRequest();\n } catch (err) {\n running = false;\n setState({ type: \"error\", error: toError(err) });\n return;\n }\n if (!running) return;\n\n setState({ type: \"awaiting_approval\", request });\n openWindow(request.approvalUrl);\n\n const deadline = now() + timeoutMs;\n scheduleNextPoll(request, deadline);\n },\n\n reset(): void {\n running = false;\n clearPoll();\n setState({ type: \"idle\" });\n },\n };\n}\n"],"mappings":"AA6EA,MAAM,2BAA2B;AACjC,MAAM,qBAAqB;AAE3B,SAAS,QAAQ,OAAuB;AACtC,SAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACjE;AASO,SAAS,wBACd,YACA,UAAgC,CAAC,GACX;AACtB,QAAM,iBAAiB,QAAQ,kBAAkB;AACjD,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,aACJ,QAAQ,eACP,CAAC,QAAgB;AAChB,QAAI,OAAO,WAAW,eAAe,OAAO,MAAM;AAChD,aAAO,KAAK,KAAK,UAAU,qBAAqB;AAAA,IAClD;AAAA,EACF;AACF,QAAM,eACJ,QAAQ,iBACP,CAAC,IAAgB,OAAe,WAAW,WAAW,IAAI,EAAE;AAC/D,QAAM,iBACJ,QAAQ,mBACP,CAAC,WAAoB;AACpB,eAAW,aAAa,MAAe;AAAA,EACzC;AACF,QAAM,MAAM,QAAQ,QAAQ,MAAM,KAAK,IAAI;AAE3C,MAAI,QAA+B,EAAE,MAAM,OAAO;AAClD,QAAM,YAAY,oBAAI,IAAgB;AACtC,MAAI,aAAsB;AAC1B,MAAI,UAAU;AAEd,WAAS,OAAa;AACpB,eAAW,YAAY,UAAW,UAAS;AAAA,EAC7C;AAEA,WAAS,SAAS,MAAmC;AACnD,YAAQ;AACR,SAAK;AAAA,EACP;AAEA,WAAS,YAAkB;AACzB,QAAI,eAAe,MAAM;AACvB,qBAAe,UAAU;AACzB,mBAAa;AAAA,IACf;AAAA,EACF;AAEA,WAAS,iBAA0B;AACjC,WACE,MAAM,SAAS,cACf,MAAM,SAAS,uBACf,MAAM,SAAS;AAAA,EAEnB;AAEA,iBAAe,cAAc,SAAuC;AAClE,aAAS,EAAE,MAAM,WAAW,QAAQ,CAAC;AACrC,QAAI;AACF,YAAM,SAAS,MAAM,WAAW,WAAW,QAAQ,SAAS;AAC5D,UAAI,CAAC,QAAS;AACd,eAAS,EAAE,MAAM,QAAQ,OAAO,CAAC;AAAA,IACnC,SAAS,KAAK;AACZ,UAAI,CAAC,QAAS;AACd,eAAS,EAAE,MAAM,SAAS,OAAO,QAAQ,GAAG,EAAE,CAAC;AAAA,IACjD,UAAE;AACA,gBAAU;AAAA,IACZ;AAAA,EACF;AAEA,WAAS,iBAAiB,SAAwB,UAAwB;AACxE,iBAAa,aAAa,MAAM;AAC9B,WAAK,KAAK,SAAS,QAAQ;AAAA,IAC7B,GAAG,cAAc;AAAA,EACnB;AAEA,iBAAe,KAAK,SAAwB,UAAiC;AAC3E,QAAI,CAAC,QAAS;AACd,QAAI,IAAI,KAAK,UAAU;AACrB,gBAAU;AACV,eAAS;AAAA,QACP,MAAM;AAAA,QACN,OAAO,IAAI,MAAM,gCAAgC;AAAA,MACnD,CAAC;AACD;AAAA,IACF;AACA,QAAI;AACJ,QAAI;AACF,eAAS,MAAM,WAAW,UAAU,QAAQ,SAAS;AAAA,IACvD,SAAS,KAAK;AACZ,UAAI,CAAC,QAAS;AACd,gBAAU;AACV,eAAS,EAAE,MAAM,SAAS,OAAO,QAAQ,GAAG,EAAE,CAAC;AAC/C;AAAA,IACF;AACA,QAAI,CAAC,QAAS;AAEd,QAAI,OAAO,WAAW,YAAY;AAChC,gBAAU;AACV,YAAM,cAAc,OAAO;AAC3B;AAAA,IACF;AACA,QAAI,OAAO,WAAW,YAAY,OAAO,WAAW,WAAW;AAC7D,gBAAU;AACV,eAAS;AAAA,QACP,MAAM;AAAA,QACN,OAAO,IAAI,MAAM,kBAAkB,OAAO,MAAM,EAAE;AAAA,MACpD,CAAC;AACD;AAAA,IACF;AACA,qBAAiB,SAAS,QAAQ;AAAA,EACpC;AAEA,SAAO;AAAA,IACL,WAAW;AACT,aAAO;AAAA,IACT;AAAA,IAEA,UAAU,UAAsB;AAC9B,gBAAU,IAAI,QAAQ;AACtB,aAAO,MAAM,UAAU,OAAO,QAAQ;AAAA,IACxC;AAAA,IAEA,MAAM,QAAuB;AAC3B,UAAI,WAAW,eAAe,EAAG;AACjC,gBAAU;AACV,eAAS,EAAE,MAAM,WAAW,CAAC;AAE7B,UAAI;AACJ,UAAI;AACF,kBAAU,MAAM,WAAW,cAAc;AAAA,MAC3C,SAAS,KAAK;AACZ,kBAAU;AACV,iBAAS,EAAE,MAAM,SAAS,OAAO,QAAQ,GAAG,EAAE,CAAC;AAC/C;AAAA,MACF;AACA,UAAI,CAAC,QAAS;AAEd,eAAS,EAAE,MAAM,qBAAqB,QAAQ,CAAC;AAC/C,iBAAW,QAAQ,WAAW;AAE9B,YAAM,WAAW,IAAI,IAAI;AACzB,uBAAiB,SAAS,QAAQ;AAAA,IACpC;AAAA,IAEA,QAAc;AACZ,gBAAU;AACV,gBAAU;AACV,eAAS,EAAE,MAAM,OAAO,CAAC;AAAA,IAC3B;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,129 @@
|
|
|
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 controller_exports = {};
|
|
20
|
+
__export(controller_exports, {
|
|
21
|
+
createDirectDataController: () => createDirectDataController
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(controller_exports);
|
|
24
|
+
var import_accounts = require("viem/accounts");
|
|
25
|
+
var import_scopes = require("../protocol/scopes");
|
|
26
|
+
var import_access_request_client = require("./access-request-client");
|
|
27
|
+
var import_endpoints = require("./endpoints");
|
|
28
|
+
var import_errors = require("./errors");
|
|
29
|
+
var import_personal_server_read = require("./personal-server-read");
|
|
30
|
+
function isHexPrivateKey(value) {
|
|
31
|
+
return /^0x[0-9a-fA-F]{64}$/.test(value);
|
|
32
|
+
}
|
|
33
|
+
function createDirectDataController(config) {
|
|
34
|
+
const privateKey = config.appPrivateKey ?? config.builderPrivateKey;
|
|
35
|
+
if (!privateKey || !isHexPrivateKey(privateKey)) {
|
|
36
|
+
throw new import_errors.DirectConfigError(
|
|
37
|
+
"appPrivateKey must be a 0x-prefixed 32-byte hex string"
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
if (!config.scopes || config.scopes.length === 0) {
|
|
41
|
+
throw new import_errors.DirectConfigError("At least one scope is required");
|
|
42
|
+
}
|
|
43
|
+
for (const scope of config.scopes) {
|
|
44
|
+
(0, import_scopes.parseScope)(scope);
|
|
45
|
+
}
|
|
46
|
+
const env = config.env ?? "production";
|
|
47
|
+
const endpoints = {
|
|
48
|
+
...(0, import_endpoints.getDirectEndpoints)(env),
|
|
49
|
+
...config.endpoints
|
|
50
|
+
};
|
|
51
|
+
const account = (0, import_accounts.privateKeyToAccount)(privateKey);
|
|
52
|
+
const signMessage = (message) => account.signMessage({ message });
|
|
53
|
+
const signTypedData = account.signTypedData;
|
|
54
|
+
const chainId = endpoints.chainId;
|
|
55
|
+
const accessRequestClient = config.accessRequestClient ?? (0, import_access_request_client.createDefaultAccessRequestClient)({
|
|
56
|
+
baseUrl: endpoints.accessRequestBaseUrl,
|
|
57
|
+
approvalBaseUrl: endpoints.approvalAppBaseUrl,
|
|
58
|
+
fetchFn: config.fetchFn
|
|
59
|
+
});
|
|
60
|
+
const escrow = config.escrow ? {
|
|
61
|
+
client: config.escrow.client,
|
|
62
|
+
escrowContract: config.escrow.escrowContract,
|
|
63
|
+
chainId: config.escrow.chainId ?? chainId,
|
|
64
|
+
nonceSource: config.escrow.nonceSource,
|
|
65
|
+
signTypedData
|
|
66
|
+
} : void 0;
|
|
67
|
+
return {
|
|
68
|
+
appAddress: account.address,
|
|
69
|
+
getAppAddress() {
|
|
70
|
+
return account.address;
|
|
71
|
+
},
|
|
72
|
+
getAppIdentity() {
|
|
73
|
+
return {
|
|
74
|
+
id: config.app.id,
|
|
75
|
+
name: config.app.name,
|
|
76
|
+
homepageUrl: config.app.homepageUrl,
|
|
77
|
+
address: account.address
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
async createAccessRequest(input) {
|
|
81
|
+
return accessRequestClient.createAccessRequest({
|
|
82
|
+
appAddress: account.address,
|
|
83
|
+
app: config.app,
|
|
84
|
+
source: config.source,
|
|
85
|
+
scopes: config.scopes,
|
|
86
|
+
returnUrl: input.returnUrl
|
|
87
|
+
});
|
|
88
|
+
},
|
|
89
|
+
async getAccessRequestStatus(requestId) {
|
|
90
|
+
return accessRequestClient.getAccessRequestStatus(requestId);
|
|
91
|
+
},
|
|
92
|
+
async readApprovedData(input) {
|
|
93
|
+
const status = await accessRequestClient.getAccessRequestStatus(
|
|
94
|
+
input.requestId
|
|
95
|
+
);
|
|
96
|
+
if (status.status !== "approved" || !status.personalServerUrl || !status.grantId || !status.scope) {
|
|
97
|
+
throw new import_errors.AccessNotApprovedError(
|
|
98
|
+
"Request is not approved or is missing grantId/scope/personalServerUrl",
|
|
99
|
+
{
|
|
100
|
+
requestId: input.requestId,
|
|
101
|
+
status: status.status,
|
|
102
|
+
hasPersonalServerUrl: Boolean(status.personalServerUrl),
|
|
103
|
+
hasGrantId: Boolean(status.grantId),
|
|
104
|
+
hasScope: Boolean(status.scope)
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
const result = await (0, import_personal_server_read.readPersonalServerData)({
|
|
109
|
+
personalServerUrl: status.personalServerUrl,
|
|
110
|
+
scope: status.scope,
|
|
111
|
+
grantId: status.grantId,
|
|
112
|
+
payerAddress: account.address,
|
|
113
|
+
signMessage,
|
|
114
|
+
escrow,
|
|
115
|
+
fetchFn: config.personalServerFetch
|
|
116
|
+
});
|
|
117
|
+
return {
|
|
118
|
+
scope: status.scope,
|
|
119
|
+
data: result.data,
|
|
120
|
+
payment: result.payment
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
126
|
+
0 && (module.exports = {
|
|
127
|
+
createDirectDataController
|
|
128
|
+
});
|
|
129
|
+
//# sourceMappingURL=controller.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/direct/controller.ts"],"sourcesContent":["/**\n * Direct Data Controller — the server-side facade for the two-tab Data\n * Portability flow.\n *\n * @remarks\n * One controller owns an app's private key, source, scopes, app identity, and\n * payment flow. It exposes the three methods the builder guide documents:\n *\n * - {@link DirectDataController.createAccessRequest} — start an approval request.\n * - {@link DirectDataController.getAccessRequestStatus} — poll while the Vana tab is open.\n * - {@link DirectDataController.readApprovedData} — read from the Personal Server,\n * handling 402 Payment Required.\n *\n * Access requests are created through the Vana Account access-request API; the\n * Personal Server read uses Web3Signed auth; and payment uses the DPv2 escrow\n * surface (`protocol/escrow`) — when a read returns `402`, the controller signs\n * a `GenericPayment` with the app key, settles it through the escrow gateway,\n * and retries.\n *\n * @category Direct\n * @module direct/controller\n */\n\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport type { Hex } from \"viem\";\nimport type { Web3SignedSignFn } from \"../auth/web3-signed-builder\";\nimport { parseScope } from \"../protocol/scopes\";\nimport {\n createDefaultAccessRequestClient,\n type FetchLike,\n} from \"./access-request-client\";\nimport { getDirectEndpoints } from \"./endpoints\";\nimport { AccessNotApprovedError, DirectConfigError } from \"./errors\";\nimport {\n type EscrowPaymentConfig,\n type SignTypedDataFn,\n} from \"./escrow-payment\";\nimport {\n readPersonalServerData,\n type PersonalServerFetch,\n} from \"./personal-server-read\";\nimport type {\n AccessRequest,\n AccessRequestClient,\n AccessRequestStatus,\n ApprovedDataResult,\n AppIdentity,\n DirectAppConfig,\n DirectEnv,\n DirectServiceEndpoints,\n} from \"./types\";\n\n/** Configuration for {@link createDirectDataController}. */\nexport interface DirectDataControllerConfig {\n /** Target environment. Defaults to `\"production\"`. */\n env?: DirectEnv;\n /**\n * The app private key (`0x`-prefixed, 32 bytes). Server-side only — this key\n * is the app's on-chain identity and is never exposed to the browser.\n */\n appPrivateKey?: string;\n /**\n * @deprecated Use {@link DirectDataControllerConfig.appPrivateKey}. Accepted as\n * a backwards-compatible alias; if both are set, `appPrivateKey` wins.\n */\n builderPrivateKey?: string;\n /** App identity advertised during approval. */\n app: DirectAppConfig;\n /** Data source key (e.g. `\"icloud_notes\"`). */\n source: string;\n /** Scopes to request (e.g. `[\"icloud_notes.notes\"]`). At least one required. */\n scopes: string[];\n /**\n * Override the resolved service endpoints (partial). Useful for pointing at a\n * non-standard deployment.\n */\n endpoints?: Partial<DirectServiceEndpoints>;\n /**\n * Client for the Vana Account access-request API. Defaults to a client against\n * the resolved Vana Account endpoints; inject your own to point at a custom\n * deployment or to supply a test double.\n */\n accessRequestClient?: AccessRequestClient;\n /**\n * Escrow settlement config used when a Personal Server read returns `402`.\n *\n * @remarks\n * Wires the DPv2 escrow gateway (`protocol/escrow`). The controller supplies\n * the EIP-712 `signTypedData` from the app key automatically, so you provide\n * the gateway `client`, the `escrowContract` address, and (optionally) the\n * `chainId` and a durable `nonceSource`. If omitted, a `402` from the Personal\n * Server throws {@link PaymentRequiredError} carrying the amount/asset owed.\n */\n escrow?: DirectEscrowConfig;\n /** `fetch` used by the default access-request client. Defaults to `globalThis.fetch`. */\n fetchFn?: FetchLike;\n /** `fetch` used for the Personal Server read. Defaults to `globalThis.fetch`. */\n personalServerFetch?: PersonalServerFetch;\n}\n\n/**\n * Controller-level escrow config — the {@link EscrowPaymentConfig} minus the\n * `signTypedData` and `chainId` the controller injects itself.\n */\nexport interface DirectEscrowConfig extends Omit<\n EscrowPaymentConfig,\n \"signTypedData\" | \"chainId\"\n> {\n /**\n * Chain id for the EIP-712 domain. Defaults to the controller's environment\n * (1480 for production, 14800 for dev).\n */\n chainId?: number;\n}\n\n/**\n * Server-side controller for the direct Data Portability flow.\n *\n * @typeParam T - Shape of the data returned by {@link DirectDataController.readApprovedData}.\n */\nexport interface DirectDataController {\n /** The on-chain address of the app, derived from `appPrivateKey`. */\n readonly appAddress: string;\n\n /**\n * The app's on-chain address — the address to fund and inspect in the Builder\n * activity report. Equivalent to {@link DirectDataController.appAddress}.\n *\n * @returns The app's `0x`-prefixed address.\n */\n getAppAddress(): string;\n\n /**\n * The app's full identity: its configured id/name/homepage plus the derived\n * on-chain address. Useful for telling builders which app address to fund or\n * look up.\n *\n * @returns `{ id, name, homepageUrl, address }`.\n */\n getAppIdentity(): AppIdentity;\n\n /**\n * Create an access request the user can approve.\n *\n * @param input - The post-approval return URL.\n * @returns `{ requestId, approvalUrl, appAddress }`.\n */\n createAccessRequest(input: { returnUrl: string }): Promise<AccessRequest>;\n\n /**\n * Fetch the current status of an access request.\n *\n * @param requestId - The `dcr_*` id from {@link DirectDataController.createAccessRequest}.\n * @returns `{ status, personalServerUrl?, grantId?, scope? }`.\n */\n getAccessRequestStatus(requestId: string): Promise<AccessRequestStatus>;\n\n /**\n * Read the approved data from the user's Personal Server.\n *\n * @remarks\n * Resolves the request to its grant + Personal Server and performs a Web3Signed\n * read. Hides the `402 Payment Required` flow by default: if a read needs\n * payment and `escrow` is configured, it settles the grant via the escrow\n * gateway and retries, attaching a {@link DirectPaymentReceipt} under\n * `payment` so callers can inspect amount/asset/fee breakdown. If `escrow` is\n * not configured, it throws {@link PaymentRequiredError} carrying the\n * amount/asset owed.\n *\n * @param input - The `dcr_*` request id to read.\n * @returns `{ scope, data, payment? }`.\n * @throws {@link AccessNotApprovedError} if the request is not approved.\n * @throws {@link PaymentRequiredError} if payment is required but unsettled.\n */\n readApprovedData<T = unknown>(input: {\n requestId: string;\n }): Promise<ApprovedDataResult<T>>;\n}\n\nfunction isHexPrivateKey(value: string): value is Hex {\n return /^0x[0-9a-fA-F]{64}$/.test(value);\n}\n\n/**\n * Create a {@link DirectDataController}.\n *\n * @param config - Controller configuration (env, key, app identity, source, scopes).\n * @returns A ready-to-use controller.\n * @throws {@link DirectConfigError} when the key or scopes are invalid.\n */\nexport function createDirectDataController(\n config: DirectDataControllerConfig,\n): DirectDataController {\n // `appPrivateKey` is the documented field; `builderPrivateKey` is a\n // deprecated alias kept for backwards compatibility.\n const privateKey = config.appPrivateKey ?? config.builderPrivateKey;\n if (!privateKey || !isHexPrivateKey(privateKey)) {\n throw new DirectConfigError(\n \"appPrivateKey must be a 0x-prefixed 32-byte hex string\",\n );\n }\n if (!config.scopes || config.scopes.length === 0) {\n throw new DirectConfigError(\"At least one scope is required\");\n }\n // Validate scopes eagerly so misconfiguration fails at construction.\n for (const scope of config.scopes) {\n parseScope(scope);\n }\n\n const env: DirectEnv = config.env ?? \"production\";\n const endpoints: DirectServiceEndpoints = {\n ...getDirectEndpoints(env),\n ...config.endpoints,\n };\n\n const account = privateKeyToAccount(privateKey as Hex);\n const signMessage: Web3SignedSignFn = (message: string) =>\n account.signMessage({ message });\n // viem's account.signTypedData satisfies the structural SignTypedDataFn used\n // by the escrow GenericPayment signer.\n const signTypedData = account.signTypedData as unknown as SignTypedDataFn;\n const chainId = endpoints.chainId;\n\n const accessRequestClient: AccessRequestClient =\n config.accessRequestClient ??\n createDefaultAccessRequestClient({\n baseUrl: endpoints.accessRequestBaseUrl,\n approvalBaseUrl: endpoints.approvalAppBaseUrl,\n fetchFn: config.fetchFn,\n });\n\n const escrow: EscrowPaymentConfig | undefined = config.escrow\n ? {\n client: config.escrow.client,\n escrowContract: config.escrow.escrowContract,\n chainId: config.escrow.chainId ?? chainId,\n nonceSource: config.escrow.nonceSource,\n signTypedData,\n }\n : undefined;\n\n return {\n appAddress: account.address,\n\n getAppAddress(): string {\n return account.address;\n },\n\n getAppIdentity(): AppIdentity {\n return {\n id: config.app.id,\n name: config.app.name,\n homepageUrl: config.app.homepageUrl,\n address: account.address,\n };\n },\n\n async createAccessRequest(input): Promise<AccessRequest> {\n return accessRequestClient.createAccessRequest({\n appAddress: account.address,\n app: config.app,\n source: config.source,\n scopes: config.scopes,\n returnUrl: input.returnUrl,\n });\n },\n\n async getAccessRequestStatus(\n requestId: string,\n ): Promise<AccessRequestStatus> {\n return accessRequestClient.getAccessRequestStatus(requestId);\n },\n\n async readApprovedData<T = unknown>(input: {\n requestId: string;\n }): Promise<ApprovedDataResult<T>> {\n const status = await accessRequestClient.getAccessRequestStatus(\n input.requestId,\n );\n if (\n status.status !== \"approved\" ||\n !status.personalServerUrl ||\n !status.grantId ||\n !status.scope\n ) {\n throw new AccessNotApprovedError(\n \"Request is not approved or is missing grantId/scope/personalServerUrl\",\n {\n requestId: input.requestId,\n status: status.status,\n hasPersonalServerUrl: Boolean(status.personalServerUrl),\n hasGrantId: Boolean(status.grantId),\n hasScope: Boolean(status.scope),\n },\n );\n }\n\n const result = await readPersonalServerData({\n personalServerUrl: status.personalServerUrl,\n scope: status.scope,\n grantId: status.grantId,\n payerAddress: account.address,\n signMessage,\n escrow,\n fetchFn: config.personalServerFetch,\n });\n\n return {\n scope: status.scope,\n data: result.data as T,\n payment: result.payment,\n };\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBA,sBAAoC;AAGpC,oBAA2B;AAC3B,mCAGO;AACP,uBAAmC;AACnC,oBAA0D;AAK1D,kCAGO;AA2IP,SAAS,gBAAgB,OAA6B;AACpD,SAAO,sBAAsB,KAAK,KAAK;AACzC;AASO,SAAS,2BACd,QACsB;AAGtB,QAAM,aAAa,OAAO,iBAAiB,OAAO;AAClD,MAAI,CAAC,cAAc,CAAC,gBAAgB,UAAU,GAAG;AAC/C,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,OAAO,UAAU,OAAO,OAAO,WAAW,GAAG;AAChD,UAAM,IAAI,gCAAkB,gCAAgC;AAAA,EAC9D;AAEA,aAAW,SAAS,OAAO,QAAQ;AACjC,kCAAW,KAAK;AAAA,EAClB;AAEA,QAAM,MAAiB,OAAO,OAAO;AACrC,QAAM,YAAoC;AAAA,IACxC,OAAG,qCAAmB,GAAG;AAAA,IACzB,GAAG,OAAO;AAAA,EACZ;AAEA,QAAM,cAAU,qCAAoB,UAAiB;AACrD,QAAM,cAAgC,CAAC,YACrC,QAAQ,YAAY,EAAE,QAAQ,CAAC;AAGjC,QAAM,gBAAgB,QAAQ;AAC9B,QAAM,UAAU,UAAU;AAE1B,QAAM,sBACJ,OAAO,2BACP,+DAAiC;AAAA,IAC/B,SAAS,UAAU;AAAA,IACnB,iBAAiB,UAAU;AAAA,IAC3B,SAAS,OAAO;AAAA,EAClB,CAAC;AAEH,QAAM,SAA0C,OAAO,SACnD;AAAA,IACE,QAAQ,OAAO,OAAO;AAAA,IACtB,gBAAgB,OAAO,OAAO;AAAA,IAC9B,SAAS,OAAO,OAAO,WAAW;AAAA,IAClC,aAAa,OAAO,OAAO;AAAA,IAC3B;AAAA,EACF,IACA;AAEJ,SAAO;AAAA,IACL,YAAY,QAAQ;AAAA,IAEpB,gBAAwB;AACtB,aAAO,QAAQ;AAAA,IACjB;AAAA,IAEA,iBAA8B;AAC5B,aAAO;AAAA,QACL,IAAI,OAAO,IAAI;AAAA,QACf,MAAM,OAAO,IAAI;AAAA,QACjB,aAAa,OAAO,IAAI;AAAA,QACxB,SAAS,QAAQ;AAAA,MACnB;AAAA,IACF;AAAA,IAEA,MAAM,oBAAoB,OAA+B;AACvD,aAAO,oBAAoB,oBAAoB;AAAA,QAC7C,YAAY,QAAQ;AAAA,QACpB,KAAK,OAAO;AAAA,QACZ,QAAQ,OAAO;AAAA,QACf,QAAQ,OAAO;AAAA,QACf,WAAW,MAAM;AAAA,MACnB,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,uBACJ,WAC8B;AAC9B,aAAO,oBAAoB,uBAAuB,SAAS;AAAA,IAC7D;AAAA,IAEA,MAAM,iBAA8B,OAED;AACjC,YAAM,SAAS,MAAM,oBAAoB;AAAA,QACvC,MAAM;AAAA,MACR;AACA,UACE,OAAO,WAAW,cAClB,CAAC,OAAO,qBACR,CAAC,OAAO,WACR,CAAC,OAAO,OACR;AACA,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,YACE,WAAW,MAAM;AAAA,YACjB,QAAQ,OAAO;AAAA,YACf,sBAAsB,QAAQ,OAAO,iBAAiB;AAAA,YACtD,YAAY,QAAQ,OAAO,OAAO;AAAA,YAClC,UAAU,QAAQ,OAAO,KAAK;AAAA,UAChC;AAAA,QACF;AAAA,MACF;AAEA,YAAM,SAAS,UAAM,oDAAuB;AAAA,QAC1C,mBAAmB,OAAO;AAAA,QAC1B,OAAO,OAAO;AAAA,QACd,SAAS,OAAO;AAAA,QAChB,cAAc,QAAQ;AAAA,QACtB;AAAA,QACA;AAAA,QACA,SAAS,OAAO;AAAA,MAClB,CAAC;AAED,aAAO;AAAA,QACL,OAAO,OAAO;AAAA,QACd,MAAM,OAAO;AAAA,QACb,SAAS,OAAO;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direct Data Controller — the server-side facade for the two-tab Data
|
|
3
|
+
* Portability flow.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* One controller owns an app's private key, source, scopes, app identity, and
|
|
7
|
+
* payment flow. It exposes the three methods the builder guide documents:
|
|
8
|
+
*
|
|
9
|
+
* - {@link DirectDataController.createAccessRequest} — start an approval request.
|
|
10
|
+
* - {@link DirectDataController.getAccessRequestStatus} — poll while the Vana tab is open.
|
|
11
|
+
* - {@link DirectDataController.readApprovedData} — read from the Personal Server,
|
|
12
|
+
* handling 402 Payment Required.
|
|
13
|
+
*
|
|
14
|
+
* Access requests are created through the Vana Account access-request API; the
|
|
15
|
+
* Personal Server read uses Web3Signed auth; and payment uses the DPv2 escrow
|
|
16
|
+
* surface (`protocol/escrow`) — when a read returns `402`, the controller signs
|
|
17
|
+
* a `GenericPayment` with the app key, settles it through the escrow gateway,
|
|
18
|
+
* and retries.
|
|
19
|
+
*
|
|
20
|
+
* @category Direct
|
|
21
|
+
* @module direct/controller
|
|
22
|
+
*/
|
|
23
|
+
import { type FetchLike } from "./access-request-client";
|
|
24
|
+
import { type EscrowPaymentConfig } from "./escrow-payment";
|
|
25
|
+
import { type PersonalServerFetch } from "./personal-server-read";
|
|
26
|
+
import type { AccessRequest, AccessRequestClient, AccessRequestStatus, ApprovedDataResult, AppIdentity, DirectAppConfig, DirectEnv, DirectServiceEndpoints } from "./types";
|
|
27
|
+
/** Configuration for {@link createDirectDataController}. */
|
|
28
|
+
export interface DirectDataControllerConfig {
|
|
29
|
+
/** Target environment. Defaults to `"production"`. */
|
|
30
|
+
env?: DirectEnv;
|
|
31
|
+
/**
|
|
32
|
+
* The app private key (`0x`-prefixed, 32 bytes). Server-side only — this key
|
|
33
|
+
* is the app's on-chain identity and is never exposed to the browser.
|
|
34
|
+
*/
|
|
35
|
+
appPrivateKey?: string;
|
|
36
|
+
/**
|
|
37
|
+
* @deprecated Use {@link DirectDataControllerConfig.appPrivateKey}. Accepted as
|
|
38
|
+
* a backwards-compatible alias; if both are set, `appPrivateKey` wins.
|
|
39
|
+
*/
|
|
40
|
+
builderPrivateKey?: string;
|
|
41
|
+
/** App identity advertised during approval. */
|
|
42
|
+
app: DirectAppConfig;
|
|
43
|
+
/** Data source key (e.g. `"icloud_notes"`). */
|
|
44
|
+
source: string;
|
|
45
|
+
/** Scopes to request (e.g. `["icloud_notes.notes"]`). At least one required. */
|
|
46
|
+
scopes: string[];
|
|
47
|
+
/**
|
|
48
|
+
* Override the resolved service endpoints (partial). Useful for pointing at a
|
|
49
|
+
* non-standard deployment.
|
|
50
|
+
*/
|
|
51
|
+
endpoints?: Partial<DirectServiceEndpoints>;
|
|
52
|
+
/**
|
|
53
|
+
* Client for the Vana Account access-request API. Defaults to a client against
|
|
54
|
+
* the resolved Vana Account endpoints; inject your own to point at a custom
|
|
55
|
+
* deployment or to supply a test double.
|
|
56
|
+
*/
|
|
57
|
+
accessRequestClient?: AccessRequestClient;
|
|
58
|
+
/**
|
|
59
|
+
* Escrow settlement config used when a Personal Server read returns `402`.
|
|
60
|
+
*
|
|
61
|
+
* @remarks
|
|
62
|
+
* Wires the DPv2 escrow gateway (`protocol/escrow`). The controller supplies
|
|
63
|
+
* the EIP-712 `signTypedData` from the app key automatically, so you provide
|
|
64
|
+
* the gateway `client`, the `escrowContract` address, and (optionally) the
|
|
65
|
+
* `chainId` and a durable `nonceSource`. If omitted, a `402` from the Personal
|
|
66
|
+
* Server throws {@link PaymentRequiredError} carrying the amount/asset owed.
|
|
67
|
+
*/
|
|
68
|
+
escrow?: DirectEscrowConfig;
|
|
69
|
+
/** `fetch` used by the default access-request client. Defaults to `globalThis.fetch`. */
|
|
70
|
+
fetchFn?: FetchLike;
|
|
71
|
+
/** `fetch` used for the Personal Server read. Defaults to `globalThis.fetch`. */
|
|
72
|
+
personalServerFetch?: PersonalServerFetch;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Controller-level escrow config — the {@link EscrowPaymentConfig} minus the
|
|
76
|
+
* `signTypedData` and `chainId` the controller injects itself.
|
|
77
|
+
*/
|
|
78
|
+
export interface DirectEscrowConfig extends Omit<EscrowPaymentConfig, "signTypedData" | "chainId"> {
|
|
79
|
+
/**
|
|
80
|
+
* Chain id for the EIP-712 domain. Defaults to the controller's environment
|
|
81
|
+
* (1480 for production, 14800 for dev).
|
|
82
|
+
*/
|
|
83
|
+
chainId?: number;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Server-side controller for the direct Data Portability flow.
|
|
87
|
+
*
|
|
88
|
+
* @typeParam T - Shape of the data returned by {@link DirectDataController.readApprovedData}.
|
|
89
|
+
*/
|
|
90
|
+
export interface DirectDataController {
|
|
91
|
+
/** The on-chain address of the app, derived from `appPrivateKey`. */
|
|
92
|
+
readonly appAddress: string;
|
|
93
|
+
/**
|
|
94
|
+
* The app's on-chain address — the address to fund and inspect in the Builder
|
|
95
|
+
* activity report. Equivalent to {@link DirectDataController.appAddress}.
|
|
96
|
+
*
|
|
97
|
+
* @returns The app's `0x`-prefixed address.
|
|
98
|
+
*/
|
|
99
|
+
getAppAddress(): string;
|
|
100
|
+
/**
|
|
101
|
+
* The app's full identity: its configured id/name/homepage plus the derived
|
|
102
|
+
* on-chain address. Useful for telling builders which app address to fund or
|
|
103
|
+
* look up.
|
|
104
|
+
*
|
|
105
|
+
* @returns `{ id, name, homepageUrl, address }`.
|
|
106
|
+
*/
|
|
107
|
+
getAppIdentity(): AppIdentity;
|
|
108
|
+
/**
|
|
109
|
+
* Create an access request the user can approve.
|
|
110
|
+
*
|
|
111
|
+
* @param input - The post-approval return URL.
|
|
112
|
+
* @returns `{ requestId, approvalUrl, appAddress }`.
|
|
113
|
+
*/
|
|
114
|
+
createAccessRequest(input: {
|
|
115
|
+
returnUrl: string;
|
|
116
|
+
}): Promise<AccessRequest>;
|
|
117
|
+
/**
|
|
118
|
+
* Fetch the current status of an access request.
|
|
119
|
+
*
|
|
120
|
+
* @param requestId - The `dcr_*` id from {@link DirectDataController.createAccessRequest}.
|
|
121
|
+
* @returns `{ status, personalServerUrl?, grantId?, scope? }`.
|
|
122
|
+
*/
|
|
123
|
+
getAccessRequestStatus(requestId: string): Promise<AccessRequestStatus>;
|
|
124
|
+
/**
|
|
125
|
+
* Read the approved data from the user's Personal Server.
|
|
126
|
+
*
|
|
127
|
+
* @remarks
|
|
128
|
+
* Resolves the request to its grant + Personal Server and performs a Web3Signed
|
|
129
|
+
* read. Hides the `402 Payment Required` flow by default: if a read needs
|
|
130
|
+
* payment and `escrow` is configured, it settles the grant via the escrow
|
|
131
|
+
* gateway and retries, attaching a {@link DirectPaymentReceipt} under
|
|
132
|
+
* `payment` so callers can inspect amount/asset/fee breakdown. If `escrow` is
|
|
133
|
+
* not configured, it throws {@link PaymentRequiredError} carrying the
|
|
134
|
+
* amount/asset owed.
|
|
135
|
+
*
|
|
136
|
+
* @param input - The `dcr_*` request id to read.
|
|
137
|
+
* @returns `{ scope, data, payment? }`.
|
|
138
|
+
* @throws {@link AccessNotApprovedError} if the request is not approved.
|
|
139
|
+
* @throws {@link PaymentRequiredError} if payment is required but unsettled.
|
|
140
|
+
*/
|
|
141
|
+
readApprovedData<T = unknown>(input: {
|
|
142
|
+
requestId: string;
|
|
143
|
+
}): Promise<ApprovedDataResult<T>>;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Create a {@link DirectDataController}.
|
|
147
|
+
*
|
|
148
|
+
* @param config - Controller configuration (env, key, app identity, source, scopes).
|
|
149
|
+
* @returns A ready-to-use controller.
|
|
150
|
+
* @throws {@link DirectConfigError} when the key or scopes are invalid.
|
|
151
|
+
*/
|
|
152
|
+
export declare function createDirectDataController(config: DirectDataControllerConfig): DirectDataController;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
2
|
+
import { parseScope } from "../protocol/scopes.js";
|
|
3
|
+
import {
|
|
4
|
+
createDefaultAccessRequestClient
|
|
5
|
+
} from "./access-request-client.js";
|
|
6
|
+
import { getDirectEndpoints } from "./endpoints.js";
|
|
7
|
+
import { AccessNotApprovedError, DirectConfigError } from "./errors.js";
|
|
8
|
+
import {
|
|
9
|
+
readPersonalServerData
|
|
10
|
+
} from "./personal-server-read.js";
|
|
11
|
+
function isHexPrivateKey(value) {
|
|
12
|
+
return /^0x[0-9a-fA-F]{64}$/.test(value);
|
|
13
|
+
}
|
|
14
|
+
function createDirectDataController(config) {
|
|
15
|
+
const privateKey = config.appPrivateKey ?? config.builderPrivateKey;
|
|
16
|
+
if (!privateKey || !isHexPrivateKey(privateKey)) {
|
|
17
|
+
throw new DirectConfigError(
|
|
18
|
+
"appPrivateKey must be a 0x-prefixed 32-byte hex string"
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
if (!config.scopes || config.scopes.length === 0) {
|
|
22
|
+
throw new DirectConfigError("At least one scope is required");
|
|
23
|
+
}
|
|
24
|
+
for (const scope of config.scopes) {
|
|
25
|
+
parseScope(scope);
|
|
26
|
+
}
|
|
27
|
+
const env = config.env ?? "production";
|
|
28
|
+
const endpoints = {
|
|
29
|
+
...getDirectEndpoints(env),
|
|
30
|
+
...config.endpoints
|
|
31
|
+
};
|
|
32
|
+
const account = privateKeyToAccount(privateKey);
|
|
33
|
+
const signMessage = (message) => account.signMessage({ message });
|
|
34
|
+
const signTypedData = account.signTypedData;
|
|
35
|
+
const chainId = endpoints.chainId;
|
|
36
|
+
const accessRequestClient = config.accessRequestClient ?? createDefaultAccessRequestClient({
|
|
37
|
+
baseUrl: endpoints.accessRequestBaseUrl,
|
|
38
|
+
approvalBaseUrl: endpoints.approvalAppBaseUrl,
|
|
39
|
+
fetchFn: config.fetchFn
|
|
40
|
+
});
|
|
41
|
+
const escrow = config.escrow ? {
|
|
42
|
+
client: config.escrow.client,
|
|
43
|
+
escrowContract: config.escrow.escrowContract,
|
|
44
|
+
chainId: config.escrow.chainId ?? chainId,
|
|
45
|
+
nonceSource: config.escrow.nonceSource,
|
|
46
|
+
signTypedData
|
|
47
|
+
} : void 0;
|
|
48
|
+
return {
|
|
49
|
+
appAddress: account.address,
|
|
50
|
+
getAppAddress() {
|
|
51
|
+
return account.address;
|
|
52
|
+
},
|
|
53
|
+
getAppIdentity() {
|
|
54
|
+
return {
|
|
55
|
+
id: config.app.id,
|
|
56
|
+
name: config.app.name,
|
|
57
|
+
homepageUrl: config.app.homepageUrl,
|
|
58
|
+
address: account.address
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
async createAccessRequest(input) {
|
|
62
|
+
return accessRequestClient.createAccessRequest({
|
|
63
|
+
appAddress: account.address,
|
|
64
|
+
app: config.app,
|
|
65
|
+
source: config.source,
|
|
66
|
+
scopes: config.scopes,
|
|
67
|
+
returnUrl: input.returnUrl
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
async getAccessRequestStatus(requestId) {
|
|
71
|
+
return accessRequestClient.getAccessRequestStatus(requestId);
|
|
72
|
+
},
|
|
73
|
+
async readApprovedData(input) {
|
|
74
|
+
const status = await accessRequestClient.getAccessRequestStatus(
|
|
75
|
+
input.requestId
|
|
76
|
+
);
|
|
77
|
+
if (status.status !== "approved" || !status.personalServerUrl || !status.grantId || !status.scope) {
|
|
78
|
+
throw new AccessNotApprovedError(
|
|
79
|
+
"Request is not approved or is missing grantId/scope/personalServerUrl",
|
|
80
|
+
{
|
|
81
|
+
requestId: input.requestId,
|
|
82
|
+
status: status.status,
|
|
83
|
+
hasPersonalServerUrl: Boolean(status.personalServerUrl),
|
|
84
|
+
hasGrantId: Boolean(status.grantId),
|
|
85
|
+
hasScope: Boolean(status.scope)
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
const result = await readPersonalServerData({
|
|
90
|
+
personalServerUrl: status.personalServerUrl,
|
|
91
|
+
scope: status.scope,
|
|
92
|
+
grantId: status.grantId,
|
|
93
|
+
payerAddress: account.address,
|
|
94
|
+
signMessage,
|
|
95
|
+
escrow,
|
|
96
|
+
fetchFn: config.personalServerFetch
|
|
97
|
+
});
|
|
98
|
+
return {
|
|
99
|
+
scope: status.scope,
|
|
100
|
+
data: result.data,
|
|
101
|
+
payment: result.payment
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
export {
|
|
107
|
+
createDirectDataController
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/direct/controller.ts"],"sourcesContent":["/**\n * Direct Data Controller — the server-side facade for the two-tab Data\n * Portability flow.\n *\n * @remarks\n * One controller owns an app's private key, source, scopes, app identity, and\n * payment flow. It exposes the three methods the builder guide documents:\n *\n * - {@link DirectDataController.createAccessRequest} — start an approval request.\n * - {@link DirectDataController.getAccessRequestStatus} — poll while the Vana tab is open.\n * - {@link DirectDataController.readApprovedData} — read from the Personal Server,\n * handling 402 Payment Required.\n *\n * Access requests are created through the Vana Account access-request API; the\n * Personal Server read uses Web3Signed auth; and payment uses the DPv2 escrow\n * surface (`protocol/escrow`) — when a read returns `402`, the controller signs\n * a `GenericPayment` with the app key, settles it through the escrow gateway,\n * and retries.\n *\n * @category Direct\n * @module direct/controller\n */\n\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport type { Hex } from \"viem\";\nimport type { Web3SignedSignFn } from \"../auth/web3-signed-builder\";\nimport { parseScope } from \"../protocol/scopes\";\nimport {\n createDefaultAccessRequestClient,\n type FetchLike,\n} from \"./access-request-client\";\nimport { getDirectEndpoints } from \"./endpoints\";\nimport { AccessNotApprovedError, DirectConfigError } from \"./errors\";\nimport {\n type EscrowPaymentConfig,\n type SignTypedDataFn,\n} from \"./escrow-payment\";\nimport {\n readPersonalServerData,\n type PersonalServerFetch,\n} from \"./personal-server-read\";\nimport type {\n AccessRequest,\n AccessRequestClient,\n AccessRequestStatus,\n ApprovedDataResult,\n AppIdentity,\n DirectAppConfig,\n DirectEnv,\n DirectServiceEndpoints,\n} from \"./types\";\n\n/** Configuration for {@link createDirectDataController}. */\nexport interface DirectDataControllerConfig {\n /** Target environment. Defaults to `\"production\"`. */\n env?: DirectEnv;\n /**\n * The app private key (`0x`-prefixed, 32 bytes). Server-side only — this key\n * is the app's on-chain identity and is never exposed to the browser.\n */\n appPrivateKey?: string;\n /**\n * @deprecated Use {@link DirectDataControllerConfig.appPrivateKey}. Accepted as\n * a backwards-compatible alias; if both are set, `appPrivateKey` wins.\n */\n builderPrivateKey?: string;\n /** App identity advertised during approval. */\n app: DirectAppConfig;\n /** Data source key (e.g. `\"icloud_notes\"`). */\n source: string;\n /** Scopes to request (e.g. `[\"icloud_notes.notes\"]`). At least one required. */\n scopes: string[];\n /**\n * Override the resolved service endpoints (partial). Useful for pointing at a\n * non-standard deployment.\n */\n endpoints?: Partial<DirectServiceEndpoints>;\n /**\n * Client for the Vana Account access-request API. Defaults to a client against\n * the resolved Vana Account endpoints; inject your own to point at a custom\n * deployment or to supply a test double.\n */\n accessRequestClient?: AccessRequestClient;\n /**\n * Escrow settlement config used when a Personal Server read returns `402`.\n *\n * @remarks\n * Wires the DPv2 escrow gateway (`protocol/escrow`). The controller supplies\n * the EIP-712 `signTypedData` from the app key automatically, so you provide\n * the gateway `client`, the `escrowContract` address, and (optionally) the\n * `chainId` and a durable `nonceSource`. If omitted, a `402` from the Personal\n * Server throws {@link PaymentRequiredError} carrying the amount/asset owed.\n */\n escrow?: DirectEscrowConfig;\n /** `fetch` used by the default access-request client. Defaults to `globalThis.fetch`. */\n fetchFn?: FetchLike;\n /** `fetch` used for the Personal Server read. Defaults to `globalThis.fetch`. */\n personalServerFetch?: PersonalServerFetch;\n}\n\n/**\n * Controller-level escrow config — the {@link EscrowPaymentConfig} minus the\n * `signTypedData` and `chainId` the controller injects itself.\n */\nexport interface DirectEscrowConfig extends Omit<\n EscrowPaymentConfig,\n \"signTypedData\" | \"chainId\"\n> {\n /**\n * Chain id for the EIP-712 domain. Defaults to the controller's environment\n * (1480 for production, 14800 for dev).\n */\n chainId?: number;\n}\n\n/**\n * Server-side controller for the direct Data Portability flow.\n *\n * @typeParam T - Shape of the data returned by {@link DirectDataController.readApprovedData}.\n */\nexport interface DirectDataController {\n /** The on-chain address of the app, derived from `appPrivateKey`. */\n readonly appAddress: string;\n\n /**\n * The app's on-chain address — the address to fund and inspect in the Builder\n * activity report. Equivalent to {@link DirectDataController.appAddress}.\n *\n * @returns The app's `0x`-prefixed address.\n */\n getAppAddress(): string;\n\n /**\n * The app's full identity: its configured id/name/homepage plus the derived\n * on-chain address. Useful for telling builders which app address to fund or\n * look up.\n *\n * @returns `{ id, name, homepageUrl, address }`.\n */\n getAppIdentity(): AppIdentity;\n\n /**\n * Create an access request the user can approve.\n *\n * @param input - The post-approval return URL.\n * @returns `{ requestId, approvalUrl, appAddress }`.\n */\n createAccessRequest(input: { returnUrl: string }): Promise<AccessRequest>;\n\n /**\n * Fetch the current status of an access request.\n *\n * @param requestId - The `dcr_*` id from {@link DirectDataController.createAccessRequest}.\n * @returns `{ status, personalServerUrl?, grantId?, scope? }`.\n */\n getAccessRequestStatus(requestId: string): Promise<AccessRequestStatus>;\n\n /**\n * Read the approved data from the user's Personal Server.\n *\n * @remarks\n * Resolves the request to its grant + Personal Server and performs a Web3Signed\n * read. Hides the `402 Payment Required` flow by default: if a read needs\n * payment and `escrow` is configured, it settles the grant via the escrow\n * gateway and retries, attaching a {@link DirectPaymentReceipt} under\n * `payment` so callers can inspect amount/asset/fee breakdown. If `escrow` is\n * not configured, it throws {@link PaymentRequiredError} carrying the\n * amount/asset owed.\n *\n * @param input - The `dcr_*` request id to read.\n * @returns `{ scope, data, payment? }`.\n * @throws {@link AccessNotApprovedError} if the request is not approved.\n * @throws {@link PaymentRequiredError} if payment is required but unsettled.\n */\n readApprovedData<T = unknown>(input: {\n requestId: string;\n }): Promise<ApprovedDataResult<T>>;\n}\n\nfunction isHexPrivateKey(value: string): value is Hex {\n return /^0x[0-9a-fA-F]{64}$/.test(value);\n}\n\n/**\n * Create a {@link DirectDataController}.\n *\n * @param config - Controller configuration (env, key, app identity, source, scopes).\n * @returns A ready-to-use controller.\n * @throws {@link DirectConfigError} when the key or scopes are invalid.\n */\nexport function createDirectDataController(\n config: DirectDataControllerConfig,\n): DirectDataController {\n // `appPrivateKey` is the documented field; `builderPrivateKey` is a\n // deprecated alias kept for backwards compatibility.\n const privateKey = config.appPrivateKey ?? config.builderPrivateKey;\n if (!privateKey || !isHexPrivateKey(privateKey)) {\n throw new DirectConfigError(\n \"appPrivateKey must be a 0x-prefixed 32-byte hex string\",\n );\n }\n if (!config.scopes || config.scopes.length === 0) {\n throw new DirectConfigError(\"At least one scope is required\");\n }\n // Validate scopes eagerly so misconfiguration fails at construction.\n for (const scope of config.scopes) {\n parseScope(scope);\n }\n\n const env: DirectEnv = config.env ?? \"production\";\n const endpoints: DirectServiceEndpoints = {\n ...getDirectEndpoints(env),\n ...config.endpoints,\n };\n\n const account = privateKeyToAccount(privateKey as Hex);\n const signMessage: Web3SignedSignFn = (message: string) =>\n account.signMessage({ message });\n // viem's account.signTypedData satisfies the structural SignTypedDataFn used\n // by the escrow GenericPayment signer.\n const signTypedData = account.signTypedData as unknown as SignTypedDataFn;\n const chainId = endpoints.chainId;\n\n const accessRequestClient: AccessRequestClient =\n config.accessRequestClient ??\n createDefaultAccessRequestClient({\n baseUrl: endpoints.accessRequestBaseUrl,\n approvalBaseUrl: endpoints.approvalAppBaseUrl,\n fetchFn: config.fetchFn,\n });\n\n const escrow: EscrowPaymentConfig | undefined = config.escrow\n ? {\n client: config.escrow.client,\n escrowContract: config.escrow.escrowContract,\n chainId: config.escrow.chainId ?? chainId,\n nonceSource: config.escrow.nonceSource,\n signTypedData,\n }\n : undefined;\n\n return {\n appAddress: account.address,\n\n getAppAddress(): string {\n return account.address;\n },\n\n getAppIdentity(): AppIdentity {\n return {\n id: config.app.id,\n name: config.app.name,\n homepageUrl: config.app.homepageUrl,\n address: account.address,\n };\n },\n\n async createAccessRequest(input): Promise<AccessRequest> {\n return accessRequestClient.createAccessRequest({\n appAddress: account.address,\n app: config.app,\n source: config.source,\n scopes: config.scopes,\n returnUrl: input.returnUrl,\n });\n },\n\n async getAccessRequestStatus(\n requestId: string,\n ): Promise<AccessRequestStatus> {\n return accessRequestClient.getAccessRequestStatus(requestId);\n },\n\n async readApprovedData<T = unknown>(input: {\n requestId: string;\n }): Promise<ApprovedDataResult<T>> {\n const status = await accessRequestClient.getAccessRequestStatus(\n input.requestId,\n );\n if (\n status.status !== \"approved\" ||\n !status.personalServerUrl ||\n !status.grantId ||\n !status.scope\n ) {\n throw new AccessNotApprovedError(\n \"Request is not approved or is missing grantId/scope/personalServerUrl\",\n {\n requestId: input.requestId,\n status: status.status,\n hasPersonalServerUrl: Boolean(status.personalServerUrl),\n hasGrantId: Boolean(status.grantId),\n hasScope: Boolean(status.scope),\n },\n );\n }\n\n const result = await readPersonalServerData({\n personalServerUrl: status.personalServerUrl,\n scope: status.scope,\n grantId: status.grantId,\n payerAddress: account.address,\n signMessage,\n escrow,\n fetchFn: config.personalServerFetch,\n });\n\n return {\n scope: status.scope,\n data: result.data as T,\n payment: result.payment,\n };\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
DEV_ENDPOINTS: () => DEV_ENDPOINTS,
|
|
22
|
+
PRODUCTION_ENDPOINTS: () => PRODUCTION_ENDPOINTS,
|
|
23
|
+
getDirectEndpoints: () => getDirectEndpoints
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(endpoints_exports);
|
|
26
|
+
const PRODUCTION_ENDPOINTS = {
|
|
27
|
+
chainId: 1480,
|
|
28
|
+
accessRequestBaseUrl: "https://app.vana.org",
|
|
29
|
+
approvalAppBaseUrl: "https://app.vana.org"
|
|
30
|
+
};
|
|
31
|
+
const DEV_ENDPOINTS = {
|
|
32
|
+
chainId: 14800,
|
|
33
|
+
accessRequestBaseUrl: "https://app-dev.vana.org",
|
|
34
|
+
approvalAppBaseUrl: "https://app-dev.vana.org"
|
|
35
|
+
};
|
|
36
|
+
function getDirectEndpoints(env) {
|
|
37
|
+
return env === "dev" ? DEV_ENDPOINTS : PRODUCTION_ENDPOINTS;
|
|
38
|
+
}
|
|
39
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
40
|
+
0 && (module.exports = {
|
|
41
|
+
DEV_ENDPOINTS,
|
|
42
|
+
PRODUCTION_ENDPOINTS,
|
|
43
|
+
getDirectEndpoints
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=endpoints.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/direct/endpoints.ts"],"sourcesContent":["/**\n * Per-environment service URLs for the Direct Data Controller.\n *\n * @remarks\n * The SDK ships production defaults; pass `env: \"dev\"` only when testing against\n * Vana's dev stack. This module is the single source of truth for those URLs.\n *\n * @category Direct\n * @module direct/endpoints\n */\n\nimport type { DirectEnv, DirectServiceEndpoints } from \"./types\";\n\n/** Production (mainnet) service URLs. */\nexport const PRODUCTION_ENDPOINTS: DirectServiceEndpoints = {\n chainId: 1480,\n accessRequestBaseUrl: \"https://app.vana.org\",\n approvalAppBaseUrl: \"https://app.vana.org\",\n} as const;\n\n/** Dev/testnet (moksha) service URLs. */\nexport const DEV_ENDPOINTS: DirectServiceEndpoints = {\n chainId: 14800,\n accessRequestBaseUrl: \"https://app-dev.vana.org\",\n approvalAppBaseUrl: \"https://app-dev.vana.org\",\n} as const;\n\n/**\n * Resolve the default {@link DirectServiceEndpoints} for an environment.\n *\n * @param env - Target environment.\n * @returns The default endpoints for that environment.\n */\nexport function getDirectEndpoints(env: DirectEnv): DirectServiceEndpoints {\n return env === \"dev\" ? DEV_ENDPOINTS : PRODUCTION_ENDPOINTS;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcO,MAAM,uBAA+C;AAAA,EAC1D,SAAS;AAAA,EACT,sBAAsB;AAAA,EACtB,oBAAoB;AACtB;AAGO,MAAM,gBAAwC;AAAA,EACnD,SAAS;AAAA,EACT,sBAAsB;AAAA,EACtB,oBAAoB;AACtB;AAQO,SAAS,mBAAmB,KAAwC;AACzE,SAAO,QAAQ,QAAQ,gBAAgB;AACzC;","names":[]}
|