@tanakayuto/intmax402-client 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 +5 -0
- package/dist/client.d.ts +17 -0
- package/dist/client.js +78 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/package.json +39 -0
package/README.md
ADDED
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface INTMAX402ClientOptions {
|
|
2
|
+
privateKey: string;
|
|
3
|
+
environment?: "mainnet" | "testnet";
|
|
4
|
+
}
|
|
5
|
+
export declare class INTMAX402Client {
|
|
6
|
+
private privateKey;
|
|
7
|
+
private environment;
|
|
8
|
+
private address;
|
|
9
|
+
private initialized;
|
|
10
|
+
constructor(options: INTMAX402ClientOptions);
|
|
11
|
+
private deriveAddress;
|
|
12
|
+
init(): Promise<void>;
|
|
13
|
+
getAddress(): string;
|
|
14
|
+
getRpcUrl(): string;
|
|
15
|
+
sign(nonce: string): Promise<string>;
|
|
16
|
+
fetch(url: string, options?: RequestInit): Promise<Response>;
|
|
17
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.INTMAX402Client = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const intmax402_core_1 = require("@tanakayuto/intmax402-core");
|
|
6
|
+
const RPC_URLS = {
|
|
7
|
+
mainnet: "https://api.rpc.intmax.io?network=ethereum",
|
|
8
|
+
testnet: "https://sepolia.gateway.tenderly.co",
|
|
9
|
+
};
|
|
10
|
+
class INTMAX402Client {
|
|
11
|
+
privateKey;
|
|
12
|
+
environment;
|
|
13
|
+
address;
|
|
14
|
+
initialized = false;
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.privateKey = options.privateKey;
|
|
17
|
+
this.environment = options.environment || "testnet";
|
|
18
|
+
this.address = this.deriveAddress(options.privateKey);
|
|
19
|
+
}
|
|
20
|
+
deriveAddress(privateKey) {
|
|
21
|
+
// Derive a deterministic address from private key using hash
|
|
22
|
+
// In production, use secp256k1 to derive the actual Ethereum address
|
|
23
|
+
const hash = (0, crypto_1.createHash)("sha256").update(privateKey).digest("hex");
|
|
24
|
+
return "0x" + hash.slice(0, 40);
|
|
25
|
+
}
|
|
26
|
+
async init() {
|
|
27
|
+
// In production, this would call IntMaxNodeClient.login()
|
|
28
|
+
// which takes ~7 seconds for initial setup
|
|
29
|
+
this.initialized = true;
|
|
30
|
+
}
|
|
31
|
+
getAddress() {
|
|
32
|
+
return this.address;
|
|
33
|
+
}
|
|
34
|
+
getRpcUrl() {
|
|
35
|
+
return RPC_URLS[this.environment];
|
|
36
|
+
}
|
|
37
|
+
async sign(nonce) {
|
|
38
|
+
// Sign the nonce using the private key
|
|
39
|
+
// In production, use secp256k1 to create an Ethereum personal_sign signature
|
|
40
|
+
// For now, create an HMAC-based signature as placeholder
|
|
41
|
+
const message = `\x19Ethereum Signed Message:\n${nonce.length}${nonce}`;
|
|
42
|
+
const sig = (0, crypto_1.createHmac)("sha256", this.privateKey).update(message).digest("hex");
|
|
43
|
+
// Pad to 65 bytes (130 hex chars) to match Ethereum signature format
|
|
44
|
+
const padded = sig.padEnd(130, "0");
|
|
45
|
+
return "0x" + padded;
|
|
46
|
+
}
|
|
47
|
+
async fetch(url, options) {
|
|
48
|
+
// First request - expect 401/402
|
|
49
|
+
const initialResponse = await globalThis.fetch(url, options);
|
|
50
|
+
if (initialResponse.status !== 401 && initialResponse.status !== 402) {
|
|
51
|
+
return initialResponse;
|
|
52
|
+
}
|
|
53
|
+
const wwwAuth = initialResponse.headers.get("www-authenticate");
|
|
54
|
+
if (!wwwAuth) {
|
|
55
|
+
return initialResponse;
|
|
56
|
+
}
|
|
57
|
+
const challenge = (0, intmax402_core_1.parseWWWAuthenticate)(wwwAuth);
|
|
58
|
+
if (!challenge) {
|
|
59
|
+
return initialResponse;
|
|
60
|
+
}
|
|
61
|
+
// Sign the nonce
|
|
62
|
+
const signature = await this.sign(challenge.nonce);
|
|
63
|
+
// Build authorization header
|
|
64
|
+
let authHeader = `INTMAX402 address="${this.address}", nonce="${challenge.nonce}", signature="${signature}"`;
|
|
65
|
+
// If payment mode, would need to send payment first and include txHash
|
|
66
|
+
// For now, just include the signature
|
|
67
|
+
// Retry with credentials
|
|
68
|
+
const retryOptions = {
|
|
69
|
+
...options,
|
|
70
|
+
headers: {
|
|
71
|
+
...(options?.headers || {}),
|
|
72
|
+
Authorization: authHeader,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
return globalThis.fetch(url, retryOptions);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.INTMAX402Client = INTMAX402Client;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { INTMAX402Client, INTMAX402ClientOptions } from "./client";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.INTMAX402Client = void 0;
|
|
4
|
+
var client_1 = require("./client");
|
|
5
|
+
Object.defineProperty(exports, "INTMAX402Client", { enumerable: true, get: function () { return client_1.INTMAX402Client; } });
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tanakayuto/intmax402-client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@tanakayuto/intmax402-core": "0.1.0"
|
|
8
|
+
},
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"typescript": "^5.4.0",
|
|
11
|
+
"@types/node": "^20.0.0"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/zaq2989/intmax402"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"intmax",
|
|
27
|
+
"http-402",
|
|
28
|
+
"payment",
|
|
29
|
+
"ai-agent",
|
|
30
|
+
"express",
|
|
31
|
+
"web3",
|
|
32
|
+
"zk"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc",
|
|
36
|
+
"clean": "rm -rf dist",
|
|
37
|
+
"typecheck": "tsc --noEmit"
|
|
38
|
+
}
|
|
39
|
+
}
|