@opendatalabs/vana-sdk 3.13.4 → 3.14.1
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/dist/account/personal-server-lite-owner-binding.d.ts +1 -1
- package/dist/account/personal-server-registration.d.ts +1 -1
- package/dist/auth/errors.d.ts +1 -1
- package/dist/auth/oauth-client.d.ts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/chains/index.d.ts +2 -2
- package/dist/chains.browser.d.ts +2 -2
- package/dist/chains.d.ts +2 -2
- package/dist/chains.node.d.ts +2 -2
- package/dist/config/contracts.config.cjs +1 -1
- package/dist/config/contracts.config.cjs.map +1 -1
- package/dist/config/contracts.config.js +1 -1
- package/dist/config/contracts.config.js.map +1 -1
- package/dist/contracts/contractController.d.ts +4 -4
- package/dist/core/client.d.ts +1 -1
- package/dist/crypto/ecies/base.d.ts +1 -1
- package/dist/crypto/ecies/browser.d.ts +1 -1
- package/dist/crypto/ecies/index.d.ts +2 -2
- package/dist/crypto/ecies/node.d.ts +1 -1
- package/dist/crypto/services/WalletKeyEncryptionService.d.ts +1 -1
- package/dist/direct/access-request-client.cjs +3 -1
- package/dist/direct/access-request-client.cjs.map +1 -1
- package/dist/direct/access-request-client.d.ts +2 -2
- package/dist/direct/access-request-client.js +3 -1
- package/dist/direct/access-request-client.js.map +1 -1
- package/dist/direct/connect-flow.d.ts +1 -1
- package/dist/direct/controller.cjs +72 -32
- package/dist/direct/controller.cjs.map +1 -1
- package/dist/direct/controller.d.ts +48 -10
- package/dist/direct/controller.js +77 -33
- package/dist/direct/controller.js.map +1 -1
- package/dist/direct/endpoints.d.ts +1 -1
- package/dist/direct/errors.cjs +11 -2
- package/dist/direct/errors.cjs.map +1 -1
- package/dist/direct/errors.d.ts +14 -1
- package/dist/direct/errors.js +9 -1
- package/dist/direct/errors.js.map +1 -1
- package/dist/direct/escrow-payment.cjs +147 -12
- package/dist/direct/escrow-payment.cjs.map +1 -1
- package/dist/direct/escrow-payment.d.ts +65 -12
- package/dist/direct/escrow-payment.js +143 -12
- package/dist/direct/escrow-payment.js.map +1 -1
- package/dist/direct/personal-server-read.cjs +164 -23
- package/dist/direct/personal-server-read.cjs.map +1 -1
- package/dist/direct/personal-server-read.d.ts +28 -18
- package/dist/direct/personal-server-read.js +167 -25
- package/dist/direct/personal-server-read.js.map +1 -1
- package/dist/direct/types.cjs.map +1 -1
- package/dist/direct/types.d.ts +81 -21
- package/dist/direct/types.js.map +1 -1
- package/dist/direct/use-direct-vana-connect.d.ts +1 -1
- package/dist/generated/abi/index.d.ts +25 -25
- package/dist/generated/addresses.cjs +6 -6
- package/dist/generated/addresses.cjs.map +1 -1
- package/dist/generated/addresses.d.ts +6 -6
- package/dist/generated/addresses.js +6 -6
- package/dist/generated/addresses.js.map +1 -1
- package/dist/index.browser.d.ts +44 -44
- package/dist/index.browser.js +6 -6
- package/dist/index.browser.js.map +2 -2
- package/dist/index.node.cjs +498 -6
- package/dist/index.node.cjs.map +4 -4
- package/dist/index.node.d.ts +48 -45
- package/dist/index.node.js +486 -6
- package/dist/index.node.js.map +4 -4
- package/dist/node.d.ts +1 -1
- package/dist/platform/browser-only.d.ts +3 -3
- package/dist/platform/browser-safe.d.ts +3 -3
- package/dist/platform/browser.d.ts +1 -1
- package/dist/platform/index.d.ts +5 -5
- package/dist/platform/node.d.ts +1 -1
- package/dist/platform/ports/openpgp-port.d.ts +1 -1
- package/dist/platform/utils.d.ts +1 -1
- package/dist/platform.browser.d.ts +4 -4
- package/dist/platform.d.ts +5 -5
- package/dist/platform.node.d.ts +5 -5
- package/dist/protocol/data-point-status.d.ts +1 -1
- package/dist/protocol/eip712.cjs.map +1 -1
- package/dist/protocol/eip712.js.map +1 -1
- package/dist/protocol/escrow-deposit.d.ts +1 -1
- package/dist/protocol/escrow.cjs.map +1 -1
- package/dist/protocol/escrow.d.ts +11 -4
- package/dist/protocol/escrow.js.map +1 -1
- package/dist/protocol/fee-registry.d.ts +1 -1
- package/dist/protocol/gateway.cjs.map +1 -1
- package/dist/protocol/gateway.js.map +1 -1
- package/dist/protocol/grants.d.ts +1 -1
- package/dist/protocol/personal-server-data.d.ts +2 -2
- package/dist/protocol/personal-server-registration.d.ts +2 -2
- package/dist/react.d.ts +3 -3
- package/dist/server.cjs +12 -0
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.ts +8 -8
- package/dist/server.js +12 -0
- package/dist/server.js.map +1 -1
- package/dist/session-relay/client.d.ts +1 -1
- package/dist/session-relay/endpoints.d.ts +1 -1
- package/dist/session-relay/errors.d.ts +1 -1
- package/dist/session-relay/index.d.ts +5 -5
- package/dist/session-relay/signing.d.ts +1 -1
- package/dist/session-relay/types.d.ts +1 -1
- package/dist/session-relay.d.ts +5 -5
- package/dist/storage/default.d.ts +2 -2
- package/dist/storage/index.d.ts +16 -16
- package/dist/storage/manager.d.ts +1 -1
- package/dist/storage/providers/callback-storage.d.ts +2 -2
- package/dist/storage/providers/dropbox.d.ts +1 -1
- package/dist/storage/providers/google-drive.d.ts +1 -1
- package/dist/storage/providers/ipfs.d.ts +1 -1
- package/dist/storage/providers/pinata.d.ts +1 -1
- package/dist/storage/providers/r2.d.ts +1 -1
- package/dist/storage/providers/vana-storage.d.ts +3 -3
- package/dist/types/config.d.ts +1 -1
- package/dist/types/index.d.ts +6 -6
- package/dist/types.d.ts +1 -1
- package/package.json +13 -1
|
@@ -3,9 +3,10 @@ import {
|
|
|
3
3
|
NATIVE_ASSET_ADDRESS
|
|
4
4
|
} from "../protocol/escrow.js";
|
|
5
5
|
import {
|
|
6
|
-
|
|
6
|
+
buildEscrowPaymentHeader,
|
|
7
|
+
DATA_ACCESS_OP_TYPE,
|
|
7
8
|
GRANT_OP_TYPE,
|
|
8
|
-
|
|
9
|
+
paymentResponseMetadataFromHeader
|
|
9
10
|
} from "./escrow-payment.js";
|
|
10
11
|
import { PaymentRequiredError, PersonalServerReadError } from "./errors.js";
|
|
11
12
|
const TRANSPORT_RETRY_DEFAULTS = {
|
|
@@ -78,31 +79,99 @@ function parseAccessRecord(value) {
|
|
|
78
79
|
function isBytes32Hex(value) {
|
|
79
80
|
return /^0x[0-9a-fA-F]{64}$/.test(value);
|
|
80
81
|
}
|
|
81
|
-
|
|
82
|
+
const UINT256_MAX = (1n << 256n) - 1n;
|
|
83
|
+
function isAddressHex(value) {
|
|
84
|
+
return /^0x[0-9a-fA-F]{40}$/.test(value);
|
|
85
|
+
}
|
|
86
|
+
function isUint256Decimal(value, allowZero) {
|
|
87
|
+
const pattern = allowZero ? /^(0|[1-9]\d*)$/ : /^[1-9]\d*$/;
|
|
88
|
+
return value.length <= UINT256_MAX.toString().length && pattern.test(value) && BigInt(value) <= UINT256_MAX;
|
|
89
|
+
}
|
|
90
|
+
function isValidDataAccessRecord(record) {
|
|
91
|
+
return isBytes32Hex(record.dataPointId) && isUint256Decimal(record.version, false) && isAddressHex(record.accessor) && isBytes32Hex(record.recordId) && /^0x[0-9a-fA-F]{130}$/.test(record.signature);
|
|
92
|
+
}
|
|
93
|
+
function parseLegacyGrantOperation(params) {
|
|
82
94
|
const { challengeGrantId, challengeOpId, challengeOpType, grantId } = params;
|
|
83
|
-
|
|
95
|
+
const opType = challengeOpType ?? GRANT_OP_TYPE;
|
|
96
|
+
if (opType !== GRANT_OP_TYPE) {
|
|
84
97
|
throw new PersonalServerReadError(
|
|
85
98
|
"Personal Server payment challenge used an unsupported escrow op type",
|
|
86
99
|
402,
|
|
87
100
|
{ opType: challengeOpType }
|
|
88
101
|
);
|
|
89
102
|
}
|
|
90
|
-
const
|
|
91
|
-
if (!
|
|
92
|
-
if (!isBytes32Hex(challengedGrantId)) {
|
|
103
|
+
const opId = challengeOpId ?? challengeGrantId ?? grantId;
|
|
104
|
+
if (!opId || !isBytes32Hex(opId)) {
|
|
93
105
|
throw new PersonalServerReadError(
|
|
94
106
|
"Personal Server payment challenge used an invalid escrow op id",
|
|
95
107
|
402,
|
|
96
|
-
{ opId
|
|
108
|
+
{ opId }
|
|
97
109
|
);
|
|
98
110
|
}
|
|
99
|
-
if (
|
|
111
|
+
if (opId.toLowerCase() !== grantId.toLowerCase()) {
|
|
100
112
|
throw new PersonalServerReadError(
|
|
101
113
|
"Personal Server payment challenge did not match the requested grant",
|
|
102
114
|
402,
|
|
103
|
-
{ opId
|
|
115
|
+
{ opId, grantId }
|
|
104
116
|
);
|
|
105
117
|
}
|
|
118
|
+
return { opType: GRANT_OP_TYPE, opId };
|
|
119
|
+
}
|
|
120
|
+
function hasDataAccessMarker(body) {
|
|
121
|
+
if (stringField(body, "opType") === DATA_ACCESS_OP_TYPE) return true;
|
|
122
|
+
return Array.isArray(body.accepts) && body.accepts.some((value) => {
|
|
123
|
+
const accept = asRecord(value);
|
|
124
|
+
return stringField(asRecord(accept?.message), "opType") === DATA_ACCESS_OP_TYPE;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function parseCanonicalDataAccessAccept(value) {
|
|
128
|
+
const accept = asRecord(value);
|
|
129
|
+
const message = asRecord(accept?.message);
|
|
130
|
+
if (stringField(accept, "scheme") !== "vana-escrow-grant" || stringField(message, "opType") !== DATA_ACCESS_OP_TYPE) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const network = stringField(accept, "network");
|
|
134
|
+
const payerAddress = stringField(message, "payerAddress");
|
|
135
|
+
const opId = stringField(message, "opId");
|
|
136
|
+
const asset = stringField(message, "asset");
|
|
137
|
+
const amount = stringField(message, "amount");
|
|
138
|
+
const paymentNonce = stringField(message, "paymentNonce");
|
|
139
|
+
const accessRecord = parseAccessRecord(accept?.accessRecord);
|
|
140
|
+
const acceptAsset = stringField(accept, "asset");
|
|
141
|
+
const acceptAmount = stringField(accept, "amount");
|
|
142
|
+
if (!network || !payerAddress || !isAddressHex(payerAddress) || !opId || !isBytes32Hex(opId) || !asset || !isAddressHex(asset) || !amount || !isUint256Decimal(amount, true) || !paymentNonce || !isUint256Decimal(paymentNonce, false) || !accessRecord || !isValidDataAccessRecord(accessRecord) || payerAddress.toLowerCase() !== accessRecord.accessor.toLowerCase() || opId.toLowerCase() !== accessRecord.recordId.toLowerCase() || !acceptAsset || acceptAsset.toLowerCase() !== asset.toLowerCase() || acceptAmount !== amount) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
opType: DATA_ACCESS_OP_TYPE,
|
|
147
|
+
opId,
|
|
148
|
+
network,
|
|
149
|
+
paymentNonce,
|
|
150
|
+
accessRecord,
|
|
151
|
+
asset,
|
|
152
|
+
amount
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function parseCanonicalDataAccessPayment(params) {
|
|
156
|
+
const { body, grantId, raw } = params;
|
|
157
|
+
if (body.x402Version !== 1 || body.error !== "PAYMENT_REQUIRED") {
|
|
158
|
+
throw new PersonalServerReadError(
|
|
159
|
+
"Personal Server data-access payment response was not a canonical x402 challenge",
|
|
160
|
+
402
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
const operation = Array.isArray(body.accepts) ? body.accepts.map(parseCanonicalDataAccessAccept).find((candidate) => candidate !== null) : void 0;
|
|
164
|
+
if (!operation) {
|
|
165
|
+
return void 0;
|
|
166
|
+
}
|
|
167
|
+
return { grantId, raw, ...operation };
|
|
168
|
+
}
|
|
169
|
+
function preferredLegacyAccept(body) {
|
|
170
|
+
if (!Array.isArray(body.accepts)) return void 0;
|
|
171
|
+
return body.accepts.map(asRecord).find((accept) => {
|
|
172
|
+
const message = asRecord(accept?.message);
|
|
173
|
+
return stringField(accept, "scheme") === "vana-escrow-grant" && stringField(message, "opType") === GRANT_OP_TYPE;
|
|
174
|
+
});
|
|
106
175
|
}
|
|
107
176
|
async function buildPersonalServerDataReadRequest(params) {
|
|
108
177
|
const base = stripTrailingSlash(params.personalServerUrl);
|
|
@@ -128,32 +197,103 @@ async function parsePersonalServerPaymentRequired(res, grantId) {
|
|
|
128
197
|
raw = void 0;
|
|
129
198
|
}
|
|
130
199
|
const body = asRecord(raw) ?? {};
|
|
131
|
-
|
|
132
|
-
|
|
200
|
+
if (hasDataAccessMarker(body)) {
|
|
201
|
+
const dataAccessOperation = parseCanonicalDataAccessPayment({
|
|
202
|
+
body,
|
|
203
|
+
grantId,
|
|
204
|
+
raw
|
|
205
|
+
});
|
|
206
|
+
if (dataAccessOperation) return dataAccessOperation;
|
|
207
|
+
}
|
|
208
|
+
const hasAcceptsEnvelope = Object.prototype.hasOwnProperty.call(
|
|
209
|
+
body,
|
|
210
|
+
"accepts"
|
|
211
|
+
);
|
|
212
|
+
if (hasAcceptsEnvelope && (body.x402Version !== 1 || body.error !== "PAYMENT_REQUIRED")) {
|
|
213
|
+
throw new PersonalServerReadError(
|
|
214
|
+
"Personal Server grant payment response was not a canonical x402 challenge",
|
|
215
|
+
402
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
const accept = preferredLegacyAccept(body);
|
|
219
|
+
if (hasDataAccessMarker(body) && !accept) {
|
|
220
|
+
throw new PersonalServerReadError(
|
|
221
|
+
"Personal Server data-access payment challenge was untrusted or incomplete",
|
|
222
|
+
402
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
if (hasAcceptsEnvelope && !accept) {
|
|
226
|
+
throw new PersonalServerReadError(
|
|
227
|
+
"Personal Server grant payment challenge had no compatible escrow offer",
|
|
228
|
+
402
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
if (accept) {
|
|
232
|
+
const message = asRecord(accept.message);
|
|
233
|
+
const network = stringField(accept, "network");
|
|
234
|
+
const payerAddress = stringField(message, "payerAddress");
|
|
235
|
+
const opId = stringField(message, "opId");
|
|
236
|
+
const asset = stringField(message, "asset");
|
|
237
|
+
const amount = stringField(message, "amount");
|
|
238
|
+
const paymentNonce = stringField(message, "paymentNonce");
|
|
239
|
+
const acceptAsset = stringField(accept, "asset");
|
|
240
|
+
const acceptAmount = stringField(accept, "amount");
|
|
241
|
+
const accessRecord2 = parseAccessRecord(accept.accessRecord);
|
|
242
|
+
const hasAccessRecord = accept.accessRecord !== void 0;
|
|
243
|
+
if (!network || !payerAddress || !isAddressHex(payerAddress) || !opId || !isBytes32Hex(opId) || !asset || !isAddressHex(asset) || !amount || !isUint256Decimal(amount, true) || !paymentNonce || !isUint256Decimal(paymentNonce, false) || !acceptAsset || acceptAsset.toLowerCase() !== asset.toLowerCase() || acceptAmount !== amount || hasAccessRecord && (!accessRecord2 || !isValidDataAccessRecord(accessRecord2) || accessRecord2.accessor.toLowerCase() !== payerAddress.toLowerCase()) || amount === "0" && !accessRecord2) {
|
|
244
|
+
throw new PersonalServerReadError(
|
|
245
|
+
"Personal Server grant payment challenge was untrusted or incomplete",
|
|
246
|
+
402
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
const operation2 = parseLegacyGrantOperation({
|
|
250
|
+
challengeOpId: opId,
|
|
251
|
+
challengeOpType: stringField(message, "opType"),
|
|
252
|
+
grantId
|
|
253
|
+
});
|
|
254
|
+
return {
|
|
255
|
+
grantId,
|
|
256
|
+
...operation2,
|
|
257
|
+
network,
|
|
258
|
+
paymentNonce,
|
|
259
|
+
asset,
|
|
260
|
+
amount,
|
|
261
|
+
raw,
|
|
262
|
+
...accessRecord2 ? { accessRecord: accessRecord2 } : {}
|
|
263
|
+
};
|
|
264
|
+
}
|
|
133
265
|
const challengeGrantId = stringField(body, "grantId");
|
|
134
|
-
const challengeOpId = stringField(
|
|
135
|
-
const challengeOpType = stringField(
|
|
136
|
-
|
|
266
|
+
const challengeOpId = stringField(body, "opId");
|
|
267
|
+
const challengeOpType = stringField(body, "opType");
|
|
268
|
+
const accessRecord = parseAccessRecord(body.accessRecord);
|
|
269
|
+
const operation = parseLegacyGrantOperation({
|
|
137
270
|
challengeGrantId,
|
|
138
271
|
challengeOpId,
|
|
139
272
|
challengeOpType,
|
|
140
273
|
grantId
|
|
141
274
|
});
|
|
142
|
-
const amountValue = stringField(
|
|
143
|
-
|
|
275
|
+
const amountValue = stringField(body, "amount") ?? stringField(body, "maxAmountRequired") ?? "0";
|
|
276
|
+
const payment = {
|
|
144
277
|
grantId,
|
|
145
|
-
network: stringField(
|
|
146
|
-
paymentNonce: stringField(
|
|
147
|
-
|
|
148
|
-
asset: stringField(message, "asset") ?? stringField(body, "asset") ?? NATIVE_ASSET_ADDRESS,
|
|
278
|
+
network: stringField(body, "network"),
|
|
279
|
+
paymentNonce: stringField(body, "paymentNonce"),
|
|
280
|
+
asset: stringField(body, "asset") ?? NATIVE_ASSET_ADDRESS,
|
|
149
281
|
amount: amountValue,
|
|
150
282
|
raw
|
|
151
283
|
};
|
|
284
|
+
return {
|
|
285
|
+
...payment,
|
|
286
|
+
...operation,
|
|
287
|
+
...accessRecord ? { accessRecord } : {}
|
|
288
|
+
};
|
|
152
289
|
}
|
|
153
290
|
function hasPositiveAmount(amount) {
|
|
154
291
|
if (!/^\d+$/.test(amount)) return false;
|
|
155
292
|
return BigInt(amount) > 0n;
|
|
156
293
|
}
|
|
294
|
+
function isReceiptOnlyGrantAcknowledgment(required, payerAddress) {
|
|
295
|
+
return required.opType === GRANT_OP_TYPE && required.amount === "0" && required.accessRecord !== void 0 && isValidDataAccessRecord(required.accessRecord) && required.accessRecord.accessor.toLowerCase() === payerAddress.toLowerCase();
|
|
296
|
+
}
|
|
157
297
|
async function readPersonalServerData(params) {
|
|
158
298
|
const fetchFn = params.fetchFn ?? globalThis.fetch;
|
|
159
299
|
if (!fetchFn) {
|
|
@@ -193,9 +333,9 @@ async function readPersonalServerData(params) {
|
|
|
193
333
|
}
|
|
194
334
|
);
|
|
195
335
|
}
|
|
196
|
-
if (!hasPositiveAmount(required.amount)) {
|
|
336
|
+
if (required.opType === GRANT_OP_TYPE && !hasPositiveAmount(required.amount) && !isReceiptOnlyGrantAcknowledgment(required, params.payerAddress)) {
|
|
197
337
|
throw new PaymentRequiredError(
|
|
198
|
-
"Personal Server payment challenge
|
|
338
|
+
"Personal Server payment challenge included neither a positive amount nor a valid access receipt",
|
|
199
339
|
{
|
|
200
340
|
scope: params.scope,
|
|
201
341
|
grantId: required.grantId,
|
|
@@ -204,7 +344,7 @@ async function readPersonalServerData(params) {
|
|
|
204
344
|
}
|
|
205
345
|
);
|
|
206
346
|
}
|
|
207
|
-
const paymentHeader = await
|
|
347
|
+
const paymentHeader = await buildEscrowPaymentHeader({
|
|
208
348
|
payerAddress: params.payerAddress,
|
|
209
349
|
required,
|
|
210
350
|
config: params.escrow
|
|
@@ -241,7 +381,9 @@ async function readPersonalServerData(params) {
|
|
|
241
381
|
{ scope: params.scope, body: detail.slice(0, 500) }
|
|
242
382
|
);
|
|
243
383
|
}
|
|
244
|
-
payment =
|
|
384
|
+
payment = paymentResponseMetadataFromHeader(
|
|
385
|
+
res.headers.get("X-PAYMENT-RESPONSE")
|
|
386
|
+
);
|
|
245
387
|
return { data: await res.json(), payment };
|
|
246
388
|
}
|
|
247
389
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/direct/personal-server-read.ts"],"sourcesContent":["/**\n * Personal Server data-read request builder and the 402 -> escrow-pay -> retry loop.\n *\n * @remarks\n * The read targets the Personal Server data path (`/v1/data/{scope}`),\n * authenticates with a Web3Signed header (built on {@link buildWeb3SignedHeader}),\n * and — on `402 Payment Required` — settles the grant's data-access fee through\n * the DPv2 escrow gateway and retries once.\n *\n * The 402 body is parsed into a {@link PersonalServerPaymentRequired} (grant id,\n * asset, and amount owed), which drives the escrow settlement.\n *\n * @category Direct\n * @module direct/personal-server-read\n */\n\nimport { buildWeb3SignedHeader } from \"../auth/web3-signed-builder\";\nimport type { Web3SignedSignFn } from \"../auth/web3-signed-builder\";\nimport {\n NATIVE_ASSET_ADDRESS,\n type EscrowAccessRecord,\n} from \"../protocol/escrow\";\nimport {\n buildGrantPaymentHeader,\n GRANT_OP_TYPE,\n paymentReceiptFromHeader,\n type EscrowPaymentConfig,\n} from \"./escrow-payment\";\nimport { PaymentRequiredError, PersonalServerReadError } from \"./errors\";\nimport type {\n DirectPaymentReceipt,\n PersonalServerPaymentRequired,\n} from \"./types\";\n\n/** Minimal `Response`-like shape so the read loop is testable without a DOM. */\nexport interface FetchResponseLike {\n ok: boolean;\n status: number;\n statusText: string;\n headers: { get(name: string): string | null };\n json(): Promise<unknown>;\n text(): Promise<string>;\n}\n\n/** Minimal `fetch` signature accepted by {@link readPersonalServerData}. */\nexport type PersonalServerFetch = (\n input: string,\n init: {\n method: string;\n headers: Record<string, string>;\n },\n) => Promise<FetchResponseLike>;\n\n/** A built, ready-to-send Personal Server data read request. */\nexport interface PersonalServerDataReadRequest {\n /** Absolute URL of the read endpoint. */\n url: string;\n /** HTTP method (always `\"GET\"`). */\n method: \"GET\";\n /** Request path used in the Web3Signed `uri` claim (e.g. `/v1/data/{scope}`). */\n path: string;\n /** Headers including the Web3Signed `Authorization` value. */\n headers: Record<string, string>;\n}\n\n/**\n * Transport-level retry knobs for {@link readPersonalServerData}.\n *\n * @remarks\n * Applies only when the underlying `fetch` **throws** (connection reset, DNS,\n * socket died mid-handshake — the browser-PS relay drop window). A received\n * HTTP response is never retried here: 402 has its own payment loop and other\n * statuses are surfaced to the caller unchanged.\n */\nexport interface PersonalServerTransportRetryOptions {\n /** Total attempts including the first (default 3). `1` disables retries. */\n attempts?: number;\n /** Delay before the first retry (ms); doubles per retry (default 1_000). */\n initialDelayMs?: number;\n /** Cap on the between-retry delay (ms, default 5_000). */\n maxDelayMs?: number;\n}\n\nconst TRANSPORT_RETRY_DEFAULTS: Required<PersonalServerTransportRetryOptions> =\n {\n attempts: 3,\n initialDelayMs: 1_000,\n maxDelayMs: 5_000,\n };\n\n/** Clamp a caller-supplied attempt count to a finite integer >= 1. */\nfunction resolveAttempts(attempts: number): number {\n return Number.isFinite(attempts) ? Math.max(1, Math.floor(attempts)) : 1;\n}\n\n/** An aborted request is the caller's intent to stop — never retry it. */\nfunction isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === \"AbortError\";\n}\n\nconst sleep = (ms: number) =>\n new Promise<void>((resolve) => setTimeout(resolve, ms));\n\n/**\n * Run a fetch with bounded transport retries.\n *\n * Each attempt rebuilds the request via `buildRequest` so the Web3Signed\n * header is freshly signed (local app-key signature — cheap), while letting\n * the caller pin anything that must NOT be regenerated across attempts\n * (an already-signed `X-PAYMENT` header keeps its paymentNonce, so a retry\n * can never mint a second escrow payment for the same read).\n */\nasync function fetchWithTransportRetry(\n fetchFn: PersonalServerFetch,\n buildRequest: () => Promise<{\n url: string;\n method: string;\n headers: Record<string, string>;\n }>,\n retry: Required<PersonalServerTransportRetryOptions>,\n): Promise<FetchResponseLike> {\n const attempts = resolveAttempts(retry.attempts);\n let lastError: unknown;\n for (let attempt = 0; attempt < attempts; attempt += 1) {\n if (attempt > 0) {\n await sleep(\n Math.min(retry.maxDelayMs, retry.initialDelayMs * 2 ** (attempt - 1)),\n );\n }\n const request = await buildRequest();\n try {\n return await fetchFn(request.url, {\n method: request.method,\n headers: request.headers,\n });\n } catch (error) {\n // An abort is a deliberate cancellation, not a flaky tunnel — surface it\n // immediately instead of burning attempts (and backoff) on it.\n if (isAbortError(error)) {\n throw error;\n }\n lastError = error;\n }\n }\n throw lastError;\n}\n\n/** Outcome of {@link readPersonalServerData}: the payload plus optional receipt. */\nexport interface PersonalServerReadResult {\n /** The decoded JSON payload returned by the Personal Server. */\n data: unknown;\n /** Present only when this read required (and settled) a payment. */\n payment?: DirectPaymentReceipt;\n}\n\nfunction stripTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\n/** Compute the data path for a scope (`/v1/data/{scope}`). */\nexport function dataPathForScope(scope: string): string {\n return `/v1/data/${encodeURIComponent(scope)}`;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction stringField(\n record: Record<string, unknown> | undefined,\n field: string,\n): string | undefined {\n const value = record?.[field];\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction parseAccessRecord(value: unknown): EscrowAccessRecord | undefined {\n const record = asRecord(value);\n const dataPointId = stringField(record, \"dataPointId\");\n const version = stringField(record, \"version\");\n const accessor = stringField(record, \"accessor\");\n const recordId = stringField(record, \"recordId\");\n const signature = stringField(record, \"signature\");\n\n if (!dataPointId || !version || !accessor || !recordId || !signature) {\n return undefined;\n }\n\n return {\n dataPointId: dataPointId as `0x${string}`,\n version,\n accessor: accessor as `0x${string}`,\n recordId: recordId as `0x${string}`,\n signature: signature as `0x${string}`,\n };\n}\n\nfunction isBytes32Hex(value: string): boolean {\n return /^0x[0-9a-fA-F]{64}$/.test(value);\n}\n\nfunction assertChallengeMatchesGrant(params: {\n challengeGrantId?: string;\n challengeOpId?: string;\n challengeOpType?: string;\n grantId: string;\n}): void {\n const { challengeGrantId, challengeOpId, challengeOpType, grantId } = params;\n\n if (challengeOpType && challengeOpType !== GRANT_OP_TYPE) {\n throw new PersonalServerReadError(\n \"Personal Server payment challenge used an unsupported escrow op type\",\n 402,\n { opType: challengeOpType },\n );\n }\n\n const challengedGrantId = challengeOpId ?? challengeGrantId;\n if (!challengedGrantId) return;\n\n if (!isBytes32Hex(challengedGrantId)) {\n throw new PersonalServerReadError(\n \"Personal Server payment challenge used an invalid escrow op id\",\n 402,\n { opId: challengedGrantId },\n );\n }\n\n if (challengedGrantId.toLowerCase() !== grantId.toLowerCase()) {\n throw new PersonalServerReadError(\n \"Personal Server payment challenge did not match the requested grant\",\n 402,\n { opId: challengedGrantId, grantId },\n );\n }\n}\n\n/**\n * Build a Web3Signed-authenticated Personal Server data read request.\n *\n * @param params - Personal Server URL, scope, grant id, and an EIP-191 signer.\n * @returns The request URL, method, path, and headers (including `Authorization`).\n */\nexport async function buildPersonalServerDataReadRequest(params: {\n /** Base URL of the user's Personal Server. */\n personalServerUrl: string;\n /** Scope to read (e.g. `\"icloud_notes.notes\"`). */\n scope: string;\n /** Grant id authorizing the read. */\n grantId: string;\n /** EIP-191 signer for the Web3Signed header (the app key). */\n signMessage: Web3SignedSignFn;\n}): Promise<PersonalServerDataReadRequest> {\n const base = stripTrailingSlash(params.personalServerUrl);\n const path = dataPathForScope(params.scope);\n const authorization = await buildWeb3SignedHeader({\n signMessage: params.signMessage,\n aud: base,\n method: \"GET\",\n uri: path,\n grantId: params.grantId,\n });\n const headers: Record<string, string> = {\n Authorization: authorization,\n Accept: \"application/json\",\n };\n return { url: `${base}${path}`, method: \"GET\", path, headers };\n}\n\n/**\n * Parse a `402 Payment Required` body into a {@link PersonalServerPaymentRequired}.\n *\n * @remarks\n * Accepts a few field spellings and falls back to the read's own grantId and the\n * native asset when a field is absent.\n *\n * @param res - The 402 response.\n * @param grantId - The grant id of the read (default `opId`).\n * @returns The parsed payment requirement.\n */\nexport async function parsePersonalServerPaymentRequired(\n res: FetchResponseLike,\n grantId: string,\n): Promise<PersonalServerPaymentRequired> {\n let raw: unknown = undefined;\n try {\n raw = await res.json();\n } catch {\n raw = undefined;\n }\n const body = asRecord(raw) ?? {};\n const accept =\n Array.isArray(body.accepts) && body.accepts.length > 0\n ? asRecord(body.accepts[0])\n : undefined;\n const message = asRecord(accept?.message);\n const challengeGrantId = stringField(body, \"grantId\");\n const challengeOpId =\n stringField(message, \"opId\") ?? stringField(body, \"opId\");\n const challengeOpType =\n stringField(message, \"opType\") ?? stringField(body, \"opType\");\n\n assertChallengeMatchesGrant({\n challengeGrantId,\n challengeOpId,\n challengeOpType,\n grantId,\n });\n\n const amountValue =\n stringField(message, \"amount\") ??\n stringField(body, \"amount\") ??\n stringField(body, \"maxAmountRequired\") ??\n \"0\";\n return {\n grantId,\n network: stringField(accept, \"network\") ?? stringField(body, \"network\"),\n paymentNonce:\n stringField(message, \"paymentNonce\") ?? stringField(body, \"paymentNonce\"),\n accessRecord: parseAccessRecord(accept?.accessRecord ?? body.accessRecord),\n asset:\n stringField(message, \"asset\") ??\n stringField(body, \"asset\") ??\n NATIVE_ASSET_ADDRESS,\n amount: amountValue,\n raw,\n };\n}\n\nfunction hasPositiveAmount(amount: string): boolean {\n if (!/^\\d+$/.test(amount)) return false;\n return BigInt(amount) > 0n;\n}\n\n/**\n * Read approved data from a Personal Server, settling a 402 via escrow.\n *\n * @remarks\n * Sends a Web3Signed-authenticated `GET /v1/data/{scope}`. On `402`, parses what\n * is owed, authorizes an escrow payment for the grant via `escrow`, and retries\n * once. If escrow is not configured, throws {@link PaymentRequiredError} carrying\n * the parsed requirement so callers can debug amount/asset.\n *\n * Transport failures (fetch throwing — the browser-PS relay reconnect window)\n * are retried with backoff per `transportRetry` (default 3 attempts). The paid\n * retry reuses the already-signed `X-PAYMENT` header, so transport retries can\n * never double-pay.\n *\n * @param params - Connection details, app signer, optional escrow config and fetch.\n * @returns `{ data, payment? }`.\n */\nexport async function readPersonalServerData(params: {\n personalServerUrl: string;\n scope: string;\n grantId: string;\n payerAddress: `0x${string}`;\n signMessage: Web3SignedSignFn;\n escrow?: EscrowPaymentConfig;\n fetchFn?: PersonalServerFetch;\n transportRetry?: PersonalServerTransportRetryOptions;\n}): Promise<PersonalServerReadResult> {\n const fetchFn =\n params.fetchFn ?? (globalThis.fetch as unknown as PersonalServerFetch);\n if (!fetchFn) {\n throw new PersonalServerReadError(\n \"No fetch implementation available for Personal Server read\",\n );\n }\n const transportRetry = {\n ...TRANSPORT_RETRY_DEFAULTS,\n ...params.transportRetry,\n };\n\n const buildRequest = () =>\n buildPersonalServerDataReadRequest({\n personalServerUrl: params.personalServerUrl,\n scope: params.scope,\n grantId: params.grantId,\n signMessage: params.signMessage,\n });\n\n let res = await fetchWithTransportRetry(\n fetchFn,\n buildRequest,\n transportRetry,\n );\n\n let payment: DirectPaymentReceipt | undefined;\n\n if (res.status === 402) {\n const required = await parsePersonalServerPaymentRequired(\n res,\n params.grantId,\n );\n if (!params.escrow) {\n throw new PaymentRequiredError(\n \"Personal Server requires payment but no escrow config is set\",\n {\n scope: params.scope,\n grantId: required.grantId,\n asset: required.asset,\n amount: required.amount,\n },\n );\n }\n\n if (!hasPositiveAmount(required.amount)) {\n throw new PaymentRequiredError(\n \"Personal Server payment challenge did not include a positive amount\",\n {\n scope: params.scope,\n grantId: required.grantId,\n asset: required.asset,\n amount: required.amount,\n },\n );\n }\n\n const paymentHeader = await buildGrantPaymentHeader({\n payerAddress: params.payerAddress,\n required,\n config: params.escrow,\n });\n\n // Re-sign and retry with x402 payment proof for the Personal Server to\n // validate. The payment header is built exactly once: transport retries\n // below re-sign only the Web3Signed auth and resend the SAME X-PAYMENT\n // (same paymentNonce), so a dropped tunnel cannot mint a second payment.\n res = await fetchWithTransportRetry(\n fetchFn,\n async () => {\n const retry = await buildRequest();\n return {\n ...retry,\n headers: { ...retry.headers, \"X-PAYMENT\": paymentHeader },\n };\n },\n transportRetry,\n );\n\n if (res.status === 402) {\n throw new PaymentRequiredError(\n \"Personal Server still requires payment after escrow settlement\",\n {\n scope: params.scope,\n grantId: required.grantId,\n asset: required.asset,\n amount: required.amount,\n payment,\n },\n );\n }\n }\n\n if (!res.ok) {\n const detail = await res.text().catch(() => \"\");\n throw new PersonalServerReadError(\n `Personal Server read failed: ${res.status} ${res.statusText}`,\n res.status,\n { scope: params.scope, body: detail.slice(0, 500) },\n );\n }\n\n payment = paymentReceiptFromHeader(res.headers.get(\"X-PAYMENT-RESPONSE\"));\n return { data: await res.json(), payment };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/direct/personal-server-read.ts"],"sourcesContent":["/**\n * Personal Server data-read request builder and the 402 -> escrow-pay -> retry loop.\n *\n * @remarks\n * The read targets the Personal Server data path (`/v1/data/{scope}`),\n * authenticates with a Web3Signed header (built on {@link buildWeb3SignedHeader}),\n * and — on `402 Payment Required` — signs the challenged escrow operation and\n * retries once.\n *\n * The 402 body is parsed into a validated grant or receipt-bound data-access\n * operation, which drives the escrow settlement.\n *\n * @category Direct\n * @module direct/personal-server-read\n */\n\nimport { buildWeb3SignedHeader } from \"../auth/web3-signed-builder\";\nimport type { Web3SignedSignFn } from \"../auth/web3-signed-builder\";\nimport {\n NATIVE_ASSET_ADDRESS,\n type EscrowAccessRecord,\n} from \"../protocol/escrow\";\nimport {\n buildEscrowPaymentHeader,\n DATA_ACCESS_OP_TYPE,\n GRANT_OP_TYPE,\n paymentResponseMetadataFromHeader,\n type EscrowPaymentHeaderConfig,\n} from \"./escrow-payment\";\nimport { PaymentRequiredError, PersonalServerReadError } from \"./errors\";\nimport type {\n DirectPaymentResponseMetadata,\n PersonalServerDataAccessPaymentOperation,\n PersonalServerPaymentOperation,\n} from \"./types\";\n\n/** Minimal `Response`-like shape so the read loop is testable without a DOM. */\nexport interface FetchResponseLike {\n ok: boolean;\n status: number;\n statusText: string;\n headers: { get(name: string): string | null };\n json(): Promise<unknown>;\n text(): Promise<string>;\n}\n\n/** Minimal `fetch` signature accepted by {@link readPersonalServerData}. */\nexport type PersonalServerFetch = (\n input: string,\n init: {\n method: string;\n headers: Record<string, string>;\n },\n) => Promise<FetchResponseLike>;\n\n/** A built, ready-to-send Personal Server data read request. */\nexport interface PersonalServerDataReadRequest {\n /** Absolute URL of the read endpoint. */\n url: string;\n /** HTTP method (always `\"GET\"`). */\n method: \"GET\";\n /** Request path used in the Web3Signed `uri` claim (e.g. `/v1/data/{scope}`). */\n path: string;\n /** Headers including the Web3Signed `Authorization` value. */\n headers: Record<string, string>;\n}\n\n/**\n * Transport-level retry knobs for {@link readPersonalServerData}.\n *\n * @remarks\n * Applies only when the underlying `fetch` **throws** (connection reset, DNS,\n * socket died mid-handshake — the browser-PS relay drop window). A received\n * HTTP response is never retried here: 402 has its own payment loop and other\n * statuses are surfaced to the caller unchanged.\n */\nexport interface PersonalServerTransportRetryOptions {\n /** Total attempts including the first (default 3). `1` disables retries. */\n attempts?: number;\n /** Delay before the first retry (ms); doubles per retry (default 1_000). */\n initialDelayMs?: number;\n /** Cap on the between-retry delay (ms, default 5_000). */\n maxDelayMs?: number;\n}\n\nconst TRANSPORT_RETRY_DEFAULTS: Required<PersonalServerTransportRetryOptions> =\n {\n attempts: 3,\n initialDelayMs: 1_000,\n maxDelayMs: 5_000,\n };\n\n/** Clamp a caller-supplied attempt count to a finite integer >= 1. */\nfunction resolveAttempts(attempts: number): number {\n return Number.isFinite(attempts) ? Math.max(1, Math.floor(attempts)) : 1;\n}\n\n/** An aborted request is the caller's intent to stop — never retry it. */\nfunction isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === \"AbortError\";\n}\n\nconst sleep = (ms: number) =>\n new Promise<void>((resolve) => setTimeout(resolve, ms));\n\n/**\n * Run a fetch with bounded transport retries.\n *\n * Each attempt rebuilds the request via `buildRequest` so the Web3Signed\n * header is freshly signed (local app-key signature — cheap), while letting\n * the caller pin anything that must NOT be regenerated across attempts\n * (an already-signed `X-PAYMENT` header keeps its paymentNonce, so a retry\n * can never mint a second escrow payment for the same read).\n */\nasync function fetchWithTransportRetry(\n fetchFn: PersonalServerFetch,\n buildRequest: () => Promise<{\n url: string;\n method: string;\n headers: Record<string, string>;\n }>,\n retry: Required<PersonalServerTransportRetryOptions>,\n): Promise<FetchResponseLike> {\n const attempts = resolveAttempts(retry.attempts);\n let lastError: unknown;\n for (let attempt = 0; attempt < attempts; attempt += 1) {\n if (attempt > 0) {\n await sleep(\n Math.min(retry.maxDelayMs, retry.initialDelayMs * 2 ** (attempt - 1)),\n );\n }\n const request = await buildRequest();\n try {\n return await fetchFn(request.url, {\n method: request.method,\n headers: request.headers,\n });\n } catch (error) {\n // An abort is a deliberate cancellation, not a flaky tunnel — surface it\n // immediately instead of burning attempts (and backoff) on it.\n if (isAbortError(error)) {\n throw error;\n }\n lastError = error;\n }\n }\n throw lastError;\n}\n\n/** Outcome of {@link readPersonalServerData}. */\nexport interface PersonalServerReadResult {\n /** The decoded JSON payload returned by the Personal Server. */\n data: unknown;\n /**\n * Shape-validated but unauthenticated payment metadata echoed by the\n * Personal Server. Never treat this field as accounting proof.\n */\n payment?: DirectPaymentResponseMetadata;\n}\n\nfunction stripTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\n/** Compute the data path for a scope (`/v1/data/{scope}`). */\nexport function dataPathForScope(scope: string): string {\n return `/v1/data/${encodeURIComponent(scope)}`;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction stringField(\n record: Record<string, unknown> | undefined,\n field: string,\n): string | undefined {\n const value = record?.[field];\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction parseAccessRecord(value: unknown): EscrowAccessRecord | undefined {\n const record = asRecord(value);\n const dataPointId = stringField(record, \"dataPointId\");\n const version = stringField(record, \"version\");\n const accessor = stringField(record, \"accessor\");\n const recordId = stringField(record, \"recordId\");\n const signature = stringField(record, \"signature\");\n\n if (!dataPointId || !version || !accessor || !recordId || !signature) {\n return undefined;\n }\n\n return {\n dataPointId: dataPointId as `0x${string}`,\n version,\n accessor: accessor as `0x${string}`,\n recordId: recordId as `0x${string}`,\n signature: signature as `0x${string}`,\n };\n}\n\nfunction isBytes32Hex(value: string): boolean {\n return /^0x[0-9a-fA-F]{64}$/.test(value);\n}\n\nconst UINT256_MAX = (1n << 256n) - 1n;\n\nfunction isAddressHex(value: string): boolean {\n return /^0x[0-9a-fA-F]{40}$/.test(value);\n}\n\nfunction isUint256Decimal(value: string, allowZero: boolean): boolean {\n const pattern = allowZero ? /^(0|[1-9]\\d*)$/ : /^[1-9]\\d*$/;\n return (\n value.length <= UINT256_MAX.toString().length &&\n pattern.test(value) &&\n BigInt(value) <= UINT256_MAX\n );\n}\n\nfunction isValidDataAccessRecord(record: EscrowAccessRecord): boolean {\n return (\n isBytes32Hex(record.dataPointId) &&\n isUint256Decimal(record.version, false) &&\n isAddressHex(record.accessor) &&\n isBytes32Hex(record.recordId) &&\n /^0x[0-9a-fA-F]{130}$/.test(record.signature)\n );\n}\n\nfunction parseLegacyGrantOperation(params: {\n challengeGrantId?: string;\n challengeOpId?: string;\n challengeOpType?: string;\n grantId: string;\n}): { opType: typeof GRANT_OP_TYPE; opId: string } {\n const { challengeGrantId, challengeOpId, challengeOpType, grantId } = params;\n\n const opType = challengeOpType ?? GRANT_OP_TYPE;\n if (opType !== GRANT_OP_TYPE) {\n throw new PersonalServerReadError(\n \"Personal Server payment challenge used an unsupported escrow op type\",\n 402,\n { opType: challengeOpType },\n );\n }\n\n const opId = challengeOpId ?? challengeGrantId ?? grantId;\n\n if (!opId || !isBytes32Hex(opId)) {\n throw new PersonalServerReadError(\n \"Personal Server payment challenge used an invalid escrow op id\",\n 402,\n { opId },\n );\n }\n\n if (opId.toLowerCase() !== grantId.toLowerCase()) {\n throw new PersonalServerReadError(\n \"Personal Server payment challenge did not match the requested grant\",\n 402,\n { opId, grantId },\n );\n }\n\n return { opType: GRANT_OP_TYPE, opId };\n}\n\nfunction hasDataAccessMarker(body: Record<string, unknown>): boolean {\n if (stringField(body, \"opType\") === DATA_ACCESS_OP_TYPE) return true;\n return (\n Array.isArray(body.accepts) &&\n body.accepts.some((value) => {\n const accept = asRecord(value);\n return (\n stringField(asRecord(accept?.message), \"opType\") === DATA_ACCESS_OP_TYPE\n );\n })\n );\n}\n\nfunction parseCanonicalDataAccessAccept(\n value: unknown,\n): Omit<PersonalServerDataAccessPaymentOperation, \"grantId\" | \"raw\"> | null {\n const accept = asRecord(value);\n const message = asRecord(accept?.message);\n if (\n stringField(accept, \"scheme\") !== \"vana-escrow-grant\" ||\n stringField(message, \"opType\") !== DATA_ACCESS_OP_TYPE\n ) {\n return null;\n }\n\n const network = stringField(accept, \"network\");\n const payerAddress = stringField(message, \"payerAddress\");\n const opId = stringField(message, \"opId\");\n const asset = stringField(message, \"asset\");\n const amount = stringField(message, \"amount\");\n const paymentNonce = stringField(message, \"paymentNonce\");\n const accessRecord = parseAccessRecord(accept?.accessRecord);\n const acceptAsset = stringField(accept, \"asset\");\n const acceptAmount = stringField(accept, \"amount\");\n\n if (\n !network ||\n !payerAddress ||\n !isAddressHex(payerAddress) ||\n !opId ||\n !isBytes32Hex(opId) ||\n !asset ||\n !isAddressHex(asset) ||\n !amount ||\n !isUint256Decimal(amount, true) ||\n !paymentNonce ||\n !isUint256Decimal(paymentNonce, false) ||\n !accessRecord ||\n !isValidDataAccessRecord(accessRecord) ||\n payerAddress.toLowerCase() !== accessRecord.accessor.toLowerCase() ||\n opId.toLowerCase() !== accessRecord.recordId.toLowerCase() ||\n !acceptAsset ||\n acceptAsset.toLowerCase() !== asset.toLowerCase() ||\n acceptAmount !== amount\n ) {\n return null;\n }\n\n return {\n opType: DATA_ACCESS_OP_TYPE,\n opId,\n network,\n paymentNonce,\n accessRecord,\n asset,\n amount,\n };\n}\n\nfunction parseCanonicalDataAccessPayment(params: {\n body: Record<string, unknown>;\n grantId: string;\n raw: unknown;\n}): PersonalServerDataAccessPaymentOperation | undefined {\n const { body, grantId, raw } = params;\n if (body.x402Version !== 1 || body.error !== \"PAYMENT_REQUIRED\") {\n throw new PersonalServerReadError(\n \"Personal Server data-access payment response was not a canonical x402 challenge\",\n 402,\n );\n }\n\n const operation = Array.isArray(body.accepts)\n ? body.accepts\n .map(parseCanonicalDataAccessAccept)\n .find((candidate) => candidate !== null)\n : undefined;\n if (!operation) {\n return undefined;\n }\n\n return { grantId, raw, ...operation };\n}\n\nfunction preferredLegacyAccept(body: Record<string, unknown>) {\n if (!Array.isArray(body.accepts)) return undefined;\n return body.accepts.map(asRecord).find((accept) => {\n const message = asRecord(accept?.message);\n return (\n stringField(accept, \"scheme\") === \"vana-escrow-grant\" &&\n stringField(message, \"opType\") === GRANT_OP_TYPE\n );\n });\n}\n\n/**\n * Build a Web3Signed-authenticated Personal Server data read request.\n *\n * @param params - Personal Server URL, scope, grant id, and an EIP-191 signer.\n * @returns The request URL, method, path, and headers (including `Authorization`).\n */\nexport async function buildPersonalServerDataReadRequest(params: {\n /** Base URL of the user's Personal Server. */\n personalServerUrl: string;\n /** Scope to read (e.g. `\"icloud_notes.notes\"`). */\n scope: string;\n /** Grant id authorizing the read. */\n grantId: string;\n /** EIP-191 signer for the Web3Signed header (the app key). */\n signMessage: Web3SignedSignFn;\n}): Promise<PersonalServerDataReadRequest> {\n const base = stripTrailingSlash(params.personalServerUrl);\n const path = dataPathForScope(params.scope);\n const authorization = await buildWeb3SignedHeader({\n signMessage: params.signMessage,\n aud: base,\n method: \"GET\",\n uri: path,\n grantId: params.grantId,\n });\n const headers: Record<string, string> = {\n Authorization: authorization,\n Accept: \"application/json\",\n };\n return { url: `${base}${path}`, method: \"GET\", path, headers };\n}\n\n/**\n * Parse a `402 Payment Required` body into a validated payment operation.\n *\n * @remarks\n * Accepts a few field spellings and falls back to the read's own grantId and the\n * native asset when a field is absent from a legacy grant challenge.\n *\n * Receipt-bound `data_access` uses a fail-closed canonical path: one compatible\n * `accepts` entry must contain the scheme, network, message, and complete\n * receipt. Its positive uint256 `paymentNonce` is mandatory because the\n * Personal Server encodes challenge freshness in that nonce and checks it on\n * retry. This parser shape-validates the receipt and binds `opId` to `recordId`;\n * it does not recover or verify the server signature.\n *\n * @param res - The 402 response.\n * @param grantId - The grant id of the read (default legacy grant `opId`).\n * @returns The parsed payment requirement.\n */\nexport async function parsePersonalServerPaymentRequired(\n res: FetchResponseLike,\n grantId: string,\n): Promise<PersonalServerPaymentOperation> {\n let raw: unknown = undefined;\n try {\n raw = await res.json();\n } catch {\n raw = undefined;\n }\n const body = asRecord(raw) ?? {};\n if (hasDataAccessMarker(body)) {\n const dataAccessOperation = parseCanonicalDataAccessPayment({\n body,\n grantId,\n raw,\n });\n if (dataAccessOperation) return dataAccessOperation;\n }\n\n // Legacy grant challenges predate the canonical x402 envelope. Retain their\n // field fallbacks only for truly flat bodies. Once an accepts envelope is\n // present, validate its canonical framing and select only a compatible offer.\n const hasAcceptsEnvelope = Object.prototype.hasOwnProperty.call(\n body,\n \"accepts\",\n );\n if (\n hasAcceptsEnvelope &&\n (body.x402Version !== 1 || body.error !== \"PAYMENT_REQUIRED\")\n ) {\n throw new PersonalServerReadError(\n \"Personal Server grant payment response was not a canonical x402 challenge\",\n 402,\n );\n }\n const accept = preferredLegacyAccept(body);\n if (hasDataAccessMarker(body) && !accept) {\n throw new PersonalServerReadError(\n \"Personal Server data-access payment challenge was untrusted or incomplete\",\n 402,\n );\n }\n if (hasAcceptsEnvelope && !accept) {\n throw new PersonalServerReadError(\n \"Personal Server grant payment challenge had no compatible escrow offer\",\n 402,\n );\n }\n\n if (accept) {\n const message = asRecord(accept.message);\n const network = stringField(accept, \"network\");\n const payerAddress = stringField(message, \"payerAddress\");\n const opId = stringField(message, \"opId\");\n const asset = stringField(message, \"asset\");\n const amount = stringField(message, \"amount\");\n const paymentNonce = stringField(message, \"paymentNonce\");\n const acceptAsset = stringField(accept, \"asset\");\n const acceptAmount = stringField(accept, \"amount\");\n const accessRecord = parseAccessRecord(accept.accessRecord);\n const hasAccessRecord = accept.accessRecord !== undefined;\n if (\n !network ||\n !payerAddress ||\n !isAddressHex(payerAddress) ||\n !opId ||\n !isBytes32Hex(opId) ||\n !asset ||\n !isAddressHex(asset) ||\n !amount ||\n !isUint256Decimal(amount, true) ||\n !paymentNonce ||\n !isUint256Decimal(paymentNonce, false) ||\n !acceptAsset ||\n acceptAsset.toLowerCase() !== asset.toLowerCase() ||\n acceptAmount !== amount ||\n (hasAccessRecord &&\n (!accessRecord ||\n !isValidDataAccessRecord(accessRecord) ||\n accessRecord.accessor.toLowerCase() !==\n payerAddress.toLowerCase())) ||\n (amount === \"0\" && !accessRecord)\n ) {\n throw new PersonalServerReadError(\n \"Personal Server grant payment challenge was untrusted or incomplete\",\n 402,\n );\n }\n const operation = parseLegacyGrantOperation({\n challengeOpId: opId,\n challengeOpType: stringField(message, \"opType\"),\n grantId,\n });\n return {\n grantId,\n ...operation,\n network,\n paymentNonce,\n asset,\n amount,\n raw,\n ...(accessRecord ? { accessRecord } : {}),\n };\n }\n\n const challengeGrantId = stringField(body, \"grantId\");\n const challengeOpId = stringField(body, \"opId\");\n const challengeOpType = stringField(body, \"opType\");\n\n const accessRecord = parseAccessRecord(body.accessRecord);\n const operation = parseLegacyGrantOperation({\n challengeGrantId,\n challengeOpId,\n challengeOpType,\n grantId,\n });\n\n const amountValue =\n stringField(body, \"amount\") ??\n stringField(body, \"maxAmountRequired\") ??\n \"0\";\n const payment = {\n grantId,\n network: stringField(body, \"network\"),\n paymentNonce: stringField(body, \"paymentNonce\"),\n asset: stringField(body, \"asset\") ?? NATIVE_ASSET_ADDRESS,\n amount: amountValue,\n raw,\n };\n return {\n ...payment,\n ...operation,\n ...(accessRecord ? { accessRecord } : {}),\n };\n}\n\nfunction hasPositiveAmount(amount: string): boolean {\n if (!/^\\d+$/.test(amount)) return false;\n return BigInt(amount) > 0n;\n}\n\nfunction isReceiptOnlyGrantAcknowledgment(\n required: PersonalServerPaymentOperation,\n payerAddress: string,\n): boolean {\n return (\n required.opType === GRANT_OP_TYPE &&\n required.amount === \"0\" &&\n required.accessRecord !== undefined &&\n isValidDataAccessRecord(required.accessRecord) &&\n required.accessRecord.accessor.toLowerCase() === payerAddress.toLowerCase()\n );\n}\n\n/**\n * Read approved data from a Personal Server, settling a 402 via escrow.\n *\n * @remarks\n * Sends a Web3Signed-authenticated `GET /v1/data/{scope}`. On `402`, parses what\n * is owed, authorizes the challenged escrow operation, and retries once. If\n * escrow is not configured, throws {@link PaymentRequiredError} carrying the\n * parsed requirement so callers can debug amount/asset.\n *\n * Transport failures (fetch throwing — the browser-PS relay reconnect window)\n * are retried with backoff per `transportRetry` (default 3 attempts). The paid\n * retry reuses the already-signed `X-PAYMENT` header, so transport retries can\n * never double-pay.\n *\n * @param params - Connection details, app signer, optional escrow config and fetch.\n * @returns `{ data, payment? }`.\n */\nexport async function readPersonalServerData(params: {\n personalServerUrl: string;\n scope: string;\n grantId: string;\n payerAddress: `0x${string}`;\n signMessage: Web3SignedSignFn;\n escrow?: EscrowPaymentHeaderConfig;\n fetchFn?: PersonalServerFetch;\n transportRetry?: PersonalServerTransportRetryOptions;\n}): Promise<PersonalServerReadResult> {\n const fetchFn =\n params.fetchFn ?? (globalThis.fetch as unknown as PersonalServerFetch);\n if (!fetchFn) {\n throw new PersonalServerReadError(\n \"No fetch implementation available for Personal Server read\",\n );\n }\n const transportRetry = {\n ...TRANSPORT_RETRY_DEFAULTS,\n ...params.transportRetry,\n };\n\n const buildRequest = () =>\n buildPersonalServerDataReadRequest({\n personalServerUrl: params.personalServerUrl,\n scope: params.scope,\n grantId: params.grantId,\n signMessage: params.signMessage,\n });\n\n let res = await fetchWithTransportRetry(\n fetchFn,\n buildRequest,\n transportRetry,\n );\n\n let payment: DirectPaymentResponseMetadata | undefined;\n\n if (res.status === 402) {\n const required = await parsePersonalServerPaymentRequired(\n res,\n params.grantId,\n );\n if (!params.escrow) {\n throw new PaymentRequiredError(\n \"Personal Server requires payment but no escrow config is set\",\n {\n scope: params.scope,\n grantId: required.grantId,\n asset: required.asset,\n amount: required.amount,\n },\n );\n }\n\n if (\n required.opType === GRANT_OP_TYPE &&\n !hasPositiveAmount(required.amount) &&\n !isReceiptOnlyGrantAcknowledgment(required, params.payerAddress)\n ) {\n throw new PaymentRequiredError(\n \"Personal Server payment challenge included neither a positive amount nor a valid access receipt\",\n {\n scope: params.scope,\n grantId: required.grantId,\n asset: required.asset,\n amount: required.amount,\n },\n );\n }\n\n const paymentHeader = await buildEscrowPaymentHeader({\n payerAddress: params.payerAddress,\n required,\n config: params.escrow,\n });\n\n // Re-sign and retry with x402 payment proof for the Personal Server to\n // validate. The payment header is built exactly once: transport retries\n // below re-sign only the Web3Signed auth and resend the SAME X-PAYMENT\n // (same paymentNonce), so a dropped tunnel cannot mint a second payment.\n res = await fetchWithTransportRetry(\n fetchFn,\n async () => {\n const retry = await buildRequest();\n return {\n ...retry,\n headers: { ...retry.headers, \"X-PAYMENT\": paymentHeader },\n };\n },\n transportRetry,\n );\n\n if (res.status === 402) {\n throw new PaymentRequiredError(\n \"Personal Server still requires payment after escrow settlement\",\n {\n scope: params.scope,\n grantId: required.grantId,\n asset: required.asset,\n amount: required.amount,\n payment,\n },\n );\n }\n }\n\n if (!res.ok) {\n const detail = await res.text().catch(() => \"\");\n throw new PersonalServerReadError(\n `Personal Server read failed: ${res.status} ${res.statusText}`,\n res.status,\n { scope: params.scope, body: detail.slice(0, 500) },\n );\n }\n\n payment = paymentResponseMetadataFromHeader(\n res.headers.get(\"X-PAYMENT-RESPONSE\"),\n );\n return { data: await res.json(), payment };\n}\n"],"mappings":"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","names":["accessRecord","operation"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/direct/types.ts"],"sourcesContent":["import type { EscrowAccessRecord } from \"../protocol/escrow\";\nimport type { ProtocolNetwork } from \"../protocol/networks\";\n\n/**\n * Shared types for the Direct Data Controller and the browser connect helper.\n *\n * @remarks\n * These types describe the \"two-tab\" Data Portability flow documented in the\n * builder guide: a backend controller creates an access request, the browser\n * opens Vana for user approval, and the backend reads the approved data from\n * the user's Personal Server (handling 402 Payment Required).\n *\n * @category Direct\n * @module direct/types\n */\n\n/**\n * Target environment for a {@link DirectDataController}.\n *\n * - `\"production\"` — Vana mainnet stack (default service URLs).\n * - `\"dev\"` — Vana internal dev stack. Use only when testing against\n * Vana's dev infrastructure.\n */\nexport type DirectEnv = \"dev\" | \"production\";\n\n/**\n * Vana network used for chain-aware Direct defaults.\n *\n * - `\"mainnet\"` — Vana mainnet (`chainId` 1480).\n * - `\"moksha\"` — Moksha testnet (`chainId` 14800).\n */\nexport type DirectNetwork = ProtocolNetwork;\n\n/**\n * App identity advertised to users during approval and attributed in Builder\n * League activity reports.\n */\nexport interface DirectAppConfig {\n /** Stable, human-readable app id (e.g. `\"notes-lens\"`). */\n id: string;\n /** Display name shown to the user in the Vana approval UI. */\n name: string;\n /** Public homepage URL for the app. */\n homepageUrl: string;\n}\n\n/**\n * Resolved app identity: the configured {@link DirectAppConfig} plus the app's\n * derived on-chain address (the address to fund and inspect).\n */\nexport interface AppIdentity extends DirectAppConfig {\n /** The app's `0x`-prefixed on-chain address (derived from `appPrivateKey`). */\n address: string;\n}\n\n/**\n * Resolved service URLs and chain id for a given {@link DirectEnv}.\n *\n * @remarks\n * Centralizes the per-environment base URLs the controller talks to. Each can\n * be overridden via {@link DirectDataControllerConfig.endpoints} when pointing\n * at a non-standard deployment.\n */\nexport interface DirectServiceEndpoints {\n /** Vana chain id for this environment (1480 mainnet, 14800 moksha). */\n chainId: number;\n /** Base URL of the Vana Account access-request API that issues `dcr_*` ids. */\n accessRequestBaseUrl: string;\n /** Base URL users are sent to for approval (the Vana app). */\n approvalAppBaseUrl: string;\n /** Base URL of the DP RPC escrow gateway used to settle `402 Payment Required`. */\n escrowGatewayUrl: string;\n}\n\n/** Result of {@link DirectDataController.createAccessRequest}. */\nexport interface AccessRequest {\n /** Opaque request id (e.g. `\"dcr_123\"`). */\n requestId: string;\n /** URL the browser opens so the user can approve the requested scopes. */\n approvalUrl: string;\n /** On-chain address of the (registered or reused) app. */\n appAddress: string;\n}\n\n/**\n * Lifecycle status of an access request.\n *\n * @remarks\n * - `\"pending\"` — created, awaiting user approval.\n * - `\"approved\"` / `\"ready_for_read\"` — the grant exists and the Personal\n * Server is reachable; the data is read-ready (see {@link DirectDataController.readApprovedData}).\n * - `\"completed\"` — the app has already read the data and acknowledged it, so\n * the DCR is terminal. A `\"completed\"` request is **not** read-ready — the\n * browser Personal Server may no longer be serving it.\n * - `\"denied\"` / `\"expired\"` — terminal, no data was delivered.\n */\nexport type AccessRequestStatusValue =\n | \"pending\"\n | \"approved\"\n | \"ready_for_read\"\n | \"completed\"\n | \"denied\"\n | \"expired\";\n\n/** Result of {@link DirectDataController.getAccessRequestStatus}. */\nexport interface AccessRequestStatus {\n /** Current lifecycle status of the request. */\n status: AccessRequestStatusValue;\n /** Personal Server base URL — present once data is ready to read. */\n personalServerUrl?: string;\n /** Grant id covering the approved scope — present once data is ready to read. */\n grantId?: string;\n /** The approved scope — present once data is ready to read. */\n scope?: string;\n}\n\n/** Result of {@link DirectDataController.readApprovedData}. */\nexport interface ApprovedDataResult<T = unknown> {\n /** The scope the data was read for. */\n scope: string;\n /** The decoded payload returned by the Personal Server. */\n data: T;\n /**\n * Payment receipt — present only when this read required (and settled) a\n * payment. Lets builders inspect the amount, asset, and fee breakdown without\n * digging into the underlying 402/escrow exchange. Reads served from a paid-up\n * grant omit this field.\n */\n payment?: DirectPaymentReceipt;\n}\n\n/**\n * Client for the Vana Account access-request API — the service that turns a\n * registered app + scopes into a `dcr_*` id and approval URL.\n *\n * @remarks\n * The controller uses a default client against the Vana Account endpoints. You\n * can inject your own implementation to point at a custom deployment or to\n * supply a test double.\n */\nexport interface AccessRequestClient {\n /**\n * Create an access request for the given app + scopes.\n *\n * @param input - App identity, source, scopes, network, and the post-approval return URL.\n * @returns The created {@link AccessRequest}.\n */\n createAccessRequest(input: {\n appAddress: string;\n app: DirectAppConfig;\n source: string;\n scopes: string[];\n returnUrl: string;\n /** Vana protocol network for this request (`\"mainnet\"` or `\"moksha\"`). */\n network: DirectNetwork;\n }): Promise<AccessRequest>;\n\n /**\n * Fetch the current status of a previously created access request.\n *\n * @param requestId - The `dcr_*` id returned by {@link AccessRequestClient.createAccessRequest}.\n * @returns The current {@link AccessRequestStatus}.\n */\n getAccessRequestStatus(requestId: string): Promise<AccessRequestStatus>;\n\n /**\n * Acknowledge that the app successfully read the approved data.\n *\n * @remarks\n * Direct Vana Web DCRs remain in `ready_for_read` while the browser Personal\n * Server is serving the app. After a successful Personal Server read, the\n * controller calls this hook so Vana Web can mark the request completed and\n * close/redirect the approval tab.\n *\n * Optional so injected clients from older SDK integrations keep compiling;\n * the default HTTP client implements it.\n */\n acknowledgeRead?(requestId: string): Promise<void>;\n}\n\n/**\n * Op-type vocabulary used by the DPv2 escrow payment surface.\n *\n * @remarks\n * These are the operations the gateway prices and settles via\n * `POST /v1/escrow/pay` (`opType` field of the `GenericPayment` message). A\n * direct data read settles the {@link DirectOpType.DataAccess} op for the\n * approved grant; the other op types are listed here for completeness and to\n * give builders a typed vocabulary when inspecting fee breakdowns.\n *\n * Note: the escrow `GenericPayment` `opType` is currently `\"grant\"` on the wire\n * for grant lifecycle payments; this enum names the higher-level fee categories\n * the gateway reports in a {@link PaymentBreakdown}.\n */\nexport const DirectOpType = {\n GrantRegistration: \"grant_registration\",\n DataAccess: \"data_access\",\n DataRegistration: \"data_registration\",\n ServerRegistration: \"server_registration\",\n BuilderRegistration: \"builder_registration\",\n} as const;\n\n/** A direct-flow op type (see {@link DirectOpType}). */\nexport type DirectOpTypeValue =\n (typeof DirectOpType)[keyof typeof DirectOpType];\n\n/**\n * What a Personal Server `402 Payment Required` tells the controller is owed for\n * a data read.\n *\n * @remarks\n * The PS read 402 body identifies the grant to settle and the amount/asset. The\n * controller settles it via the DPv2 escrow gateway (`/v1/escrow/pay`). The full\n * unmodified body is preserved under {@link PersonalServerPaymentRequired.raw}.\n */\nexport interface PersonalServerPaymentRequired {\n /** Grant id to settle (the escrow `opId`). Defaults to the read's grantId. */\n grantId: string;\n /** X402 network advertised by the Personal Server challenge. */\n network?: string;\n /** Payment nonce requested by the 402 challenge. */\n paymentNonce?: string;\n /** Server-signed data access receipt requested by the 402 challenge. */\n accessRecord?: EscrowAccessRecord;\n /** Asset address owed (zero address = native VANA). */\n asset: string;\n /** Amount owed, as a decimal base-unit string (preserves uint256 precision). */\n amount: string;\n /** The full, unmodified 402 response body. */\n raw: unknown;\n}\n\n/**\n * Structured payment metadata attached to a successful paid read.\n *\n * @remarks\n * Derived from the gateway's {@link EscrowPayResult}. Lets builders debug the\n * amount, asset, and per-op fee breakdown without re-deriving anything from the\n * raw 402/payment exchange.\n */\nexport interface DirectPaymentReceipt {\n /** Op type settled (the gateway `opType`, e.g. `\"grant\"`). */\n opType: string;\n /** Op id settled (the grant id). */\n opId: string;\n /** Asset paid in (zero address = native VANA). */\n asset: string;\n /** Total amount paid, as a decimal base-unit string. */\n amount: string;\n /** Payment nonce used for this settlement. */\n paymentNonce: string;\n /** Fee breakdown reported by the gateway (registration vs data-access fee). */\n breakdown: DirectFeeBreakdown;\n /** ISO timestamp the gateway recorded the payment. */\n paidAt: string;\n}\n\n/**\n * Per-op fee breakdown reported by the gateway.\n *\n * @remarks\n * Mirrors the escrow {@link PaymentBreakdown}: a one-time registration fee plus\n * the per-read data-access fee, and whether this settlement covered the\n * registration fee.\n */\nexport interface DirectFeeBreakdown {\n /** One-time registration fee for the op, as a decimal base-unit string. */\n registrationFee: string;\n /** Per-read data-access fee, as a decimal base-unit string. */\n dataAccessFee: string;\n /** True when this settlement paid the registration fee. */\n registrationPaid: boolean;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAkMO,MAAM,eAAe;AAAA,EAC1B,mBAAmB;AAAA,EACnB,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,qBAAqB;AACvB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/direct/types.ts"],"sourcesContent":["import type { EscrowAccessRecord } from \"../protocol/escrow\";\nimport type { ProtocolNetwork } from \"../protocol/networks\";\n\n/**\n * Shared types for the Direct Data Controller and the browser connect helper.\n *\n * @remarks\n * These types describe the \"two-tab\" Data Portability flow documented in the\n * builder guide: a backend controller creates an access request, the browser\n * opens Vana for user approval, and the backend reads the approved data from\n * the user's Personal Server (handling 402 Payment Required).\n *\n * @category Direct\n * @module direct/types\n */\n\n/**\n * Target environment for a {@link DirectDataController}.\n *\n * - `\"production\"` — Vana mainnet stack (default service URLs).\n * - `\"dev\"` — Vana internal dev stack. Use only when testing against\n * Vana's dev infrastructure.\n */\nexport type DirectEnv = \"dev\" | \"production\";\n\n/**\n * Vana network used for chain-aware Direct defaults.\n *\n * - `\"mainnet\"` — Vana mainnet (`chainId` 1480).\n * - `\"moksha\"` — Moksha testnet (`chainId` 14800).\n */\nexport type DirectNetwork = ProtocolNetwork;\n\n/**\n * App identity advertised to users during approval and attributed in Builder\n * League activity reports.\n */\nexport interface DirectAppConfig {\n /** Stable, human-readable app id (e.g. `\"notes-lens\"`). */\n id: string;\n /** Display name shown to the user in the Vana approval UI. */\n name: string;\n /** Public homepage URL for the app. */\n homepageUrl: string;\n}\n\n/**\n * Resolved app identity: the configured {@link DirectAppConfig} plus the app's\n * derived on-chain address (the address to fund and inspect).\n */\nexport interface AppIdentity extends DirectAppConfig {\n /** The app's `0x`-prefixed on-chain address (derived from `appPrivateKey`). */\n address: string;\n}\n\n/**\n * Resolved service URLs and chain id for a given {@link DirectEnv}.\n *\n * @remarks\n * Centralizes the per-environment base URLs the controller talks to. Each can\n * be overridden via {@link DirectDataControllerConfig.endpoints} when pointing\n * at a non-standard deployment.\n */\nexport interface DirectServiceEndpoints {\n /** Vana chain id for this environment (1480 mainnet, 14800 moksha). */\n chainId: number;\n /** Base URL of the Vana Account access-request API that issues `dcr_*` ids. */\n accessRequestBaseUrl: string;\n /** Base URL users are sent to for approval (the Vana app). */\n approvalAppBaseUrl: string;\n /** Base URL of the DP RPC escrow gateway used to settle `402 Payment Required`. */\n escrowGatewayUrl: string;\n}\n\n/** Result of {@link DirectDataController.createAccessRequest}. */\nexport interface AccessRequest {\n /** Opaque request id (e.g. `\"dcr_123\"`). */\n requestId: string;\n /** URL the browser opens so the user can approve the requested scopes. */\n approvalUrl: string;\n /** On-chain address of the (registered or reused) app. */\n appAddress: string;\n}\n\n/**\n * Lifecycle status of an access request.\n *\n * @remarks\n * - `\"pending\"` — created, awaiting user approval.\n * - `\"approved\"` / `\"ready_for_read\"` — the grant exists and the Personal\n * Server is reachable; the data is read-ready (see {@link DirectDataController.readApprovedData}).\n * - `\"completed\"` — the app has already read the data and acknowledged it, so\n * the DCR is terminal. A `\"completed\"` request is **not** read-ready — the\n * browser Personal Server may no longer be serving it.\n * - `\"denied\"` / `\"expired\"` — terminal, no data was delivered.\n */\nexport type AccessRequestStatusValue =\n | \"pending\"\n | \"approved\"\n | \"ready_for_read\"\n | \"completed\"\n | \"denied\"\n | \"expired\";\n\n/** Result of {@link DirectDataController.getAccessRequestStatus}. */\nexport interface AccessRequestStatus {\n /** Current lifecycle status of the request. */\n status: AccessRequestStatusValue;\n /** Personal Server base URL — present once data is ready to read. */\n personalServerUrl?: string;\n /** Grant id covering the approved scope — present once data is ready to read. */\n grantId?: string;\n /**\n * The first approved scope — present once data is ready to read.\n *\n * @remarks\n * Kept for backwards compatibility. A request can approve many scopes; read\n * {@link AccessRequestStatus.scopes} to see all of them.\n */\n scope?: string;\n /**\n * Every scope the user approved on this request — present once data is ready\n * to read.\n *\n * @remarks\n * A grant is keyed by `(user, app)` and carries a list of scopes, so a single\n * approval can cover several. Against an older Vana Account deployment that\n * only returns `scope`, this falls back to `[scope]`.\n */\n scopes?: string[];\n}\n\n/** Result of {@link DirectDataController.readApprovedData}. */\nexport interface ApprovedDataResult<T = unknown> {\n /** The scope the data was read for. */\n scope: string;\n /** The decoded payload returned by the Personal Server. */\n data: T;\n /**\n * Shape-validated but unauthenticated payment metadata echoed by the\n * Personal Server. Use for display/debugging, not accounting proof.\n */\n payment?: DirectPaymentResponseMetadata;\n}\n\n/**\n * Result of {@link DirectDataController.readApprovedData} across every approved\n * scope.\n *\n * @remarks\n * Successes and failures are reported side by side rather than as a thrown\n * error, because each scope read settles its own fee: throwing on the third\n * scope would discard data the app has already paid for. Check `errors` before\n * treating the read as complete.\n */\nexport interface MultiScopeDataResult<T = unknown> {\n /** Scopes that read successfully, keyed by scope. */\n results: Record<string, ApprovedDataResult<T>>;\n /** Scopes that failed, keyed by scope. Empty when every scope read. */\n errors: Record<string, Error>;\n}\n\n/**\n * Client for the Vana Account access-request API — the service that turns a\n * registered app + scopes into a `dcr_*` id and approval URL.\n *\n * @remarks\n * The controller uses a default client against the Vana Account endpoints. You\n * can inject your own implementation to point at a custom deployment or to\n * supply a test double.\n */\nexport interface AccessRequestClient {\n /**\n * Create an access request for the given app + scopes.\n *\n * @param input - App identity, source, scopes, network, and the post-approval return URL.\n * @returns The created {@link AccessRequest}.\n */\n createAccessRequest(input: {\n appAddress: string;\n app: DirectAppConfig;\n source: string;\n scopes: string[];\n returnUrl: string;\n /** Vana protocol network for this request (`\"mainnet\"` or `\"moksha\"`). */\n network: DirectNetwork;\n }): Promise<AccessRequest>;\n\n /**\n * Fetch the current status of a previously created access request.\n *\n * @param requestId - The `dcr_*` id returned by {@link AccessRequestClient.createAccessRequest}.\n * @returns The current {@link AccessRequestStatus}.\n */\n getAccessRequestStatus(requestId: string): Promise<AccessRequestStatus>;\n\n /**\n * Acknowledge that the app successfully read the approved data.\n *\n * @remarks\n * Direct Vana Web DCRs remain in `ready_for_read` while the browser Personal\n * Server is serving the app. After a successful Personal Server read, the\n * controller calls this hook so Vana Web can mark the request completed and\n * close/redirect the approval tab.\n *\n * Optional so injected clients from older SDK integrations keep compiling;\n * the default HTTP client implements it.\n */\n acknowledgeRead?(requestId: string): Promise<void>;\n}\n\n/**\n * Op-type vocabulary used by the DPv2 escrow payment surface.\n *\n * @remarks\n * These are the operations the gateway prices and settles via\n * `POST /v1/escrow/pay` (`opType` field of the `GenericPayment` message). A\n * direct data read settles the {@link DirectOpType.DataAccess} op for the\n * approved grant; the other op types are listed here for completeness and to\n * give builders a typed vocabulary when inspecting fee breakdowns.\n *\n * GenericPayment uses `\"grant\"` for legacy grant lifecycle payments and\n * `\"data_access\"` for standalone receipt-bound reads.\n */\nexport const DirectOpType = {\n GrantRegistration: \"grant_registration\",\n DataAccess: \"data_access\",\n DataRegistration: \"data_registration\",\n ServerRegistration: \"server_registration\",\n BuilderRegistration: \"builder_registration\",\n} as const;\n\n/** A direct-flow op type (see {@link DirectOpType}). */\nexport type DirectOpTypeValue =\n (typeof DirectOpType)[keyof typeof DirectOpType];\n\n/**\n * What a Personal Server `402 Payment Required` tells the controller is owed for\n * a data read.\n *\n * @remarks\n * The PS read 402 body identifies the challenged operation and amount/asset.\n * The controller settles it via the DPv2 escrow gateway (`/v1/escrow/pay`). The\n * full unmodified body is preserved under\n * {@link PersonalServerPaymentRequired.raw}.\n */\nexport interface PersonalServerPaymentRequired {\n /** Grant id authorizing the Personal Server read. */\n grantId: string;\n /** X402 network advertised by the Personal Server challenge. */\n network?: string;\n /** Payment nonce requested by the 402 challenge. */\n paymentNonce?: string;\n /** Data-access receipt carrying a signature for the gateway to verify. */\n accessRecord?: EscrowAccessRecord;\n /** Asset address owed (zero address = native VANA). */\n asset: string;\n /** Amount owed, as a decimal base-unit string (preserves uint256 precision). */\n amount: string;\n /** The full, unmodified 402 response body. */\n raw: unknown;\n}\n\n/** A validated legacy grant payment challenge. */\nexport interface PersonalServerGrantPaymentOperation extends PersonalServerPaymentRequired {\n /** Escrow operation discriminator. */\n opType: \"grant\";\n /** Grant id settled by the escrow payment. */\n opId: string;\n}\n\n/** A validated receipt-bound data-access payment challenge. */\nexport interface PersonalServerDataAccessPaymentOperation extends PersonalServerPaymentRequired {\n /** Escrow operation discriminator. */\n opType: \"data_access\";\n /** Access-record id settled by the escrow payment. */\n opId: string;\n /** Complete receipt whose signature is verified later by the gateway. */\n accessRecord: EscrowAccessRecord;\n /** Positive uint256 nonce supplied by the Personal Server challenge. */\n paymentNonce: string;\n}\n\n/**\n * A Personal Server payment challenge whose escrow operation has been\n * validated.\n *\n * @remarks\n * Validation here is structural and binds operation ids to their receipt. It\n * does not cryptographically verify the receipt signature; the Personal\n * Server and Data Gateway perform that verification.\n */\nexport type PersonalServerPaymentOperation =\n | PersonalServerGrantPaymentOperation\n | PersonalServerDataAccessPaymentOperation;\n\n/** Shape-validated payment response returned directly by the escrow gateway. */\nexport interface DirectPaymentReceipt {\n /** Op type settled (the gateway `opType`, e.g. `\"grant\"`). */\n opType: string;\n /** Op id settled (a grant id or access-record id). */\n opId: string;\n /** Asset paid in (zero address = native VANA). */\n asset: string;\n /** Total amount paid, as a decimal base-unit string. */\n amount: string;\n /** Payment nonce used for this settlement. */\n paymentNonce: string;\n /** Fee breakdown reported by the gateway (registration vs data-access fee). */\n breakdown: DirectFeeBreakdown;\n /** ISO timestamp the gateway recorded the payment. */\n paidAt: string;\n}\n\n/**\n * Untrusted payment response metadata echoed by a Personal Server.\n *\n * @remarks\n * The SDK validates every field before exposing this shape, but the response\n * header is not signed by the gateway. Use it for display and debugging only,\n * never as accounting proof that a payment occurred.\n */\nexport type DirectPaymentResponseMetadata = DirectPaymentReceipt;\n\n/**\n * Per-op fee breakdown reported by the gateway.\n *\n * @remarks\n * Mirrors the escrow {@link PaymentBreakdown}: a one-time registration fee plus\n * the per-read data-access fee, and whether this settlement covered the\n * registration fee.\n */\nexport interface DirectFeeBreakdown {\n /** One-time registration fee for the op, as a decimal base-unit string. */\n registrationFee: string;\n /** Per-read data-access fee, as a decimal base-unit string. */\n dataAccessFee: string;\n /** True when this settlement paid the registration fee. */\n registrationPaid: boolean;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgOO,MAAM,eAAe;AAAA,EAC1B,mBAAmB;AAAA,EACnB,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,qBAAqB;AACvB;","names":[]}
|
package/dist/direct/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { EscrowAccessRecord } from "../protocol/escrow";
|
|
2
|
-
import type { ProtocolNetwork } from "../protocol/networks";
|
|
1
|
+
import type { EscrowAccessRecord } from "../protocol/escrow.js";
|
|
2
|
+
import type { ProtocolNetwork } from "../protocol/networks.js";
|
|
3
3
|
/**
|
|
4
4
|
* Shared types for the Direct Data Controller and the browser connect helper.
|
|
5
5
|
*
|
|
@@ -95,8 +95,24 @@ export interface AccessRequestStatus {
|
|
|
95
95
|
personalServerUrl?: string;
|
|
96
96
|
/** Grant id covering the approved scope — present once data is ready to read. */
|
|
97
97
|
grantId?: string;
|
|
98
|
-
/**
|
|
98
|
+
/**
|
|
99
|
+
* The first approved scope — present once data is ready to read.
|
|
100
|
+
*
|
|
101
|
+
* @remarks
|
|
102
|
+
* Kept for backwards compatibility. A request can approve many scopes; read
|
|
103
|
+
* {@link AccessRequestStatus.scopes} to see all of them.
|
|
104
|
+
*/
|
|
99
105
|
scope?: string;
|
|
106
|
+
/**
|
|
107
|
+
* Every scope the user approved on this request — present once data is ready
|
|
108
|
+
* to read.
|
|
109
|
+
*
|
|
110
|
+
* @remarks
|
|
111
|
+
* A grant is keyed by `(user, app)` and carries a list of scopes, so a single
|
|
112
|
+
* approval can cover several. Against an older Vana Account deployment that
|
|
113
|
+
* only returns `scope`, this falls back to `[scope]`.
|
|
114
|
+
*/
|
|
115
|
+
scopes?: string[];
|
|
100
116
|
}
|
|
101
117
|
/** Result of {@link DirectDataController.readApprovedData}. */
|
|
102
118
|
export interface ApprovedDataResult<T = unknown> {
|
|
@@ -105,12 +121,26 @@ export interface ApprovedDataResult<T = unknown> {
|
|
|
105
121
|
/** The decoded payload returned by the Personal Server. */
|
|
106
122
|
data: T;
|
|
107
123
|
/**
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* digging into the underlying 402/escrow exchange. Reads served from a paid-up
|
|
111
|
-
* grant omit this field.
|
|
124
|
+
* Shape-validated but unauthenticated payment metadata echoed by the
|
|
125
|
+
* Personal Server. Use for display/debugging, not accounting proof.
|
|
112
126
|
*/
|
|
113
|
-
payment?:
|
|
127
|
+
payment?: DirectPaymentResponseMetadata;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Result of {@link DirectDataController.readApprovedData} across every approved
|
|
131
|
+
* scope.
|
|
132
|
+
*
|
|
133
|
+
* @remarks
|
|
134
|
+
* Successes and failures are reported side by side rather than as a thrown
|
|
135
|
+
* error, because each scope read settles its own fee: throwing on the third
|
|
136
|
+
* scope would discard data the app has already paid for. Check `errors` before
|
|
137
|
+
* treating the read as complete.
|
|
138
|
+
*/
|
|
139
|
+
export interface MultiScopeDataResult<T = unknown> {
|
|
140
|
+
/** Scopes that read successfully, keyed by scope. */
|
|
141
|
+
results: Record<string, ApprovedDataResult<T>>;
|
|
142
|
+
/** Scopes that failed, keyed by scope. Empty when every scope read. */
|
|
143
|
+
errors: Record<string, Error>;
|
|
114
144
|
}
|
|
115
145
|
/**
|
|
116
146
|
* Client for the Vana Account access-request API — the service that turns a
|
|
@@ -168,9 +198,8 @@ export interface AccessRequestClient {
|
|
|
168
198
|
* approved grant; the other op types are listed here for completeness and to
|
|
169
199
|
* give builders a typed vocabulary when inspecting fee breakdowns.
|
|
170
200
|
*
|
|
171
|
-
*
|
|
172
|
-
* for
|
|
173
|
-
* the gateway reports in a {@link PaymentBreakdown}.
|
|
201
|
+
* GenericPayment uses `"grant"` for legacy grant lifecycle payments and
|
|
202
|
+
* `"data_access"` for standalone receipt-bound reads.
|
|
174
203
|
*/
|
|
175
204
|
export declare const DirectOpType: {
|
|
176
205
|
readonly GrantRegistration: "grant_registration";
|
|
@@ -186,18 +215,19 @@ export type DirectOpTypeValue = (typeof DirectOpType)[keyof typeof DirectOpType]
|
|
|
186
215
|
* a data read.
|
|
187
216
|
*
|
|
188
217
|
* @remarks
|
|
189
|
-
* The PS read 402 body identifies the
|
|
190
|
-
* controller settles it via the DPv2 escrow gateway (`/v1/escrow/pay`). The
|
|
191
|
-
* unmodified body is preserved under
|
|
218
|
+
* The PS read 402 body identifies the challenged operation and amount/asset.
|
|
219
|
+
* The controller settles it via the DPv2 escrow gateway (`/v1/escrow/pay`). The
|
|
220
|
+
* full unmodified body is preserved under
|
|
221
|
+
* {@link PersonalServerPaymentRequired.raw}.
|
|
192
222
|
*/
|
|
193
223
|
export interface PersonalServerPaymentRequired {
|
|
194
|
-
/** Grant id
|
|
224
|
+
/** Grant id authorizing the Personal Server read. */
|
|
195
225
|
grantId: string;
|
|
196
226
|
/** X402 network advertised by the Personal Server challenge. */
|
|
197
227
|
network?: string;
|
|
198
228
|
/** Payment nonce requested by the 402 challenge. */
|
|
199
229
|
paymentNonce?: string;
|
|
200
|
-
/**
|
|
230
|
+
/** Data-access receipt carrying a signature for the gateway to verify. */
|
|
201
231
|
accessRecord?: EscrowAccessRecord;
|
|
202
232
|
/** Asset address owed (zero address = native VANA). */
|
|
203
233
|
asset: string;
|
|
@@ -206,18 +236,39 @@ export interface PersonalServerPaymentRequired {
|
|
|
206
236
|
/** The full, unmodified 402 response body. */
|
|
207
237
|
raw: unknown;
|
|
208
238
|
}
|
|
239
|
+
/** A validated legacy grant payment challenge. */
|
|
240
|
+
export interface PersonalServerGrantPaymentOperation extends PersonalServerPaymentRequired {
|
|
241
|
+
/** Escrow operation discriminator. */
|
|
242
|
+
opType: "grant";
|
|
243
|
+
/** Grant id settled by the escrow payment. */
|
|
244
|
+
opId: string;
|
|
245
|
+
}
|
|
246
|
+
/** A validated receipt-bound data-access payment challenge. */
|
|
247
|
+
export interface PersonalServerDataAccessPaymentOperation extends PersonalServerPaymentRequired {
|
|
248
|
+
/** Escrow operation discriminator. */
|
|
249
|
+
opType: "data_access";
|
|
250
|
+
/** Access-record id settled by the escrow payment. */
|
|
251
|
+
opId: string;
|
|
252
|
+
/** Complete receipt whose signature is verified later by the gateway. */
|
|
253
|
+
accessRecord: EscrowAccessRecord;
|
|
254
|
+
/** Positive uint256 nonce supplied by the Personal Server challenge. */
|
|
255
|
+
paymentNonce: string;
|
|
256
|
+
}
|
|
209
257
|
/**
|
|
210
|
-
*
|
|
258
|
+
* A Personal Server payment challenge whose escrow operation has been
|
|
259
|
+
* validated.
|
|
211
260
|
*
|
|
212
261
|
* @remarks
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
262
|
+
* Validation here is structural and binds operation ids to their receipt. It
|
|
263
|
+
* does not cryptographically verify the receipt signature; the Personal
|
|
264
|
+
* Server and Data Gateway perform that verification.
|
|
216
265
|
*/
|
|
266
|
+
export type PersonalServerPaymentOperation = PersonalServerGrantPaymentOperation | PersonalServerDataAccessPaymentOperation;
|
|
267
|
+
/** Shape-validated payment response returned directly by the escrow gateway. */
|
|
217
268
|
export interface DirectPaymentReceipt {
|
|
218
269
|
/** Op type settled (the gateway `opType`, e.g. `"grant"`). */
|
|
219
270
|
opType: string;
|
|
220
|
-
/** Op id settled (
|
|
271
|
+
/** Op id settled (a grant id or access-record id). */
|
|
221
272
|
opId: string;
|
|
222
273
|
/** Asset paid in (zero address = native VANA). */
|
|
223
274
|
asset: string;
|
|
@@ -230,6 +281,15 @@ export interface DirectPaymentReceipt {
|
|
|
230
281
|
/** ISO timestamp the gateway recorded the payment. */
|
|
231
282
|
paidAt: string;
|
|
232
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* Untrusted payment response metadata echoed by a Personal Server.
|
|
286
|
+
*
|
|
287
|
+
* @remarks
|
|
288
|
+
* The SDK validates every field before exposing this shape, but the response
|
|
289
|
+
* header is not signed by the gateway. Use it for display and debugging only,
|
|
290
|
+
* never as accounting proof that a payment occurred.
|
|
291
|
+
*/
|
|
292
|
+
export type DirectPaymentResponseMetadata = DirectPaymentReceipt;
|
|
233
293
|
/**
|
|
234
294
|
* Per-op fee breakdown reported by the gateway.
|
|
235
295
|
*
|