@opendatalabs/vana-sdk 3.15.0 → 3.17.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 +107 -0
- package/dist/errors.cjs +94 -2
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +123 -0
- package/dist/errors.js +82 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.browser.d.ts +4 -0
- package/dist/index.browser.js +1155 -14
- package/dist/index.browser.js.map +4 -4
- package/dist/index.node.cjs +1205 -15
- package/dist/index.node.cjs.map +4 -4
- package/dist/index.node.d.ts +4 -0
- package/dist/index.node.js +1155 -14
- package/dist/index.node.js.map +4 -4
- package/dist/protocol/gateway.cjs +16 -2
- package/dist/protocol/gateway.cjs.map +1 -1
- package/dist/protocol/gateway.d.ts +2 -0
- package/dist/protocol/gateway.js +16 -2
- package/dist/protocol/gateway.js.map +1 -1
- package/dist/protocol/lineage.cjs +287 -0
- package/dist/protocol/lineage.cjs.map +1 -0
- package/dist/protocol/lineage.d.ts +228 -0
- package/dist/protocol/lineage.js +258 -0
- package/dist/protocol/lineage.js.map +1 -0
- package/dist/protocol/lineage.test.d.ts +1 -0
- package/dist/protocol/personal-server-error-body.cjs +57 -0
- package/dist/protocol/personal-server-error-body.cjs.map +1 -0
- package/dist/protocol/personal-server-error-body.d.ts +18 -0
- package/dist/protocol/personal-server-error-body.js +32 -0
- package/dist/protocol/personal-server-error-body.js.map +1 -0
- package/dist/protocol/personal-server-write.cjs +623 -0
- package/dist/protocol/personal-server-write.cjs.map +1 -0
- package/dist/protocol/personal-server-write.d.ts +284 -0
- package/dist/protocol/personal-server-write.js +601 -0
- package/dist/protocol/personal-server-write.js.map +1 -0
- package/dist/protocol/personal-server-write.test.d.ts +1 -0
- package/dist/protocol/scope-actions.cjs +185 -0
- package/dist/protocol/scope-actions.cjs.map +1 -0
- package/dist/protocol/scope-actions.d.ts +145 -0
- package/dist/protocol/scope-actions.js +154 -0
- package/dist/protocol/scope-actions.js.map +1 -0
- package/dist/protocol/scope-actions.test.d.ts +1 -0
- package/dist/protocol/write-signer.cjs +67 -0
- package/dist/protocol/write-signer.cjs.map +1 -0
- package/dist/protocol/write-signer.d.ts +59 -0
- package/dist/protocol/write-signer.js +43 -0
- package/dist/protocol/write-signer.js.map +1 -0
- package/dist/protocol/write-signer.test.d.ts +1 -0
- package/dist/tests/mock-personal-server.d.ts +127 -0
- package/package.json +1 -1
|
@@ -0,0 +1,287 @@
|
|
|
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 lineage_exports = {};
|
|
20
|
+
__export(lineage_exports, {
|
|
21
|
+
LineageEntrySchema: () => LineageEntrySchema,
|
|
22
|
+
LineageGraphSchema: () => LineageGraphSchema,
|
|
23
|
+
LineageNodeSchema: () => LineageNodeSchema,
|
|
24
|
+
RedactedLineageNodeSchema: () => RedactedLineageNodeSchema,
|
|
25
|
+
assertDerivedScopeNaming: () => assertDerivedScopeNaming,
|
|
26
|
+
deriveDataPointId: () => deriveDataPointId,
|
|
27
|
+
derivedScopeViolatesNaming: () => derivedScopeViolatesNaming,
|
|
28
|
+
gatewayLineagePath: () => gatewayLineagePath,
|
|
29
|
+
getGatewayLineage: () => getGatewayLineage,
|
|
30
|
+
getLineage: () => getLineage,
|
|
31
|
+
getPersonalServerLineage: () => getPersonalServerLineage,
|
|
32
|
+
isDataPointId: () => isDataPointId,
|
|
33
|
+
isRedactedLineageNode: () => isRedactedLineageNode,
|
|
34
|
+
personalServerLineagePath: () => personalServerLineagePath,
|
|
35
|
+
scopeNamespace: () => scopeNamespace
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(lineage_exports);
|
|
38
|
+
var import_viem = require("viem");
|
|
39
|
+
var import_zod = require("zod");
|
|
40
|
+
var import_web3_signed_builder = require("../auth/web3-signed-builder");
|
|
41
|
+
var import_errors = require("../errors");
|
|
42
|
+
var import_personal_server_error_body = require("./personal-server-error-body");
|
|
43
|
+
var import_write_signer = require("./write-signer");
|
|
44
|
+
const DATA_POINT_ID_PATTERN = /^0x[0-9a-fA-F]{64}$/;
|
|
45
|
+
function isDataPointId(value) {
|
|
46
|
+
return typeof value === "string" && DATA_POINT_ID_PATTERN.test(value);
|
|
47
|
+
}
|
|
48
|
+
function deriveDataPointId(ownerAddress, scope) {
|
|
49
|
+
if (!(0, import_viem.isAddress)(ownerAddress, { strict: false })) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`ownerAddress is not an EVM address: ${String(ownerAddress)}`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
return (0, import_viem.keccak256)(
|
|
55
|
+
(0, import_viem.encodeAbiParameters)(
|
|
56
|
+
[
|
|
57
|
+
{ name: "ownerAddress", type: "address" },
|
|
58
|
+
{ name: "scope", type: "string" }
|
|
59
|
+
],
|
|
60
|
+
[ownerAddress, scope]
|
|
61
|
+
)
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
const DataPointIdSchema = import_zod.z.string().regex(DATA_POINT_ID_PATTERN).transform((value) => value.toLowerCase());
|
|
65
|
+
const VERSION_PATTERN = /^[1-9]\d*$/;
|
|
66
|
+
const NODE_VERSION_PATTERN = /^(0|[1-9]\d*)$/;
|
|
67
|
+
const VersionSchema = import_zod.z.union([import_zod.z.string(), import_zod.z.number()]).transform(String).refine((value) => NODE_VERSION_PATTERN.test(value), {
|
|
68
|
+
message: "version must be a decimal integer"
|
|
69
|
+
});
|
|
70
|
+
const ViewVersionSchema = VersionSchema.refine(
|
|
71
|
+
(value) => VERSION_PATTERN.test(value),
|
|
72
|
+
{ message: "version must be a positive decimal integer" }
|
|
73
|
+
);
|
|
74
|
+
function scopeNamespace(scope) {
|
|
75
|
+
const dot = scope.indexOf(".");
|
|
76
|
+
return dot === -1 ? scope : scope.slice(0, dot);
|
|
77
|
+
}
|
|
78
|
+
function derivedScopeViolatesNaming(derivedScope, sourceScope) {
|
|
79
|
+
return scopeNamespace(derivedScope) === scopeNamespace(sourceScope);
|
|
80
|
+
}
|
|
81
|
+
function assertDerivedScopeNaming(derivedScope, sourceScopes) {
|
|
82
|
+
for (const sourceScope of sourceScopes) {
|
|
83
|
+
if (derivedScopeViolatesNaming(derivedScope, sourceScope)) {
|
|
84
|
+
throw new import_errors.WriteRequestError(
|
|
85
|
+
`Derived scope ${derivedScope} must not share its first segment with source scope ${sourceScope}; put derivatives in the app's own namespace`,
|
|
86
|
+
{ scope: derivedScope, sourceScope }
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const LineageNodeSchema = import_zod.z.object({
|
|
92
|
+
dataPointId: DataPointIdSchema,
|
|
93
|
+
scope: import_zod.z.string(),
|
|
94
|
+
/**
|
|
95
|
+
* The node's current version, decimal string; `"0"` for a source that no
|
|
96
|
+
* longer resolves to a registered data point.
|
|
97
|
+
*/
|
|
98
|
+
version: VersionSchema,
|
|
99
|
+
/** The node's tombstone time, or `null` when live. */
|
|
100
|
+
deletedAt: import_zod.z.string().nullable()
|
|
101
|
+
});
|
|
102
|
+
const RedactedLineageNodeSchema = import_zod.z.object({
|
|
103
|
+
dataPointId: DataPointIdSchema,
|
|
104
|
+
redacted: import_zod.z.literal(true)
|
|
105
|
+
});
|
|
106
|
+
const LineageEntrySchema = import_zod.z.union([
|
|
107
|
+
RedactedLineageNodeSchema,
|
|
108
|
+
LineageNodeSchema
|
|
109
|
+
]);
|
|
110
|
+
const LineageGraphSchema = import_zod.z.object({
|
|
111
|
+
dataPointId: DataPointIdSchema,
|
|
112
|
+
/** The data point owner; every node in the view belongs to it. */
|
|
113
|
+
ownerAddress: import_zod.z.string().optional(),
|
|
114
|
+
scope: import_zod.z.string(),
|
|
115
|
+
/**
|
|
116
|
+
* The derived record's version whose lineage is shown: the requested one,
|
|
117
|
+
* else the current one, else (current is a tombstone) the last version
|
|
118
|
+
* that carried lineage.
|
|
119
|
+
*/
|
|
120
|
+
version: ViewVersionSchema,
|
|
121
|
+
deletedAt: import_zod.z.string().nullable(),
|
|
122
|
+
sources: import_zod.z.array(LineageEntrySchema),
|
|
123
|
+
derivatives: import_zod.z.array(LineageEntrySchema),
|
|
124
|
+
/** `true` when `derivatives` was cut at the server's cap (1000). */
|
|
125
|
+
derivativesTruncated: import_zod.z.boolean().optional()
|
|
126
|
+
});
|
|
127
|
+
function isRedactedLineageNode(entry) {
|
|
128
|
+
return "redacted" in entry && entry.redacted === true;
|
|
129
|
+
}
|
|
130
|
+
function personalServerLineagePath(scope, version) {
|
|
131
|
+
return `/v1/data/${encodeURIComponent(scope)}/lineage${version === void 0 ? "" : `/${String(version)}`}`;
|
|
132
|
+
}
|
|
133
|
+
function gatewayLineagePath(dataPointId, version) {
|
|
134
|
+
return `/v1/data/${dataPointId.toLowerCase()}/lineage${version === void 0 ? "" : `/${String(version)}`}`;
|
|
135
|
+
}
|
|
136
|
+
function normalizeBaseUrl(url) {
|
|
137
|
+
return url.replace(/\/+$/, "");
|
|
138
|
+
}
|
|
139
|
+
function resolveFetch(fetchFn) {
|
|
140
|
+
const resolved = fetchFn ?? globalThis.fetch;
|
|
141
|
+
if (resolved === void 0) {
|
|
142
|
+
throw new import_errors.LineageReadError("No fetch implementation available");
|
|
143
|
+
}
|
|
144
|
+
return resolved;
|
|
145
|
+
}
|
|
146
|
+
function normalizeVersion(version) {
|
|
147
|
+
if (version === void 0) return void 0;
|
|
148
|
+
const text = String(version);
|
|
149
|
+
if (!VERSION_PATTERN.test(text)) {
|
|
150
|
+
throw new import_errors.LineageReadError(
|
|
151
|
+
"version must be a positive decimal integer",
|
|
152
|
+
void 0,
|
|
153
|
+
"INVALID_VERSION",
|
|
154
|
+
{ version }
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
return text;
|
|
158
|
+
}
|
|
159
|
+
async function lineageReadFailure(source, response) {
|
|
160
|
+
const { errorCode, message, details } = await (0, import_personal_server_error_body.readPersonalServerErrorBody)(response);
|
|
161
|
+
return new import_errors.LineageReadError(
|
|
162
|
+
message ?? `${source} lineage read failed: ${response.status} ${response.statusText}`,
|
|
163
|
+
response.status,
|
|
164
|
+
errorCode,
|
|
165
|
+
details
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
async function parseLineageGraph(source, response) {
|
|
169
|
+
let body;
|
|
170
|
+
try {
|
|
171
|
+
body = await response.json();
|
|
172
|
+
} catch (err) {
|
|
173
|
+
throw new import_errors.LineageReadError(
|
|
174
|
+
`${source} lineage response is not JSON`,
|
|
175
|
+
response.status,
|
|
176
|
+
null,
|
|
177
|
+
{ cause: err instanceof Error ? err.message : String(err) }
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
const envelope = (0, import_personal_server_error_body.isRecord)(body) && (0, import_personal_server_error_body.isRecord)(body.data) ? body : void 0;
|
|
181
|
+
const parsed = LineageGraphSchema.safeParse(envelope?.data ?? body);
|
|
182
|
+
if (!parsed.success) {
|
|
183
|
+
throw new import_errors.LineageReadError(
|
|
184
|
+
`${source} lineage response is not a lineage view`,
|
|
185
|
+
response.status,
|
|
186
|
+
null,
|
|
187
|
+
{ issues: parsed.error.issues }
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
const proof = (0, import_personal_server_error_body.isRecord)(envelope?.proof) ? envelope.proof : void 0;
|
|
191
|
+
return proof === void 0 ? parsed.data : { ...parsed.data, proof };
|
|
192
|
+
}
|
|
193
|
+
async function sendLineageRead(source, fetchFn, url, headers) {
|
|
194
|
+
let response;
|
|
195
|
+
try {
|
|
196
|
+
response = await fetchFn(url, { method: "GET", headers });
|
|
197
|
+
} catch (err) {
|
|
198
|
+
throw new import_errors.LineageReadError(
|
|
199
|
+
`${source} lineage read failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
200
|
+
void 0,
|
|
201
|
+
null,
|
|
202
|
+
{ cause: err instanceof Error ? err.message : String(err) }
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
if (!response.ok) {
|
|
206
|
+
throw await lineageReadFailure(source, response);
|
|
207
|
+
}
|
|
208
|
+
return parseLineageGraph(source, response);
|
|
209
|
+
}
|
|
210
|
+
async function getPersonalServerLineage(params) {
|
|
211
|
+
const fetchFn = resolveFetch(params.fetch);
|
|
212
|
+
const baseUrl = normalizeBaseUrl(params.personalServerUrl);
|
|
213
|
+
const audience = params.audience ?? baseUrl;
|
|
214
|
+
const signer = (0, import_write_signer.resolveWriteSigner)(params.signer, { account: params.account });
|
|
215
|
+
const path = personalServerLineagePath(
|
|
216
|
+
params.scope,
|
|
217
|
+
normalizeVersion(params.version)
|
|
218
|
+
);
|
|
219
|
+
const headers = new Headers(params.headers);
|
|
220
|
+
headers.set(
|
|
221
|
+
"Authorization",
|
|
222
|
+
await (0, import_web3_signed_builder.buildWeb3SignedHeader)({
|
|
223
|
+
signMessage: signer.signMessage,
|
|
224
|
+
aud: audience,
|
|
225
|
+
method: "GET",
|
|
226
|
+
uri: path,
|
|
227
|
+
grantId: params.grantId
|
|
228
|
+
})
|
|
229
|
+
);
|
|
230
|
+
return sendLineageRead(
|
|
231
|
+
"Personal Server",
|
|
232
|
+
fetchFn,
|
|
233
|
+
`${baseUrl}${path}`,
|
|
234
|
+
headers
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
async function getGatewayLineage(params) {
|
|
238
|
+
if (!isDataPointId(params.dataPointId)) {
|
|
239
|
+
throw new import_errors.LineageReadError(
|
|
240
|
+
"dataPointId must be a 32-byte hex string (see deriveDataPointId)",
|
|
241
|
+
void 0,
|
|
242
|
+
"INVALID_DATA_POINT_ID",
|
|
243
|
+
{ dataPointId: params.dataPointId }
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
const fetchFn = resolveFetch(params.fetch);
|
|
247
|
+
const baseUrl = normalizeBaseUrl(params.gatewayUrl);
|
|
248
|
+
const signer = (0, import_write_signer.resolveWriteSigner)(params.signer, { account: params.account });
|
|
249
|
+
const uri = gatewayLineagePath(
|
|
250
|
+
params.dataPointId,
|
|
251
|
+
normalizeVersion(params.version)
|
|
252
|
+
);
|
|
253
|
+
const headers = new Headers(params.headers);
|
|
254
|
+
headers.set(
|
|
255
|
+
"Authorization",
|
|
256
|
+
await (0, import_web3_signed_builder.buildWeb3SignedHeader)({
|
|
257
|
+
signMessage: signer.signMessage,
|
|
258
|
+
aud: baseUrl,
|
|
259
|
+
method: "GET",
|
|
260
|
+
uri,
|
|
261
|
+
grantId: params.grantId?.toLowerCase()
|
|
262
|
+
})
|
|
263
|
+
);
|
|
264
|
+
return sendLineageRead("Gateway", fetchFn, `${baseUrl}${uri}`, headers);
|
|
265
|
+
}
|
|
266
|
+
function getLineage(params) {
|
|
267
|
+
return "personalServerUrl" in params ? getPersonalServerLineage(params) : getGatewayLineage(params);
|
|
268
|
+
}
|
|
269
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
270
|
+
0 && (module.exports = {
|
|
271
|
+
LineageEntrySchema,
|
|
272
|
+
LineageGraphSchema,
|
|
273
|
+
LineageNodeSchema,
|
|
274
|
+
RedactedLineageNodeSchema,
|
|
275
|
+
assertDerivedScopeNaming,
|
|
276
|
+
deriveDataPointId,
|
|
277
|
+
derivedScopeViolatesNaming,
|
|
278
|
+
gatewayLineagePath,
|
|
279
|
+
getGatewayLineage,
|
|
280
|
+
getLineage,
|
|
281
|
+
getPersonalServerLineage,
|
|
282
|
+
isDataPointId,
|
|
283
|
+
isRedactedLineageNode,
|
|
284
|
+
personalServerLineagePath,
|
|
285
|
+
scopeNamespace
|
|
286
|
+
});
|
|
287
|
+
//# sourceMappingURL=lineage.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/protocol/lineage.ts"],"sourcesContent":["/**\n * Derivative lineage: which data points a record was derived from, and which\n * records were derived from it.\n *\n * @remarks\n * A data point is addressed by `keccak256(abi.encode(address owner, string\n * scope))` ({@link deriveDataPointId}). A builder writing a derivative names\n * its sources through the `lineage` option of {@link writeData}; the Personal\n * Server stores them under the reserved `$lineage` key and both the Personal\n * Server (`GET /v1/data/:scope/lineage[/:version]`) and the gateway\n * (`GET /v1/data/:dataPointId/lineage[/:version]`) answer the resulting view.\n * Nodes the caller holds no grant for come back as\n * `{ dataPointId, redacted: true }`; a source that no longer resolves comes\n * back with `version: \"0\"`.\n *\n * A derived scope must not share its first dot-segment with any source scope\n * (a grant on `chatgpt.*` must never read a derivative of\n * `chatgpt.conversations`): see {@link assertDerivedScopeNaming}.\n *\n * @category Protocol\n */\n\nimport {\n encodeAbiParameters,\n isAddress,\n keccak256,\n type Address,\n type Hex,\n} from \"viem\";\nimport { z } from \"zod\";\nimport { buildWeb3SignedHeader } from \"../auth/web3-signed-builder\";\nimport { LineageReadError, WriteRequestError } from \"../errors\";\nimport {\n isRecord,\n readPersonalServerErrorBody,\n} from \"./personal-server-error-body\";\nimport {\n resolveWriteSigner,\n type ResolveWriteSignerOptions,\n type WriteSignerSource,\n} from \"./write-signer\";\n\nconst DATA_POINT_ID_PATTERN = /^0x[0-9a-fA-F]{64}$/;\n\n/** `true` when `value` is a 32-byte hex data point id. */\nexport function isDataPointId(value: unknown): value is Hex {\n return typeof value === \"string\" && DATA_POINT_ID_PATTERN.test(value);\n}\n\n/**\n * Derive the DataRegistryV2 data point id for an owner and scope:\n * `keccak256(abi.encode(address ownerAddress, string scope))`.\n *\n * @param ownerAddress - The data owner (the Personal Server owner).\n * @param scope - The scope the data point is stored under.\n * @returns The 32-byte id, lowercase hex.\n * @throws Error when `ownerAddress` is not an EVM address.\n */\nexport function deriveDataPointId(ownerAddress: Address, scope: string): Hex {\n if (!isAddress(ownerAddress, { strict: false })) {\n throw new Error(\n `ownerAddress is not an EVM address: ${String(ownerAddress)}`,\n );\n }\n return keccak256(\n encodeAbiParameters(\n [\n { name: \"ownerAddress\", type: \"address\" },\n { name: \"scope\", type: \"string\" },\n ],\n [ownerAddress, scope],\n ),\n );\n}\n\nconst DataPointIdSchema = z\n .string()\n .regex(DATA_POINT_ID_PATTERN)\n .transform((value) => value.toLowerCase() as Hex);\n\nconst VERSION_PATTERN = /^[1-9]\\d*$/;\nconst NODE_VERSION_PATTERN = /^(0|[1-9]\\d*)$/;\n\n// Versions are decimal integers, strings on the wire; a numeric value is\n// normalised to the same representation. A node's version may be \"0\": a\n// source that no longer resolves to a registered data point.\nconst VersionSchema = z\n .union([z.string(), z.number()])\n .transform(String)\n .refine((value) => NODE_VERSION_PATTERN.test(value), {\n message: \"version must be a decimal integer\",\n });\n// The view's own version is a registered one: always positive.\nconst ViewVersionSchema = VersionSchema.refine(\n (value) => VERSION_PATTERN.test(value),\n { message: \"version must be a positive decimal integer\" },\n);\n\n/** First dot-segment of a scope (`chatgpt` for `chatgpt.conversations`). */\nexport function scopeNamespace(scope: string): string {\n const dot = scope.indexOf(\".\");\n return dot === -1 ? scope : scope.slice(0, dot);\n}\n\n/**\n * The naming rule: a derived scope and a source scope must not share their\n * first dot-segment, because a `prefix.*` grant would then cover both and\n * leak across the lineage edge. Mirrors the Personal Server's check\n * (`LINEAGE_SCOPE_UNDER_SOURCE_PREFIX`).\n */\nexport function derivedScopeViolatesNaming(\n derivedScope: string,\n sourceScope: string,\n): boolean {\n return scopeNamespace(derivedScope) === scopeNamespace(sourceScope);\n}\n\n/**\n * Throw when `derivedScope` shares its first dot-segment with any source\n * scope (see {@link derivedScopeViolatesNaming}).\n *\n * @throws {WriteRequestError} Naming the offending source scope in `details`.\n */\nexport function assertDerivedScopeNaming(\n derivedScope: string,\n sourceScopes: readonly string[],\n): void {\n for (const sourceScope of sourceScopes) {\n if (derivedScopeViolatesNaming(derivedScope, sourceScope)) {\n throw new WriteRequestError(\n `Derived scope ${derivedScope} must not share its first segment with source scope ${sourceScope}; put derivatives in the app's own namespace`,\n { scope: derivedScope, sourceScope },\n );\n }\n }\n}\n\nexport const LineageNodeSchema = z.object({\n dataPointId: DataPointIdSchema,\n scope: z.string(),\n /**\n * The node's current version, decimal string; `\"0\"` for a source that no\n * longer resolves to a registered data point.\n */\n version: VersionSchema,\n /** The node's tombstone time, or `null` when live. */\n deletedAt: z.string().nullable(),\n});\n\nexport const RedactedLineageNodeSchema = z.object({\n dataPointId: DataPointIdSchema,\n redacted: z.literal(true),\n});\n\nexport const LineageEntrySchema = z.union([\n RedactedLineageNodeSchema,\n LineageNodeSchema,\n]);\n\nexport const LineageGraphSchema = z.object({\n dataPointId: DataPointIdSchema,\n /** The data point owner; every node in the view belongs to it. */\n ownerAddress: z.string().optional(),\n scope: z.string(),\n /**\n * The derived record's version whose lineage is shown: the requested one,\n * else the current one, else (current is a tombstone) the last version\n * that carried lineage.\n */\n version: ViewVersionSchema,\n deletedAt: z.string().nullable(),\n sources: z.array(LineageEntrySchema),\n derivatives: z.array(LineageEntrySchema),\n /** `true` when `derivatives` was cut at the server's cap (1000). */\n derivativesTruncated: z.boolean().optional(),\n});\n\n/** A lineage node the caller is allowed to see. */\nexport type LineageNode = z.infer<typeof LineageNodeSchema>;\n\n/** A lineage node the caller holds no grant for: only its id is disclosed. */\nexport type RedactedLineageNode = z.infer<typeof RedactedLineageNodeSchema>;\n\n/** One entry of a lineage graph. Narrow with {@link isRedactedLineageNode}. */\nexport type LineageEntry = z.infer<typeof LineageEntrySchema>;\n\n/** The lineage view of one data point (the `data` of the response). */\nexport type LineageGraph = z.infer<typeof LineageGraphSchema>;\n\n/** A lineage read: the view plus the gateway's attestation over it. */\nexport interface LineageReadResult extends LineageGraph {\n /**\n * The gateway `proof` (`GatewayAttestation` over the served view, so a\n * redacted view verifies on its own). Passed through as received; absent\n * when the server sent none.\n */\n proof?: Record<string, unknown>;\n}\n\n/** `true` when the entry was redacted (the caller holds no grant for it). */\nexport function isRedactedLineageNode(\n entry: LineageEntry,\n): entry is RedactedLineageNode {\n return \"redacted\" in entry && entry.redacted === true;\n}\n\n/**\n * The Personal Server lineage path: `/v1/data/:scope/lineage[/:version]`.\n * The version is a path segment (a query string is refused by the server),\n * so the signed `uri` covers the whole request.\n */\nexport function personalServerLineagePath(\n scope: string,\n version?: string | number,\n): string {\n return `/v1/data/${encodeURIComponent(scope)}/lineage${version === undefined ? \"\" : `/${String(version)}`}`;\n}\n\n/**\n * The gateway lineage path: `/v1/data/<id lowercase>/lineage[/:version]`,\n * what the request is signed over and sent to. The grant view is the signed\n * `grantId` claim, never a query parameter.\n */\nexport function gatewayLineagePath(\n dataPointId: Hex,\n version?: string | number,\n): string {\n return `/v1/data/${dataPointId.toLowerCase()}/lineage${version === undefined ? \"\" : `/${String(version)}`}`;\n}\n\ninterface LineageRequestOptions {\n /**\n * Read the lineage as of this version (a positive decimal integer);\n * omitted = the current version, or the last version that carried lineage\n * when the current one is a tombstone.\n */\n version?: string | number;\n /** `fetch` to use; defaults to `globalThis.fetch`. */\n fetch?: typeof fetch;\n /** Extra request headers. */\n headers?: HeadersInit;\n}\n\n/** Lineage read against the Personal Server holding the record. */\nexport interface PersonalServerLineageParams extends LineageRequestOptions {\n /** Personal Server origin, e.g. `https://ps.example.com`. */\n personalServerUrl: string;\n /** The scope whose lineage to read. */\n scope: string;\n /** A grant covering the scope, sent as the signed `grantId` claim. */\n grantId: string;\n /** Builder key: a viem `LocalAccount`, `WalletClient`, or `{ signMessage }`. */\n signer: WriteSignerSource;\n /** Account for a viem wallet client without a hoisted account. */\n account?: ResolveWriteSignerOptions[\"account\"];\n /** Web3Signed audience; defaults to `personalServerUrl`. */\n audience?: string;\n}\n\n/** Lineage read against the gateway, by data point id. */\nexport interface GatewayLineageParams extends LineageRequestOptions {\n /** Gateway origin, e.g. `https://dp-rpc.vana.org`. */\n gatewayUrl: string;\n /** The data point whose lineage to read (see {@link deriveDataPointId}). */\n dataPointId: Hex;\n /**\n * The key the request is signed with (Web3Signed, audience = the gateway\n * origin). The signer decides the view: the owner or one of its servers\n * gets the full view; a registered builder holding a live grant covering\n * the data point's scope gets that grant's view; anyone else is refused.\n */\n signer: WriteSignerSource;\n /** Account for a viem wallet client without a hoisted account. */\n account?: ResolveWriteSignerOptions[\"account\"];\n /**\n * The grant whose view to read, sent lowercased as the signed `grantId`\n * claim (never as a query parameter). An owner or server uses it to fetch\n * the view a builder's grant sees; a builder needs it to see anything.\n */\n grantId?: string;\n}\n\nexport type GetLineageParams =\n | PersonalServerLineageParams\n | GatewayLineageParams;\n\nfunction normalizeBaseUrl(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\nfunction resolveFetch(fetchFn: typeof fetch | undefined): typeof fetch {\n const resolved = fetchFn ?? globalThis.fetch;\n if (resolved === undefined) {\n throw new LineageReadError(\"No fetch implementation available\");\n }\n return resolved;\n}\n\nfunction normalizeVersion(\n version: string | number | undefined,\n): string | undefined {\n if (version === undefined) return undefined;\n const text = String(version);\n if (!VERSION_PATTERN.test(text)) {\n throw new LineageReadError(\n \"version must be a positive decimal integer\",\n undefined,\n \"INVALID_VERSION\",\n { version },\n );\n }\n return text;\n}\n\nasync function lineageReadFailure(\n source: string,\n response: Response,\n): Promise<LineageReadError> {\n const { errorCode, message, details } =\n await readPersonalServerErrorBody(response);\n return new LineageReadError(\n message ??\n `${source} lineage read failed: ${response.status} ${response.statusText}`,\n response.status,\n errorCode,\n details,\n );\n}\n\nasync function parseLineageGraph(\n source: string,\n response: Response,\n): Promise<LineageReadResult> {\n let body: unknown;\n try {\n body = await response.json();\n } catch (err) {\n throw new LineageReadError(\n `${source} lineage response is not JSON`,\n response.status,\n null,\n { cause: err instanceof Error ? err.message : String(err) },\n );\n }\n // Both servers answer the gateway envelope `{ data, proof }`; a bare view\n // is accepted too.\n const envelope = isRecord(body) && isRecord(body.data) ? body : undefined;\n const parsed = LineageGraphSchema.safeParse(envelope?.data ?? body);\n if (!parsed.success) {\n throw new LineageReadError(\n `${source} lineage response is not a lineage view`,\n response.status,\n null,\n { issues: parsed.error.issues },\n );\n }\n const proof = isRecord(envelope?.proof) ? envelope.proof : undefined;\n return proof === undefined ? parsed.data : { ...parsed.data, proof };\n}\n\nasync function sendLineageRead(\n source: string,\n fetchFn: typeof fetch,\n url: string,\n headers: Headers,\n): Promise<LineageReadResult> {\n let response: Response;\n try {\n response = await fetchFn(url, { method: \"GET\", headers });\n } catch (err) {\n throw new LineageReadError(\n `${source} lineage read failed: ${err instanceof Error ? err.message : String(err)}`,\n undefined,\n null,\n { cause: err instanceof Error ? err.message : String(err) },\n );\n }\n if (!response.ok) {\n throw await lineageReadFailure(source, response);\n }\n return parseLineageGraph(source, response);\n}\n\n/**\n * Read a scope's lineage from the Personal Server that stores it.\n *\n * @remarks\n * Sends `GET /v1/data/:scope/lineage[/:version]` with a Web3Signed\n * `Authorization` header carrying `grantId`, the same authentication a data\n * read uses; the signed `uri` is the full path, version segment included.\n * The server resolves the data point id, fetches the view the grant sees\n * from the gateway and returns the gateway's `data` + `proof`.\n *\n * @returns The lineage view, with redacted entries for nodes the grant does\n * not cover, plus the gateway attestation.\n * @throws {LineageReadError} On a non-2xx answer (`errorCode`: read errors,\n * `INVALID_VERSION`, `NOT_FOUND` when the scope or version is not\n * registered at the gateway, `LINEAGE_FORBIDDEN`, `LINEAGE_GATEWAY_ERROR`,\n * `LINEAGE_UNAVAILABLE`), an unreadable body, a bad `version`, or a\n * transport failure.\n */\nexport async function getPersonalServerLineage(\n params: PersonalServerLineageParams,\n): Promise<LineageReadResult> {\n const fetchFn = resolveFetch(params.fetch);\n const baseUrl = normalizeBaseUrl(params.personalServerUrl);\n const audience = params.audience ?? baseUrl;\n const signer = resolveWriteSigner(params.signer, { account: params.account });\n const path = personalServerLineagePath(\n params.scope,\n normalizeVersion(params.version),\n );\n const headers = new Headers(params.headers);\n headers.set(\n \"Authorization\",\n await buildWeb3SignedHeader({\n signMessage: signer.signMessage,\n aud: audience,\n method: \"GET\",\n uri: path,\n grantId: params.grantId,\n }),\n );\n return sendLineageRead(\n \"Personal Server\",\n fetchFn,\n `${baseUrl}${path}`,\n headers,\n );\n}\n\n/**\n * Read a data point's lineage from the gateway.\n *\n * @remarks\n * Sends `GET /v1/data/:dataPointId/lineage[/:version]` with a Web3Signed\n * `Authorization` header: `aud` = the gateway origin, `uri` =\n * {@link gatewayLineagePath} (lowercase id, version segment included),\n * empty-body `bodyHash`, and the lowercased `grantId` claim when given. The\n * gateway answers a uniform 404 for an unknown data point and for a signer\n * it will not serve, so the two cannot be told apart from outside.\n *\n * @returns The lineage view, with redacted entries for nodes the caller's\n * grant does not cover, plus the gateway attestation.\n * @throws {LineageReadError} On a malformed `dataPointId` or `version`, a\n * non-2xx answer (400 malformed request, 401 `LINEAGE_SIGNATURE_REQUIRED`\n * / `LINEAGE_SIGNATURE_INVALID`, 404 unknown or not served), an unreadable\n * body, or a transport failure.\n */\nexport async function getGatewayLineage(\n params: GatewayLineageParams,\n): Promise<LineageReadResult> {\n if (!isDataPointId(params.dataPointId)) {\n throw new LineageReadError(\n \"dataPointId must be a 32-byte hex string (see deriveDataPointId)\",\n undefined,\n \"INVALID_DATA_POINT_ID\",\n { dataPointId: params.dataPointId },\n );\n }\n const fetchFn = resolveFetch(params.fetch);\n const baseUrl = normalizeBaseUrl(params.gatewayUrl);\n const signer = resolveWriteSigner(params.signer, { account: params.account });\n const uri = gatewayLineagePath(\n params.dataPointId,\n normalizeVersion(params.version),\n );\n const headers = new Headers(params.headers);\n headers.set(\n \"Authorization\",\n await buildWeb3SignedHeader({\n signMessage: signer.signMessage,\n aud: baseUrl,\n method: \"GET\",\n uri,\n grantId: params.grantId?.toLowerCase(),\n }),\n );\n return sendLineageRead(\"Gateway\", fetchFn, `${baseUrl}${uri}`, headers);\n}\n\n/**\n * Read a lineage view from either the Personal Server (by scope) or the\n * gateway (by data point id), chosen by the params shape.\n *\n * @example\n * ```typescript\n * const fromPs = await getLineage({ personalServerUrl, scope, grantId, signer });\n * const fromGateway = await getLineage({ gatewayUrl, dataPointId, grantId, signer });\n * ```\n */\nexport function getLineage(\n params: GetLineageParams,\n): Promise<LineageReadResult> {\n return \"personalServerUrl\" in params\n ? getPersonalServerLineage(params)\n : getGatewayLineage(params);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derivative lineage: which data points a record was derived from, and which
|
|
3
|
+
* records were derived from it.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* A data point is addressed by `keccak256(abi.encode(address owner, string
|
|
7
|
+
* scope))` ({@link deriveDataPointId}). A builder writing a derivative names
|
|
8
|
+
* its sources through the `lineage` option of {@link writeData}; the Personal
|
|
9
|
+
* Server stores them under the reserved `$lineage` key and both the Personal
|
|
10
|
+
* Server (`GET /v1/data/:scope/lineage[/:version]`) and the gateway
|
|
11
|
+
* (`GET /v1/data/:dataPointId/lineage[/:version]`) answer the resulting view.
|
|
12
|
+
* Nodes the caller holds no grant for come back as
|
|
13
|
+
* `{ dataPointId, redacted: true }`; a source that no longer resolves comes
|
|
14
|
+
* back with `version: "0"`.
|
|
15
|
+
*
|
|
16
|
+
* A derived scope must not share its first dot-segment with any source scope
|
|
17
|
+
* (a grant on `chatgpt.*` must never read a derivative of
|
|
18
|
+
* `chatgpt.conversations`): see {@link assertDerivedScopeNaming}.
|
|
19
|
+
*
|
|
20
|
+
* @category Protocol
|
|
21
|
+
*/
|
|
22
|
+
import { type Address, type Hex } from "viem";
|
|
23
|
+
import { z } from "zod";
|
|
24
|
+
import { type ResolveWriteSignerOptions, type WriteSignerSource } from "./write-signer.js";
|
|
25
|
+
/** `true` when `value` is a 32-byte hex data point id. */
|
|
26
|
+
export declare function isDataPointId(value: unknown): value is Hex;
|
|
27
|
+
/**
|
|
28
|
+
* Derive the DataRegistryV2 data point id for an owner and scope:
|
|
29
|
+
* `keccak256(abi.encode(address ownerAddress, string scope))`.
|
|
30
|
+
*
|
|
31
|
+
* @param ownerAddress - The data owner (the Personal Server owner).
|
|
32
|
+
* @param scope - The scope the data point is stored under.
|
|
33
|
+
* @returns The 32-byte id, lowercase hex.
|
|
34
|
+
* @throws Error when `ownerAddress` is not an EVM address.
|
|
35
|
+
*/
|
|
36
|
+
export declare function deriveDataPointId(ownerAddress: Address, scope: string): Hex;
|
|
37
|
+
/** First dot-segment of a scope (`chatgpt` for `chatgpt.conversations`). */
|
|
38
|
+
export declare function scopeNamespace(scope: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* The naming rule: a derived scope and a source scope must not share their
|
|
41
|
+
* first dot-segment, because a `prefix.*` grant would then cover both and
|
|
42
|
+
* leak across the lineage edge. Mirrors the Personal Server's check
|
|
43
|
+
* (`LINEAGE_SCOPE_UNDER_SOURCE_PREFIX`).
|
|
44
|
+
*/
|
|
45
|
+
export declare function derivedScopeViolatesNaming(derivedScope: string, sourceScope: string): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Throw when `derivedScope` shares its first dot-segment with any source
|
|
48
|
+
* scope (see {@link derivedScopeViolatesNaming}).
|
|
49
|
+
*
|
|
50
|
+
* @throws {WriteRequestError} Naming the offending source scope in `details`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function assertDerivedScopeNaming(derivedScope: string, sourceScopes: readonly string[]): void;
|
|
53
|
+
export declare const LineageNodeSchema: z.ZodObject<{
|
|
54
|
+
dataPointId: z.ZodPipe<z.ZodString, z.ZodTransform<`0x${string}`, string>>;
|
|
55
|
+
scope: z.ZodString;
|
|
56
|
+
version: z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<string, string | number>>;
|
|
57
|
+
deletedAt: z.ZodNullable<z.ZodString>;
|
|
58
|
+
}, z.core.$strip>;
|
|
59
|
+
export declare const RedactedLineageNodeSchema: z.ZodObject<{
|
|
60
|
+
dataPointId: z.ZodPipe<z.ZodString, z.ZodTransform<`0x${string}`, string>>;
|
|
61
|
+
redacted: z.ZodLiteral<true>;
|
|
62
|
+
}, z.core.$strip>;
|
|
63
|
+
export declare const LineageEntrySchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
64
|
+
dataPointId: z.ZodPipe<z.ZodString, z.ZodTransform<`0x${string}`, string>>;
|
|
65
|
+
redacted: z.ZodLiteral<true>;
|
|
66
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
67
|
+
dataPointId: z.ZodPipe<z.ZodString, z.ZodTransform<`0x${string}`, string>>;
|
|
68
|
+
scope: z.ZodString;
|
|
69
|
+
version: z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<string, string | number>>;
|
|
70
|
+
deletedAt: z.ZodNullable<z.ZodString>;
|
|
71
|
+
}, z.core.$strip>]>;
|
|
72
|
+
export declare const LineageGraphSchema: z.ZodObject<{
|
|
73
|
+
dataPointId: z.ZodPipe<z.ZodString, z.ZodTransform<`0x${string}`, string>>;
|
|
74
|
+
ownerAddress: z.ZodOptional<z.ZodString>;
|
|
75
|
+
scope: z.ZodString;
|
|
76
|
+
version: z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<string, string | number>>;
|
|
77
|
+
deletedAt: z.ZodNullable<z.ZodString>;
|
|
78
|
+
sources: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
79
|
+
dataPointId: z.ZodPipe<z.ZodString, z.ZodTransform<`0x${string}`, string>>;
|
|
80
|
+
redacted: z.ZodLiteral<true>;
|
|
81
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
82
|
+
dataPointId: z.ZodPipe<z.ZodString, z.ZodTransform<`0x${string}`, string>>;
|
|
83
|
+
scope: z.ZodString;
|
|
84
|
+
version: z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<string, string | number>>;
|
|
85
|
+
deletedAt: z.ZodNullable<z.ZodString>;
|
|
86
|
+
}, z.core.$strip>]>>;
|
|
87
|
+
derivatives: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
88
|
+
dataPointId: z.ZodPipe<z.ZodString, z.ZodTransform<`0x${string}`, string>>;
|
|
89
|
+
redacted: z.ZodLiteral<true>;
|
|
90
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
91
|
+
dataPointId: z.ZodPipe<z.ZodString, z.ZodTransform<`0x${string}`, string>>;
|
|
92
|
+
scope: z.ZodString;
|
|
93
|
+
version: z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<string, string | number>>;
|
|
94
|
+
deletedAt: z.ZodNullable<z.ZodString>;
|
|
95
|
+
}, z.core.$strip>]>>;
|
|
96
|
+
derivativesTruncated: z.ZodOptional<z.ZodBoolean>;
|
|
97
|
+
}, z.core.$strip>;
|
|
98
|
+
/** A lineage node the caller is allowed to see. */
|
|
99
|
+
export type LineageNode = z.infer<typeof LineageNodeSchema>;
|
|
100
|
+
/** A lineage node the caller holds no grant for: only its id is disclosed. */
|
|
101
|
+
export type RedactedLineageNode = z.infer<typeof RedactedLineageNodeSchema>;
|
|
102
|
+
/** One entry of a lineage graph. Narrow with {@link isRedactedLineageNode}. */
|
|
103
|
+
export type LineageEntry = z.infer<typeof LineageEntrySchema>;
|
|
104
|
+
/** The lineage view of one data point (the `data` of the response). */
|
|
105
|
+
export type LineageGraph = z.infer<typeof LineageGraphSchema>;
|
|
106
|
+
/** A lineage read: the view plus the gateway's attestation over it. */
|
|
107
|
+
export interface LineageReadResult extends LineageGraph {
|
|
108
|
+
/**
|
|
109
|
+
* The gateway `proof` (`GatewayAttestation` over the served view, so a
|
|
110
|
+
* redacted view verifies on its own). Passed through as received; absent
|
|
111
|
+
* when the server sent none.
|
|
112
|
+
*/
|
|
113
|
+
proof?: Record<string, unknown>;
|
|
114
|
+
}
|
|
115
|
+
/** `true` when the entry was redacted (the caller holds no grant for it). */
|
|
116
|
+
export declare function isRedactedLineageNode(entry: LineageEntry): entry is RedactedLineageNode;
|
|
117
|
+
/**
|
|
118
|
+
* The Personal Server lineage path: `/v1/data/:scope/lineage[/:version]`.
|
|
119
|
+
* The version is a path segment (a query string is refused by the server),
|
|
120
|
+
* so the signed `uri` covers the whole request.
|
|
121
|
+
*/
|
|
122
|
+
export declare function personalServerLineagePath(scope: string, version?: string | number): string;
|
|
123
|
+
/**
|
|
124
|
+
* The gateway lineage path: `/v1/data/<id lowercase>/lineage[/:version]`,
|
|
125
|
+
* what the request is signed over and sent to. The grant view is the signed
|
|
126
|
+
* `grantId` claim, never a query parameter.
|
|
127
|
+
*/
|
|
128
|
+
export declare function gatewayLineagePath(dataPointId: Hex, version?: string | number): string;
|
|
129
|
+
interface LineageRequestOptions {
|
|
130
|
+
/**
|
|
131
|
+
* Read the lineage as of this version (a positive decimal integer);
|
|
132
|
+
* omitted = the current version, or the last version that carried lineage
|
|
133
|
+
* when the current one is a tombstone.
|
|
134
|
+
*/
|
|
135
|
+
version?: string | number;
|
|
136
|
+
/** `fetch` to use; defaults to `globalThis.fetch`. */
|
|
137
|
+
fetch?: typeof fetch;
|
|
138
|
+
/** Extra request headers. */
|
|
139
|
+
headers?: HeadersInit;
|
|
140
|
+
}
|
|
141
|
+
/** Lineage read against the Personal Server holding the record. */
|
|
142
|
+
export interface PersonalServerLineageParams extends LineageRequestOptions {
|
|
143
|
+
/** Personal Server origin, e.g. `https://ps.example.com`. */
|
|
144
|
+
personalServerUrl: string;
|
|
145
|
+
/** The scope whose lineage to read. */
|
|
146
|
+
scope: string;
|
|
147
|
+
/** A grant covering the scope, sent as the signed `grantId` claim. */
|
|
148
|
+
grantId: string;
|
|
149
|
+
/** Builder key: a viem `LocalAccount`, `WalletClient`, or `{ signMessage }`. */
|
|
150
|
+
signer: WriteSignerSource;
|
|
151
|
+
/** Account for a viem wallet client without a hoisted account. */
|
|
152
|
+
account?: ResolveWriteSignerOptions["account"];
|
|
153
|
+
/** Web3Signed audience; defaults to `personalServerUrl`. */
|
|
154
|
+
audience?: string;
|
|
155
|
+
}
|
|
156
|
+
/** Lineage read against the gateway, by data point id. */
|
|
157
|
+
export interface GatewayLineageParams extends LineageRequestOptions {
|
|
158
|
+
/** Gateway origin, e.g. `https://dp-rpc.vana.org`. */
|
|
159
|
+
gatewayUrl: string;
|
|
160
|
+
/** The data point whose lineage to read (see {@link deriveDataPointId}). */
|
|
161
|
+
dataPointId: Hex;
|
|
162
|
+
/**
|
|
163
|
+
* The key the request is signed with (Web3Signed, audience = the gateway
|
|
164
|
+
* origin). The signer decides the view: the owner or one of its servers
|
|
165
|
+
* gets the full view; a registered builder holding a live grant covering
|
|
166
|
+
* the data point's scope gets that grant's view; anyone else is refused.
|
|
167
|
+
*/
|
|
168
|
+
signer: WriteSignerSource;
|
|
169
|
+
/** Account for a viem wallet client without a hoisted account. */
|
|
170
|
+
account?: ResolveWriteSignerOptions["account"];
|
|
171
|
+
/**
|
|
172
|
+
* The grant whose view to read, sent lowercased as the signed `grantId`
|
|
173
|
+
* claim (never as a query parameter). An owner or server uses it to fetch
|
|
174
|
+
* the view a builder's grant sees; a builder needs it to see anything.
|
|
175
|
+
*/
|
|
176
|
+
grantId?: string;
|
|
177
|
+
}
|
|
178
|
+
export type GetLineageParams = PersonalServerLineageParams | GatewayLineageParams;
|
|
179
|
+
/**
|
|
180
|
+
* Read a scope's lineage from the Personal Server that stores it.
|
|
181
|
+
*
|
|
182
|
+
* @remarks
|
|
183
|
+
* Sends `GET /v1/data/:scope/lineage[/:version]` with a Web3Signed
|
|
184
|
+
* `Authorization` header carrying `grantId`, the same authentication a data
|
|
185
|
+
* read uses; the signed `uri` is the full path, version segment included.
|
|
186
|
+
* The server resolves the data point id, fetches the view the grant sees
|
|
187
|
+
* from the gateway and returns the gateway's `data` + `proof`.
|
|
188
|
+
*
|
|
189
|
+
* @returns The lineage view, with redacted entries for nodes the grant does
|
|
190
|
+
* not cover, plus the gateway attestation.
|
|
191
|
+
* @throws {LineageReadError} On a non-2xx answer (`errorCode`: read errors,
|
|
192
|
+
* `INVALID_VERSION`, `NOT_FOUND` when the scope or version is not
|
|
193
|
+
* registered at the gateway, `LINEAGE_FORBIDDEN`, `LINEAGE_GATEWAY_ERROR`,
|
|
194
|
+
* `LINEAGE_UNAVAILABLE`), an unreadable body, a bad `version`, or a
|
|
195
|
+
* transport failure.
|
|
196
|
+
*/
|
|
197
|
+
export declare function getPersonalServerLineage(params: PersonalServerLineageParams): Promise<LineageReadResult>;
|
|
198
|
+
/**
|
|
199
|
+
* Read a data point's lineage from the gateway.
|
|
200
|
+
*
|
|
201
|
+
* @remarks
|
|
202
|
+
* Sends `GET /v1/data/:dataPointId/lineage[/:version]` with a Web3Signed
|
|
203
|
+
* `Authorization` header: `aud` = the gateway origin, `uri` =
|
|
204
|
+
* {@link gatewayLineagePath} (lowercase id, version segment included),
|
|
205
|
+
* empty-body `bodyHash`, and the lowercased `grantId` claim when given. The
|
|
206
|
+
* gateway answers a uniform 404 for an unknown data point and for a signer
|
|
207
|
+
* it will not serve, so the two cannot be told apart from outside.
|
|
208
|
+
*
|
|
209
|
+
* @returns The lineage view, with redacted entries for nodes the caller's
|
|
210
|
+
* grant does not cover, plus the gateway attestation.
|
|
211
|
+
* @throws {LineageReadError} On a malformed `dataPointId` or `version`, a
|
|
212
|
+
* non-2xx answer (400 malformed request, 401 `LINEAGE_SIGNATURE_REQUIRED`
|
|
213
|
+
* / `LINEAGE_SIGNATURE_INVALID`, 404 unknown or not served), an unreadable
|
|
214
|
+
* body, or a transport failure.
|
|
215
|
+
*/
|
|
216
|
+
export declare function getGatewayLineage(params: GatewayLineageParams): Promise<LineageReadResult>;
|
|
217
|
+
/**
|
|
218
|
+
* Read a lineage view from either the Personal Server (by scope) or the
|
|
219
|
+
* gateway (by data point id), chosen by the params shape.
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```typescript
|
|
223
|
+
* const fromPs = await getLineage({ personalServerUrl, scope, grantId, signer });
|
|
224
|
+
* const fromGateway = await getLineage({ gatewayUrl, dataPointId, grantId, signer });
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
227
|
+
export declare function getLineage(params: GetLineageParams): Promise<LineageReadResult>;
|
|
228
|
+
export {};
|