@xkova/sdk 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +453 -0
- package/dist/abi.d.ts +10288 -0
- package/dist/abi.js +6645 -0
- package/dist/client.d.ts +80 -0
- package/dist/client.js +251 -0
- package/dist/cursor.d.ts +21 -0
- package/dist/cursor.js +28 -0
- package/dist/errors.d.ts +31 -0
- package/dist/errors.js +63 -0
- package/dist/generated/types.d.ts +13371 -0
- package/dist/generated/types.js +3 -0
- package/dist/idempotency.d.ts +25 -0
- package/dist/idempotency.js +46 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +8 -0
- package/dist/member-action-intents.d.ts +72 -0
- package/dist/member-action-intents.js +181 -0
- package/dist/member-bff.d.ts +535 -0
- package/dist/member-bff.js +1594 -0
- package/dist/member-resources.d.ts +203 -0
- package/dist/member-resources.js +56 -0
- package/dist/request-signing.d.ts +23 -0
- package/dist/request-signing.js +112 -0
- package/dist/resources/account-holders.d.ts +295 -0
- package/dist/resources/account-holders.js +166 -0
- package/dist/resources/base.d.ts +47 -0
- package/dist/resources/base.js +25 -0
- package/dist/resources/branding.d.ts +154 -0
- package/dist/resources/branding.js +34 -0
- package/dist/resources/chains.d.ts +6 -0
- package/dist/resources/chains.js +6 -0
- package/dist/resources/contacts.d.ts +55 -0
- package/dist/resources/contacts.js +22 -0
- package/dist/resources/escrows.d.ts +45 -0
- package/dist/resources/escrows.js +18 -0
- package/dist/resources/fee-schedules.d.ts +40 -0
- package/dist/resources/fee-schedules.js +15 -0
- package/dist/resources/index.d.ts +21 -0
- package/dist/resources/index.js +21 -0
- package/dist/resources/integration-gateways.d.ts +114 -0
- package/dist/resources/integration-gateways.js +27 -0
- package/dist/resources/onboarding.d.ts +18 -0
- package/dist/resources/onboarding.js +9 -0
- package/dist/resources/payment-requests.d.ts +115 -0
- package/dist/resources/payment-requests.js +27 -0
- package/dist/resources/payments.d.ts +182 -0
- package/dist/resources/payments.js +33 -0
- package/dist/resources/ramps.d.ts +163 -0
- package/dist/resources/ramps.js +44 -0
- package/dist/resources/rwa.d.ts +397 -0
- package/dist/resources/rwa.js +150 -0
- package/dist/resources/tenant.d.ts +136 -0
- package/dist/resources/tenant.js +42 -0
- package/dist/resources/tokenization.d.ts +394 -0
- package/dist/resources/tokenization.js +126 -0
- package/dist/resources/transactions.d.ts +8 -0
- package/dist/resources/transactions.js +6 -0
- package/dist/resources/wallets.d.ts +56 -0
- package/dist/resources/wallets.js +21 -0
- package/dist/resources/webhooks.d.ts +115 -0
- package/dist/resources/webhooks.js +43 -0
- package/dist/resources/workflows.d.ts +44 -0
- package/dist/resources/workflows.js +70 -0
- package/dist/resources/workspace-tokens.d.ts +6 -0
- package/dist/resources/workspace-tokens.js +6 -0
- package/dist/resources/workspaces.d.ts +25 -0
- package/dist/resources/workspaces.js +12 -0
- package/dist/retry.d.ts +21 -0
- package/dist/retry.js +44 -0
- package/dist/rwa-verify.d.ts +50 -0
- package/dist/rwa-verify.js +159 -0
- package/dist/webhook.d.ts +24 -0
- package/dist/webhook.js +56 -0
- package/llms.txt +84 -0
- package/package.json +62 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface VerifyInclusionInput {
|
|
2
|
+
/** Raw leaf data as hex: the metadata version's `chain_leaf`. */
|
|
3
|
+
readonly leafData: string;
|
|
4
|
+
/** 0-based index of the leaf in the tree (its `version_seq`). */
|
|
5
|
+
readonly leafIndex: number;
|
|
6
|
+
/** Number of leaves in the tree the STH committed to (`tree_size`). */
|
|
7
|
+
readonly treeSize: number;
|
|
8
|
+
/** Audit path, leaf→root, as hex node hashes. */
|
|
9
|
+
readonly proof: readonly string[];
|
|
10
|
+
/** The signed tree head's `root_hash` (hex). */
|
|
11
|
+
readonly root: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Checks the leaf and audit path against the root using RFC 6962 section 2.1.1.
|
|
15
|
+
* This does not authenticate the root; verify its signed tree head separately.
|
|
16
|
+
*/
|
|
17
|
+
export declare function verifyInclusion(input: VerifyInclusionInput): boolean;
|
|
18
|
+
export interface VerifyConsistencyInput {
|
|
19
|
+
/** Size of the earlier tree (the earlier STH's `tree_size`). */
|
|
20
|
+
readonly first: number;
|
|
21
|
+
/** Size of the later tree (the later STH's `tree_size`). */
|
|
22
|
+
readonly second: number;
|
|
23
|
+
/** Consistency proof, hex node hashes. */
|
|
24
|
+
readonly proof: readonly string[];
|
|
25
|
+
/** The earlier STH's `root_hash` (hex). */
|
|
26
|
+
readonly firstRoot: string;
|
|
27
|
+
/** The later STH's `root_hash` (hex). */
|
|
28
|
+
readonly secondRoot: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Checks that the earlier tree is a prefix of the later tree using RFC 6962
|
|
32
|
+
* section 2.1.2. Retain an earlier trusted tree head to detect rewritten history.
|
|
33
|
+
*/
|
|
34
|
+
export declare function verifyConsistency(input: VerifyConsistencyInput): boolean;
|
|
35
|
+
export interface VerifyTreeHeadInput {
|
|
36
|
+
readonly treeSize: number;
|
|
37
|
+
/** The STH root hash (hex, 0x-prefixed 32 bytes). */
|
|
38
|
+
readonly rootHash: string;
|
|
39
|
+
readonly timestampMs: number;
|
|
40
|
+
readonly chainId: number;
|
|
41
|
+
/** The STH signature (hex). */
|
|
42
|
+
readonly signature: string;
|
|
43
|
+
/** The address the signature is expected to recover to (the trusted signer). */
|
|
44
|
+
readonly expectedSigner: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Checks the EIP-712 signature against `expectedSigner`. Obtain that address
|
|
48
|
+
* from a trusted source, not from the proof being verified.
|
|
49
|
+
*/
|
|
50
|
+
export declare function verifySth(input: VerifyTreeHeadInput): Promise<boolean>;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify RWA transparency proofs offline. Inclusion checks a metadata version
|
|
3
|
+
* against a tree head; consistency checks that a later tree only appended data.
|
|
4
|
+
* Verify the tree head's signature separately against a trusted signer address.
|
|
5
|
+
*
|
|
6
|
+
* RFC 6962 domain separation: leaf = SHA-256(0x00 || data),
|
|
7
|
+
* node = SHA-256(0x01 || left || right).
|
|
8
|
+
*/
|
|
9
|
+
import { createHash } from 'node:crypto';
|
|
10
|
+
import { hashTypedData, recoverAddress } from 'viem';
|
|
11
|
+
const LEAF_PREFIX = Buffer.from([0x00]);
|
|
12
|
+
const NODE_PREFIX = Buffer.from([0x01]);
|
|
13
|
+
function hashLeaf(data) {
|
|
14
|
+
return createHash('sha256').update(LEAF_PREFIX).update(data).digest();
|
|
15
|
+
}
|
|
16
|
+
function hashNode(left, right) {
|
|
17
|
+
return createHash('sha256').update(NODE_PREFIX).update(left).update(right).digest();
|
|
18
|
+
}
|
|
19
|
+
function fromHex(h, expectedBytes) {
|
|
20
|
+
const raw = h.startsWith('0x') ? h.slice(2) : h;
|
|
21
|
+
if (!/^(?:[0-9a-fA-F]{2})*$/.test(raw)) {
|
|
22
|
+
throw new Error('invalid hex');
|
|
23
|
+
}
|
|
24
|
+
const value = Buffer.from(raw, 'hex');
|
|
25
|
+
if (expectedBytes !== undefined && value.length !== expectedBytes) {
|
|
26
|
+
throw new Error(`expected ${expectedBytes} bytes`);
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Checks the leaf and audit path against the root using RFC 6962 section 2.1.1.
|
|
32
|
+
* This does not authenticate the root; verify its signed tree head separately.
|
|
33
|
+
*/
|
|
34
|
+
export function verifyInclusion(input) {
|
|
35
|
+
const { leafIndex, treeSize } = input;
|
|
36
|
+
if (!Number.isInteger(leafIndex) || !Number.isInteger(treeSize))
|
|
37
|
+
return false;
|
|
38
|
+
if (leafIndex < 0 || leafIndex >= treeSize)
|
|
39
|
+
return false;
|
|
40
|
+
try {
|
|
41
|
+
let fn = leafIndex;
|
|
42
|
+
let sn = treeSize - 1;
|
|
43
|
+
let r = hashLeaf(fromHex(input.leafData));
|
|
44
|
+
for (const pHex of input.proof) {
|
|
45
|
+
if (sn === 0)
|
|
46
|
+
return false;
|
|
47
|
+
const p = fromHex(pHex, 32);
|
|
48
|
+
if ((fn & 1) === 1 || fn === sn) {
|
|
49
|
+
r = hashNode(p, r);
|
|
50
|
+
if ((fn & 1) === 0) {
|
|
51
|
+
do {
|
|
52
|
+
fn >>= 1;
|
|
53
|
+
sn >>= 1;
|
|
54
|
+
} while ((fn & 1) === 0 && fn !== 0);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
r = hashNode(r, p);
|
|
59
|
+
}
|
|
60
|
+
fn >>= 1;
|
|
61
|
+
sn >>= 1;
|
|
62
|
+
}
|
|
63
|
+
return sn === 0 && r.equals(fromHex(input.root, 32));
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Checks that the earlier tree is a prefix of the later tree using RFC 6962
|
|
71
|
+
* section 2.1.2. Retain an earlier trusted tree head to detect rewritten history.
|
|
72
|
+
*/
|
|
73
|
+
export function verifyConsistency(input) {
|
|
74
|
+
const { first, second } = input;
|
|
75
|
+
if (!Number.isInteger(first) || !Number.isInteger(second))
|
|
76
|
+
return false;
|
|
77
|
+
if (first < 1 || first > second)
|
|
78
|
+
return false;
|
|
79
|
+
try {
|
|
80
|
+
const firstRoot = fromHex(input.firstRoot, 32);
|
|
81
|
+
const secondRoot = fromHex(input.secondRoot, 32);
|
|
82
|
+
if (first === second)
|
|
83
|
+
return input.proof.length === 0 && firstRoot.equals(secondRoot);
|
|
84
|
+
const isPow2 = (first & (first - 1)) === 0;
|
|
85
|
+
const proof = (isPow2 ? [input.firstRoot, ...input.proof] : input.proof).map((hex) => fromHex(hex, 32));
|
|
86
|
+
if (proof.length === 0)
|
|
87
|
+
return false;
|
|
88
|
+
let fn = first - 1;
|
|
89
|
+
let sn = second - 1;
|
|
90
|
+
while ((fn & 1) === 1) {
|
|
91
|
+
fn >>= 1;
|
|
92
|
+
sn >>= 1;
|
|
93
|
+
}
|
|
94
|
+
let fr = proof[0];
|
|
95
|
+
let sr = proof[0];
|
|
96
|
+
for (let i = 1; i < proof.length; i++) {
|
|
97
|
+
const c = proof[i];
|
|
98
|
+
if (sn === 0)
|
|
99
|
+
return false;
|
|
100
|
+
if ((fn & 1) === 1 || fn === sn) {
|
|
101
|
+
fr = hashNode(c, fr);
|
|
102
|
+
sr = hashNode(c, sr);
|
|
103
|
+
if ((fn & 1) === 0) {
|
|
104
|
+
do {
|
|
105
|
+
fn >>= 1;
|
|
106
|
+
sn >>= 1;
|
|
107
|
+
} while ((fn & 1) === 0 && fn !== 0);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
sr = hashNode(sr, c);
|
|
112
|
+
}
|
|
113
|
+
fn >>= 1;
|
|
114
|
+
sn >>= 1;
|
|
115
|
+
}
|
|
116
|
+
return sn === 0 && fr.equals(firstRoot) && sr.equals(secondRoot);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const TREE_HEAD_TYPES = {
|
|
123
|
+
TreeHead: [
|
|
124
|
+
{ name: 'treeSize', type: 'uint256' },
|
|
125
|
+
{ name: 'rootHash', type: 'bytes32' },
|
|
126
|
+
{ name: 'timestampMs', type: 'uint256' },
|
|
127
|
+
],
|
|
128
|
+
};
|
|
129
|
+
const TRANSPARENCY_LOG_VERIFYING_CONTRACT = '0x0000000000000000000000000000000000000000';
|
|
130
|
+
/**
|
|
131
|
+
* Checks the EIP-712 signature against `expectedSigner`. Obtain that address
|
|
132
|
+
* from a trusted source, not from the proof being verified.
|
|
133
|
+
*/
|
|
134
|
+
export async function verifySth(input) {
|
|
135
|
+
try {
|
|
136
|
+
const root = input.rootHash.startsWith('0x') ? input.rootHash : `0x${input.rootHash}`;
|
|
137
|
+
const sig = input.signature.startsWith('0x') ? input.signature : `0x${input.signature}`;
|
|
138
|
+
const digest = hashTypedData({
|
|
139
|
+
domain: {
|
|
140
|
+
name: 'XKOVA TransparencyLog',
|
|
141
|
+
version: '1',
|
|
142
|
+
chainId: input.chainId,
|
|
143
|
+
verifyingContract: TRANSPARENCY_LOG_VERIFYING_CONTRACT,
|
|
144
|
+
},
|
|
145
|
+
types: TREE_HEAD_TYPES,
|
|
146
|
+
primaryType: 'TreeHead',
|
|
147
|
+
message: {
|
|
148
|
+
treeSize: BigInt(input.treeSize),
|
|
149
|
+
rootHash: root,
|
|
150
|
+
timestampMs: BigInt(input.timestampMs),
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
const recovered = await recoverAddress({ hash: digest, signature: sig });
|
|
154
|
+
return recovered.toLowerCase() === input.expectedSigner.toLowerCase();
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify the raw body before parsing it; reserializing JSON changes the bytes
|
|
3
|
+
* covered by the signature. The header is `t=<unix_ts>,v1=<hex_hmac_sha256>`.
|
|
4
|
+
* HMAC-SHA256 covers `<t>.<rawBody>`. The default timestamp tolerance is five
|
|
5
|
+
* minutes in either direction.
|
|
6
|
+
*/
|
|
7
|
+
export type VerifyWebhookSignatureResult = {
|
|
8
|
+
valid: true;
|
|
9
|
+
} | {
|
|
10
|
+
valid: false;
|
|
11
|
+
reason: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function verifyWebhookSignature(opts: {
|
|
14
|
+
/** The raw request body as XKOVA sent it. Byte-for-byte sensitive. */
|
|
15
|
+
rawBody: string;
|
|
16
|
+
/** Value of the `XKOVA-Webhook-Signature` request header. */
|
|
17
|
+
header: string;
|
|
18
|
+
/** Endpoint secret; rotate via /v1/webhook-endpoints/{id}/rotate. */
|
|
19
|
+
secret: string;
|
|
20
|
+
/** Override clock for tests; defaults to Date.now(). */
|
|
21
|
+
now?: () => number;
|
|
22
|
+
/** Override tolerance window; default 300s. */
|
|
23
|
+
toleranceSec?: number;
|
|
24
|
+
}): VerifyWebhookSignatureResult;
|
package/dist/webhook.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify the raw body before parsing it; reserializing JSON changes the bytes
|
|
3
|
+
* covered by the signature. The header is `t=<unix_ts>,v1=<hex_hmac_sha256>`.
|
|
4
|
+
* HMAC-SHA256 covers `<t>.<rawBody>`. The default timestamp tolerance is five
|
|
5
|
+
* minutes in either direction.
|
|
6
|
+
*/
|
|
7
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
8
|
+
const REPLAY_WINDOW_SEC = 300;
|
|
9
|
+
export function verifyWebhookSignature(opts) {
|
|
10
|
+
const parsed = parseHeader(opts.header);
|
|
11
|
+
if (!parsed)
|
|
12
|
+
return { valid: false, reason: 'malformed_header' };
|
|
13
|
+
const tolerance = opts.toleranceSec ?? REPLAY_WINDOW_SEC;
|
|
14
|
+
const nowSec = Math.floor((opts.now?.() ?? Date.now()) / 1000);
|
|
15
|
+
if (Math.abs(nowSec - parsed.timestampSec) > tolerance) {
|
|
16
|
+
return { valid: false, reason: 'timestamp_outside_tolerance' };
|
|
17
|
+
}
|
|
18
|
+
const expectedHex = createHmac('sha256', opts.secret)
|
|
19
|
+
.update(`${parsed.timestampSec}.${opts.rawBody}`)
|
|
20
|
+
.digest('hex');
|
|
21
|
+
const expected = Buffer.from(expectedHex, 'hex');
|
|
22
|
+
for (const v1 of parsed.v1Hexes) {
|
|
23
|
+
const candidate = Buffer.from(v1, 'hex');
|
|
24
|
+
if (candidate.length !== expected.length)
|
|
25
|
+
continue;
|
|
26
|
+
if (timingSafeEqual(candidate, expected))
|
|
27
|
+
return { valid: true };
|
|
28
|
+
}
|
|
29
|
+
return { valid: false, reason: 'no_signature_match' };
|
|
30
|
+
}
|
|
31
|
+
function parseHeader(header) {
|
|
32
|
+
const parts = header.split(',').map((s) => s.trim());
|
|
33
|
+
let t = null;
|
|
34
|
+
const v1s = [];
|
|
35
|
+
for (const p of parts) {
|
|
36
|
+
const eq = p.indexOf('=');
|
|
37
|
+
if (eq < 0)
|
|
38
|
+
return null;
|
|
39
|
+
const key = p.slice(0, eq);
|
|
40
|
+
const val = p.slice(eq + 1);
|
|
41
|
+
if (key === 't') {
|
|
42
|
+
const n = Number.parseInt(val, 10);
|
|
43
|
+
if (!Number.isFinite(n) || n <= 0)
|
|
44
|
+
return null;
|
|
45
|
+
t = n;
|
|
46
|
+
}
|
|
47
|
+
else if (key === 'v1') {
|
|
48
|
+
if (!/^[0-9a-f]+$/.test(val))
|
|
49
|
+
return null;
|
|
50
|
+
v1s.push(val);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (t === null || v1s.length === 0)
|
|
54
|
+
return null;
|
|
55
|
+
return { timestampSec: t, v1Hexes: v1s };
|
|
56
|
+
}
|
package/llms.txt
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Build with @xkova/sdk
|
|
2
|
+
|
|
3
|
+
Use this package on a Node.js 22+ server. Read the installed declarations before writing code: live documentation may describe a newer release. Use @xkova/browser for browser calls to your own same-origin backend for frontend (BFF).
|
|
4
|
+
|
|
5
|
+
## Read first
|
|
6
|
+
|
|
7
|
+
- [Package guide](README.md): installation, production signing, Hosted Auth, member sessions, durable stores, cancellation, errors, webhooks, and proof verification.
|
|
8
|
+
- [Client declarations](dist/client.d.ts): exact resource properties and client options for this installed release.
|
|
9
|
+
- [Customer API types](dist/generated/types.d.ts): exact request bodies, responses, parameters, and operation IDs. Import types through @xkova/sdk/types.
|
|
10
|
+
- [Member BFF declarations](dist/member-bff.d.ts): authorization, session persistence, refresh, logout, action reviews, and human authorization.
|
|
11
|
+
- [Member resources](dist/member-resources.d.ts): typed resources bound to the exact authenticated member.
|
|
12
|
+
- [Quickstart](https://docs.xkova.com/getting-started.html): sandbox access and first authenticated call.
|
|
13
|
+
- [Customer OpenAPI](https://docs.xkova.com/data/openapi-customer.json): machine-readable customer contract for the current published documentation.
|
|
14
|
+
- [SDK guide](https://docs.xkova.com/sdk-overview.html): client and resource examples.
|
|
15
|
+
- [Workflow guide](https://docs.xkova.com/sdk-workflows.html): supported workflow helpers.
|
|
16
|
+
- [Member integration](https://docs.xkova.com/embedded-member.html): browser, BFF, identity, and signing boundaries.
|
|
17
|
+
- [Documentation index](https://docs.xkova.com/llms.txt): current public feature guides.
|
|
18
|
+
- [Full documentation](https://docs.xkova.com/llms-full.txt): expanded public guidance. Console concepts do not imply SDK methods.
|
|
19
|
+
|
|
20
|
+
## Choose a client
|
|
21
|
+
|
|
22
|
+
1. Server business integration: create XKOVAClient.forTenant({ baseUrl, apiKey }). Use https://sandbox-api.xkova.com for sandbox and https://api.xkova.com for production. The API key binds the workspace and mode.
|
|
23
|
+
2. Member application: use XKOVAMemberBffClient from @xkova/sdk/member-bff in your BFF. Resolve confidential sessions to request-scoped resources with resolveResources(). The browser sends only its application cookie and CSRF proof to your BFF.
|
|
24
|
+
3. Browser companion: optionally install @xkova/browser. It calls your same-origin routes; it does not create those routes or install a session store.
|
|
25
|
+
4. Institution staff and management: use the Console and its documented setup flows. Do not invent customer SDK methods for API-key lifecycle, treasury administration, staff governance, or platform management.
|
|
26
|
+
|
|
27
|
+
## Find a capability
|
|
28
|
+
|
|
29
|
+
Each namespace below is a property of XKOVAClient. Read its declaration under dist/resources/ for exact methods and parameters.
|
|
30
|
+
|
|
31
|
+
| Need | Namespace or entry point |
|
|
32
|
+
| --- | --- |
|
|
33
|
+
| Discover supported networks and usable assets | chains, workspaceTokens, workspaces |
|
|
34
|
+
| Account holders, consent, profile, avatar, balances, verification, history | accountHolders; resolveResources().self for a member |
|
|
35
|
+
| Wallets and coordinated provisioning | wallets; resolveResources().self for a member |
|
|
36
|
+
| Contacts and recipients | contacts |
|
|
37
|
+
| Quotes, payments, status, cancellation | payments |
|
|
38
|
+
| Escrow creation, status, events, cancellation initialization | escrows |
|
|
39
|
+
| Funding and payment requests | paymentRequests |
|
|
40
|
+
| Deposits, conversion, withdrawals, off-ramp status | ramps |
|
|
41
|
+
| Transaction history | transactions |
|
|
42
|
+
| Fee schedules and platform fees | feeSchedules |
|
|
43
|
+
| Customer tokens, deployment, minting, supply, access | tokenization |
|
|
44
|
+
| Real-world assets, cap tables, distributions, corporate actions, provenance | rwa |
|
|
45
|
+
| Gateway registration and conformance | integrationGateways |
|
|
46
|
+
| Branding and sending-domain configuration | branding |
|
|
47
|
+
| Tenant reads, Hosted application registration, exact origins and callbacks | tenant |
|
|
48
|
+
| Setup progress | onboarding |
|
|
49
|
+
| Webhook subscriptions and delivery operations | webhooks |
|
|
50
|
+
| Token deployment/mint polling and off-ramp initiation | workflows |
|
|
51
|
+
| Session exchange, durable review recovery, fresh human authorization | @xkova/sdk/member-bff |
|
|
52
|
+
| Verify webhook signatures over raw body bytes | @xkova/sdk/webhook |
|
|
53
|
+
| Offline RWA transparency proofs | @xkova/sdk/rwa-verify |
|
|
54
|
+
| Customer contract ABIs | @xkova/sdk/abi |
|
|
55
|
+
|
|
56
|
+
API availability does not grant permission. Product entitlement, selected API-key scopes and roles, account eligibility, configured policies, and required human approval still apply. Production outbound operations require explicit institution policy setup. Discover chains and assets; never silently pick the first or assume a default network.
|
|
57
|
+
|
|
58
|
+
## Requests and results
|
|
59
|
+
|
|
60
|
+
- Start with the README's sandbox read example. Validate required environment variables on the server; never emit their values into logs, generated files, browser bundles, or prompts.
|
|
61
|
+
- Use exported package entry points and typed resource methods. Do not import dist files as runtime subpaths, use private endpoints, fabricate request fields, or suppress type errors with any.
|
|
62
|
+
- Production writes require the bearer key plus an active asymmetric requestSigner credential. Its async callback signs through your key provider. The SDK supplies RFC 9421 signatures and RFC 9530 digests. Production reads use bearer authentication.
|
|
63
|
+
- Generate one idempotency key before a logical mutation and persist it. Reuse it only with the identical request. The SDK does not automatically retry writes. A timeout or disconnect can leave the outcome unknown; reconcile the existing resource before starting another operation.
|
|
64
|
+
- Use decimal strings for monetary values according to the request type. Preserve asset and chain identity throughout a flow. Do not perform monetary calculations with JavaScript floating-point numbers.
|
|
65
|
+
- Read pagination and response types. Use paginateCursor or collectCursor where applicable; bound collection sizes and polling. Propagate AbortSignal and request deadlines.
|
|
66
|
+
- Handle XKOVAApiError with its code, status, correlationId, and retryAfter. Handle XKOVAUploadError for the object-storage stage. Do not expose transport headers, provider proofs, or signed URLs in user errors or logs.
|
|
67
|
+
- For webhooks, verify the signature against the exact raw body before parsing or acting. Deduplicate event processing and reconcile authoritative resource status. An accepted request, signing result, or 202 response is not settled money.
|
|
68
|
+
|
|
69
|
+
## Member applications
|
|
70
|
+
|
|
71
|
+
- Keep the API key, provider proof, XKOVA member session, and refresh credentials server-side. Never accept a caller-selected acting account holder or browser-provided member authority.
|
|
72
|
+
- Register exact application origins and callbacks. Enforce the browser Origin and a session-bound CSRF proof for mutations. Durable cookies are host-only, Secure, HttpOnly, Path=/, and SameSite=Strict. A short-lived SameSite=Lax transaction cookie is only for cross-site authorization callbacks.
|
|
73
|
+
- Implement durable session and authorization transaction stores from the exported contracts. Serialize refresh/logout across BFF replicas and encrypt sensitive records at rest. An in-memory demonstration is not a production store.
|
|
74
|
+
- Hosted Auth is optional. Your registered identity provider determines proof verification and fresh human authorization. Do not silently switch providers or substitute Hosted login for a customer's configured identity flow.
|
|
75
|
+
- Reuse one createMemberActionReference() from @xkova/browser for a durable review. Save the draft before setup detours. Expired or missing reviews require checking activity and an explicit new review.
|
|
76
|
+
- Setup readiness is advisory. beginMemberAction() and completeMemberAction() obtain fresh approval for the exact resource. Browser code must not receive provider wallet credentials or internal signing capabilities. Completion of authorization is distinct from execution and settlement.
|
|
77
|
+
|
|
78
|
+
## Dependencies
|
|
79
|
+
|
|
80
|
+
The server SDK uses viem for offline RWA signature verification. The browser companion has no runtime dependencies. Neither imports Thirdweb. You may see Thirdweb in API provider metadata, but these integrations require no Thirdweb SDK or credentials.
|
|
81
|
+
|
|
82
|
+
## Before handing off code
|
|
83
|
+
|
|
84
|
+
List the Console setup and stores the application needs. Test denied access, uncertain writes, pagination, cancellation, and terminal outcomes. Report a missing method or setup requirement explicitly. Do not invent methods, suppress type errors, or bypass authorization to make an example run.
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xkova/sdk",
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
|
+
"description": "Server-side TypeScript client for the XKOVA customer API, with customer-only generated types and production request signing.",
|
|
5
|
+
"homepage": "https://docs.xkova.com",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/XKOVA/typescript-sdk.git",
|
|
9
|
+
"directory": "packages/sdk"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/XKOVA/typescript-sdk/issues"
|
|
13
|
+
},
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./types": {
|
|
23
|
+
"types": "./dist/generated/types.d.ts",
|
|
24
|
+
"default": "./dist/generated/types.js"
|
|
25
|
+
},
|
|
26
|
+
"./errors": {
|
|
27
|
+
"types": "./dist/errors.d.ts",
|
|
28
|
+
"default": "./dist/errors.js"
|
|
29
|
+
},
|
|
30
|
+
"./member-bff": {
|
|
31
|
+
"types": "./dist/member-bff.d.ts",
|
|
32
|
+
"default": "./dist/member-bff.js"
|
|
33
|
+
},
|
|
34
|
+
"./webhook": {
|
|
35
|
+
"types": "./dist/webhook.d.ts",
|
|
36
|
+
"default": "./dist/webhook.js"
|
|
37
|
+
},
|
|
38
|
+
"./rwa-verify": {
|
|
39
|
+
"types": "./dist/rwa-verify.d.ts",
|
|
40
|
+
"default": "./dist/rwa-verify.js"
|
|
41
|
+
},
|
|
42
|
+
"./abi": {
|
|
43
|
+
"types": "./dist/abi.d.ts",
|
|
44
|
+
"default": "./dist/abi.js"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"dist",
|
|
49
|
+
"llms.txt"
|
|
50
|
+
],
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"viem": "^2.21.0"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=22.0.0"
|
|
56
|
+
},
|
|
57
|
+
"license": "Apache-2.0",
|
|
58
|
+
"publishConfig": {
|
|
59
|
+
"access": "public",
|
|
60
|
+
"tag": "alpha"
|
|
61
|
+
}
|
|
62
|
+
}
|