kstablepay-rail-sdk 0.1.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 +76 -0
- package/dist/client.d.ts +15 -0
- package/dist/client.js +91 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +12 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/types.d.ts +171 -0
- package/dist/types.js +1 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# kstablepay-rail-sdk
|
|
2
|
+
|
|
3
|
+
Node.js SDK for K-STable Pay onchain rail APIs.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i kstablepay-rail-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { createKstChainClient } from "kstablepay-rail-sdk";
|
|
15
|
+
|
|
16
|
+
const kstchain = createKstChainClient({
|
|
17
|
+
baseUrl: process.env.PAY_API_BASE_URL!,
|
|
18
|
+
walletSecretKey: process.env.WALLET_SECRET_KEY!,
|
|
19
|
+
walletAccessKey: process.env.WALLET_ACCESS_KEY, // optional
|
|
20
|
+
timeoutMs: 10000,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const issued = await kstchain.signPayload({
|
|
24
|
+
orderId: "ord_20260321_0001",
|
|
25
|
+
merchantKey: "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
26
|
+
payerAddress: "0xC8313324B6C16Cec8F410ebfE1b22Ff4f5d2DDC8",
|
|
27
|
+
currency: "KST",
|
|
28
|
+
amount: "1000000",
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const latest = await kstchain.getSignPayload(issued.paymentKey);
|
|
32
|
+
|
|
33
|
+
const authorized = await kstchain.authorize({
|
|
34
|
+
paymentKey: issued.paymentKey,
|
|
35
|
+
signature: "0x...",
|
|
36
|
+
payloadHash: latest.payloadHash,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const command = await kstchain.getCommand(authorized.commandId);
|
|
40
|
+
console.log(command.status);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## API
|
|
44
|
+
|
|
45
|
+
- `health()`
|
|
46
|
+
- `ready()`
|
|
47
|
+
- `signPayload(req, opts?)`
|
|
48
|
+
- `getSignPayload(paymentKey, opts?)`
|
|
49
|
+
- `authorize(req, opts?)`
|
|
50
|
+
- `capture(req, opts?)`
|
|
51
|
+
- `void(req, opts?)`
|
|
52
|
+
- `refund(req, opts?)`
|
|
53
|
+
- `settle(req, opts?)`
|
|
54
|
+
- `getCommand(commandId, opts?)`
|
|
55
|
+
- `confirm(req, opts?)`
|
|
56
|
+
|
|
57
|
+
## Error handling
|
|
58
|
+
|
|
59
|
+
SDK throws `KstApiError` for non-2xx or error envelope responses.
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { KstApiError } from "kstablepay-rail-sdk";
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
await kstchain.authorize({ paymentKey, signature });
|
|
66
|
+
} catch (e) {
|
|
67
|
+
if (e instanceof KstApiError) {
|
|
68
|
+
console.error(e.status, e.code, e.message);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Notes
|
|
74
|
+
|
|
75
|
+
- This SDK is intended for **server-side (Node >= 18)** usage.
|
|
76
|
+
- Do not expose `walletSecretKey` in browser/frontend code.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CaptureRequest, ClientOptions, CommandData, ConfirmData, ConfirmRequest, HealthData, IssueSignPayloadRequest, ReadyData, RefundRequest, RequestOptions, SettleRequest, SignPayloadData, SubmitSignatureData, SubmitSignatureRequest, VoidRequest } from "./types.js";
|
|
2
|
+
export interface KstChainClient {
|
|
3
|
+
health(): Promise<HealthData>;
|
|
4
|
+
ready(): Promise<ReadyData>;
|
|
5
|
+
signPayload(req: IssueSignPayloadRequest, opts?: RequestOptions): Promise<SignPayloadData>;
|
|
6
|
+
getSignPayload(paymentKey: string, opts?: RequestOptions): Promise<SignPayloadData>;
|
|
7
|
+
authorize(req: SubmitSignatureRequest, opts?: RequestOptions): Promise<SubmitSignatureData>;
|
|
8
|
+
capture(req: CaptureRequest, opts?: RequestOptions): Promise<CommandData>;
|
|
9
|
+
void(req: VoidRequest, opts?: RequestOptions): Promise<CommandData>;
|
|
10
|
+
refund(req: RefundRequest, opts?: RequestOptions): Promise<CommandData>;
|
|
11
|
+
settle(req: SettleRequest, opts?: RequestOptions): Promise<CommandData>;
|
|
12
|
+
getCommand(commandId: string, opts?: RequestOptions): Promise<CommandData>;
|
|
13
|
+
confirm(req: ConfirmRequest, opts?: RequestOptions): Promise<ConfirmData>;
|
|
14
|
+
}
|
|
15
|
+
export declare function createKstChainClient(options: ClientOptions): KstChainClient;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { KstApiError } from "./errors.js";
|
|
2
|
+
const DEFAULT_TIMEOUT_MS = 10000;
|
|
3
|
+
export function createKstChainClient(options) {
|
|
4
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl);
|
|
5
|
+
const walletSecretKey = options.walletSecretKey?.trim();
|
|
6
|
+
const walletAccessKey = options.walletAccessKey?.trim();
|
|
7
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
8
|
+
if (!walletSecretKey) {
|
|
9
|
+
throw new Error("walletSecretKey is required");
|
|
10
|
+
}
|
|
11
|
+
if (!fetchImpl) {
|
|
12
|
+
throw new Error("No fetch implementation available");
|
|
13
|
+
}
|
|
14
|
+
const defaultTimeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
15
|
+
const call = async (method, path, body, opts) => {
|
|
16
|
+
const headers = {
|
|
17
|
+
"X-Wallet-Secret-Key": walletSecretKey,
|
|
18
|
+
};
|
|
19
|
+
if (walletAccessKey) {
|
|
20
|
+
headers["X-Wallet-Access-Key"] = walletAccessKey;
|
|
21
|
+
}
|
|
22
|
+
if (opts?.idempotencyKey) {
|
|
23
|
+
headers["Idempotency-Key"] = opts.idempotencyKey;
|
|
24
|
+
}
|
|
25
|
+
const timeoutMs = opts?.timeoutMs ?? defaultTimeoutMs;
|
|
26
|
+
const ac = new AbortController();
|
|
27
|
+
const timeout = setTimeout(() => ac.abort(), timeoutMs);
|
|
28
|
+
try {
|
|
29
|
+
const res = await fetchImpl(baseUrl + path, {
|
|
30
|
+
method,
|
|
31
|
+
headers: {
|
|
32
|
+
...headers,
|
|
33
|
+
...(body ? { "Content-Type": "application/json" } : {}),
|
|
34
|
+
},
|
|
35
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
36
|
+
signal: mergeSignals(ac.signal, opts?.signal),
|
|
37
|
+
});
|
|
38
|
+
let parsed;
|
|
39
|
+
try {
|
|
40
|
+
parsed = await res.json();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
throw new KstApiError(res.status, "INVALID_RESPONSE", "response is not valid json");
|
|
44
|
+
}
|
|
45
|
+
const envelope = parsed;
|
|
46
|
+
if (!envelope || typeof envelope !== "object" || !("success" in envelope)) {
|
|
47
|
+
throw new KstApiError(res.status, "INVALID_ENVELOPE", "response envelope is invalid", parsed);
|
|
48
|
+
}
|
|
49
|
+
if (!res.ok || envelope.success === false) {
|
|
50
|
+
const code = envelope?.error?.code ?? "REQUEST_FAILED";
|
|
51
|
+
const message = envelope?.error?.message ?? `request failed with status ${res.status}`;
|
|
52
|
+
throw new KstApiError(res.status, code, message, parsed);
|
|
53
|
+
}
|
|
54
|
+
return envelope.data;
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
clearTimeout(timeout);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
health: () => call("GET", "/healthz"),
|
|
62
|
+
ready: () => call("GET", "/readyz"),
|
|
63
|
+
signPayload: (req, opts) => call("POST", "/v1/onchain/sign-payload", req, opts),
|
|
64
|
+
getSignPayload: (paymentKey, opts) => call("GET", `/v1/onchain/sign-payloads/${encodeURIComponent(paymentKey)}`, undefined, opts),
|
|
65
|
+
authorize: (req, opts) => call("POST", "/v1/onchain/authorize", req, opts),
|
|
66
|
+
capture: (req, opts) => call("POST", "/v1/onchain/capture", req, opts),
|
|
67
|
+
void: (req, opts) => call("POST", "/v1/onchain/void", req, opts),
|
|
68
|
+
refund: (req, opts) => call("POST", "/v1/onchain/refund", req, opts),
|
|
69
|
+
settle: (req, opts) => call("POST", "/v1/onchain/settle", req, opts),
|
|
70
|
+
getCommand: (commandId, opts) => call("GET", `/v1/onchain/commands/${encodeURIComponent(commandId)}`, undefined, opts),
|
|
71
|
+
confirm: (req, opts) => call("POST", "/v1/onchain/confirm", req, opts),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function normalizeBaseUrl(baseUrl) {
|
|
75
|
+
const out = baseUrl.trim();
|
|
76
|
+
if (!out) {
|
|
77
|
+
throw new Error("baseUrl is required");
|
|
78
|
+
}
|
|
79
|
+
return out.endsWith("/") ? out.slice(0, -1) : out;
|
|
80
|
+
}
|
|
81
|
+
function mergeSignals(a, b) {
|
|
82
|
+
if (!b)
|
|
83
|
+
return a;
|
|
84
|
+
if (b.aborted)
|
|
85
|
+
return b;
|
|
86
|
+
const ac = new AbortController();
|
|
87
|
+
const abort = () => ac.abort();
|
|
88
|
+
a.addEventListener("abort", abort, { once: true });
|
|
89
|
+
b.addEventListener("abort", abort, { once: true });
|
|
90
|
+
return ac.signal;
|
|
91
|
+
}
|
package/dist/errors.d.ts
ADDED
package/dist/errors.js
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { createKstChainClient } from "./client.js";
|
|
2
|
+
export type { KstChainClient } from "./client.js";
|
|
3
|
+
export { KstApiError } from "./errors.js";
|
|
4
|
+
export type { AuthorizationPayload, CapturePayload, CaptureRequest, ClientOptions, CommandData, CommandStatus, CommandType, ConfirmData, ConfirmRequest, Envelope, ErrorEnvelope, HealthData, IssueSignPayloadRequest, ReadyData, RefundPayload, RefundRequest, RequestOptions, SettlePayload, SettleRequest, SignPayloadData, SignPayloadStatus, SubmitSignatureData, SubmitSignatureRequest, SuccessEnvelope, VoidPayload, VoidRequest, } from "./types.js";
|
package/dist/index.js
ADDED
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
export type CommandType = "authorize" | "capture" | "void" | "settle" | "refund";
|
|
2
|
+
export type CommandStatus = "pending" | "processing" | "submitted" | "authorized_confirmed" | "succeeded" | "failed" | "dead_letter";
|
|
3
|
+
export type SignPayloadStatus = "issued" | "submitted";
|
|
4
|
+
export interface EnvelopeBase {
|
|
5
|
+
success: boolean;
|
|
6
|
+
timestamp: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ErrorBody {
|
|
9
|
+
code: string;
|
|
10
|
+
message: string;
|
|
11
|
+
}
|
|
12
|
+
export interface SuccessEnvelope<T> extends EnvelopeBase {
|
|
13
|
+
success: true;
|
|
14
|
+
data: T;
|
|
15
|
+
}
|
|
16
|
+
export interface ErrorEnvelope extends EnvelopeBase {
|
|
17
|
+
success: false;
|
|
18
|
+
error: ErrorBody;
|
|
19
|
+
}
|
|
20
|
+
export type Envelope<T> = SuccessEnvelope<T> | ErrorEnvelope;
|
|
21
|
+
export interface AuthorizationPayload {
|
|
22
|
+
paymentKey?: string;
|
|
23
|
+
paymentId: string;
|
|
24
|
+
merchantKey: string;
|
|
25
|
+
payerAddress: string;
|
|
26
|
+
tokenAddress: string;
|
|
27
|
+
amount: string;
|
|
28
|
+
nonce: number;
|
|
29
|
+
deadline: number;
|
|
30
|
+
}
|
|
31
|
+
export interface CapturePayload {
|
|
32
|
+
paymentId: string;
|
|
33
|
+
}
|
|
34
|
+
export interface VoidPayload {
|
|
35
|
+
paymentId: string;
|
|
36
|
+
}
|
|
37
|
+
export interface RefundPayload {
|
|
38
|
+
paymentId: string;
|
|
39
|
+
refundAmount: string;
|
|
40
|
+
refundDestination: string;
|
|
41
|
+
}
|
|
42
|
+
export interface SettlePayload {
|
|
43
|
+
paymentId: string;
|
|
44
|
+
merchantId?: string;
|
|
45
|
+
settlementMethod?: "stablecoin" | "fiat";
|
|
46
|
+
merchantWalletAddress: string;
|
|
47
|
+
tokenAddress: string;
|
|
48
|
+
grossAmount: string;
|
|
49
|
+
feeAmount: string;
|
|
50
|
+
netAmount: string;
|
|
51
|
+
fiatCurrency?: string;
|
|
52
|
+
fiatAmount?: string;
|
|
53
|
+
burnAmount?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface CommandData {
|
|
56
|
+
id: string;
|
|
57
|
+
type: CommandType;
|
|
58
|
+
status: CommandStatus;
|
|
59
|
+
authorization?: AuthorizationPayload;
|
|
60
|
+
signature?: string;
|
|
61
|
+
payloadHash?: string;
|
|
62
|
+
capture?: CapturePayload;
|
|
63
|
+
void?: VoidPayload;
|
|
64
|
+
settle?: SettlePayload;
|
|
65
|
+
refund?: RefundPayload;
|
|
66
|
+
txHash?: string;
|
|
67
|
+
error?: string;
|
|
68
|
+
retryCount: number;
|
|
69
|
+
maxRetries: number;
|
|
70
|
+
nextAttemptAt?: string;
|
|
71
|
+
processingAt?: string;
|
|
72
|
+
submittedAt?: string;
|
|
73
|
+
deadLetterReason?: string;
|
|
74
|
+
createdAt: string;
|
|
75
|
+
updatedAt: string;
|
|
76
|
+
}
|
|
77
|
+
export interface IssueSignPayloadRequest {
|
|
78
|
+
orderId: string;
|
|
79
|
+
merchantKey: string;
|
|
80
|
+
payerAddress: string;
|
|
81
|
+
currency: "KST" | "USDC";
|
|
82
|
+
amount: string;
|
|
83
|
+
deadline?: number;
|
|
84
|
+
}
|
|
85
|
+
export interface SignPayloadData {
|
|
86
|
+
paymentKey: string;
|
|
87
|
+
paymentSessionId: string;
|
|
88
|
+
payloadHash: string;
|
|
89
|
+
payloadReady: boolean;
|
|
90
|
+
nonce: number;
|
|
91
|
+
deadline: number;
|
|
92
|
+
status: SignPayloadStatus;
|
|
93
|
+
}
|
|
94
|
+
export interface SubmitSignatureRequest {
|
|
95
|
+
paymentKey: string;
|
|
96
|
+
signature: string;
|
|
97
|
+
payloadHash?: string;
|
|
98
|
+
}
|
|
99
|
+
export interface SubmitSignatureData {
|
|
100
|
+
commandId: string;
|
|
101
|
+
paymentKey: string;
|
|
102
|
+
status: SignPayloadStatus;
|
|
103
|
+
command: CommandData;
|
|
104
|
+
}
|
|
105
|
+
export interface CaptureRequest {
|
|
106
|
+
requestId?: string;
|
|
107
|
+
paymentKey: string;
|
|
108
|
+
}
|
|
109
|
+
export interface VoidRequest {
|
|
110
|
+
requestId?: string;
|
|
111
|
+
paymentKey: string;
|
|
112
|
+
}
|
|
113
|
+
export interface RefundRequest {
|
|
114
|
+
requestId?: string;
|
|
115
|
+
paymentKey: string;
|
|
116
|
+
refundAmount: string;
|
|
117
|
+
refundDestination?: string;
|
|
118
|
+
}
|
|
119
|
+
export interface SettleRequest {
|
|
120
|
+
requestId?: string;
|
|
121
|
+
paymentKey: string;
|
|
122
|
+
settlementMethod?: "stablecoin" | "fiat";
|
|
123
|
+
merchantWalletAddress?: string;
|
|
124
|
+
tokenAddress?: string;
|
|
125
|
+
grossAmount?: string;
|
|
126
|
+
feeAmount?: string;
|
|
127
|
+
netAmount?: string;
|
|
128
|
+
fiatCurrency?: string;
|
|
129
|
+
fiatAmount?: string;
|
|
130
|
+
burnAmount?: string;
|
|
131
|
+
settlementDelayDays?: number;
|
|
132
|
+
}
|
|
133
|
+
export interface ConfirmRequest {
|
|
134
|
+
paymentKey: string;
|
|
135
|
+
orderId: string;
|
|
136
|
+
amount: string;
|
|
137
|
+
}
|
|
138
|
+
export interface ConfirmData {
|
|
139
|
+
paymentKey: string;
|
|
140
|
+
orderId: string;
|
|
141
|
+
amount: string;
|
|
142
|
+
commandId?: string;
|
|
143
|
+
commandStatus?: CommandStatus;
|
|
144
|
+
txHash?: string;
|
|
145
|
+
result: "success" | "failed";
|
|
146
|
+
reason?: string;
|
|
147
|
+
}
|
|
148
|
+
export interface HealthData {
|
|
149
|
+
status: string;
|
|
150
|
+
}
|
|
151
|
+
export interface ReadyData {
|
|
152
|
+
status: string;
|
|
153
|
+
chainId: number;
|
|
154
|
+
l1ChainId: number;
|
|
155
|
+
escrowContract: string;
|
|
156
|
+
dbHost?: string;
|
|
157
|
+
dbPort?: number;
|
|
158
|
+
dbName?: string;
|
|
159
|
+
}
|
|
160
|
+
export interface RequestOptions {
|
|
161
|
+
idempotencyKey?: string;
|
|
162
|
+
timeoutMs?: number;
|
|
163
|
+
signal?: AbortSignal;
|
|
164
|
+
}
|
|
165
|
+
export interface ClientOptions {
|
|
166
|
+
baseUrl: string;
|
|
167
|
+
walletSecretKey: string;
|
|
168
|
+
walletAccessKey?: string;
|
|
169
|
+
timeoutMs?: number;
|
|
170
|
+
fetchImpl?: typeof fetch;
|
|
171
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kstablepay-rail-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Node SDK for K-STable Pay onchain rail APIs",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "K-STable Pay",
|
|
7
|
+
"homepage": "https://github.com/moonyaeyoon/k-stable-pay",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/moonyaeyoon/k-stable-pay.git",
|
|
11
|
+
"directory": "infra/packages/kstchain-sdk"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"kstable",
|
|
15
|
+
"pay",
|
|
16
|
+
"wallet",
|
|
17
|
+
"sdk",
|
|
18
|
+
"onchain",
|
|
19
|
+
"rail"
|
|
20
|
+
],
|
|
21
|
+
"type": "module",
|
|
22
|
+
"main": "./dist/index.js",
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"import": "./dist/index.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"README.md"
|
|
33
|
+
],
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc -p tsconfig.json",
|
|
39
|
+
"clean": "rm -rf dist",
|
|
40
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"typescript": "^5.9.2"
|
|
44
|
+
}
|
|
45
|
+
}
|