@paysponge/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/LICENSE +21 -0
- package/README.md +138 -0
- package/dist/admin.d.ts +81 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/admin.js +108 -0
- package/dist/admin.js.map +1 -0
- package/dist/api/agents.d.ts +37 -0
- package/dist/api/agents.d.ts.map +1 -0
- package/dist/api/agents.js +63 -0
- package/dist/api/agents.js.map +1 -0
- package/dist/api/http.d.ts +29 -0
- package/dist/api/http.d.ts.map +1 -0
- package/dist/api/http.js +101 -0
- package/dist/api/http.js.map +1 -0
- package/dist/api/index.d.ts +6 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +6 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/public-tools.d.ts +52 -0
- package/dist/api/public-tools.d.ts.map +1 -0
- package/dist/api/public-tools.js +68 -0
- package/dist/api/public-tools.js.map +1 -0
- package/dist/api/transactions.d.ts +30 -0
- package/dist/api/transactions.d.ts.map +1 -0
- package/dist/api/transactions.js +176 -0
- package/dist/api/transactions.js.map +1 -0
- package/dist/api/wallets.d.ts +33 -0
- package/dist/api/wallets.d.ts.map +1 -0
- package/dist/api/wallets.js +121 -0
- package/dist/api/wallets.js.map +1 -0
- package/dist/auth/credentials.d.ts +37 -0
- package/dist/auth/credentials.d.ts.map +1 -0
- package/dist/auth/credentials.js +100 -0
- package/dist/auth/credentials.js.map +1 -0
- package/dist/auth/device-flow.d.ts +25 -0
- package/dist/auth/device-flow.d.ts.map +1 -0
- package/dist/auth/device-flow.js +161 -0
- package/dist/auth/device-flow.js.map +1 -0
- package/dist/auth/index.d.ts +3 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +3 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +116 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/client.d.ts +383 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +384 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/config.d.ts +27 -0
- package/dist/mcp/config.d.ts.map +1 -0
- package/dist/mcp/config.js +34 -0
- package/dist/mcp/config.js.map +1 -0
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +2 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/tools/definitions.d.ts +16 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/definitions.js +330 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/executor.d.ts +56 -0
- package/dist/tools/executor.d.ts.map +1 -0
- package/dist/tools/executor.js +182 -0
- package/dist/tools/executor.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +3 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/schemas.d.ts +924 -0
- package/dist/types/schemas.d.ts.map +1 -0
- package/dist/types/schemas.js +360 -0
- package/dist/types/schemas.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import * as os from "node:os";
|
|
4
|
+
import { CredentialsSchema } from "../types/schemas.js";
|
|
5
|
+
const CREDENTIALS_DIR = ".spongewallet";
|
|
6
|
+
const CREDENTIALS_FILE = "credentials.json";
|
|
7
|
+
/**
|
|
8
|
+
* Get the credentials directory path
|
|
9
|
+
*/
|
|
10
|
+
export function getCredentialsDir() {
|
|
11
|
+
return path.join(os.homedir(), CREDENTIALS_DIR);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get the credentials file path
|
|
15
|
+
*/
|
|
16
|
+
export function getCredentialsPath() {
|
|
17
|
+
return path.join(getCredentialsDir(), CREDENTIALS_FILE);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Ensure the credentials directory exists
|
|
21
|
+
*/
|
|
22
|
+
function ensureCredentialsDir() {
|
|
23
|
+
const dir = getCredentialsDir();
|
|
24
|
+
if (!fs.existsSync(dir)) {
|
|
25
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Load credentials from disk
|
|
30
|
+
* @returns Credentials if found and valid, null otherwise
|
|
31
|
+
*/
|
|
32
|
+
export function loadCredentials() {
|
|
33
|
+
const credPath = getCredentialsPath();
|
|
34
|
+
if (!fs.existsSync(credPath)) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const content = fs.readFileSync(credPath, "utf-8");
|
|
39
|
+
const data = JSON.parse(content);
|
|
40
|
+
const result = CredentialsSchema.safeParse(data);
|
|
41
|
+
if (!result.success) {
|
|
42
|
+
console.warn("Invalid credentials file, ignoring");
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return result.data;
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
console.warn("Failed to read credentials file:", error);
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Save credentials to disk
|
|
54
|
+
*/
|
|
55
|
+
export function saveCredentials(credentials) {
|
|
56
|
+
ensureCredentialsDir();
|
|
57
|
+
const credPath = getCredentialsPath();
|
|
58
|
+
// Validate before saving
|
|
59
|
+
const validated = CredentialsSchema.parse(credentials);
|
|
60
|
+
fs.writeFileSync(credPath, JSON.stringify(validated, null, 2), {
|
|
61
|
+
mode: 0o600, // Read/write for owner only
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Delete credentials from disk
|
|
66
|
+
*/
|
|
67
|
+
export function deleteCredentials() {
|
|
68
|
+
const credPath = getCredentialsPath();
|
|
69
|
+
if (fs.existsSync(credPath)) {
|
|
70
|
+
fs.unlinkSync(credPath);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if credentials exist
|
|
75
|
+
*/
|
|
76
|
+
export function hasCredentials() {
|
|
77
|
+
return fs.existsSync(getCredentialsPath());
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get API key from environment variable or credentials file
|
|
81
|
+
* @param envVarName Name of the environment variable to check (default: SPONGE_API_KEY)
|
|
82
|
+
*/
|
|
83
|
+
export function getApiKey(envVarName = "SPONGE_API_KEY") {
|
|
84
|
+
// Check environment variable first
|
|
85
|
+
const envKey = process.env[envVarName];
|
|
86
|
+
if (envKey) {
|
|
87
|
+
return envKey;
|
|
88
|
+
}
|
|
89
|
+
// Fall back to credentials file
|
|
90
|
+
const creds = loadCredentials();
|
|
91
|
+
return creds?.apiKey ?? null;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get agent ID from credentials file
|
|
95
|
+
*/
|
|
96
|
+
export function getAgentId() {
|
|
97
|
+
const creds = loadCredentials();
|
|
98
|
+
return creds?.agentId ?? null;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/auth/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAoB,MAAM,qBAAqB,CAAC;AAK1E,MAAM,eAAe,GAAG,eAAe,CAAC;AACxC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;AAE5C;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,gBAAgB,CAAC,CAAC;AAC1D,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB;IAC3B,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAC;IAEtC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACjC,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAEjD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,kCAAkC,EAAE,KAAK,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,WAAwB;IACtD,oBAAoB,EAAE,CAAC;IACvB,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAC;IAEtC,yBAAyB;IACzB,MAAM,SAAS,GAAG,iBAAiB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAEvD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QAC7D,IAAI,EAAE,KAAK,EAAE,4BAA4B;KAC1C,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAC;IAEtC,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,EAAE,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,UAAU,GAAG,gBAAgB;IACrD,mCAAmC;IACnC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACvC,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,gCAAgC;IAChC,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAChC,OAAO,KAAK,EAAE,MAAM,IAAI,IAAI,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAChC,OAAO,KAAK,EAAE,OAAO,IAAI,IAAI,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type TokenResponse } from "../types/schemas.js";
|
|
2
|
+
export interface DeviceFlowOptions {
|
|
3
|
+
/** Base URL for the API */
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
/** Disable auto-opening browser */
|
|
6
|
+
noBrowser?: boolean;
|
|
7
|
+
/** Use testnets only */
|
|
8
|
+
testnet?: boolean;
|
|
9
|
+
/** Agent name to create (if new user) */
|
|
10
|
+
agentName?: string;
|
|
11
|
+
/** Type of key to generate: "agent" (default) or "master" */
|
|
12
|
+
keyType?: "agent" | "master";
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Start the OAuth Device Flow authentication
|
|
16
|
+
*
|
|
17
|
+
* This flow:
|
|
18
|
+
* 1. Requests a device code from the server
|
|
19
|
+
* 2. Opens the browser to the verification URL
|
|
20
|
+
* 3. Copies the user code to clipboard
|
|
21
|
+
* 4. Polls for token until approved or expired
|
|
22
|
+
* 5. Saves credentials and returns the API key
|
|
23
|
+
*/
|
|
24
|
+
export declare function deviceFlowAuth(options?: DeviceFlowOptions): Promise<TokenResponse>;
|
|
25
|
+
//# sourceMappingURL=device-flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-flow.d.ts","sourceRoot":"","sources":["../../src/auth/device-flow.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,aAAa,EAEnB,MAAM,qBAAqB,CAAC;AAK7B,MAAM,WAAW,iBAAiB;IAChC,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wBAAwB;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,aAAa,CAAC,CA6ExB"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { DeviceCodeResponseSchema, TokenResponseSchema, } from "../types/schemas.js";
|
|
2
|
+
import { saveCredentials, getCredentialsPath } from "./credentials.js";
|
|
3
|
+
const DEFAULT_BASE_URL = "https://api.wallet.paysponge.com";
|
|
4
|
+
/**
|
|
5
|
+
* Start the OAuth Device Flow authentication
|
|
6
|
+
*
|
|
7
|
+
* This flow:
|
|
8
|
+
* 1. Requests a device code from the server
|
|
9
|
+
* 2. Opens the browser to the verification URL
|
|
10
|
+
* 3. Copies the user code to clipboard
|
|
11
|
+
* 4. Polls for token until approved or expired
|
|
12
|
+
* 5. Saves credentials and returns the API key
|
|
13
|
+
*/
|
|
14
|
+
export async function deviceFlowAuth(options = {}) {
|
|
15
|
+
const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
|
|
16
|
+
// Step 1: Request device code
|
|
17
|
+
console.log("Starting authentication...\n");
|
|
18
|
+
const deviceCodeResponse = await requestDeviceCode(baseUrl, {
|
|
19
|
+
testnet: options.testnet,
|
|
20
|
+
agentName: options.agentName,
|
|
21
|
+
keyType: options.keyType,
|
|
22
|
+
});
|
|
23
|
+
// Step 2: Display instructions and optionally open browser
|
|
24
|
+
console.log("To authenticate, visit:");
|
|
25
|
+
console.log(` ${deviceCodeResponse.verificationUri}\n`);
|
|
26
|
+
console.log(`Enter this code: ${deviceCodeResponse.userCode}\n`);
|
|
27
|
+
// Try to copy to clipboard
|
|
28
|
+
try {
|
|
29
|
+
const clipboardy = await import("clipboardy");
|
|
30
|
+
await clipboardy.default.write(deviceCodeResponse.userCode);
|
|
31
|
+
console.log("(Code copied to clipboard)\n");
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// Clipboard not available, that's fine
|
|
35
|
+
}
|
|
36
|
+
// Try to open browser
|
|
37
|
+
if (!options.noBrowser) {
|
|
38
|
+
try {
|
|
39
|
+
const open = await import("open");
|
|
40
|
+
await open.default(deviceCodeResponse.verificationUri);
|
|
41
|
+
console.log("Opening browser...\n");
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Browser not available, that's fine
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
console.log("Waiting for approval...");
|
|
48
|
+
// Step 3: Poll for token
|
|
49
|
+
const tokenResponse = await pollForToken(baseUrl, deviceCodeResponse.deviceCode, deviceCodeResponse.interval, deviceCodeResponse.expiresIn);
|
|
50
|
+
// Step 4: Save credentials (only for agent keys with agentId)
|
|
51
|
+
if (tokenResponse.agentId) {
|
|
52
|
+
const credentials = {
|
|
53
|
+
apiKey: tokenResponse.apiKey,
|
|
54
|
+
agentId: tokenResponse.agentId,
|
|
55
|
+
testnet: options.testnet,
|
|
56
|
+
createdAt: new Date(),
|
|
57
|
+
baseUrl: baseUrl !== DEFAULT_BASE_URL ? baseUrl : undefined,
|
|
58
|
+
};
|
|
59
|
+
saveCredentials(credentials);
|
|
60
|
+
}
|
|
61
|
+
// Step 5: Display success message with API key
|
|
62
|
+
const isMaster = options.keyType === "master";
|
|
63
|
+
console.log("\n" + "=".repeat(60));
|
|
64
|
+
console.log("Authentication successful!\n");
|
|
65
|
+
console.log(`Your ${isMaster ? "master " : ""}API key: ${tokenResponse.apiKey}\n`);
|
|
66
|
+
if (isMaster) {
|
|
67
|
+
console.log("Use this key to create agents programmatically:");
|
|
68
|
+
console.log(" - Set SPONGE_MASTER_KEY environment variable, or");
|
|
69
|
+
console.log(" - Pass directly: new SpongeAdmin({ apiKey: '...' })\n");
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
console.log("Save this key for other machines/deployments:");
|
|
73
|
+
console.log(" - Set SPONGE_API_KEY environment variable, or");
|
|
74
|
+
console.log(" - Pass directly: SpongeWallet.connect({ apiKey: '...' })\n");
|
|
75
|
+
console.log(`Key cached locally at ${getCredentialsPath()}`);
|
|
76
|
+
}
|
|
77
|
+
console.log("=".repeat(60) + "\n");
|
|
78
|
+
return tokenResponse;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Request a device code from the server
|
|
82
|
+
*/
|
|
83
|
+
async function requestDeviceCode(baseUrl, options) {
|
|
84
|
+
const response = await fetch(`${baseUrl}/api/oauth/device/authorization`, {
|
|
85
|
+
method: "POST",
|
|
86
|
+
headers: {
|
|
87
|
+
"Content-Type": "application/json",
|
|
88
|
+
},
|
|
89
|
+
body: JSON.stringify({
|
|
90
|
+
clientId: "spongewallet-sdk",
|
|
91
|
+
scope: "wallet:read wallet:write transaction:sign",
|
|
92
|
+
testnet: options.testnet,
|
|
93
|
+
agentName: options.agentName,
|
|
94
|
+
keyType: options.keyType,
|
|
95
|
+
}),
|
|
96
|
+
});
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
const error = await response.text();
|
|
99
|
+
throw new Error(`Failed to start device flow: ${error}`);
|
|
100
|
+
}
|
|
101
|
+
const data = await response.json();
|
|
102
|
+
return DeviceCodeResponseSchema.parse(data);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Poll for token until approved or expired
|
|
106
|
+
*/
|
|
107
|
+
async function pollForToken(baseUrl, deviceCode, intervalSeconds, expiresInSeconds) {
|
|
108
|
+
const startTime = Date.now();
|
|
109
|
+
const expiresAt = startTime + expiresInSeconds * 1000;
|
|
110
|
+
let interval = intervalSeconds * 1000;
|
|
111
|
+
while (Date.now() < expiresAt) {
|
|
112
|
+
await sleep(interval);
|
|
113
|
+
try {
|
|
114
|
+
const response = await fetch(`${baseUrl}/api/oauth/device/token`, {
|
|
115
|
+
method: "POST",
|
|
116
|
+
headers: {
|
|
117
|
+
"Content-Type": "application/json",
|
|
118
|
+
},
|
|
119
|
+
body: JSON.stringify({
|
|
120
|
+
grantType: "urn:ietf:params:oauth:grant-type:device_code",
|
|
121
|
+
deviceCode,
|
|
122
|
+
clientId: "spongewallet-sdk",
|
|
123
|
+
}),
|
|
124
|
+
});
|
|
125
|
+
if (response.ok) {
|
|
126
|
+
const data = await response.json();
|
|
127
|
+
return TokenResponseSchema.parse(data);
|
|
128
|
+
}
|
|
129
|
+
// Handle error responses
|
|
130
|
+
const errorData = (await response.json().catch(() => ({})));
|
|
131
|
+
const error = errorData.error;
|
|
132
|
+
switch (error) {
|
|
133
|
+
case "authorization_pending":
|
|
134
|
+
// Keep polling
|
|
135
|
+
process.stdout.write(".");
|
|
136
|
+
break;
|
|
137
|
+
case "slow_down":
|
|
138
|
+
// Increase polling interval
|
|
139
|
+
interval += 5000;
|
|
140
|
+
break;
|
|
141
|
+
case "access_denied":
|
|
142
|
+
throw new Error("Access denied by user");
|
|
143
|
+
case "expired_token":
|
|
144
|
+
throw new Error("Device code expired. Please try again.");
|
|
145
|
+
default:
|
|
146
|
+
throw new Error(`Authentication failed: ${errorData.errorDescription ?? error ?? "Unknown error"}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (error instanceof Error) {
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
throw new Error(`Network error during authentication: ${error}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
throw new Error("Device code expired. Please try again.");
|
|
157
|
+
}
|
|
158
|
+
function sleep(ms) {
|
|
159
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=device-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-flow.js","sourceRoot":"","sources":["../../src/auth/device-flow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/bin/cli.ts"],"names":[],"mappings":""}
|
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { deviceFlowAuth } from "../auth/device-flow.js";
|
|
3
|
+
import { loadCredentials, deleteCredentials, getCredentialsPath, } from "../auth/credentials.js";
|
|
4
|
+
const VERSION = "0.1.0";
|
|
5
|
+
async function main() {
|
|
6
|
+
const args = process.argv.slice(2);
|
|
7
|
+
const command = args[0];
|
|
8
|
+
switch (command) {
|
|
9
|
+
case "login":
|
|
10
|
+
await login(args.slice(1));
|
|
11
|
+
break;
|
|
12
|
+
case "logout":
|
|
13
|
+
await logout();
|
|
14
|
+
break;
|
|
15
|
+
case "whoami":
|
|
16
|
+
await whoami();
|
|
17
|
+
break;
|
|
18
|
+
case "version":
|
|
19
|
+
case "--version":
|
|
20
|
+
case "-v":
|
|
21
|
+
console.log(`@spongewallet/sdk v${VERSION}`);
|
|
22
|
+
break;
|
|
23
|
+
case "help":
|
|
24
|
+
case "--help":
|
|
25
|
+
case "-h":
|
|
26
|
+
default:
|
|
27
|
+
printHelp();
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function login(args) {
|
|
32
|
+
const options = {};
|
|
33
|
+
for (let i = 0; i < args.length; i++) {
|
|
34
|
+
const arg = args[i];
|
|
35
|
+
if (arg === "--testnet" || arg === "-t") {
|
|
36
|
+
options.testnet = true;
|
|
37
|
+
}
|
|
38
|
+
else if (arg === "--no-browser") {
|
|
39
|
+
options.noBrowser = true;
|
|
40
|
+
}
|
|
41
|
+
else if (arg === "--base-url" && args[i + 1]) {
|
|
42
|
+
options.baseUrl = args[++i];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
await deviceFlowAuth(options);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
console.error("Login failed:", error instanceof Error ? error.message : error);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function logout() {
|
|
54
|
+
const creds = loadCredentials();
|
|
55
|
+
if (!creds) {
|
|
56
|
+
console.log("Not logged in.");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
deleteCredentials();
|
|
60
|
+
console.log("Logged out successfully.");
|
|
61
|
+
console.log(`Removed credentials from ${getCredentialsPath()}`);
|
|
62
|
+
}
|
|
63
|
+
async function whoami() {
|
|
64
|
+
const creds = loadCredentials();
|
|
65
|
+
if (!creds) {
|
|
66
|
+
console.log("Not logged in.");
|
|
67
|
+
console.log("Run `spongewallet login` to authenticate.");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
console.log("Logged in as:");
|
|
71
|
+
console.log(` Agent ID: ${creds.agentId}`);
|
|
72
|
+
if (creds.agentName) {
|
|
73
|
+
console.log(` Agent Name: ${creds.agentName}`);
|
|
74
|
+
}
|
|
75
|
+
console.log(` API Key: ${creds.apiKey.substring(0, 20)}...`);
|
|
76
|
+
if (creds.testnet) {
|
|
77
|
+
console.log(" Mode: Testnet only");
|
|
78
|
+
}
|
|
79
|
+
console.log(` Credentials: ${getCredentialsPath()}`);
|
|
80
|
+
}
|
|
81
|
+
function printHelp() {
|
|
82
|
+
console.log(`
|
|
83
|
+
@spongewallet/sdk - CLI for managing agent wallets
|
|
84
|
+
|
|
85
|
+
Usage:
|
|
86
|
+
spongewallet <command> [options]
|
|
87
|
+
|
|
88
|
+
Commands:
|
|
89
|
+
login Authenticate with SpongeWallet (opens browser)
|
|
90
|
+
logout Remove stored credentials
|
|
91
|
+
whoami Show current authentication status
|
|
92
|
+
version Show version number
|
|
93
|
+
help Show this help message
|
|
94
|
+
|
|
95
|
+
Login Options:
|
|
96
|
+
--testnet, -t Use testnets only
|
|
97
|
+
--no-browser Don't auto-open browser
|
|
98
|
+
--base-url URL Use custom API URL
|
|
99
|
+
|
|
100
|
+
Examples:
|
|
101
|
+
spongewallet login # Authenticate
|
|
102
|
+
spongewallet login --testnet # Authenticate for testnets only
|
|
103
|
+
spongewallet whoami # Show current status
|
|
104
|
+
spongewallet logout # Remove credentials
|
|
105
|
+
|
|
106
|
+
Environment Variables:
|
|
107
|
+
SPONGE_API_KEY API key (skips login if set)
|
|
108
|
+
|
|
109
|
+
For more information, visit: https://docs.spongewallet.com
|
|
110
|
+
`);
|
|
111
|
+
}
|
|
112
|
+
main().catch((error) => {
|
|
113
|
+
console.error("Error:", error);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
});
|
|
116
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/bin/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAExB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,OAAO;YACV,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3B,MAAM;QACR,KAAK,QAAQ;YACX,MAAM,MAAM,EAAE,CAAC;YACf,MAAM;QACR,KAAK,QAAQ;YACX,MAAM,MAAM,EAAE,CAAC;YACf,MAAM;QACR,KAAK,SAAS,CAAC;QACf,KAAK,WAAW,CAAC;QACjB,KAAK,IAAI;YACP,OAAO,CAAC,GAAG,CAAC,sBAAsB,OAAO,EAAE,CAAC,CAAC;YAC7C,MAAM;QACR,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI,CAAC;QACV;YACE,SAAS,EAAE,CAAC;YACZ,MAAM;IACV,CAAC;AACH,CAAC;AAED,KAAK,UAAU,KAAK,CAAC,IAAc;IACjC,MAAM,OAAO,GACX,EAAE,CAAC;IAEL,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACxC,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;QACzB,CAAC;aAAM,IAAI,GAAG,KAAK,cAAc,EAAE,CAAC;YAClC,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;QAC3B,CAAC;aAAM,IAAI,GAAG,KAAK,YAAY,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAC/C,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CACX,eAAe,EACf,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAC/C,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,MAAM;IACnB,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAEhC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAC9B,OAAO;IACT,CAAC;IAED,iBAAiB,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,4BAA4B,kBAAkB,EAAE,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,KAAK,UAAU,MAAM;IACnB,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAEhC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;QACzD,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC7B,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5C,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;IAC9D,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,kBAAkB,kBAAkB,EAAE,EAAE,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4Bb,CAAC,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|