@opendatalabs/vana-sdk 3.16.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 +3 -0
- package/dist/index.browser.js +988 -12
- package/dist/index.browser.js.map +4 -4
- package/dist/index.node.cjs +1030 -13
- package/dist/index.node.cjs.map +4 -4
- package/dist/index.node.d.ts +3 -0
- package/dist/index.node.js +988 -12
- package/dist/index.node.js.map +4 -4
- 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/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
package/dist/index.node.js
CHANGED
|
@@ -1288,6 +1288,76 @@ var TransactionPendingError = class extends VanaError {
|
|
|
1288
1288
|
};
|
|
1289
1289
|
}
|
|
1290
1290
|
};
|
|
1291
|
+
var PersonalServerWriteError = class extends VanaError {
|
|
1292
|
+
constructor(message, code, status, errorCode = null, details) {
|
|
1293
|
+
super(message, code);
|
|
1294
|
+
this.status = status;
|
|
1295
|
+
this.errorCode = errorCode;
|
|
1296
|
+
this.details = details;
|
|
1297
|
+
}
|
|
1298
|
+
status;
|
|
1299
|
+
errorCode;
|
|
1300
|
+
details;
|
|
1301
|
+
};
|
|
1302
|
+
var WriteRequestError = class extends PersonalServerWriteError {
|
|
1303
|
+
constructor(message, details) {
|
|
1304
|
+
super(message, "WRITE_INVALID_REQUEST", void 0, null, details);
|
|
1305
|
+
}
|
|
1306
|
+
};
|
|
1307
|
+
var WriteTransportError = class extends PersonalServerWriteError {
|
|
1308
|
+
constructor(message, attempts, cause) {
|
|
1309
|
+
super(message, "WRITE_TRANSPORT_ERROR", void 0, null, { attempts });
|
|
1310
|
+
this.attempts = attempts;
|
|
1311
|
+
this.cause = cause;
|
|
1312
|
+
}
|
|
1313
|
+
attempts;
|
|
1314
|
+
};
|
|
1315
|
+
var WriteSessionError = class extends PersonalServerWriteError {
|
|
1316
|
+
constructor(message, status, errorCode = null, details) {
|
|
1317
|
+
super(message, "WRITE_SESSION_REJECTED", status, errorCode, details);
|
|
1318
|
+
}
|
|
1319
|
+
};
|
|
1320
|
+
var WriteSessionExpiredError = class extends PersonalServerWriteError {
|
|
1321
|
+
constructor(message, details) {
|
|
1322
|
+
super(message, "WRITE_SESSION_EXPIRED", void 0, null, details);
|
|
1323
|
+
}
|
|
1324
|
+
};
|
|
1325
|
+
var WriteUnauthorizedError = class extends PersonalServerWriteError {
|
|
1326
|
+
constructor(message, errorCode = null, details) {
|
|
1327
|
+
super(message, "WRITE_UNAUTHORIZED", 401, errorCode, details);
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
var WriteForbiddenError = class extends PersonalServerWriteError {
|
|
1331
|
+
constructor(message, errorCode = null, details) {
|
|
1332
|
+
super(message, "WRITE_FORBIDDEN", 403, errorCode, details);
|
|
1333
|
+
}
|
|
1334
|
+
};
|
|
1335
|
+
var WriteConflictError = class extends PersonalServerWriteError {
|
|
1336
|
+
constructor(message, errorCode = null, details) {
|
|
1337
|
+
super(message, "WRITE_CONFLICT", 409, errorCode, details);
|
|
1338
|
+
}
|
|
1339
|
+
};
|
|
1340
|
+
var WriteLineageError = class extends PersonalServerWriteError {
|
|
1341
|
+
constructor(message, status = 422, errorCode = null, details) {
|
|
1342
|
+
super(message, "WRITE_LINEAGE_REJECTED", status, errorCode, details);
|
|
1343
|
+
}
|
|
1344
|
+
};
|
|
1345
|
+
var WriteRejectedError = class extends PersonalServerWriteError {
|
|
1346
|
+
constructor(message, status, errorCode = null, details) {
|
|
1347
|
+
super(message, "WRITE_REJECTED", status, errorCode, details);
|
|
1348
|
+
}
|
|
1349
|
+
};
|
|
1350
|
+
var LineageReadError = class extends VanaError {
|
|
1351
|
+
constructor(message, status, errorCode = null, details) {
|
|
1352
|
+
super(message, "LINEAGE_READ_ERROR");
|
|
1353
|
+
this.status = status;
|
|
1354
|
+
this.errorCode = errorCode;
|
|
1355
|
+
this.details = details;
|
|
1356
|
+
}
|
|
1357
|
+
status;
|
|
1358
|
+
errorCode;
|
|
1359
|
+
details;
|
|
1360
|
+
};
|
|
1291
1361
|
|
|
1292
1362
|
// src/contracts/contractController.ts
|
|
1293
1363
|
import {
|
|
@@ -32799,13 +32869,13 @@ function createViemPersonalServerRegistrationSigner(source, options = {}) {
|
|
|
32799
32869
|
if (isPersonalServerRegistrationSigner(source)) {
|
|
32800
32870
|
return source;
|
|
32801
32871
|
}
|
|
32802
|
-
const
|
|
32803
|
-
if (
|
|
32872
|
+
const accountAddress2 = getAccountAddress(options.account) ?? getAccountAddress(source.account);
|
|
32873
|
+
if (accountAddress2) {
|
|
32804
32874
|
return {
|
|
32805
|
-
address:
|
|
32875
|
+
address: accountAddress2,
|
|
32806
32876
|
signTypedData: (typedData) => source.signTypedData({
|
|
32807
32877
|
...typedData,
|
|
32808
|
-
account: options.account ?? source.account ??
|
|
32878
|
+
account: options.account ?? source.account ?? accountAddress2
|
|
32809
32879
|
})
|
|
32810
32880
|
};
|
|
32811
32881
|
}
|
|
@@ -32890,12 +32960,12 @@ function createViemPersonalServerLiteOwnerBindingSigner(source, options = {}) {
|
|
|
32890
32960
|
if (isPersonalServerLiteOwnerBindingSigner(source)) {
|
|
32891
32961
|
return source;
|
|
32892
32962
|
}
|
|
32893
|
-
const
|
|
32894
|
-
if (
|
|
32963
|
+
const accountAddress2 = getAccountAddress2(options.account) ?? getAccountAddress2(source.account);
|
|
32964
|
+
if (accountAddress2) {
|
|
32895
32965
|
return {
|
|
32896
|
-
address:
|
|
32966
|
+
address: accountAddress2,
|
|
32897
32967
|
signMessage: ({ message }) => source.signMessage({
|
|
32898
|
-
account: options.account ?? source.account ??
|
|
32968
|
+
account: options.account ?? source.account ?? accountAddress2,
|
|
32899
32969
|
message
|
|
32900
32970
|
})
|
|
32901
32971
|
};
|
|
@@ -33718,6 +33788,867 @@ function tryGrantPermissions(scopes) {
|
|
|
33718
33788
|
}
|
|
33719
33789
|
}
|
|
33720
33790
|
|
|
33791
|
+
// src/protocol/personal-server-write.ts
|
|
33792
|
+
import { sha256 as sha2565 } from "@noble/hashes/sha2";
|
|
33793
|
+
import { bytesToHex as bytesToHex2, isAddress as isAddress5 } from "viem";
|
|
33794
|
+
import { z as z4 } from "zod";
|
|
33795
|
+
|
|
33796
|
+
// src/protocol/lineage.ts
|
|
33797
|
+
import {
|
|
33798
|
+
encodeAbiParameters,
|
|
33799
|
+
isAddress as isAddress4,
|
|
33800
|
+
keccak256
|
|
33801
|
+
} from "viem";
|
|
33802
|
+
import { z as z3 } from "zod";
|
|
33803
|
+
|
|
33804
|
+
// src/protocol/personal-server-error-body.ts
|
|
33805
|
+
function isRecord2(value) {
|
|
33806
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
33807
|
+
}
|
|
33808
|
+
async function readPersonalServerErrorBody(response) {
|
|
33809
|
+
let body;
|
|
33810
|
+
try {
|
|
33811
|
+
body = await response.json();
|
|
33812
|
+
} catch {
|
|
33813
|
+
return { errorCode: null, message: null };
|
|
33814
|
+
}
|
|
33815
|
+
if (!isRecord2(body)) return { errorCode: null, message: null };
|
|
33816
|
+
const nested = isRecord2(body.error) ? body.error : null;
|
|
33817
|
+
const gatewayShape = typeof body.error === "string" && typeof body.code === "string";
|
|
33818
|
+
const code = nested?.errorCode ?? nested?.code ?? body.errorCode ?? (gatewayShape ? body.code : void 0) ?? (typeof body.error === "string" ? body.error : void 0) ?? body.code;
|
|
33819
|
+
const message = nested?.message ?? body.message ?? (gatewayShape ? body.error : void 0);
|
|
33820
|
+
const gatewayDetails = {};
|
|
33821
|
+
for (const key of ["unknown", "scope", "sourceScope"]) {
|
|
33822
|
+
if (gatewayShape && body[key] !== void 0)
|
|
33823
|
+
gatewayDetails[key] = body[key];
|
|
33824
|
+
}
|
|
33825
|
+
const details = nested?.details ?? body.details ?? (Object.keys(gatewayDetails).length > 0 ? gatewayDetails : void 0);
|
|
33826
|
+
return {
|
|
33827
|
+
errorCode: typeof code === "string" ? code : null,
|
|
33828
|
+
message: typeof message === "string" ? message : null,
|
|
33829
|
+
...isRecord2(details) ? { details } : {}
|
|
33830
|
+
};
|
|
33831
|
+
}
|
|
33832
|
+
|
|
33833
|
+
// src/protocol/write-signer.ts
|
|
33834
|
+
function isRecord3(value) {
|
|
33835
|
+
return value !== null && typeof value === "object";
|
|
33836
|
+
}
|
|
33837
|
+
function isViemWriteAccount(source) {
|
|
33838
|
+
return isRecord3(source) && source.type === "local" && typeof source.address === "string" && typeof source.signMessage === "function";
|
|
33839
|
+
}
|
|
33840
|
+
function isViemWriteWalletClient(source) {
|
|
33841
|
+
return isRecord3(source) && typeof source.signMessage === "function" && source.type !== "local" && (source.type === "walletClient" || "transport" in source);
|
|
33842
|
+
}
|
|
33843
|
+
function accountAddress(account) {
|
|
33844
|
+
return typeof account === "string" ? account : account.address;
|
|
33845
|
+
}
|
|
33846
|
+
function resolveWriteSigner(source, options = {}) {
|
|
33847
|
+
if (isViemWriteWalletClient(source)) {
|
|
33848
|
+
const account = options.account ?? source.account;
|
|
33849
|
+
if (account === void 0) {
|
|
33850
|
+
throw new WriteRequestError(
|
|
33851
|
+
"Viem wallet client requires an account option or account property"
|
|
33852
|
+
);
|
|
33853
|
+
}
|
|
33854
|
+
return {
|
|
33855
|
+
address: accountAddress(account),
|
|
33856
|
+
signMessage: (message) => source.signMessage({ account, message })
|
|
33857
|
+
};
|
|
33858
|
+
}
|
|
33859
|
+
if (isViemWriteAccount(source)) {
|
|
33860
|
+
return {
|
|
33861
|
+
address: source.address,
|
|
33862
|
+
signMessage: (message) => source.signMessage({ message })
|
|
33863
|
+
};
|
|
33864
|
+
}
|
|
33865
|
+
if (!isRecord3(source) || typeof source.signMessage !== "function") {
|
|
33866
|
+
throw new WriteRequestError(
|
|
33867
|
+
"signer must be a viem LocalAccount, a viem WalletClient, or a { signMessage } object"
|
|
33868
|
+
);
|
|
33869
|
+
}
|
|
33870
|
+
return source;
|
|
33871
|
+
}
|
|
33872
|
+
|
|
33873
|
+
// src/protocol/lineage.ts
|
|
33874
|
+
var DATA_POINT_ID_PATTERN = /^0x[0-9a-fA-F]{64}$/;
|
|
33875
|
+
function isDataPointId(value) {
|
|
33876
|
+
return typeof value === "string" && DATA_POINT_ID_PATTERN.test(value);
|
|
33877
|
+
}
|
|
33878
|
+
function deriveDataPointId(ownerAddress, scope) {
|
|
33879
|
+
if (!isAddress4(ownerAddress, { strict: false })) {
|
|
33880
|
+
throw new Error(
|
|
33881
|
+
`ownerAddress is not an EVM address: ${String(ownerAddress)}`
|
|
33882
|
+
);
|
|
33883
|
+
}
|
|
33884
|
+
return keccak256(
|
|
33885
|
+
encodeAbiParameters(
|
|
33886
|
+
[
|
|
33887
|
+
{ name: "ownerAddress", type: "address" },
|
|
33888
|
+
{ name: "scope", type: "string" }
|
|
33889
|
+
],
|
|
33890
|
+
[ownerAddress, scope]
|
|
33891
|
+
)
|
|
33892
|
+
);
|
|
33893
|
+
}
|
|
33894
|
+
var DataPointIdSchema = z3.string().regex(DATA_POINT_ID_PATTERN).transform((value) => value.toLowerCase());
|
|
33895
|
+
var VERSION_PATTERN = /^[1-9]\d*$/;
|
|
33896
|
+
var NODE_VERSION_PATTERN = /^(0|[1-9]\d*)$/;
|
|
33897
|
+
var VersionSchema = z3.union([z3.string(), z3.number()]).transform(String).refine((value) => NODE_VERSION_PATTERN.test(value), {
|
|
33898
|
+
message: "version must be a decimal integer"
|
|
33899
|
+
});
|
|
33900
|
+
var ViewVersionSchema = VersionSchema.refine(
|
|
33901
|
+
(value) => VERSION_PATTERN.test(value),
|
|
33902
|
+
{ message: "version must be a positive decimal integer" }
|
|
33903
|
+
);
|
|
33904
|
+
function scopeNamespace(scope) {
|
|
33905
|
+
const dot = scope.indexOf(".");
|
|
33906
|
+
return dot === -1 ? scope : scope.slice(0, dot);
|
|
33907
|
+
}
|
|
33908
|
+
function derivedScopeViolatesNaming(derivedScope, sourceScope) {
|
|
33909
|
+
return scopeNamespace(derivedScope) === scopeNamespace(sourceScope);
|
|
33910
|
+
}
|
|
33911
|
+
function assertDerivedScopeNaming(derivedScope, sourceScopes) {
|
|
33912
|
+
for (const sourceScope of sourceScopes) {
|
|
33913
|
+
if (derivedScopeViolatesNaming(derivedScope, sourceScope)) {
|
|
33914
|
+
throw new WriteRequestError(
|
|
33915
|
+
`Derived scope ${derivedScope} must not share its first segment with source scope ${sourceScope}; put derivatives in the app's own namespace`,
|
|
33916
|
+
{ scope: derivedScope, sourceScope }
|
|
33917
|
+
);
|
|
33918
|
+
}
|
|
33919
|
+
}
|
|
33920
|
+
}
|
|
33921
|
+
var LineageNodeSchema = z3.object({
|
|
33922
|
+
dataPointId: DataPointIdSchema,
|
|
33923
|
+
scope: z3.string(),
|
|
33924
|
+
/**
|
|
33925
|
+
* The node's current version, decimal string; `"0"` for a source that no
|
|
33926
|
+
* longer resolves to a registered data point.
|
|
33927
|
+
*/
|
|
33928
|
+
version: VersionSchema,
|
|
33929
|
+
/** The node's tombstone time, or `null` when live. */
|
|
33930
|
+
deletedAt: z3.string().nullable()
|
|
33931
|
+
});
|
|
33932
|
+
var RedactedLineageNodeSchema = z3.object({
|
|
33933
|
+
dataPointId: DataPointIdSchema,
|
|
33934
|
+
redacted: z3.literal(true)
|
|
33935
|
+
});
|
|
33936
|
+
var LineageEntrySchema = z3.union([
|
|
33937
|
+
RedactedLineageNodeSchema,
|
|
33938
|
+
LineageNodeSchema
|
|
33939
|
+
]);
|
|
33940
|
+
var LineageGraphSchema = z3.object({
|
|
33941
|
+
dataPointId: DataPointIdSchema,
|
|
33942
|
+
/** The data point owner; every node in the view belongs to it. */
|
|
33943
|
+
ownerAddress: z3.string().optional(),
|
|
33944
|
+
scope: z3.string(),
|
|
33945
|
+
/**
|
|
33946
|
+
* The derived record's version whose lineage is shown: the requested one,
|
|
33947
|
+
* else the current one, else (current is a tombstone) the last version
|
|
33948
|
+
* that carried lineage.
|
|
33949
|
+
*/
|
|
33950
|
+
version: ViewVersionSchema,
|
|
33951
|
+
deletedAt: z3.string().nullable(),
|
|
33952
|
+
sources: z3.array(LineageEntrySchema),
|
|
33953
|
+
derivatives: z3.array(LineageEntrySchema),
|
|
33954
|
+
/** `true` when `derivatives` was cut at the server's cap (1000). */
|
|
33955
|
+
derivativesTruncated: z3.boolean().optional()
|
|
33956
|
+
});
|
|
33957
|
+
function isRedactedLineageNode(entry) {
|
|
33958
|
+
return "redacted" in entry && entry.redacted === true;
|
|
33959
|
+
}
|
|
33960
|
+
function personalServerLineagePath(scope, version) {
|
|
33961
|
+
return `/v1/data/${encodeURIComponent(scope)}/lineage${version === void 0 ? "" : `/${String(version)}`}`;
|
|
33962
|
+
}
|
|
33963
|
+
function gatewayLineagePath(dataPointId, version) {
|
|
33964
|
+
return `/v1/data/${dataPointId.toLowerCase()}/lineage${version === void 0 ? "" : `/${String(version)}`}`;
|
|
33965
|
+
}
|
|
33966
|
+
function normalizeBaseUrl(url) {
|
|
33967
|
+
return url.replace(/\/+$/, "");
|
|
33968
|
+
}
|
|
33969
|
+
function resolveFetch(fetchFn) {
|
|
33970
|
+
const resolved = fetchFn ?? globalThis.fetch;
|
|
33971
|
+
if (resolved === void 0) {
|
|
33972
|
+
throw new LineageReadError("No fetch implementation available");
|
|
33973
|
+
}
|
|
33974
|
+
return resolved;
|
|
33975
|
+
}
|
|
33976
|
+
function normalizeVersion(version) {
|
|
33977
|
+
if (version === void 0) return void 0;
|
|
33978
|
+
const text = String(version);
|
|
33979
|
+
if (!VERSION_PATTERN.test(text)) {
|
|
33980
|
+
throw new LineageReadError(
|
|
33981
|
+
"version must be a positive decimal integer",
|
|
33982
|
+
void 0,
|
|
33983
|
+
"INVALID_VERSION",
|
|
33984
|
+
{ version }
|
|
33985
|
+
);
|
|
33986
|
+
}
|
|
33987
|
+
return text;
|
|
33988
|
+
}
|
|
33989
|
+
async function lineageReadFailure(source, response) {
|
|
33990
|
+
const { errorCode, message, details } = await readPersonalServerErrorBody(response);
|
|
33991
|
+
return new LineageReadError(
|
|
33992
|
+
message ?? `${source} lineage read failed: ${response.status} ${response.statusText}`,
|
|
33993
|
+
response.status,
|
|
33994
|
+
errorCode,
|
|
33995
|
+
details
|
|
33996
|
+
);
|
|
33997
|
+
}
|
|
33998
|
+
async function parseLineageGraph(source, response) {
|
|
33999
|
+
let body;
|
|
34000
|
+
try {
|
|
34001
|
+
body = await response.json();
|
|
34002
|
+
} catch (err) {
|
|
34003
|
+
throw new LineageReadError(
|
|
34004
|
+
`${source} lineage response is not JSON`,
|
|
34005
|
+
response.status,
|
|
34006
|
+
null,
|
|
34007
|
+
{ cause: err instanceof Error ? err.message : String(err) }
|
|
34008
|
+
);
|
|
34009
|
+
}
|
|
34010
|
+
const envelope = isRecord2(body) && isRecord2(body.data) ? body : void 0;
|
|
34011
|
+
const parsed = LineageGraphSchema.safeParse(envelope?.data ?? body);
|
|
34012
|
+
if (!parsed.success) {
|
|
34013
|
+
throw new LineageReadError(
|
|
34014
|
+
`${source} lineage response is not a lineage view`,
|
|
34015
|
+
response.status,
|
|
34016
|
+
null,
|
|
34017
|
+
{ issues: parsed.error.issues }
|
|
34018
|
+
);
|
|
34019
|
+
}
|
|
34020
|
+
const proof = isRecord2(envelope?.proof) ? envelope.proof : void 0;
|
|
34021
|
+
return proof === void 0 ? parsed.data : { ...parsed.data, proof };
|
|
34022
|
+
}
|
|
34023
|
+
async function sendLineageRead(source, fetchFn, url, headers) {
|
|
34024
|
+
let response;
|
|
34025
|
+
try {
|
|
34026
|
+
response = await fetchFn(url, { method: "GET", headers });
|
|
34027
|
+
} catch (err) {
|
|
34028
|
+
throw new LineageReadError(
|
|
34029
|
+
`${source} lineage read failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
34030
|
+
void 0,
|
|
34031
|
+
null,
|
|
34032
|
+
{ cause: err instanceof Error ? err.message : String(err) }
|
|
34033
|
+
);
|
|
34034
|
+
}
|
|
34035
|
+
if (!response.ok) {
|
|
34036
|
+
throw await lineageReadFailure(source, response);
|
|
34037
|
+
}
|
|
34038
|
+
return parseLineageGraph(source, response);
|
|
34039
|
+
}
|
|
34040
|
+
async function getPersonalServerLineage(params) {
|
|
34041
|
+
const fetchFn = resolveFetch(params.fetch);
|
|
34042
|
+
const baseUrl = normalizeBaseUrl(params.personalServerUrl);
|
|
34043
|
+
const audience = params.audience ?? baseUrl;
|
|
34044
|
+
const signer = resolveWriteSigner(params.signer, { account: params.account });
|
|
34045
|
+
const path = personalServerLineagePath(
|
|
34046
|
+
params.scope,
|
|
34047
|
+
normalizeVersion(params.version)
|
|
34048
|
+
);
|
|
34049
|
+
const headers = new Headers(params.headers);
|
|
34050
|
+
headers.set(
|
|
34051
|
+
"Authorization",
|
|
34052
|
+
await buildWeb3SignedHeader({
|
|
34053
|
+
signMessage: signer.signMessage,
|
|
34054
|
+
aud: audience,
|
|
34055
|
+
method: "GET",
|
|
34056
|
+
uri: path,
|
|
34057
|
+
grantId: params.grantId
|
|
34058
|
+
})
|
|
34059
|
+
);
|
|
34060
|
+
return sendLineageRead(
|
|
34061
|
+
"Personal Server",
|
|
34062
|
+
fetchFn,
|
|
34063
|
+
`${baseUrl}${path}`,
|
|
34064
|
+
headers
|
|
34065
|
+
);
|
|
34066
|
+
}
|
|
34067
|
+
async function getGatewayLineage(params) {
|
|
34068
|
+
if (!isDataPointId(params.dataPointId)) {
|
|
34069
|
+
throw new LineageReadError(
|
|
34070
|
+
"dataPointId must be a 32-byte hex string (see deriveDataPointId)",
|
|
34071
|
+
void 0,
|
|
34072
|
+
"INVALID_DATA_POINT_ID",
|
|
34073
|
+
{ dataPointId: params.dataPointId }
|
|
34074
|
+
);
|
|
34075
|
+
}
|
|
34076
|
+
const fetchFn = resolveFetch(params.fetch);
|
|
34077
|
+
const baseUrl = normalizeBaseUrl(params.gatewayUrl);
|
|
34078
|
+
const signer = resolveWriteSigner(params.signer, { account: params.account });
|
|
34079
|
+
const uri = gatewayLineagePath(
|
|
34080
|
+
params.dataPointId,
|
|
34081
|
+
normalizeVersion(params.version)
|
|
34082
|
+
);
|
|
34083
|
+
const headers = new Headers(params.headers);
|
|
34084
|
+
headers.set(
|
|
34085
|
+
"Authorization",
|
|
34086
|
+
await buildWeb3SignedHeader({
|
|
34087
|
+
signMessage: signer.signMessage,
|
|
34088
|
+
aud: baseUrl,
|
|
34089
|
+
method: "GET",
|
|
34090
|
+
uri,
|
|
34091
|
+
grantId: params.grantId?.toLowerCase()
|
|
34092
|
+
})
|
|
34093
|
+
);
|
|
34094
|
+
return sendLineageRead("Gateway", fetchFn, `${baseUrl}${uri}`, headers);
|
|
34095
|
+
}
|
|
34096
|
+
function getLineage(params) {
|
|
34097
|
+
return "personalServerUrl" in params ? getPersonalServerLineage(params) : getGatewayLineage(params);
|
|
34098
|
+
}
|
|
34099
|
+
|
|
34100
|
+
// src/protocol/personal-server-write.ts
|
|
34101
|
+
var WRITE_SESSION_PATH = "/v1/write/session";
|
|
34102
|
+
var WRITE_SIGNATURE_HEADER = "X-Vana-Write-Signature";
|
|
34103
|
+
var WRITE_METADATA_HEADER = "X-Vana-Metadata";
|
|
34104
|
+
var LINEAGE_FIELD = "lineage";
|
|
34105
|
+
var MAX_LINEAGE_SOURCES = 256;
|
|
34106
|
+
var WRITE_FILENAME_HEADER = "X-Filename";
|
|
34107
|
+
var WRITE_CONTENT_DISPOSITION_HEADER = "Content-Disposition";
|
|
34108
|
+
var WRITER_ATTRIBUTION_KEY = "$writtenBy";
|
|
34109
|
+
var LINEAGE_KEY = "$lineage";
|
|
34110
|
+
var RESERVED_WRITE_KEYS = [
|
|
34111
|
+
WRITER_ATTRIBUTION_KEY,
|
|
34112
|
+
LINEAGE_KEY
|
|
34113
|
+
];
|
|
34114
|
+
var WriteDataResultSchema = IngestResponseSchema.extend({
|
|
34115
|
+
// Present when the write carried lineage: the validated, lowercased ids.
|
|
34116
|
+
lineage: z4.object({ sources: z4.array(z4.string()) }).optional()
|
|
34117
|
+
});
|
|
34118
|
+
var WriteSessionResponseSchema = z4.object({
|
|
34119
|
+
access_token: z4.string().min(1),
|
|
34120
|
+
token_type: z4.string(),
|
|
34121
|
+
expires_in: z4.number().nonnegative(),
|
|
34122
|
+
scope: z4.string()
|
|
34123
|
+
});
|
|
34124
|
+
function normalizeBaseUrl2(url) {
|
|
34125
|
+
return url.replace(/\/+$/, "");
|
|
34126
|
+
}
|
|
34127
|
+
function resolveFetch2(fetchFn) {
|
|
34128
|
+
const resolved = fetchFn ?? globalThis.fetch;
|
|
34129
|
+
if (resolved === void 0) {
|
|
34130
|
+
throw new WriteRequestError("No fetch implementation available");
|
|
34131
|
+
}
|
|
34132
|
+
return resolved;
|
|
34133
|
+
}
|
|
34134
|
+
function dataPath(scope) {
|
|
34135
|
+
return `/v1/data/${encodeURIComponent(scope)}`;
|
|
34136
|
+
}
|
|
34137
|
+
function errorMessage(err) {
|
|
34138
|
+
return err instanceof Error ? err.message : String(err);
|
|
34139
|
+
}
|
|
34140
|
+
function finiteOr(value, fallback) {
|
|
34141
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
34142
|
+
}
|
|
34143
|
+
function sleep2(ms) {
|
|
34144
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
34145
|
+
}
|
|
34146
|
+
var issuedProofIats = /* @__PURE__ */ new Map();
|
|
34147
|
+
var issuedProofBuckets = /* @__PURE__ */ new Map();
|
|
34148
|
+
var issuedProofIatsPrunedAtSec = 0;
|
|
34149
|
+
var WEB3_SIGNED_PROOF_LIFETIME_SECONDS = 300;
|
|
34150
|
+
var WEB3_SIGNED_CLOCK_SKEW_SECONDS = 60;
|
|
34151
|
+
var PROOF_IAT_RETENTION_SECONDS = WEB3_SIGNED_PROOF_LIFETIME_SECONDS + WEB3_SIGNED_CLOCK_SKEW_SECONDS;
|
|
34152
|
+
var PROOF_IAT_MAX_AHEAD_SECONDS = 30;
|
|
34153
|
+
function pruneIssuedProofIats(nowSec) {
|
|
34154
|
+
if (issuedProofIatsPrunedAtSec === nowSec) return;
|
|
34155
|
+
issuedProofIatsPrunedAtSec = nowSec;
|
|
34156
|
+
const cutoff = nowSec - PROOF_IAT_RETENTION_SECONDS;
|
|
34157
|
+
for (const [sec, keys] of issuedProofBuckets) {
|
|
34158
|
+
if (sec >= cutoff) continue;
|
|
34159
|
+
for (const key of keys) issuedProofIats.delete(key);
|
|
34160
|
+
issuedProofBuckets.delete(sec);
|
|
34161
|
+
}
|
|
34162
|
+
}
|
|
34163
|
+
function setIssuedProofIat(key, iat, previous) {
|
|
34164
|
+
if (previous !== void 0) {
|
|
34165
|
+
const bucket2 = issuedProofBuckets.get(previous);
|
|
34166
|
+
bucket2?.delete(key);
|
|
34167
|
+
if (bucket2?.size === 0) issuedProofBuckets.delete(previous);
|
|
34168
|
+
}
|
|
34169
|
+
issuedProofIats.set(key, iat);
|
|
34170
|
+
let bucket = issuedProofBuckets.get(iat);
|
|
34171
|
+
if (bucket === void 0) {
|
|
34172
|
+
bucket = /* @__PURE__ */ new Set();
|
|
34173
|
+
issuedProofBuckets.set(iat, bucket);
|
|
34174
|
+
}
|
|
34175
|
+
bucket.add(key);
|
|
34176
|
+
}
|
|
34177
|
+
function nextProofIat(proofKey) {
|
|
34178
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
34179
|
+
pruneIssuedProofIats(nowSec);
|
|
34180
|
+
const last = issuedProofIats.get(proofKey);
|
|
34181
|
+
const iat = last === void 0 ? nowSec : Math.max(nowSec, last + 1);
|
|
34182
|
+
setIssuedProofIat(proofKey, iat, last);
|
|
34183
|
+
const waitSec = iat - nowSec - PROOF_IAT_MAX_AHEAD_SECONDS;
|
|
34184
|
+
if (waitSec <= 0) return Promise.resolve(iat);
|
|
34185
|
+
return sleep2(waitSec * 1e3).then(() => iat);
|
|
34186
|
+
}
|
|
34187
|
+
function proofKeyFor(parts) {
|
|
34188
|
+
return bytesToHex2(
|
|
34189
|
+
sha2565(
|
|
34190
|
+
new TextEncoder().encode(
|
|
34191
|
+
JSON.stringify([
|
|
34192
|
+
parts.aud,
|
|
34193
|
+
parts.method,
|
|
34194
|
+
parts.uri,
|
|
34195
|
+
parts.grantId,
|
|
34196
|
+
parts.signedBytes ? bytesToHex2(sha2565(parts.signedBytes)) : ""
|
|
34197
|
+
])
|
|
34198
|
+
)
|
|
34199
|
+
)
|
|
34200
|
+
);
|
|
34201
|
+
}
|
|
34202
|
+
async function sendWithFreshProof(label, fetchFn, options, proofKey, build) {
|
|
34203
|
+
const attempts = Math.max(1, Math.floor(finiteOr(options?.attempts, 3)));
|
|
34204
|
+
let delayMs = Math.max(0, finiteOr(options?.initialDelayMs, 1e3));
|
|
34205
|
+
let lastError;
|
|
34206
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
34207
|
+
const { url, init } = await build(await nextProofIat(proofKey));
|
|
34208
|
+
try {
|
|
34209
|
+
return await fetchFn(url, init);
|
|
34210
|
+
} catch (err) {
|
|
34211
|
+
lastError = err;
|
|
34212
|
+
}
|
|
34213
|
+
if (attempt < attempts - 1) {
|
|
34214
|
+
await sleep2(delayMs);
|
|
34215
|
+
delayMs *= 2;
|
|
34216
|
+
}
|
|
34217
|
+
}
|
|
34218
|
+
throw new WriteTransportError(
|
|
34219
|
+
`${label} failed after ${attempts} attempt(s): ${errorMessage(lastError)}`,
|
|
34220
|
+
attempts,
|
|
34221
|
+
lastError
|
|
34222
|
+
);
|
|
34223
|
+
}
|
|
34224
|
+
async function openWriteSession(params) {
|
|
34225
|
+
const fetchFn = resolveFetch2(params.fetch);
|
|
34226
|
+
const personalServerUrl = normalizeBaseUrl2(params.personalServerUrl);
|
|
34227
|
+
const audience = params.audience ?? personalServerUrl;
|
|
34228
|
+
const signer = resolveWriteSigner(params.signer, { account: params.account });
|
|
34229
|
+
const response = await sendWithFreshProof(
|
|
34230
|
+
"Write session handshake",
|
|
34231
|
+
fetchFn,
|
|
34232
|
+
params.retry,
|
|
34233
|
+
proofKeyFor({
|
|
34234
|
+
aud: audience,
|
|
34235
|
+
method: "POST",
|
|
34236
|
+
uri: WRITE_SESSION_PATH,
|
|
34237
|
+
grantId: params.grantId
|
|
34238
|
+
}),
|
|
34239
|
+
async (iat) => {
|
|
34240
|
+
const headers = new Headers(params.headers);
|
|
34241
|
+
headers.set(
|
|
34242
|
+
"Authorization",
|
|
34243
|
+
await buildWeb3SignedHeader({
|
|
34244
|
+
signMessage: signer.signMessage,
|
|
34245
|
+
aud: audience,
|
|
34246
|
+
method: "POST",
|
|
34247
|
+
uri: WRITE_SESSION_PATH,
|
|
34248
|
+
grantId: params.grantId,
|
|
34249
|
+
iat
|
|
34250
|
+
})
|
|
34251
|
+
);
|
|
34252
|
+
return {
|
|
34253
|
+
url: `${personalServerUrl}${WRITE_SESSION_PATH}`,
|
|
34254
|
+
init: { method: "POST", headers }
|
|
34255
|
+
};
|
|
34256
|
+
}
|
|
34257
|
+
);
|
|
34258
|
+
const mintedAt = Date.now();
|
|
34259
|
+
if (!response.ok) {
|
|
34260
|
+
const { errorCode, message, details } = await readPersonalServerErrorBody(response);
|
|
34261
|
+
throw new WriteSessionError(
|
|
34262
|
+
message ?? `Write session handshake failed: ${response.status} ${response.statusText}`,
|
|
34263
|
+
response.status,
|
|
34264
|
+
errorCode,
|
|
34265
|
+
details
|
|
34266
|
+
);
|
|
34267
|
+
}
|
|
34268
|
+
let body;
|
|
34269
|
+
try {
|
|
34270
|
+
body = await response.json();
|
|
34271
|
+
} catch (err) {
|
|
34272
|
+
throw new WriteSessionError(
|
|
34273
|
+
"Write session response is not JSON",
|
|
34274
|
+
response.status,
|
|
34275
|
+
null,
|
|
34276
|
+
{ cause: errorMessage(err) }
|
|
34277
|
+
);
|
|
34278
|
+
}
|
|
34279
|
+
const parsed = WriteSessionResponseSchema.safeParse(body);
|
|
34280
|
+
if (!parsed.success) {
|
|
34281
|
+
throw new WriteSessionError(
|
|
34282
|
+
"Write session response is not a session",
|
|
34283
|
+
response.status,
|
|
34284
|
+
null,
|
|
34285
|
+
{ issues: parsed.error.issues }
|
|
34286
|
+
);
|
|
34287
|
+
}
|
|
34288
|
+
if (parsed.data.token_type.toLowerCase() !== "bearer") {
|
|
34289
|
+
throw new WriteSessionError(
|
|
34290
|
+
`Write session token type is not Bearer: ${parsed.data.token_type}`,
|
|
34291
|
+
response.status
|
|
34292
|
+
);
|
|
34293
|
+
}
|
|
34294
|
+
return {
|
|
34295
|
+
personalServerUrl,
|
|
34296
|
+
audience,
|
|
34297
|
+
grantId: params.grantId,
|
|
34298
|
+
accessToken: parsed.data.access_token,
|
|
34299
|
+
expiresAt: mintedAt + parsed.data.expires_in * 1e3,
|
|
34300
|
+
writeScopes: parsed.data.scope.split(" ").filter((s) => s.length > 0),
|
|
34301
|
+
signer
|
|
34302
|
+
};
|
|
34303
|
+
}
|
|
34304
|
+
function isWriteSession(value) {
|
|
34305
|
+
if (!isRecord2(value)) return false;
|
|
34306
|
+
const signer = value.signer;
|
|
34307
|
+
return typeof value.personalServerUrl === "string" && typeof value.audience === "string" && typeof value.grantId === "string" && typeof value.accessToken === "string" && value.accessToken.length > 0 && typeof value.expiresAt === "number" && Number.isFinite(value.expiresAt) && Array.isArray(value.writeScopes) && value.writeScopes.every((scope) => typeof scope === "string") && isRecord2(signer) && typeof signer.signMessage === "function";
|
|
34308
|
+
}
|
|
34309
|
+
function sessionCoversScope(session, scope) {
|
|
34310
|
+
if (!isRecord2(session) || !Array.isArray(session.writeScopes) || !session.writeScopes.every((pattern) => typeof pattern === "string")) {
|
|
34311
|
+
throw new WriteRequestError("session must come from openWriteSession");
|
|
34312
|
+
}
|
|
34313
|
+
return session.writeScopes.some(
|
|
34314
|
+
(pattern) => scopeMatchesPattern(scope, pattern)
|
|
34315
|
+
);
|
|
34316
|
+
}
|
|
34317
|
+
function normalizeBinaryMimeType(contentType) {
|
|
34318
|
+
if (!contentType) return "application/octet-stream";
|
|
34319
|
+
return contentType.split(";")[0].trim() || "application/octet-stream";
|
|
34320
|
+
}
|
|
34321
|
+
function parseWriteMetadataHeader(value) {
|
|
34322
|
+
if (value === null) return void 0;
|
|
34323
|
+
const trimmed = value.trim();
|
|
34324
|
+
if (trimmed === "") return void 0;
|
|
34325
|
+
try {
|
|
34326
|
+
return JSON.parse(trimmed);
|
|
34327
|
+
} catch {
|
|
34328
|
+
return value;
|
|
34329
|
+
}
|
|
34330
|
+
}
|
|
34331
|
+
function encodeWriteMetadataHeader(metadata) {
|
|
34332
|
+
let json;
|
|
34333
|
+
try {
|
|
34334
|
+
json = JSON.stringify(metadata);
|
|
34335
|
+
} catch (err) {
|
|
34336
|
+
throw new WriteRequestError(
|
|
34337
|
+
`metadata is not JSON-serialisable: ${errorMessage(err)}`
|
|
34338
|
+
);
|
|
34339
|
+
}
|
|
34340
|
+
if (typeof json !== "string") {
|
|
34341
|
+
throw new WriteRequestError("metadata must serialise to JSON");
|
|
34342
|
+
}
|
|
34343
|
+
return json.replace(
|
|
34344
|
+
/[\u007f-\uffff]/g,
|
|
34345
|
+
(c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`
|
|
34346
|
+
);
|
|
34347
|
+
}
|
|
34348
|
+
function binaryWriteSignedBytes(input) {
|
|
34349
|
+
const metadata = parseWriteMetadataHeader(input.metadataHeader ?? null);
|
|
34350
|
+
const record = {
|
|
34351
|
+
$binary: true,
|
|
34352
|
+
mimeType: normalizeBinaryMimeType(input.contentType),
|
|
34353
|
+
...input.filename ? { filename: input.filename } : {},
|
|
34354
|
+
sizeBytes: input.bytes.length,
|
|
34355
|
+
contentHash: bytesToHex2(sha2565(input.bytes)),
|
|
34356
|
+
encoding: "base64",
|
|
34357
|
+
content: toBase64(input.bytes),
|
|
34358
|
+
...metadata !== void 0 ? { metadata } : {}
|
|
34359
|
+
};
|
|
34360
|
+
return new TextEncoder().encode(JSON.stringify(record));
|
|
34361
|
+
}
|
|
34362
|
+
var PRINTABLE_ASCII = /^[\x20-\x7e]*$/;
|
|
34363
|
+
function setFilenameHeader(headers, filename) {
|
|
34364
|
+
if (PRINTABLE_ASCII.test(filename)) {
|
|
34365
|
+
headers.set(WRITE_FILENAME_HEADER, filename);
|
|
34366
|
+
return;
|
|
34367
|
+
}
|
|
34368
|
+
headers.set(
|
|
34369
|
+
WRITE_CONTENT_DISPOSITION_HEADER,
|
|
34370
|
+
`attachment; filename*=UTF-8''${encodeURIComponent(filename)}`
|
|
34371
|
+
);
|
|
34372
|
+
}
|
|
34373
|
+
function assertNoReservedKeys(value, where) {
|
|
34374
|
+
for (const key of RESERVED_WRITE_KEYS) {
|
|
34375
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
34376
|
+
throw new WriteRequestError(
|
|
34377
|
+
`${where} must not contain the reserved ${key} key; the Personal Server stamps it`,
|
|
34378
|
+
{ key }
|
|
34379
|
+
);
|
|
34380
|
+
}
|
|
34381
|
+
}
|
|
34382
|
+
}
|
|
34383
|
+
function isLineagePair(value) {
|
|
34384
|
+
return isRecord2(value) && typeof value.ownerAddress === "string" && typeof value.scope === "string";
|
|
34385
|
+
}
|
|
34386
|
+
function normalizeLineage(lineage, derivedScope) {
|
|
34387
|
+
if (!Array.isArray(lineage)) {
|
|
34388
|
+
throw new WriteRequestError("lineage must be an array of data point ids");
|
|
34389
|
+
}
|
|
34390
|
+
if (lineage.length > MAX_LINEAGE_SOURCES) {
|
|
34391
|
+
throw new WriteRequestError(
|
|
34392
|
+
`lineage lists ${lineage.length} sources; the maximum is ${MAX_LINEAGE_SOURCES}`,
|
|
34393
|
+
{ max: MAX_LINEAGE_SOURCES, count: lineage.length }
|
|
34394
|
+
);
|
|
34395
|
+
}
|
|
34396
|
+
const seen = /* @__PURE__ */ new Set();
|
|
34397
|
+
const sources = [];
|
|
34398
|
+
const sourceScopes = [];
|
|
34399
|
+
const ownIds = /* @__PURE__ */ new Set();
|
|
34400
|
+
for (const entry of lineage) {
|
|
34401
|
+
let id;
|
|
34402
|
+
if (isLineagePair(entry)) {
|
|
34403
|
+
if (!isAddress5(entry.ownerAddress, { strict: false })) {
|
|
34404
|
+
throw new WriteRequestError(
|
|
34405
|
+
"lineage source ownerAddress must be an EVM address",
|
|
34406
|
+
{ ownerAddress: entry.ownerAddress }
|
|
34407
|
+
);
|
|
34408
|
+
}
|
|
34409
|
+
if (entry.scope.length === 0) {
|
|
34410
|
+
throw new WriteRequestError("lineage source scope is required");
|
|
34411
|
+
}
|
|
34412
|
+
id = deriveDataPointId(entry.ownerAddress, entry.scope);
|
|
34413
|
+
sourceScopes.push(entry.scope);
|
|
34414
|
+
ownIds.add(deriveDataPointId(entry.ownerAddress, derivedScope));
|
|
34415
|
+
} else if (isDataPointId(entry)) {
|
|
34416
|
+
id = entry;
|
|
34417
|
+
} else {
|
|
34418
|
+
throw new WriteRequestError(
|
|
34419
|
+
"lineage entries must be 32-byte hex data point ids or { ownerAddress, scope } pairs",
|
|
34420
|
+
{ entry }
|
|
34421
|
+
);
|
|
34422
|
+
}
|
|
34423
|
+
const normalized = id.toLowerCase();
|
|
34424
|
+
if (seen.has(normalized)) {
|
|
34425
|
+
throw new WriteRequestError("lineage must not repeat a data point id", {
|
|
34426
|
+
dataPointId: normalized
|
|
34427
|
+
});
|
|
34428
|
+
}
|
|
34429
|
+
seen.add(normalized);
|
|
34430
|
+
sources.push(normalized);
|
|
34431
|
+
}
|
|
34432
|
+
for (const own of ownIds) {
|
|
34433
|
+
if (seen.has(own)) {
|
|
34434
|
+
throw new WriteRequestError(
|
|
34435
|
+
"lineage must not cite the record's own data point",
|
|
34436
|
+
{ dataPointId: own, scope: derivedScope }
|
|
34437
|
+
);
|
|
34438
|
+
}
|
|
34439
|
+
}
|
|
34440
|
+
assertDerivedScopeNaming(derivedScope, sourceScopes);
|
|
34441
|
+
return sources;
|
|
34442
|
+
}
|
|
34443
|
+
function assertNoLineageField(value, where) {
|
|
34444
|
+
if (Object.prototype.hasOwnProperty.call(value, LINEAGE_FIELD)) {
|
|
34445
|
+
throw new WriteRequestError(
|
|
34446
|
+
`${where}.${LINEAGE_FIELD} is reserved; pass sources through the lineage option`
|
|
34447
|
+
);
|
|
34448
|
+
}
|
|
34449
|
+
}
|
|
34450
|
+
function buildMetadataHeader(metadata, sources) {
|
|
34451
|
+
if (metadata !== void 0) {
|
|
34452
|
+
if (!isRecord2(metadata)) {
|
|
34453
|
+
throw new WriteRequestError("metadata must be a plain object");
|
|
34454
|
+
}
|
|
34455
|
+
assertNoReservedKeys(metadata, "metadata");
|
|
34456
|
+
assertNoLineageField(metadata, "metadata");
|
|
34457
|
+
}
|
|
34458
|
+
if (metadata === void 0 && sources === void 0) return void 0;
|
|
34459
|
+
return encodeWriteMetadataHeader({
|
|
34460
|
+
...metadata ?? {},
|
|
34461
|
+
...sources !== void 0 ? { [LINEAGE_FIELD]: sources } : {}
|
|
34462
|
+
});
|
|
34463
|
+
}
|
|
34464
|
+
function prepareWrite(params) {
|
|
34465
|
+
if (params.binary !== void 0 && params.data !== void 0) {
|
|
34466
|
+
throw new WriteRequestError("Pass either data or binary, not both");
|
|
34467
|
+
}
|
|
34468
|
+
const rawLineage = params.lineage;
|
|
34469
|
+
const sources = rawLineage === void 0 || rawLineage === null ? void 0 : normalizeLineage(rawLineage, params.scope);
|
|
34470
|
+
if (params.binary !== void 0) {
|
|
34471
|
+
const { bytes, contentType, filename } = params.binary;
|
|
34472
|
+
if (!(bytes instanceof Uint8Array)) {
|
|
34473
|
+
throw new WriteRequestError("binary.bytes must be a Uint8Array");
|
|
34474
|
+
}
|
|
34475
|
+
if (typeof contentType !== "string" || contentType.trim() === "") {
|
|
34476
|
+
throw new WriteRequestError("binary.contentType is required");
|
|
34477
|
+
}
|
|
34478
|
+
if (filename !== void 0) {
|
|
34479
|
+
if (typeof filename !== "string") {
|
|
34480
|
+
throw new WriteRequestError("binary.filename must be a string");
|
|
34481
|
+
}
|
|
34482
|
+
if (filename !== filename.trim()) {
|
|
34483
|
+
throw new WriteRequestError(
|
|
34484
|
+
"binary.filename must not have leading or trailing whitespace"
|
|
34485
|
+
);
|
|
34486
|
+
}
|
|
34487
|
+
}
|
|
34488
|
+
const metadataHeader = buildMetadataHeader(params.metadata, sources);
|
|
34489
|
+
return {
|
|
34490
|
+
body: bytes,
|
|
34491
|
+
signedBytes: binaryWriteSignedBytes({
|
|
34492
|
+
bytes,
|
|
34493
|
+
contentType,
|
|
34494
|
+
filename,
|
|
34495
|
+
metadataHeader
|
|
34496
|
+
}),
|
|
34497
|
+
contentType,
|
|
34498
|
+
filename,
|
|
34499
|
+
metadataHeader
|
|
34500
|
+
};
|
|
34501
|
+
}
|
|
34502
|
+
if (params.data === void 0) {
|
|
34503
|
+
throw new WriteRequestError("Pass data (a JSON object) or binary");
|
|
34504
|
+
}
|
|
34505
|
+
if (!isRecord2(params.data)) {
|
|
34506
|
+
throw new WriteRequestError("data must be a plain JSON object");
|
|
34507
|
+
}
|
|
34508
|
+
if (params.metadata !== void 0) {
|
|
34509
|
+
throw new WriteRequestError(
|
|
34510
|
+
"metadata applies to binary writes; put fields to store inside data"
|
|
34511
|
+
);
|
|
34512
|
+
}
|
|
34513
|
+
assertNoReservedKeys(params.data, "data");
|
|
34514
|
+
assertNoLineageField(params.data, "data");
|
|
34515
|
+
const record = sources === void 0 ? params.data : { ...params.data, [LINEAGE_FIELD]: sources };
|
|
34516
|
+
let text;
|
|
34517
|
+
try {
|
|
34518
|
+
text = JSON.stringify(record);
|
|
34519
|
+
} catch (err) {
|
|
34520
|
+
throw new WriteRequestError(
|
|
34521
|
+
`data is not JSON-serialisable: ${errorMessage(err)}`
|
|
34522
|
+
);
|
|
34523
|
+
}
|
|
34524
|
+
if (typeof text !== "string" || !text.startsWith("{")) {
|
|
34525
|
+
throw new WriteRequestError("data must serialise to a JSON object");
|
|
34526
|
+
}
|
|
34527
|
+
const body = new TextEncoder().encode(text);
|
|
34528
|
+
return {
|
|
34529
|
+
body,
|
|
34530
|
+
signedBytes: body,
|
|
34531
|
+
contentType: "application/json"
|
|
34532
|
+
};
|
|
34533
|
+
}
|
|
34534
|
+
async function writeErrorFromResponse(response) {
|
|
34535
|
+
const { errorCode, message, details } = await readPersonalServerErrorBody(response);
|
|
34536
|
+
const text = message ?? `Personal Server write failed: ${response.status} ${response.statusText}`;
|
|
34537
|
+
if (response.status === 422 || errorCode?.startsWith("LINEAGE_")) {
|
|
34538
|
+
return new WriteLineageError(text, response.status, errorCode, details);
|
|
34539
|
+
}
|
|
34540
|
+
switch (response.status) {
|
|
34541
|
+
case 401:
|
|
34542
|
+
return new WriteUnauthorizedError(text, errorCode, details);
|
|
34543
|
+
case 403:
|
|
34544
|
+
return new WriteForbiddenError(text, errorCode, details);
|
|
34545
|
+
case 409:
|
|
34546
|
+
return new WriteConflictError(text, errorCode, details);
|
|
34547
|
+
default:
|
|
34548
|
+
return new WriteRejectedError(text, response.status, errorCode, details);
|
|
34549
|
+
}
|
|
34550
|
+
}
|
|
34551
|
+
async function writeData(params) {
|
|
34552
|
+
const { session } = params;
|
|
34553
|
+
if (!isWriteSession(session)) {
|
|
34554
|
+
throw new WriteRequestError("session must come from openWriteSession");
|
|
34555
|
+
}
|
|
34556
|
+
const fetchFn = resolveFetch2(params.fetch);
|
|
34557
|
+
if (typeof params.scope !== "string" || params.scope.length === 0) {
|
|
34558
|
+
throw new WriteRequestError("scope is required");
|
|
34559
|
+
}
|
|
34560
|
+
const prepared = prepareWrite(params);
|
|
34561
|
+
if (Date.now() >= session.expiresAt) {
|
|
34562
|
+
throw new WriteSessionExpiredError(
|
|
34563
|
+
"Write session has expired; open a new session",
|
|
34564
|
+
{ grantId: session.grantId, expiresAt: session.expiresAt }
|
|
34565
|
+
);
|
|
34566
|
+
}
|
|
34567
|
+
const path = dataPath(params.scope);
|
|
34568
|
+
const response = await sendWithFreshProof(
|
|
34569
|
+
`Write to ${params.scope}`,
|
|
34570
|
+
fetchFn,
|
|
34571
|
+
params.retry,
|
|
34572
|
+
proofKeyFor({
|
|
34573
|
+
aud: session.audience,
|
|
34574
|
+
method: "POST",
|
|
34575
|
+
uri: path,
|
|
34576
|
+
grantId: session.grantId,
|
|
34577
|
+
signedBytes: prepared.signedBytes
|
|
34578
|
+
}),
|
|
34579
|
+
async (iat) => {
|
|
34580
|
+
const headers = new Headers(params.headers);
|
|
34581
|
+
headers.set("Content-Type", prepared.contentType);
|
|
34582
|
+
headers.set("Authorization", `Bearer ${session.accessToken}`);
|
|
34583
|
+
if (prepared.filename) {
|
|
34584
|
+
setFilenameHeader(headers, prepared.filename);
|
|
34585
|
+
}
|
|
34586
|
+
if (prepared.metadataHeader !== void 0) {
|
|
34587
|
+
headers.set(WRITE_METADATA_HEADER, prepared.metadataHeader);
|
|
34588
|
+
}
|
|
34589
|
+
headers.set(
|
|
34590
|
+
WRITE_SIGNATURE_HEADER,
|
|
34591
|
+
await buildWeb3SignedHeader({
|
|
34592
|
+
signMessage: session.signer.signMessage,
|
|
34593
|
+
aud: session.audience,
|
|
34594
|
+
method: "POST",
|
|
34595
|
+
uri: path,
|
|
34596
|
+
body: prepared.signedBytes,
|
|
34597
|
+
grantId: session.grantId,
|
|
34598
|
+
iat
|
|
34599
|
+
})
|
|
34600
|
+
);
|
|
34601
|
+
return {
|
|
34602
|
+
url: `${session.personalServerUrl}${path}`,
|
|
34603
|
+
init: {
|
|
34604
|
+
method: "POST",
|
|
34605
|
+
headers,
|
|
34606
|
+
body: prepared.body
|
|
34607
|
+
}
|
|
34608
|
+
};
|
|
34609
|
+
}
|
|
34610
|
+
);
|
|
34611
|
+
if (!response.ok) {
|
|
34612
|
+
throw await writeErrorFromResponse(response);
|
|
34613
|
+
}
|
|
34614
|
+
let body;
|
|
34615
|
+
try {
|
|
34616
|
+
body = await response.json();
|
|
34617
|
+
} catch (err) {
|
|
34618
|
+
throw new WriteRejectedError(
|
|
34619
|
+
"Personal Server write response is not JSON",
|
|
34620
|
+
response.status,
|
|
34621
|
+
null,
|
|
34622
|
+
{ cause: errorMessage(err) }
|
|
34623
|
+
);
|
|
34624
|
+
}
|
|
34625
|
+
const parsed = WriteDataResultSchema.safeParse(body);
|
|
34626
|
+
if (!parsed.success) {
|
|
34627
|
+
throw new WriteRejectedError(
|
|
34628
|
+
"Personal Server write response is not an ingest result",
|
|
34629
|
+
response.status,
|
|
34630
|
+
null,
|
|
34631
|
+
{ issues: parsed.error.issues }
|
|
34632
|
+
);
|
|
34633
|
+
}
|
|
34634
|
+
return parsed.data;
|
|
34635
|
+
}
|
|
34636
|
+
async function writePersonalServerData(params) {
|
|
34637
|
+
const session = await openWriteSession({
|
|
34638
|
+
personalServerUrl: params.personalServerUrl,
|
|
34639
|
+
signer: params.signer,
|
|
34640
|
+
grantId: params.grantId,
|
|
34641
|
+
account: params.account,
|
|
34642
|
+
audience: params.audience,
|
|
34643
|
+
fetch: params.fetch,
|
|
34644
|
+
headers: params.headers,
|
|
34645
|
+
retry: params.retry
|
|
34646
|
+
});
|
|
34647
|
+
const writeParams = { ...params, session };
|
|
34648
|
+
const result = await writeData(writeParams);
|
|
34649
|
+
return { ...result, session };
|
|
34650
|
+
}
|
|
34651
|
+
|
|
33721
34652
|
// src/protocol/gateway.ts
|
|
33722
34653
|
function withGrantPermissions(grant) {
|
|
33723
34654
|
const stripped = { ...grant };
|
|
@@ -34638,7 +35569,7 @@ var KNOWN_CODES = /* @__PURE__ */ new Set([
|
|
|
34638
35569
|
"server_not_configured",
|
|
34639
35570
|
"content_too_large"
|
|
34640
35571
|
]);
|
|
34641
|
-
function
|
|
35572
|
+
function isRecord4(value) {
|
|
34642
35573
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
34643
35574
|
}
|
|
34644
35575
|
function normalizeCode(value) {
|
|
@@ -34649,10 +35580,10 @@ function normalizeCode(value) {
|
|
|
34649
35580
|
return KNOWN_CODES.has(code) ? code : null;
|
|
34650
35581
|
}
|
|
34651
35582
|
function extractPSErrorBody(body) {
|
|
34652
|
-
if (!
|
|
35583
|
+
if (!isRecord4(body)) {
|
|
34653
35584
|
return null;
|
|
34654
35585
|
}
|
|
34655
|
-
const nested =
|
|
35586
|
+
const nested = isRecord4(body.error) ? body.error : null;
|
|
34656
35587
|
const code = normalizeCode(
|
|
34657
35588
|
nested?.errorCode ?? nested?.code ?? body.errorCode ?? body.code
|
|
34658
35589
|
);
|
|
@@ -34707,7 +35638,14 @@ export {
|
|
|
34707
35638
|
InvalidScopeEntryError,
|
|
34708
35639
|
InvalidSignatureError,
|
|
34709
35640
|
IpfsStorage,
|
|
35641
|
+
LINEAGE_FIELD,
|
|
35642
|
+
LINEAGE_KEY,
|
|
35643
|
+
LineageEntrySchema,
|
|
35644
|
+
LineageGraphSchema,
|
|
35645
|
+
LineageNodeSchema,
|
|
35646
|
+
LineageReadError,
|
|
34710
35647
|
MASTER_KEY_MESSAGE,
|
|
35648
|
+
MAX_LINEAGE_SOURCES,
|
|
34711
35649
|
MissingAuthError,
|
|
34712
35650
|
NATIVE_ASSET_ADDRESS,
|
|
34713
35651
|
NATIVE_VANA_ASSET,
|
|
@@ -34726,11 +35664,14 @@ export {
|
|
|
34726
35664
|
PSError,
|
|
34727
35665
|
PermissionError,
|
|
34728
35666
|
PersonalServerError,
|
|
35667
|
+
PersonalServerWriteError,
|
|
34729
35668
|
PinataStorage,
|
|
34730
35669
|
R2Storage,
|
|
34731
35670
|
RECORD_DATA_ACCESS_TYPES,
|
|
34732
35671
|
REGISTRATION_KIND_FOR_OP,
|
|
35672
|
+
RESERVED_WRITE_KEYS,
|
|
34733
35673
|
ReadOnlyError,
|
|
35674
|
+
RedactedLineageNodeSchema,
|
|
34734
35675
|
RelayerError,
|
|
34735
35676
|
SCOPE_ACTIONS,
|
|
34736
35677
|
SERVER_REGISTRATION_TYPES,
|
|
@@ -34744,9 +35685,26 @@ export {
|
|
|
34744
35685
|
UserRejectedRequestError,
|
|
34745
35686
|
VanaError,
|
|
34746
35687
|
VanaStorage,
|
|
35688
|
+
WRITER_ATTRIBUTION_KEY,
|
|
35689
|
+
WRITE_CONTENT_DISPOSITION_HEADER,
|
|
35690
|
+
WRITE_FILENAME_HEADER,
|
|
35691
|
+
WRITE_METADATA_HEADER,
|
|
35692
|
+
WRITE_SESSION_PATH,
|
|
35693
|
+
WRITE_SIGNATURE_HEADER,
|
|
35694
|
+
WriteConflictError,
|
|
35695
|
+
WriteForbiddenError,
|
|
35696
|
+
WriteLineageError,
|
|
35697
|
+
WriteRejectedError,
|
|
35698
|
+
WriteRequestError,
|
|
35699
|
+
WriteSessionError,
|
|
35700
|
+
WriteSessionExpiredError,
|
|
35701
|
+
WriteTransportError,
|
|
35702
|
+
WriteUnauthorizedError,
|
|
35703
|
+
assertDerivedScopeNaming,
|
|
34747
35704
|
assertValidPkceVerifier,
|
|
34748
35705
|
authorizeEscrowPayment,
|
|
34749
35706
|
authorizeGrantPayment,
|
|
35707
|
+
binaryWriteSignedBytes,
|
|
34750
35708
|
buildDepositNativeRequest,
|
|
34751
35709
|
buildDepositTokenRequest,
|
|
34752
35710
|
buildEscrowPaymentHeader,
|
|
@@ -34780,17 +35738,21 @@ export {
|
|
|
34780
35738
|
dataRegistryContractAddress,
|
|
34781
35739
|
dataRegistryDomain,
|
|
34782
35740
|
decryptWithPassword,
|
|
35741
|
+
deriveDataPointId,
|
|
34783
35742
|
deriveMasterKey,
|
|
34784
35743
|
deriveScopeKey,
|
|
35744
|
+
derivedScopeViolatesNaming,
|
|
34785
35745
|
deserializeECIES,
|
|
34786
35746
|
detectPlatform,
|
|
34787
35747
|
encodeDepositNativeData,
|
|
34788
35748
|
encodeDepositTokenData,
|
|
34789
35749
|
encodeSetDataPointStatusData,
|
|
35750
|
+
encodeWriteMetadataHeader,
|
|
34790
35751
|
encryptWithPassword,
|
|
34791
35752
|
escrowContractAddress,
|
|
34792
35753
|
escrowPaymentDomain,
|
|
34793
35754
|
formatScopeEntry,
|
|
35755
|
+
gatewayLineagePath,
|
|
34794
35756
|
generatePkceVerifier,
|
|
34795
35757
|
genericPaymentDomain,
|
|
34796
35758
|
getAbi,
|
|
@@ -34800,38 +35762,50 @@ export {
|
|
|
34800
35762
|
getContractController,
|
|
34801
35763
|
getContractInfo,
|
|
34802
35764
|
getFee,
|
|
35765
|
+
getGatewayLineage,
|
|
35766
|
+
getLineage,
|
|
34803
35767
|
getOpFee,
|
|
35768
|
+
getPersonalServerLineage,
|
|
34804
35769
|
getPlatformCapabilities,
|
|
34805
35770
|
getServiceEndpoints,
|
|
34806
35771
|
grantPermissions,
|
|
34807
35772
|
grantRegistrationDomain,
|
|
34808
35773
|
grantRevocationDomain,
|
|
34809
35774
|
hasAction,
|
|
35775
|
+
isDataPointId,
|
|
34810
35776
|
isDataPortabilityGatewayConfig,
|
|
34811
35777
|
isECIESEncrypted,
|
|
34812
35778
|
isPlatformSupported,
|
|
35779
|
+
isRedactedLineageNode,
|
|
34813
35780
|
mainnetServices,
|
|
34814
35781
|
moksha,
|
|
34815
35782
|
mokshaServices,
|
|
34816
35783
|
mokshaTestnet2 as mokshaTestnet,
|
|
35784
|
+
normalizeBinaryMimeType,
|
|
35785
|
+
openWriteSession,
|
|
34817
35786
|
parsePSError,
|
|
34818
35787
|
parsePersonalServerPaymentRequired,
|
|
34819
35788
|
parseScope,
|
|
34820
35789
|
parseScopeEntry,
|
|
34821
35790
|
parseWeb3SignedHeader,
|
|
35791
|
+
parseWriteMetadataHeader,
|
|
34822
35792
|
paymentReceiptFromHeader,
|
|
34823
35793
|
paymentResponseMetadataFromHeader,
|
|
34824
35794
|
permissionsToScopes,
|
|
34825
35795
|
personalServerDataReadPath,
|
|
35796
|
+
personalServerLineagePath,
|
|
34826
35797
|
personalServerRegistrationDomain,
|
|
34827
35798
|
readPersonalServerData,
|
|
34828
35799
|
recoverServerOwner,
|
|
34829
35800
|
registerPersonalServerSignature,
|
|
35801
|
+
resolveWriteSigner,
|
|
34830
35802
|
scopeCoveredByGrant,
|
|
34831
35803
|
scopeMatchesPattern,
|
|
35804
|
+
scopeNamespace,
|
|
34832
35805
|
scopeToPathSegments,
|
|
34833
35806
|
serializeECIES,
|
|
34834
35807
|
serverRegistrationDomain,
|
|
35808
|
+
sessionCoversScope,
|
|
34835
35809
|
signPersonalServerLiteOwnerBinding,
|
|
34836
35810
|
signPersonalServerLiteOwnerBindingWithAccountClient,
|
|
34837
35811
|
signPersonalServerRegistrationWithAccount,
|
|
@@ -34841,6 +35815,8 @@ export {
|
|
|
34841
35815
|
vanaMainnet2 as vanaMainnet,
|
|
34842
35816
|
verifyGrantRegistration,
|
|
34843
35817
|
verifyPkceChallenge,
|
|
34844
|
-
verifyWeb3Signed
|
|
35818
|
+
verifyWeb3Signed,
|
|
35819
|
+
writeData,
|
|
35820
|
+
writePersonalServerData
|
|
34845
35821
|
};
|
|
34846
35822
|
//# sourceMappingURL=index.node.js.map
|