@opendatalabs/vana-sdk 3.20.1 → 3.22.0-pr.207.0dbb052
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 +64 -0
- package/dist/direct/access-request-client.cjs +100 -2
- package/dist/direct/access-request-client.cjs.map +1 -1
- package/dist/direct/access-request-client.d.ts +23 -1
- package/dist/direct/access-request-client.js +98 -1
- package/dist/direct/access-request-client.js.map +1 -1
- package/dist/direct/controller.cjs +4 -0
- package/dist/direct/controller.cjs.map +1 -1
- package/dist/direct/controller.d.ts +10 -1
- package/dist/direct/controller.js +6 -1
- package/dist/direct/controller.js.map +1 -1
- package/dist/direct/types.cjs.map +1 -1
- package/dist/direct/types.d.ts +45 -0
- package/dist/direct/types.js.map +1 -1
- package/dist/index.browser.d.ts +3 -1
- package/dist/index.browser.js +347 -4
- package/dist/index.browser.js.map +4 -4
- package/dist/index.node.cjs +389 -34
- package/dist/index.node.cjs.map +4 -4
- package/dist/index.node.d.ts +3 -1
- package/dist/index.node.js +350 -7
- package/dist/index.node.js.map +4 -4
- package/dist/protocol/derivative-questions.cjs +22 -0
- package/dist/protocol/derivative-questions.cjs.map +1 -1
- package/dist/protocol/derivative-questions.d.ts +53 -0
- package/dist/protocol/derivative-questions.js +19 -0
- package/dist/protocol/derivative-questions.js.map +1 -1
- package/dist/protocol/derivative-status.cjs +209 -0
- package/dist/protocol/derivative-status.cjs.map +1 -0
- package/dist/protocol/derivative-status.d.ts +196 -0
- package/dist/protocol/derivative-status.js +190 -0
- package/dist/protocol/derivative-status.js.map +1 -0
- package/dist/protocol/derivative-status.test.d.ts +1 -0
- package/dist/protocol/identity.cjs +194 -0
- package/dist/protocol/identity.cjs.map +1 -0
- package/dist/protocol/identity.d.ts +161 -0
- package/dist/protocol/identity.js +159 -0
- package/dist/protocol/identity.js.map +1 -0
- package/dist/protocol/identity.test.d.ts +1 -0
- package/dist/protocol/identity.vector.test.d.ts +1 -0
- package/dist/server.cjs +4 -2
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +4 -2
- package/dist/server.js.map +1 -1
- package/dist/tests/mock-personal-server.d.ts +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enclave identity and consent primitives for Personal Servers.
|
|
3
|
+
*
|
|
4
|
+
* Owner/Web -> Gateway -> Agent(CVM): derive wallet and quote
|
|
5
|
+
* Web verifies evidence; Account authenticates and encrypts the EIP-191 master
|
|
6
|
+
* signature to the enclave key; Gateway relays it blind; Agent decrypts/seals.
|
|
7
|
+
*
|
|
8
|
+
* @category Protocol
|
|
9
|
+
*/
|
|
10
|
+
import { type Address, type Hex } from "viem";
|
|
11
|
+
import { type ECIESProvider } from "../crypto/ecies/interface.js";
|
|
12
|
+
import type { ServerRegistrationMessage } from "./eip712.js";
|
|
13
|
+
export declare const ENCLAVE_IDENTITY_EVIDENCE_VERSION = 1;
|
|
14
|
+
export declare const USER_PS_ID_DOMAIN = "vana.ps-enclave.v1";
|
|
15
|
+
export declare const ENCLAVE_WALLET_PURPOSE = "vana.ps-enclave.wallet.v1";
|
|
16
|
+
export declare const MASTER_SIGNATURE_DELIVERY_VERSION = "vana.ps-enclave.delivery.v1";
|
|
17
|
+
export declare const SEALED_ENVELOPE_VERSION = 1;
|
|
18
|
+
export type UserPsId = Hex;
|
|
19
|
+
export interface EnclaveIdentityEvidence {
|
|
20
|
+
v: typeof ENCLAVE_IDENTITY_EVIDENCE_VERSION;
|
|
21
|
+
userPsId: UserPsId;
|
|
22
|
+
chainId: number;
|
|
23
|
+
ownerAddress: Address;
|
|
24
|
+
epoch: number;
|
|
25
|
+
address: Address;
|
|
26
|
+
publicKey: Hex;
|
|
27
|
+
appId: Hex;
|
|
28
|
+
composeHash: Hex;
|
|
29
|
+
osImageHash?: Hex;
|
|
30
|
+
purpose: string;
|
|
31
|
+
signatureChain: [Hex, Hex];
|
|
32
|
+
quote: Hex;
|
|
33
|
+
eventLog?: string;
|
|
34
|
+
kmsRootFingerprint: Hex;
|
|
35
|
+
}
|
|
36
|
+
export interface ExpectedIdentity {
|
|
37
|
+
ownerAddress: Address;
|
|
38
|
+
chainId: number;
|
|
39
|
+
epoch: number;
|
|
40
|
+
}
|
|
41
|
+
export interface IdentityRequest {
|
|
42
|
+
ownerAddress: Address;
|
|
43
|
+
chainId: number;
|
|
44
|
+
}
|
|
45
|
+
export type IdentityState = "prepared" | "registered" | "sealed" | "retired";
|
|
46
|
+
export interface IdentityResponse {
|
|
47
|
+
identity: EnclaveIdentityEvidence;
|
|
48
|
+
state: IdentityState;
|
|
49
|
+
created: boolean;
|
|
50
|
+
serverUrl: string;
|
|
51
|
+
serverId?: Hex;
|
|
52
|
+
serverStatus?: "pending" | "submitting" | "confirmed" | "finalized" | "failed";
|
|
53
|
+
sealed: boolean;
|
|
54
|
+
}
|
|
55
|
+
export type IdentityRegistrationRequest = {
|
|
56
|
+
version: "v2";
|
|
57
|
+
message: ServerRegistrationMessage;
|
|
58
|
+
} | {
|
|
59
|
+
version: "v3";
|
|
60
|
+
message: ServerRegistrationMessage & {
|
|
61
|
+
nonce: string;
|
|
62
|
+
deadline: string;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
export interface IdentityRegistrationResponse {
|
|
66
|
+
serverId: Hex;
|
|
67
|
+
state: "registered";
|
|
68
|
+
serverStatus: "pending";
|
|
69
|
+
}
|
|
70
|
+
/** Inner plaintext of the ECIES box. */
|
|
71
|
+
export interface MasterSignatureDelivery {
|
|
72
|
+
v: typeof MASTER_SIGNATURE_DELIVERY_VERSION;
|
|
73
|
+
userPsId: UserPsId;
|
|
74
|
+
epoch: number;
|
|
75
|
+
enclaveAddress: Address;
|
|
76
|
+
ownerAddress: Address;
|
|
77
|
+
masterSignature: Hex;
|
|
78
|
+
issuedAt: number;
|
|
79
|
+
}
|
|
80
|
+
export interface SealedSecretSubmission {
|
|
81
|
+
userPsId: UserPsId;
|
|
82
|
+
epoch: number;
|
|
83
|
+
enclaveAddress: Address;
|
|
84
|
+
ciphertext: Hex;
|
|
85
|
+
}
|
|
86
|
+
export interface SealedSecretResponse {
|
|
87
|
+
sealed: true;
|
|
88
|
+
secretHash: Hex;
|
|
89
|
+
sealedAt: string;
|
|
90
|
+
}
|
|
91
|
+
export interface AesGcmBox {
|
|
92
|
+
iv: string;
|
|
93
|
+
ciphertext: string;
|
|
94
|
+
tag: string;
|
|
95
|
+
}
|
|
96
|
+
/** Persisted enclave envelope; the Gateway treats it as opaque text. */
|
|
97
|
+
export interface SealedEnvelope extends AesGcmBox {
|
|
98
|
+
v: typeof SEALED_ENVELOPE_VERSION;
|
|
99
|
+
wrappedContentKey: AesGcmBox;
|
|
100
|
+
}
|
|
101
|
+
export interface EnclaveTrustAnchors {
|
|
102
|
+
kmsRootPubkey: Hex;
|
|
103
|
+
appIds: Hex[];
|
|
104
|
+
}
|
|
105
|
+
/** Fleet-provisioned trust anchors keyed by Vana chain ID. */
|
|
106
|
+
export declare const ENCLAVE_TRUST_ANCHORS: Record<number, EnclaveTrustAnchors>;
|
|
107
|
+
/**
|
|
108
|
+
* Derives the deterministic Personal Server ID used by enclave paths.
|
|
109
|
+
*
|
|
110
|
+
* @param chainId - Vana chain ID.
|
|
111
|
+
* @param ownerAddress - Checksummed owner address.
|
|
112
|
+
* @returns The path-compatible keccak256 digest.
|
|
113
|
+
*/
|
|
114
|
+
export declare function userPsId(chainId: number, ownerAddress: Address): UserPsId;
|
|
115
|
+
/**
|
|
116
|
+
* Builds keccak256(utf8(purpose || ":" || lowercase hex(compressed pubkey))).
|
|
117
|
+
*
|
|
118
|
+
* Matches `dstack/guest-agent/src/rpc_service.rs:612-628`.
|
|
119
|
+
*/
|
|
120
|
+
export declare function appRootPreimage(purpose: string, publicKey: Hex): Hex;
|
|
121
|
+
/**
|
|
122
|
+
* Hashes the KMS prefix, raw app ID bytes, and compressed app-root public key.
|
|
123
|
+
*
|
|
124
|
+
* Matches `dstack/kms/src/crypto.rs:23-40`; there is no separator between the
|
|
125
|
+
* raw 20-byte app ID and the compressed key.
|
|
126
|
+
*/
|
|
127
|
+
export declare function kmsIssuedPreimage(appId: Hex, appRootPublicKey: Hex): Hex;
|
|
128
|
+
/**
|
|
129
|
+
* Verifies the enclave wallet binding against fleet-provisioned trust anchors.
|
|
130
|
+
*
|
|
131
|
+
* @param evidence - Identity evidence returned by the enclave agent.
|
|
132
|
+
* @param anchors - Pinned KMS root and allowed dstack app IDs.
|
|
133
|
+
* @param expected - Owner, chain, and epoch requested by the caller.
|
|
134
|
+
*
|
|
135
|
+
* @remarks
|
|
136
|
+
* The dstack chain signs only `purpose || publicKey` and `appId || appRootPub`;
|
|
137
|
+
* owner, chain and epoch are bound to the key by the TDX quote report_data
|
|
138
|
+
* (`keccak256(userPsId || address)`), which v1 stores but does not verify
|
|
139
|
+
* (DCAP is step 4). Until then the agent's derivation check is the backstop.
|
|
140
|
+
* @throws When any identity binding or trust check fails.
|
|
141
|
+
*/
|
|
142
|
+
export declare function verifyEnclaveIdentityEvidence(evidence: EnclaveIdentityEvidence, anchors: EnclaveTrustAnchors, expected: ExpectedIdentity): Promise<void>;
|
|
143
|
+
/**
|
|
144
|
+
* Builds the authenticated master-signature plaintext delivered to an enclave.
|
|
145
|
+
*
|
|
146
|
+
* @param evidence - Verified enclave identity evidence.
|
|
147
|
+
* @param masterSignature - EIP-191 signature over the master-key message.
|
|
148
|
+
* @param now - Issuance time in Unix seconds.
|
|
149
|
+
* @returns The authenticated plaintext delivery object.
|
|
150
|
+
* @throws When the signature is malformed or does not belong to the owner.
|
|
151
|
+
*/
|
|
152
|
+
export declare function buildMasterSignatureDelivery(evidence: EnclaveIdentityEvidence, masterSignature: Hex, now?: number): Promise<MasterSignatureDelivery>;
|
|
153
|
+
/**
|
|
154
|
+
* Encrypts a master-signature delivery in the SDK's ECIES wire format.
|
|
155
|
+
*
|
|
156
|
+
* @param delivery - Plaintext delivery object.
|
|
157
|
+
* @param publicKey - Enclave 65-byte uncompressed public key.
|
|
158
|
+
* @param ecies - Platform-specific ECIES provider.
|
|
159
|
+
* @returns The 0x-prefixed serialized ciphertext.
|
|
160
|
+
*/
|
|
161
|
+
export declare function encryptMasterSignatureDelivery(delivery: MasterSignatureDelivery, publicKey: Hex, ecies: ECIESProvider): Promise<Hex>;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import * as secp256k1 from "@noble/secp256k1";
|
|
2
|
+
import {
|
|
3
|
+
concat,
|
|
4
|
+
encodePacked,
|
|
5
|
+
fromHex,
|
|
6
|
+
getAddress,
|
|
7
|
+
isAddressEqual,
|
|
8
|
+
keccak256,
|
|
9
|
+
recoverPublicKey,
|
|
10
|
+
toBytes,
|
|
11
|
+
toHex
|
|
12
|
+
} from "viem";
|
|
13
|
+
import { publicKeyToAddress } from "viem/accounts";
|
|
14
|
+
import { serializeECIES } from "../crypto/ecies/interface.js";
|
|
15
|
+
import { deriveMasterKey, recoverServerOwner } from "../crypto/keys/derive.js";
|
|
16
|
+
const ENCLAVE_IDENTITY_EVIDENCE_VERSION = 1;
|
|
17
|
+
const USER_PS_ID_DOMAIN = "vana.ps-enclave.v1";
|
|
18
|
+
const ENCLAVE_WALLET_PURPOSE = "vana.ps-enclave.wallet.v1";
|
|
19
|
+
const MASTER_SIGNATURE_DELIVERY_VERSION = "vana.ps-enclave.delivery.v1";
|
|
20
|
+
const SEALED_ENVELOPE_VERSION = 1;
|
|
21
|
+
const VANA_MAINNET_CHAIN_ID = 1480;
|
|
22
|
+
const MOKSHA_CHAIN_ID = 14800;
|
|
23
|
+
const KMS_ISSUED_PREFIX = "dstack-kms-issued";
|
|
24
|
+
const PREIMAGE_SEPARATOR = ":";
|
|
25
|
+
const UNCOMPRESSED_PUBLIC_KEY_BYTES = 65;
|
|
26
|
+
const UNCOMPRESSED_PUBLIC_KEY_PREFIX = "04";
|
|
27
|
+
const ENCLAVE_TRUST_ANCHORS = {
|
|
28
|
+
// filled at fleet provisioning; verify fails closed while empty
|
|
29
|
+
[VANA_MAINNET_CHAIN_ID]: { kmsRootPubkey: "0x", appIds: [] },
|
|
30
|
+
// filled at fleet provisioning; verify fails closed while empty
|
|
31
|
+
[MOKSHA_CHAIN_ID]: { kmsRootPubkey: "0x", appIds: [] }
|
|
32
|
+
};
|
|
33
|
+
function userPsId(chainId, ownerAddress) {
|
|
34
|
+
const packed = encodePacked(
|
|
35
|
+
["string", "uint256", "address"],
|
|
36
|
+
[USER_PS_ID_DOMAIN, BigInt(chainId), getAddress(ownerAddress)]
|
|
37
|
+
);
|
|
38
|
+
return keccak256(packed);
|
|
39
|
+
}
|
|
40
|
+
function compressPublicKey(publicKey) {
|
|
41
|
+
return secp256k1.ProjectivePoint.fromHex(
|
|
42
|
+
fromHex(publicKey, "bytes")
|
|
43
|
+
).toRawBytes(true);
|
|
44
|
+
}
|
|
45
|
+
function appRootPreimage(purpose, publicKey) {
|
|
46
|
+
const keyHex = toHex(compressPublicKey(publicKey)).slice(2);
|
|
47
|
+
return keccak256(toBytes(`${purpose}${PREIMAGE_SEPARATOR}${keyHex}`));
|
|
48
|
+
}
|
|
49
|
+
function kmsIssuedPreimage(appId, appRootPublicKey) {
|
|
50
|
+
const prefix = concat([
|
|
51
|
+
toBytes(`${KMS_ISSUED_PREFIX}${PREIMAGE_SEPARATOR}`),
|
|
52
|
+
fromHex(appId, "bytes")
|
|
53
|
+
]);
|
|
54
|
+
const compressed = compressPublicKey(appRootPublicKey);
|
|
55
|
+
return keccak256(concat([prefix, compressed]));
|
|
56
|
+
}
|
|
57
|
+
async function recoverChainKey(hash, signature, link) {
|
|
58
|
+
try {
|
|
59
|
+
return (await recoverPublicKey({ hash, signature })).toLowerCase();
|
|
60
|
+
} catch {
|
|
61
|
+
throw new Error(`Invalid enclave signature chain link ${link}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function verifyEnclaveIdentityEvidence(evidence, anchors, expected) {
|
|
65
|
+
if (evidence.v !== ENCLAVE_IDENTITY_EVIDENCE_VERSION) {
|
|
66
|
+
throw new Error("Unsupported enclave identity evidence version");
|
|
67
|
+
}
|
|
68
|
+
if (!Number.isInteger(evidence.epoch) || evidence.epoch < 1) {
|
|
69
|
+
throw new Error("Invalid enclave identity epoch");
|
|
70
|
+
}
|
|
71
|
+
if (evidence.chainId !== expected.chainId) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
"Enclave identity chain ID does not match expected chain ID"
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
if (!isAddressEqual(evidence.ownerAddress, expected.ownerAddress)) {
|
|
77
|
+
throw new Error("Enclave identity owner does not match expected owner");
|
|
78
|
+
}
|
|
79
|
+
if (evidence.epoch !== expected.epoch) {
|
|
80
|
+
throw new Error("Enclave identity epoch does not match expected epoch");
|
|
81
|
+
}
|
|
82
|
+
const expectedUserPsId = userPsId(expected.chainId, expected.ownerAddress);
|
|
83
|
+
if (evidence.userPsId.toLowerCase() !== expectedUserPsId.toLowerCase()) {
|
|
84
|
+
throw new Error("Enclave userPsId does not match expected identity");
|
|
85
|
+
}
|
|
86
|
+
if (evidence.purpose !== ENCLAVE_WALLET_PURPOSE) {
|
|
87
|
+
throw new Error("Unexpected enclave wallet purpose");
|
|
88
|
+
}
|
|
89
|
+
const derivedAddress = publicKeyToAddress(evidence.publicKey);
|
|
90
|
+
if (getAddress(derivedAddress) !== getAddress(evidence.address)) {
|
|
91
|
+
throw new Error("Enclave public key does not match its address");
|
|
92
|
+
}
|
|
93
|
+
const appRootPublicKey = await recoverChainKey(
|
|
94
|
+
appRootPreimage(evidence.purpose, evidence.publicKey),
|
|
95
|
+
evidence.signatureChain[0],
|
|
96
|
+
0
|
|
97
|
+
);
|
|
98
|
+
const kmsRootPublicKey = await recoverChainKey(
|
|
99
|
+
kmsIssuedPreimage(evidence.appId, appRootPublicKey),
|
|
100
|
+
evidence.signatureChain[1],
|
|
101
|
+
1
|
|
102
|
+
);
|
|
103
|
+
if (anchors.kmsRootPubkey === "0x") {
|
|
104
|
+
throw new Error("KMS root trust anchor is not provisioned");
|
|
105
|
+
}
|
|
106
|
+
if (kmsRootPublicKey !== anchors.kmsRootPubkey.toLowerCase()) {
|
|
107
|
+
throw new Error("KMS root public key does not match the trust anchor");
|
|
108
|
+
}
|
|
109
|
+
if (keccak256(kmsRootPublicKey) !== evidence.kmsRootFingerprint.toLowerCase()) {
|
|
110
|
+
throw new Error("KMS root fingerprint does not match the evidence");
|
|
111
|
+
}
|
|
112
|
+
const appId = evidence.appId.toLowerCase();
|
|
113
|
+
if (!anchors.appIds.some((allowedAppId) => allowedAppId.toLowerCase() === appId)) {
|
|
114
|
+
throw new Error("Enclave app ID is not trusted");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function buildMasterSignatureDelivery(evidence, masterSignature, now = Math.floor(Date.now() / 1e3)) {
|
|
118
|
+
deriveMasterKey(masterSignature);
|
|
119
|
+
const signerAddress = await recoverServerOwner(masterSignature);
|
|
120
|
+
if (!isAddressEqual(signerAddress, evidence.ownerAddress)) {
|
|
121
|
+
throw new Error("Master signature signer does not match evidence owner");
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
v: MASTER_SIGNATURE_DELIVERY_VERSION,
|
|
125
|
+
userPsId: evidence.userPsId,
|
|
126
|
+
epoch: evidence.epoch,
|
|
127
|
+
enclaveAddress: evidence.address,
|
|
128
|
+
ownerAddress: evidence.ownerAddress,
|
|
129
|
+
masterSignature,
|
|
130
|
+
issuedAt: now
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function assertUncompressedKey(publicKey) {
|
|
134
|
+
const hex = publicKey.slice(2);
|
|
135
|
+
if (hex.length !== UNCOMPRESSED_PUBLIC_KEY_BYTES * 2 || !hex.startsWith(UNCOMPRESSED_PUBLIC_KEY_PREFIX) || !/^[0-9a-fA-F]+$/.test(hex)) {
|
|
136
|
+
throw new Error("Public key must be a 65-byte uncompressed secp256k1 key");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function encryptMasterSignatureDelivery(delivery, publicKey, ecies) {
|
|
140
|
+
assertUncompressedKey(publicKey);
|
|
141
|
+
const plaintext = toBytes(JSON.stringify(delivery));
|
|
142
|
+
const encrypted = await ecies.encrypt(fromHex(publicKey, "bytes"), plaintext);
|
|
143
|
+
return `0x${serializeECIES(encrypted)}`;
|
|
144
|
+
}
|
|
145
|
+
export {
|
|
146
|
+
ENCLAVE_IDENTITY_EVIDENCE_VERSION,
|
|
147
|
+
ENCLAVE_TRUST_ANCHORS,
|
|
148
|
+
ENCLAVE_WALLET_PURPOSE,
|
|
149
|
+
MASTER_SIGNATURE_DELIVERY_VERSION,
|
|
150
|
+
SEALED_ENVELOPE_VERSION,
|
|
151
|
+
USER_PS_ID_DOMAIN,
|
|
152
|
+
appRootPreimage,
|
|
153
|
+
buildMasterSignatureDelivery,
|
|
154
|
+
encryptMasterSignatureDelivery,
|
|
155
|
+
kmsIssuedPreimage,
|
|
156
|
+
userPsId,
|
|
157
|
+
verifyEnclaveIdentityEvidence
|
|
158
|
+
};
|
|
159
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/protocol/identity.ts"],"sourcesContent":["/**\n * Enclave identity and consent primitives for Personal Servers.\n *\n * Owner/Web -> Gateway -> Agent(CVM): derive wallet and quote\n * Web verifies evidence; Account authenticates and encrypts the EIP-191 master\n * signature to the enclave key; Gateway relays it blind; Agent decrypts/seals.\n *\n * @category Protocol\n */\n\nimport * as secp256k1 from \"@noble/secp256k1\";\nimport {\n concat,\n encodePacked,\n fromHex,\n getAddress,\n isAddressEqual,\n keccak256,\n recoverPublicKey,\n toBytes,\n toHex,\n type Address,\n type Hex,\n} from \"viem\";\nimport { publicKeyToAddress } from \"viem/accounts\";\nimport { serializeECIES, type ECIESProvider } from \"../crypto/ecies/interface\";\nimport { deriveMasterKey, recoverServerOwner } from \"../crypto/keys/derive\";\nimport type { ServerRegistrationMessage } from \"./eip712\";\n\nexport const ENCLAVE_IDENTITY_EVIDENCE_VERSION = 1;\nexport const USER_PS_ID_DOMAIN = \"vana.ps-enclave.v1\";\nexport const ENCLAVE_WALLET_PURPOSE = \"vana.ps-enclave.wallet.v1\";\nexport const MASTER_SIGNATURE_DELIVERY_VERSION = \"vana.ps-enclave.delivery.v1\";\nexport const SEALED_ENVELOPE_VERSION = 1;\n\nconst VANA_MAINNET_CHAIN_ID = 1480;\nconst MOKSHA_CHAIN_ID = 14800;\nconst KMS_ISSUED_PREFIX = \"dstack-kms-issued\";\nconst PREIMAGE_SEPARATOR = \":\";\nconst UNCOMPRESSED_PUBLIC_KEY_BYTES = 65;\nconst UNCOMPRESSED_PUBLIC_KEY_PREFIX = \"04\";\n\nexport type UserPsId = Hex;\n\nexport interface EnclaveIdentityEvidence {\n v: typeof ENCLAVE_IDENTITY_EVIDENCE_VERSION;\n userPsId: UserPsId;\n chainId: number;\n ownerAddress: Address;\n epoch: number;\n address: Address;\n publicKey: Hex;\n appId: Hex;\n composeHash: Hex;\n osImageHash?: Hex;\n purpose: string;\n signatureChain: [Hex, Hex];\n quote: Hex;\n eventLog?: string;\n kmsRootFingerprint: Hex;\n}\n\nexport interface ExpectedIdentity {\n ownerAddress: Address;\n chainId: number;\n epoch: number;\n}\n\nexport interface IdentityRequest {\n ownerAddress: Address;\n chainId: number;\n}\n\nexport type IdentityState = \"prepared\" | \"registered\" | \"sealed\" | \"retired\";\n\nexport interface IdentityResponse {\n identity: EnclaveIdentityEvidence;\n state: IdentityState;\n created: boolean;\n serverUrl: string;\n serverId?: Hex;\n serverStatus?:\n | \"pending\"\n | \"submitting\"\n | \"confirmed\"\n | \"finalized\"\n | \"failed\";\n sealed: boolean;\n}\n\nexport type IdentityRegistrationRequest =\n | { version: \"v2\"; message: ServerRegistrationMessage }\n | {\n version: \"v3\";\n message: ServerRegistrationMessage & { nonce: string; deadline: string };\n };\n\nexport interface IdentityRegistrationResponse {\n serverId: Hex;\n state: \"registered\";\n serverStatus: \"pending\";\n}\n\n/** Inner plaintext of the ECIES box. */\nexport interface MasterSignatureDelivery {\n v: typeof MASTER_SIGNATURE_DELIVERY_VERSION;\n userPsId: UserPsId;\n epoch: number;\n enclaveAddress: Address;\n ownerAddress: Address;\n masterSignature: Hex;\n issuedAt: number;\n}\n\nexport interface SealedSecretSubmission {\n userPsId: UserPsId;\n epoch: number;\n enclaveAddress: Address;\n ciphertext: Hex;\n}\n\nexport interface SealedSecretResponse {\n sealed: true;\n secretHash: Hex;\n sealedAt: string;\n}\n\nexport interface AesGcmBox {\n iv: string;\n ciphertext: string;\n tag: string;\n}\n\n/** Persisted enclave envelope; the Gateway treats it as opaque text. */\nexport interface SealedEnvelope extends AesGcmBox {\n v: typeof SEALED_ENVELOPE_VERSION;\n wrappedContentKey: AesGcmBox;\n}\n\nexport interface EnclaveTrustAnchors {\n kmsRootPubkey: Hex;\n appIds: Hex[];\n}\n\n/** Fleet-provisioned trust anchors keyed by Vana chain ID. */\nexport const ENCLAVE_TRUST_ANCHORS: Record<number, EnclaveTrustAnchors> = {\n // filled at fleet provisioning; verify fails closed while empty\n [VANA_MAINNET_CHAIN_ID]: { kmsRootPubkey: \"0x\", appIds: [] },\n // filled at fleet provisioning; verify fails closed while empty\n [MOKSHA_CHAIN_ID]: { kmsRootPubkey: \"0x\", appIds: [] },\n};\n\n/**\n * Derives the deterministic Personal Server ID used by enclave paths.\n *\n * @param chainId - Vana chain ID.\n * @param ownerAddress - Checksummed owner address.\n * @returns The path-compatible keccak256 digest.\n */\nexport function userPsId(chainId: number, ownerAddress: Address): UserPsId {\n const packed = encodePacked(\n [\"string\", \"uint256\", \"address\"],\n [USER_PS_ID_DOMAIN, BigInt(chainId), getAddress(ownerAddress)],\n );\n\n return keccak256(packed);\n}\n\nfunction compressPublicKey(publicKey: Hex): Uint8Array {\n return secp256k1.ProjectivePoint.fromHex(\n fromHex(publicKey, \"bytes\"),\n ).toRawBytes(true);\n}\n\n/**\n * Builds keccak256(utf8(purpose || \":\" || lowercase hex(compressed pubkey))).\n *\n * Matches `dstack/guest-agent/src/rpc_service.rs:612-628`.\n */\nexport function appRootPreimage(purpose: string, publicKey: Hex): Hex {\n const keyHex = toHex(compressPublicKey(publicKey)).slice(2);\n return keccak256(toBytes(`${purpose}${PREIMAGE_SEPARATOR}${keyHex}`));\n}\n\n/**\n * Hashes the KMS prefix, raw app ID bytes, and compressed app-root public key.\n *\n * Matches `dstack/kms/src/crypto.rs:23-40`; there is no separator between the\n * raw 20-byte app ID and the compressed key.\n */\nexport function kmsIssuedPreimage(appId: Hex, appRootPublicKey: Hex): Hex {\n const prefix = concat([\n toBytes(`${KMS_ISSUED_PREFIX}${PREIMAGE_SEPARATOR}`),\n fromHex(appId, \"bytes\"),\n ]);\n const compressed = compressPublicKey(appRootPublicKey);\n\n return keccak256(concat([prefix, compressed]));\n}\n\nasync function recoverChainKey(\n hash: Hex,\n signature: Hex,\n link: number,\n): Promise<Hex> {\n try {\n return (await recoverPublicKey({ hash, signature })).toLowerCase() as Hex;\n } catch {\n throw new Error(`Invalid enclave signature chain link ${link}`);\n }\n}\n\n/**\n * Verifies the enclave wallet binding against fleet-provisioned trust anchors.\n *\n * @param evidence - Identity evidence returned by the enclave agent.\n * @param anchors - Pinned KMS root and allowed dstack app IDs.\n * @param expected - Owner, chain, and epoch requested by the caller.\n *\n * @remarks\n * The dstack chain signs only `purpose || publicKey` and `appId || appRootPub`;\n * owner, chain and epoch are bound to the key by the TDX quote report_data\n * (`keccak256(userPsId || address)`), which v1 stores but does not verify\n * (DCAP is step 4). Until then the agent's derivation check is the backstop.\n * @throws When any identity binding or trust check fails.\n */\nexport async function verifyEnclaveIdentityEvidence(\n evidence: EnclaveIdentityEvidence,\n anchors: EnclaveTrustAnchors,\n expected: ExpectedIdentity,\n): Promise<void> {\n if (evidence.v !== ENCLAVE_IDENTITY_EVIDENCE_VERSION) {\n throw new Error(\"Unsupported enclave identity evidence version\");\n }\n\n if (!Number.isInteger(evidence.epoch) || evidence.epoch < 1) {\n throw new Error(\"Invalid enclave identity epoch\");\n }\n\n if (evidence.chainId !== expected.chainId) {\n throw new Error(\n \"Enclave identity chain ID does not match expected chain ID\",\n );\n }\n\n if (!isAddressEqual(evidence.ownerAddress, expected.ownerAddress)) {\n throw new Error(\"Enclave identity owner does not match expected owner\");\n }\n\n if (evidence.epoch !== expected.epoch) {\n throw new Error(\"Enclave identity epoch does not match expected epoch\");\n }\n\n const expectedUserPsId = userPsId(expected.chainId, expected.ownerAddress);\n if (evidence.userPsId.toLowerCase() !== expectedUserPsId.toLowerCase()) {\n throw new Error(\"Enclave userPsId does not match expected identity\");\n }\n\n if (evidence.purpose !== ENCLAVE_WALLET_PURPOSE) {\n throw new Error(\"Unexpected enclave wallet purpose\");\n }\n\n const derivedAddress = publicKeyToAddress(evidence.publicKey);\n\n if (getAddress(derivedAddress) !== getAddress(evidence.address)) {\n throw new Error(\"Enclave public key does not match its address\");\n }\n\n const appRootPublicKey = await recoverChainKey(\n appRootPreimage(evidence.purpose, evidence.publicKey),\n evidence.signatureChain[0],\n 0,\n );\n const kmsRootPublicKey = await recoverChainKey(\n kmsIssuedPreimage(evidence.appId, appRootPublicKey),\n evidence.signatureChain[1],\n 1,\n );\n\n if (anchors.kmsRootPubkey === \"0x\") {\n throw new Error(\"KMS root trust anchor is not provisioned\");\n }\n\n if (kmsRootPublicKey !== anchors.kmsRootPubkey.toLowerCase()) {\n throw new Error(\"KMS root public key does not match the trust anchor\");\n }\n\n if (\n keccak256(kmsRootPublicKey) !== evidence.kmsRootFingerprint.toLowerCase()\n ) {\n throw new Error(\"KMS root fingerprint does not match the evidence\");\n }\n\n const appId = evidence.appId.toLowerCase();\n if (\n !anchors.appIds.some((allowedAppId) => allowedAppId.toLowerCase() === appId)\n ) {\n throw new Error(\"Enclave app ID is not trusted\");\n }\n}\n\n/**\n * Builds the authenticated master-signature plaintext delivered to an enclave.\n *\n * @param evidence - Verified enclave identity evidence.\n * @param masterSignature - EIP-191 signature over the master-key message.\n * @param now - Issuance time in Unix seconds.\n * @returns The authenticated plaintext delivery object.\n * @throws When the signature is malformed or does not belong to the owner.\n */\nexport async function buildMasterSignatureDelivery(\n evidence: EnclaveIdentityEvidence,\n masterSignature: Hex,\n now = Math.floor(Date.now() / 1000),\n): Promise<MasterSignatureDelivery> {\n deriveMasterKey(masterSignature);\n const signerAddress = await recoverServerOwner(masterSignature);\n\n if (!isAddressEqual(signerAddress, evidence.ownerAddress)) {\n throw new Error(\"Master signature signer does not match evidence owner\");\n }\n\n return {\n v: MASTER_SIGNATURE_DELIVERY_VERSION,\n userPsId: evidence.userPsId,\n epoch: evidence.epoch,\n enclaveAddress: evidence.address,\n ownerAddress: evidence.ownerAddress,\n masterSignature,\n issuedAt: now,\n };\n}\n\nfunction assertUncompressedKey(publicKey: Hex): void {\n const hex = publicKey.slice(2);\n if (\n hex.length !== UNCOMPRESSED_PUBLIC_KEY_BYTES * 2 ||\n !hex.startsWith(UNCOMPRESSED_PUBLIC_KEY_PREFIX) ||\n !/^[0-9a-fA-F]+$/.test(hex)\n ) {\n throw new Error(\"Public key must be a 65-byte uncompressed secp256k1 key\");\n }\n}\n\n/**\n * Encrypts a master-signature delivery in the SDK's ECIES wire format.\n *\n * @param delivery - Plaintext delivery object.\n * @param publicKey - Enclave 65-byte uncompressed public key.\n * @param ecies - Platform-specific ECIES provider.\n * @returns The 0x-prefixed serialized ciphertext.\n */\nexport async function encryptMasterSignatureDelivery(\n delivery: MasterSignatureDelivery,\n publicKey: Hex,\n ecies: ECIESProvider,\n): Promise<Hex> {\n assertUncompressedKey(publicKey);\n\n const plaintext = toBytes(JSON.stringify(delivery));\n const encrypted = await ecies.encrypt(fromHex(publicKey, \"bytes\"), plaintext);\n\n return `0x${serializeECIES(encrypted)}`;\n}\n"],"mappings":"AAUA,YAAY,eAAe;AAC3B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,0BAA0B;AACnC,SAAS,sBAA0C;AACnD,SAAS,iBAAiB,0BAA0B;AAG7C,MAAM,oCAAoC;AAC1C,MAAM,oBAAoB;AAC1B,MAAM,yBAAyB;AAC/B,MAAM,oCAAoC;AAC1C,MAAM,0BAA0B;AAEvC,MAAM,wBAAwB;AAC9B,MAAM,kBAAkB;AACxB,MAAM,oBAAoB;AAC1B,MAAM,qBAAqB;AAC3B,MAAM,gCAAgC;AACtC,MAAM,iCAAiC;AAyGhC,MAAM,wBAA6D;AAAA;AAAA,EAExE,CAAC,qBAAqB,GAAG,EAAE,eAAe,MAAM,QAAQ,CAAC,EAAE;AAAA;AAAA,EAE3D,CAAC,eAAe,GAAG,EAAE,eAAe,MAAM,QAAQ,CAAC,EAAE;AACvD;AASO,SAAS,SAAS,SAAiB,cAAiC;AACzE,QAAM,SAAS;AAAA,IACb,CAAC,UAAU,WAAW,SAAS;AAAA,IAC/B,CAAC,mBAAmB,OAAO,OAAO,GAAG,WAAW,YAAY,CAAC;AAAA,EAC/D;AAEA,SAAO,UAAU,MAAM;AACzB;AAEA,SAAS,kBAAkB,WAA4B;AACrD,SAAO,UAAU,gBAAgB;AAAA,IAC/B,QAAQ,WAAW,OAAO;AAAA,EAC5B,EAAE,WAAW,IAAI;AACnB;AAOO,SAAS,gBAAgB,SAAiB,WAAqB;AACpE,QAAM,SAAS,MAAM,kBAAkB,SAAS,CAAC,EAAE,MAAM,CAAC;AAC1D,SAAO,UAAU,QAAQ,GAAG,OAAO,GAAG,kBAAkB,GAAG,MAAM,EAAE,CAAC;AACtE;AAQO,SAAS,kBAAkB,OAAY,kBAA4B;AACxE,QAAM,SAAS,OAAO;AAAA,IACpB,QAAQ,GAAG,iBAAiB,GAAG,kBAAkB,EAAE;AAAA,IACnD,QAAQ,OAAO,OAAO;AAAA,EACxB,CAAC;AACD,QAAM,aAAa,kBAAkB,gBAAgB;AAErD,SAAO,UAAU,OAAO,CAAC,QAAQ,UAAU,CAAC,CAAC;AAC/C;AAEA,eAAe,gBACb,MACA,WACA,MACc;AACd,MAAI;AACF,YAAQ,MAAM,iBAAiB,EAAE,MAAM,UAAU,CAAC,GAAG,YAAY;AAAA,EACnE,QAAQ;AACN,UAAM,IAAI,MAAM,wCAAwC,IAAI,EAAE;AAAA,EAChE;AACF;AAgBA,eAAsB,8BACpB,UACA,SACA,UACe;AACf,MAAI,SAAS,MAAM,mCAAmC;AACpD,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AAEA,MAAI,CAAC,OAAO,UAAU,SAAS,KAAK,KAAK,SAAS,QAAQ,GAAG;AAC3D,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAEA,MAAI,SAAS,YAAY,SAAS,SAAS;AACzC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,eAAe,SAAS,cAAc,SAAS,YAAY,GAAG;AACjE,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACxE;AAEA,MAAI,SAAS,UAAU,SAAS,OAAO;AACrC,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACxE;AAEA,QAAM,mBAAmB,SAAS,SAAS,SAAS,SAAS,YAAY;AACzE,MAAI,SAAS,SAAS,YAAY,MAAM,iBAAiB,YAAY,GAAG;AACtE,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AAEA,MAAI,SAAS,YAAY,wBAAwB;AAC/C,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AAEA,QAAM,iBAAiB,mBAAmB,SAAS,SAAS;AAE5D,MAAI,WAAW,cAAc,MAAM,WAAW,SAAS,OAAO,GAAG;AAC/D,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AAEA,QAAM,mBAAmB,MAAM;AAAA,IAC7B,gBAAgB,SAAS,SAAS,SAAS,SAAS;AAAA,IACpD,SAAS,eAAe,CAAC;AAAA,IACzB;AAAA,EACF;AACA,QAAM,mBAAmB,MAAM;AAAA,IAC7B,kBAAkB,SAAS,OAAO,gBAAgB;AAAA,IAClD,SAAS,eAAe,CAAC;AAAA,IACzB;AAAA,EACF;AAEA,MAAI,QAAQ,kBAAkB,MAAM;AAClC,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,MAAI,qBAAqB,QAAQ,cAAc,YAAY,GAAG;AAC5D,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AAEA,MACE,UAAU,gBAAgB,MAAM,SAAS,mBAAmB,YAAY,GACxE;AACA,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AAEA,QAAM,QAAQ,SAAS,MAAM,YAAY;AACzC,MACE,CAAC,QAAQ,OAAO,KAAK,CAAC,iBAAiB,aAAa,YAAY,MAAM,KAAK,GAC3E;AACA,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACjD;AACF;AAWA,eAAsB,6BACpB,UACA,iBACA,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI,GACA;AAClC,kBAAgB,eAAe;AAC/B,QAAM,gBAAgB,MAAM,mBAAmB,eAAe;AAE9D,MAAI,CAAC,eAAe,eAAe,SAAS,YAAY,GAAG;AACzD,UAAM,IAAI,MAAM,uDAAuD;AAAA,EACzE;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,UAAU,SAAS;AAAA,IACnB,OAAO,SAAS;AAAA,IAChB,gBAAgB,SAAS;AAAA,IACzB,cAAc,SAAS;AAAA,IACvB;AAAA,IACA,UAAU;AAAA,EACZ;AACF;AAEA,SAAS,sBAAsB,WAAsB;AACnD,QAAM,MAAM,UAAU,MAAM,CAAC;AAC7B,MACE,IAAI,WAAW,gCAAgC,KAC/C,CAAC,IAAI,WAAW,8BAA8B,KAC9C,CAAC,iBAAiB,KAAK,GAAG,GAC1B;AACA,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACF;AAUA,eAAsB,+BACpB,UACA,WACA,OACc;AACd,wBAAsB,SAAS;AAE/B,QAAM,YAAY,QAAQ,KAAK,UAAU,QAAQ,CAAC;AAClD,QAAM,YAAY,MAAM,MAAM,QAAQ,QAAQ,WAAW,OAAO,GAAG,SAAS;AAE5E,SAAO,KAAK,eAAe,SAAS,CAAC;AACvC;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/server.cjs
CHANGED
|
@@ -55,7 +55,8 @@ __export(server_exports, {
|
|
|
55
55
|
scopeMatchesPattern: () => import_scopes.scopeMatchesPattern,
|
|
56
56
|
toDirectFeeBreakdown: () => import_escrow_payment.toDirectFeeBreakdown,
|
|
57
57
|
toDirectPaymentReceipt: () => import_escrow_payment.toDirectPaymentReceipt,
|
|
58
|
-
tryGrantPermissions: () => import_scope_actions.tryGrantPermissions
|
|
58
|
+
tryGrantPermissions: () => import_scope_actions.tryGrantPermissions,
|
|
59
|
+
validateAccessRequestQuestions: () => import_access_request_client.validateAccessRequestQuestions
|
|
59
60
|
});
|
|
60
61
|
module.exports = __toCommonJS(server_exports);
|
|
61
62
|
var import_controller = require("./direct/controller");
|
|
@@ -106,6 +107,7 @@ var import_types = require("./direct/types");
|
|
|
106
107
|
scopeMatchesPattern,
|
|
107
108
|
toDirectFeeBreakdown,
|
|
108
109
|
toDirectPaymentReceipt,
|
|
109
|
-
tryGrantPermissions
|
|
110
|
+
tryGrantPermissions,
|
|
111
|
+
validateAccessRequestQuestions
|
|
110
112
|
});
|
|
111
113
|
//# sourceMappingURL=server.cjs.map
|
package/dist/server.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\n * Server entry point for the Vana SDK direct Data Portability flow.\n *\n * @remarks\n * Exposes {@link createDirectDataController} and its supporting types/errors.\n * This is a Node/server entry point — it owns the app private key and must never\n * be imported into browser code.\n *\n * @example\n * ```typescript\n * import { createDirectDataController } from \"@opendatalabs/vana-sdk/server\";\n *\n * export const vana = createDirectDataController({\n * env: process.env.VANA_ENV === \"dev\" ? \"dev\" : \"production\",\n * appPrivateKey: process.env.VANA_APP_PRIVATE_KEY!,\n * app: { id: \"notes-lens\", name: \"Notes Lens\", homepageUrl: process.env.VANA_APP_URL! },\n * source: \"icloud_notes\",\n * scopes: [\"icloud_notes.notes\"],\n * });\n * ```\n *\n * @category Direct\n * @module server\n */\n\nexport {\n createDirectDataController,\n type DirectDataController,\n type DirectDataControllerConfig,\n type DirectEscrowConfig,\n} from \"./direct/controller\";\n\n// Lower-level building blocks (advanced use / custom transports).\nexport {\n createDefaultAccessRequestClient,\n buildApprovalUrl,\n type DefaultAccessRequestClientOptions,\n type FetchLike,\n} from \"./direct/access-request-client\";\nexport {\n buildPersonalServerDataReadRequest,\n readPersonalServerData,\n parsePersonalServerPaymentRequired,\n dataPathForScope,\n type PersonalServerDataReadRequest,\n type PersonalServerReadResult,\n type PersonalServerFetch,\n type PersonalServerTransportRetryOptions,\n type FetchResponseLike,\n} from \"./direct/personal-server-read\";\n// Escrow-backed payment (built on protocol/escrow).\nexport {\n authorizeEscrowPayment,\n authorizeGrantPayment,\n buildEscrowPaymentHeader,\n buildGrantPaymentHeader,\n paymentResponseMetadataFromHeader,\n toDirectPaymentReceipt,\n toDirectFeeBreakdown,\n createDefaultNonceSource,\n DATA_ACCESS_OP_TYPE,\n GRANT_OP_TYPE,\n type EscrowPaymentConfig,\n type EscrowPaymentHeaderConfig,\n type SignTypedDataFn,\n type PaymentNonceSource,\n} from \"./direct/escrow-payment\";\nexport {\n getDirectEndpoints,\n PRODUCTION_ENDPOINTS,\n DEV_ENDPOINTS,\n} from \"./direct/endpoints\";\n// Grant scope entries: the `[operation:]scope` vocabulary the controller's\n// `scopes` are written in, so a backend can build and read them without\n// reaching for a platform entry point.\nexport {\n ScopeSchema,\n parseScope,\n scopeMatchesPattern,\n scopeCoveredByGrant,\n type Scope,\n type ParsedScope,\n} from \"./protocol/scopes\";\nexport {\n SCOPE_ACTIONS,\n InvalidScopeEntryError,\n parseScopeEntry,\n formatScopeEntry,\n grantPermissions,\n permissionsToScopes,\n tryGrantPermissions,\n hasAction,\n type ScopeAction,\n type ParsedScopeEntry,\n type GrantPermission,\n} from \"./protocol/scope-actions\";\n\n// Errors\nexport {\n DirectConfigError,\n AccessNotApprovedError,\n ScopeNotApprovedError,\n PersonalServerReadError,\n PaymentRequiredError,\n} from \"./direct/errors\";\n\n// Shared types\nexport type {\n DirectEnv,\n DirectNetwork,\n DirectAppConfig,\n ForegroundDelivery,\n AppIdentity,\n DirectServiceEndpoints,\n AccessRequest,\n AccessRequestStatus,\n AccessRequestStatusValue,\n ApprovedDataResult,\n MultiScopeDataResult,\n AccessRequestClient,\n DirectOpTypeValue,\n PersonalServerDataAccessPaymentOperation,\n PersonalServerGrantPaymentOperation,\n PersonalServerPaymentOperation,\n PersonalServerPaymentRequired,\n DirectPaymentReceipt,\n DirectPaymentResponseMetadata,\n DirectFeeBreakdown,\n} from \"./direct/types\";\n\n// Op-type vocabulary constant.\nexport { DirectOpType } from \"./direct/types\";\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBA,wBAKO;AAGP,
|
|
1
|
+
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\n * Server entry point for the Vana SDK direct Data Portability flow.\n *\n * @remarks\n * Exposes {@link createDirectDataController} and its supporting types/errors.\n * This is a Node/server entry point — it owns the app private key and must never\n * be imported into browser code.\n *\n * @example\n * ```typescript\n * import { createDirectDataController } from \"@opendatalabs/vana-sdk/server\";\n *\n * export const vana = createDirectDataController({\n * env: process.env.VANA_ENV === \"dev\" ? \"dev\" : \"production\",\n * appPrivateKey: process.env.VANA_APP_PRIVATE_KEY!,\n * app: { id: \"notes-lens\", name: \"Notes Lens\", homepageUrl: process.env.VANA_APP_URL! },\n * source: \"icloud_notes\",\n * scopes: [\"icloud_notes.notes\"],\n * });\n * ```\n *\n * @category Direct\n * @module server\n */\n\nexport {\n createDirectDataController,\n type DirectDataController,\n type DirectDataControllerConfig,\n type DirectEscrowConfig,\n} from \"./direct/controller\";\n\n// Lower-level building blocks (advanced use / custom transports).\nexport {\n createDefaultAccessRequestClient,\n buildApprovalUrl,\n validateAccessRequestQuestions,\n type DefaultAccessRequestClientOptions,\n type FetchLike,\n} from \"./direct/access-request-client\";\nexport {\n buildPersonalServerDataReadRequest,\n readPersonalServerData,\n parsePersonalServerPaymentRequired,\n dataPathForScope,\n type PersonalServerDataReadRequest,\n type PersonalServerReadResult,\n type PersonalServerFetch,\n type PersonalServerTransportRetryOptions,\n type FetchResponseLike,\n} from \"./direct/personal-server-read\";\n// Escrow-backed payment (built on protocol/escrow).\nexport {\n authorizeEscrowPayment,\n authorizeGrantPayment,\n buildEscrowPaymentHeader,\n buildGrantPaymentHeader,\n paymentResponseMetadataFromHeader,\n toDirectPaymentReceipt,\n toDirectFeeBreakdown,\n createDefaultNonceSource,\n DATA_ACCESS_OP_TYPE,\n GRANT_OP_TYPE,\n type EscrowPaymentConfig,\n type EscrowPaymentHeaderConfig,\n type SignTypedDataFn,\n type PaymentNonceSource,\n} from \"./direct/escrow-payment\";\nexport {\n getDirectEndpoints,\n PRODUCTION_ENDPOINTS,\n DEV_ENDPOINTS,\n} from \"./direct/endpoints\";\n// Grant scope entries: the `[operation:]scope` vocabulary the controller's\n// `scopes` are written in, so a backend can build and read them without\n// reaching for a platform entry point.\nexport {\n ScopeSchema,\n parseScope,\n scopeMatchesPattern,\n scopeCoveredByGrant,\n type Scope,\n type ParsedScope,\n} from \"./protocol/scopes\";\nexport {\n SCOPE_ACTIONS,\n InvalidScopeEntryError,\n parseScopeEntry,\n formatScopeEntry,\n grantPermissions,\n permissionsToScopes,\n tryGrantPermissions,\n hasAction,\n type ScopeAction,\n type ParsedScopeEntry,\n type GrantPermission,\n} from \"./protocol/scope-actions\";\n\n// Errors\nexport {\n DirectConfigError,\n AccessNotApprovedError,\n ScopeNotApprovedError,\n PersonalServerReadError,\n PaymentRequiredError,\n} from \"./direct/errors\";\n\n// Shared types\nexport type {\n DirectEnv,\n DirectNetwork,\n DirectAppConfig,\n ForegroundDelivery,\n AppIdentity,\n DirectServiceEndpoints,\n AccessRequest,\n AccessRequestQuestion,\n AccessRequestStatus,\n AccessRequestStatusValue,\n ApprovedDataResult,\n MultiScopeDataResult,\n AccessRequestClient,\n DirectOpTypeValue,\n PersonalServerDataAccessPaymentOperation,\n PersonalServerGrantPaymentOperation,\n PersonalServerPaymentOperation,\n PersonalServerPaymentRequired,\n DirectPaymentReceipt,\n DirectPaymentResponseMetadata,\n DirectFeeBreakdown,\n} from \"./direct/types\";\n\n// Op-type vocabulary constant.\nexport { DirectOpType } from \"./direct/types\";\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBA,wBAKO;AAGP,mCAMO;AACP,kCAUO;AAEP,4BAeO;AACP,uBAIO;AAIP,oBAOO;AACP,2BAYO;AAGP,oBAMO;AA4BP,mBAA6B;","names":[]}
|
package/dist/server.d.ts
CHANGED
|
@@ -23,12 +23,12 @@
|
|
|
23
23
|
* @module server
|
|
24
24
|
*/
|
|
25
25
|
export { createDirectDataController, type DirectDataController, type DirectDataControllerConfig, type DirectEscrowConfig, } from "./direct/controller.js";
|
|
26
|
-
export { createDefaultAccessRequestClient, buildApprovalUrl, type DefaultAccessRequestClientOptions, type FetchLike, } from "./direct/access-request-client.js";
|
|
26
|
+
export { createDefaultAccessRequestClient, buildApprovalUrl, validateAccessRequestQuestions, type DefaultAccessRequestClientOptions, type FetchLike, } from "./direct/access-request-client.js";
|
|
27
27
|
export { buildPersonalServerDataReadRequest, readPersonalServerData, parsePersonalServerPaymentRequired, dataPathForScope, type PersonalServerDataReadRequest, type PersonalServerReadResult, type PersonalServerFetch, type PersonalServerTransportRetryOptions, type FetchResponseLike, } from "./direct/personal-server-read.js";
|
|
28
28
|
export { authorizeEscrowPayment, authorizeGrantPayment, buildEscrowPaymentHeader, buildGrantPaymentHeader, paymentResponseMetadataFromHeader, toDirectPaymentReceipt, toDirectFeeBreakdown, createDefaultNonceSource, DATA_ACCESS_OP_TYPE, GRANT_OP_TYPE, type EscrowPaymentConfig, type EscrowPaymentHeaderConfig, type SignTypedDataFn, type PaymentNonceSource, } from "./direct/escrow-payment.js";
|
|
29
29
|
export { getDirectEndpoints, PRODUCTION_ENDPOINTS, DEV_ENDPOINTS, } from "./direct/endpoints.js";
|
|
30
30
|
export { ScopeSchema, parseScope, scopeMatchesPattern, scopeCoveredByGrant, type Scope, type ParsedScope, } from "./protocol/scopes.js";
|
|
31
31
|
export { SCOPE_ACTIONS, InvalidScopeEntryError, parseScopeEntry, formatScopeEntry, grantPermissions, permissionsToScopes, tryGrantPermissions, hasAction, type ScopeAction, type ParsedScopeEntry, type GrantPermission, } from "./protocol/scope-actions.js";
|
|
32
32
|
export { DirectConfigError, AccessNotApprovedError, ScopeNotApprovedError, PersonalServerReadError, PaymentRequiredError, } from "./direct/errors.js";
|
|
33
|
-
export type { DirectEnv, DirectNetwork, DirectAppConfig, ForegroundDelivery, AppIdentity, DirectServiceEndpoints, AccessRequest, AccessRequestStatus, AccessRequestStatusValue, ApprovedDataResult, MultiScopeDataResult, AccessRequestClient, DirectOpTypeValue, PersonalServerDataAccessPaymentOperation, PersonalServerGrantPaymentOperation, PersonalServerPaymentOperation, PersonalServerPaymentRequired, DirectPaymentReceipt, DirectPaymentResponseMetadata, DirectFeeBreakdown, } from "./direct/types.js";
|
|
33
|
+
export type { DirectEnv, DirectNetwork, DirectAppConfig, ForegroundDelivery, AppIdentity, DirectServiceEndpoints, AccessRequest, AccessRequestQuestion, AccessRequestStatus, AccessRequestStatusValue, ApprovedDataResult, MultiScopeDataResult, AccessRequestClient, DirectOpTypeValue, PersonalServerDataAccessPaymentOperation, PersonalServerGrantPaymentOperation, PersonalServerPaymentOperation, PersonalServerPaymentRequired, DirectPaymentReceipt, DirectPaymentResponseMetadata, DirectFeeBreakdown, } from "./direct/types.js";
|
|
34
34
|
export { DirectOpType } from "./direct/types.js";
|
package/dist/server.js
CHANGED
|
@@ -3,7 +3,8 @@ import {
|
|
|
3
3
|
} from "./direct/controller.js";
|
|
4
4
|
import {
|
|
5
5
|
createDefaultAccessRequestClient,
|
|
6
|
-
buildApprovalUrl
|
|
6
|
+
buildApprovalUrl,
|
|
7
|
+
validateAccessRequestQuestions
|
|
7
8
|
} from "./direct/access-request-client.js";
|
|
8
9
|
import {
|
|
9
10
|
buildPersonalServerDataReadRequest,
|
|
@@ -90,6 +91,7 @@ export {
|
|
|
90
91
|
scopeMatchesPattern,
|
|
91
92
|
toDirectFeeBreakdown,
|
|
92
93
|
toDirectPaymentReceipt,
|
|
93
|
-
tryGrantPermissions
|
|
94
|
+
tryGrantPermissions,
|
|
95
|
+
validateAccessRequestQuestions
|
|
94
96
|
};
|
|
95
97
|
//# sourceMappingURL=server.js.map
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\n * Server entry point for the Vana SDK direct Data Portability flow.\n *\n * @remarks\n * Exposes {@link createDirectDataController} and its supporting types/errors.\n * This is a Node/server entry point — it owns the app private key and must never\n * be imported into browser code.\n *\n * @example\n * ```typescript\n * import { createDirectDataController } from \"@opendatalabs/vana-sdk/server\";\n *\n * export const vana = createDirectDataController({\n * env: process.env.VANA_ENV === \"dev\" ? \"dev\" : \"production\",\n * appPrivateKey: process.env.VANA_APP_PRIVATE_KEY!,\n * app: { id: \"notes-lens\", name: \"Notes Lens\", homepageUrl: process.env.VANA_APP_URL! },\n * source: \"icloud_notes\",\n * scopes: [\"icloud_notes.notes\"],\n * });\n * ```\n *\n * @category Direct\n * @module server\n */\n\nexport {\n createDirectDataController,\n type DirectDataController,\n type DirectDataControllerConfig,\n type DirectEscrowConfig,\n} from \"./direct/controller\";\n\n// Lower-level building blocks (advanced use / custom transports).\nexport {\n createDefaultAccessRequestClient,\n buildApprovalUrl,\n type DefaultAccessRequestClientOptions,\n type FetchLike,\n} from \"./direct/access-request-client\";\nexport {\n buildPersonalServerDataReadRequest,\n readPersonalServerData,\n parsePersonalServerPaymentRequired,\n dataPathForScope,\n type PersonalServerDataReadRequest,\n type PersonalServerReadResult,\n type PersonalServerFetch,\n type PersonalServerTransportRetryOptions,\n type FetchResponseLike,\n} from \"./direct/personal-server-read\";\n// Escrow-backed payment (built on protocol/escrow).\nexport {\n authorizeEscrowPayment,\n authorizeGrantPayment,\n buildEscrowPaymentHeader,\n buildGrantPaymentHeader,\n paymentResponseMetadataFromHeader,\n toDirectPaymentReceipt,\n toDirectFeeBreakdown,\n createDefaultNonceSource,\n DATA_ACCESS_OP_TYPE,\n GRANT_OP_TYPE,\n type EscrowPaymentConfig,\n type EscrowPaymentHeaderConfig,\n type SignTypedDataFn,\n type PaymentNonceSource,\n} from \"./direct/escrow-payment\";\nexport {\n getDirectEndpoints,\n PRODUCTION_ENDPOINTS,\n DEV_ENDPOINTS,\n} from \"./direct/endpoints\";\n// Grant scope entries: the `[operation:]scope` vocabulary the controller's\n// `scopes` are written in, so a backend can build and read them without\n// reaching for a platform entry point.\nexport {\n ScopeSchema,\n parseScope,\n scopeMatchesPattern,\n scopeCoveredByGrant,\n type Scope,\n type ParsedScope,\n} from \"./protocol/scopes\";\nexport {\n SCOPE_ACTIONS,\n InvalidScopeEntryError,\n parseScopeEntry,\n formatScopeEntry,\n grantPermissions,\n permissionsToScopes,\n tryGrantPermissions,\n hasAction,\n type ScopeAction,\n type ParsedScopeEntry,\n type GrantPermission,\n} from \"./protocol/scope-actions\";\n\n// Errors\nexport {\n DirectConfigError,\n AccessNotApprovedError,\n ScopeNotApprovedError,\n PersonalServerReadError,\n PaymentRequiredError,\n} from \"./direct/errors\";\n\n// Shared types\nexport type {\n DirectEnv,\n DirectNetwork,\n DirectAppConfig,\n ForegroundDelivery,\n AppIdentity,\n DirectServiceEndpoints,\n AccessRequest,\n AccessRequestStatus,\n AccessRequestStatusValue,\n ApprovedDataResult,\n MultiScopeDataResult,\n AccessRequestClient,\n DirectOpTypeValue,\n PersonalServerDataAccessPaymentOperation,\n PersonalServerGrantPaymentOperation,\n PersonalServerPaymentOperation,\n PersonalServerPaymentRequired,\n DirectPaymentReceipt,\n DirectPaymentResponseMetadata,\n DirectFeeBreakdown,\n} from \"./direct/types\";\n\n// Op-type vocabulary constant.\nexport { DirectOpType } from \"./direct/types\";\n"],"mappings":"AAyBA;AAAA,EACE;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAMK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;
|
|
1
|
+
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\n * Server entry point for the Vana SDK direct Data Portability flow.\n *\n * @remarks\n * Exposes {@link createDirectDataController} and its supporting types/errors.\n * This is a Node/server entry point — it owns the app private key and must never\n * be imported into browser code.\n *\n * @example\n * ```typescript\n * import { createDirectDataController } from \"@opendatalabs/vana-sdk/server\";\n *\n * export const vana = createDirectDataController({\n * env: process.env.VANA_ENV === \"dev\" ? \"dev\" : \"production\",\n * appPrivateKey: process.env.VANA_APP_PRIVATE_KEY!,\n * app: { id: \"notes-lens\", name: \"Notes Lens\", homepageUrl: process.env.VANA_APP_URL! },\n * source: \"icloud_notes\",\n * scopes: [\"icloud_notes.notes\"],\n * });\n * ```\n *\n * @category Direct\n * @module server\n */\n\nexport {\n createDirectDataController,\n type DirectDataController,\n type DirectDataControllerConfig,\n type DirectEscrowConfig,\n} from \"./direct/controller\";\n\n// Lower-level building blocks (advanced use / custom transports).\nexport {\n createDefaultAccessRequestClient,\n buildApprovalUrl,\n validateAccessRequestQuestions,\n type DefaultAccessRequestClientOptions,\n type FetchLike,\n} from \"./direct/access-request-client\";\nexport {\n buildPersonalServerDataReadRequest,\n readPersonalServerData,\n parsePersonalServerPaymentRequired,\n dataPathForScope,\n type PersonalServerDataReadRequest,\n type PersonalServerReadResult,\n type PersonalServerFetch,\n type PersonalServerTransportRetryOptions,\n type FetchResponseLike,\n} from \"./direct/personal-server-read\";\n// Escrow-backed payment (built on protocol/escrow).\nexport {\n authorizeEscrowPayment,\n authorizeGrantPayment,\n buildEscrowPaymentHeader,\n buildGrantPaymentHeader,\n paymentResponseMetadataFromHeader,\n toDirectPaymentReceipt,\n toDirectFeeBreakdown,\n createDefaultNonceSource,\n DATA_ACCESS_OP_TYPE,\n GRANT_OP_TYPE,\n type EscrowPaymentConfig,\n type EscrowPaymentHeaderConfig,\n type SignTypedDataFn,\n type PaymentNonceSource,\n} from \"./direct/escrow-payment\";\nexport {\n getDirectEndpoints,\n PRODUCTION_ENDPOINTS,\n DEV_ENDPOINTS,\n} from \"./direct/endpoints\";\n// Grant scope entries: the `[operation:]scope` vocabulary the controller's\n// `scopes` are written in, so a backend can build and read them without\n// reaching for a platform entry point.\nexport {\n ScopeSchema,\n parseScope,\n scopeMatchesPattern,\n scopeCoveredByGrant,\n type Scope,\n type ParsedScope,\n} from \"./protocol/scopes\";\nexport {\n SCOPE_ACTIONS,\n InvalidScopeEntryError,\n parseScopeEntry,\n formatScopeEntry,\n grantPermissions,\n permissionsToScopes,\n tryGrantPermissions,\n hasAction,\n type ScopeAction,\n type ParsedScopeEntry,\n type GrantPermission,\n} from \"./protocol/scope-actions\";\n\n// Errors\nexport {\n DirectConfigError,\n AccessNotApprovedError,\n ScopeNotApprovedError,\n PersonalServerReadError,\n PaymentRequiredError,\n} from \"./direct/errors\";\n\n// Shared types\nexport type {\n DirectEnv,\n DirectNetwork,\n DirectAppConfig,\n ForegroundDelivery,\n AppIdentity,\n DirectServiceEndpoints,\n AccessRequest,\n AccessRequestQuestion,\n AccessRequestStatus,\n AccessRequestStatusValue,\n ApprovedDataResult,\n MultiScopeDataResult,\n AccessRequestClient,\n DirectOpTypeValue,\n PersonalServerDataAccessPaymentOperation,\n PersonalServerGrantPaymentOperation,\n PersonalServerPaymentOperation,\n PersonalServerPaymentRequired,\n DirectPaymentReceipt,\n DirectPaymentResponseMetadata,\n DirectFeeBreakdown,\n} from \"./direct/types\";\n\n// Op-type vocabulary constant.\nexport { DirectOpType } from \"./direct/types\";\n"],"mappings":"AAyBA;AAAA,EACE;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAMK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AA4BP,SAAS,oBAAoB;","names":[]}
|
|
@@ -84,6 +84,13 @@ export interface MockQuestion {
|
|
|
84
84
|
};
|
|
85
85
|
status: "pending" | "ready" | "failed" | "stale";
|
|
86
86
|
error: string | null;
|
|
87
|
+
/** The coarse failure class the status route serves; null unless failed. */
|
|
88
|
+
errorCode: "inference_unavailable" | "source_missing" | "grant_invalid" | "internal" | null;
|
|
89
|
+
/**
|
|
90
|
+
* What the status route reports as the next automatic retry. The mock has
|
|
91
|
+
* no scheduler, so a test sets it through `settleQuestion`.
|
|
92
|
+
*/
|
|
93
|
+
retryAfterSeconds: number | null;
|
|
87
94
|
createdAt: string;
|
|
88
95
|
updatedAt: string;
|
|
89
96
|
lastComputedAt: string | null;
|
|
@@ -126,6 +133,8 @@ export interface MockPersonalServer {
|
|
|
126
133
|
} | {
|
|
127
134
|
status: "failed";
|
|
128
135
|
error: string;
|
|
136
|
+
errorCode?: MockQuestion["errorCode"];
|
|
137
|
+
retryAfterSeconds?: number | null;
|
|
129
138
|
} | {
|
|
130
139
|
status: "stale" | "pending";
|
|
131
140
|
}): void;
|