@gistplus/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 ADDED
@@ -0,0 +1,280 @@
1
+ # @gistplus/client
2
+
3
+ [![Twitter Follow](https://img.shields.io/twitter/follow/gistplus?style=social)](https://x.com/gistplus)
4
+
5
+ Client SDK for AI agents and applications to interact with Gist Plus providers.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @gistplus/client
11
+ ```
12
+
13
+ ## What is This?
14
+
15
+ This package enables **AI agents and applications** to:
16
+ - 🤝 Negotiate pricing with API providers
17
+ - 💰 Create prepaid sessions
18
+ - 🚀 Execute requests with automatic payment
19
+ - ✅ Verify cryptographic receipts
20
+ - 💵 Get refunds for unused balance
21
+
22
+ ## Quick Start
23
+
24
+ ```typescript
25
+ import { Connection, Keypair } from '@solana/web3.js';
26
+ import { GistClient } from '@gistplus/client';
27
+
28
+ // Initialize
29
+ const connection = new Connection('https://api.devnet.solana.com');
30
+ const wallet = Keypair.generate(); // Your agent's wallet
31
+ const client = new GistClient({ connection, wallet });
32
+
33
+ // 1. Create Intent (express your needs)
34
+ const intent = client.createIntent({
35
+ capability: 'gpt-4-inference',
36
+ maxPricePerRequest: 0.01,
37
+ token: 'USDC',
38
+ sla: { maxLatencyMs: 2000 }
39
+ });
40
+
41
+ // 2. Negotiate with provider
42
+ const offer = await client.negotiate('https://api.provider.com', intent);
43
+
44
+ // 3. Create prepaid session
45
+ const session = await client.createSession(offer);
46
+
47
+ // 4. Execute requests (payment automatic!)
48
+ const result = await client.executeRequest(session.sessionId, {
49
+ prompt: 'Explain quantum computing'
50
+ });
51
+
52
+ console.log(result.data); // API response
53
+ console.log(result.receipt); // Cryptographic proof
54
+
55
+ // 5. Close session and get refund
56
+ await client.closeSession(session.sessionId);
57
+ ```
58
+
59
+ ## Core Features
60
+
61
+ ### Automatic Negotiation
62
+ ```typescript
63
+ // Agent expresses maximum price
64
+ const intent = client.createIntent({
65
+ maxPricePerRequest: 0.01,
66
+ capability: 'ai-inference'
67
+ });
68
+
69
+ // Provider responds with actual price
70
+ const offer = await client.negotiate(endpoint, intent);
71
+
72
+ // Verify it's within budget
73
+ if (offer.pricePerRequest <= intent.maxPricePerRequest) {
74
+ // Accept!
75
+ }
76
+ ```
77
+
78
+ ### Prepaid Sessions
79
+ ```typescript
80
+ // Deposit once, make many requests
81
+ const session = await client.createSession(offer, {
82
+ depositAmount: 1.0 // 1 USDC
83
+ });
84
+
85
+ // Make multiple requests without per-request transactions
86
+ await client.executeRequest(session.sessionId, request1);
87
+ await client.executeRequest(session.sessionId, request2);
88
+ await client.executeRequest(session.sessionId, request3);
89
+ ```
90
+
91
+ ### Receipt Verification
92
+ ```typescript
93
+ const result = await client.executeRequest(sessionId, data);
94
+
95
+ // Every request gets a cryptographic receipt
96
+ console.log(result.receipt);
97
+ /*
98
+ {
99
+ receiptId: "receipt_123",
100
+ inputHash: "sha256(...)", // Tamper-proof
101
+ outputHash: "sha256(...)", // Tamper-proof
102
+ signature: "...", // Provider's signature
103
+ slaVerification: {
104
+ met: true,
105
+ metrics: { latency: { expected: 2000, actual: 1234 } }
106
+ }
107
+ }
108
+ */
109
+ ```
110
+
111
+ ### SLA Enforcement
112
+ ```typescript
113
+ // Request SLA guarantees
114
+ const intent = client.createIntent({
115
+ sla: {
116
+ maxLatencyMs: 2000, // Must respond within 2s
117
+ minUptimePercent: 99.0, // Must have 99% uptime
118
+ }
119
+ });
120
+
121
+ // If provider breaches SLA, automatic refund!
122
+ ```
123
+
124
+ ## API Reference
125
+
126
+ ### GistClient
127
+
128
+ #### Constructor
129
+ ```typescript
130
+ new GistClient({
131
+ connection: Connection, // Solana connection
132
+ wallet: Keypair, // Your wallet
133
+ httpConfig?: { // Optional HTTP settings
134
+ timeout?: number,
135
+ headers?: Record<string, string>
136
+ }
137
+ })
138
+ ```
139
+
140
+ #### Methods
141
+
142
+ **createIntent(options)**
143
+ ```typescript
144
+ client.createIntent({
145
+ capability: string,
146
+ maxPricePerRequest: number,
147
+ token: 'SOL' | 'USDC' | 'USDT' | 'BONK',
148
+ sla?: { maxLatencyMs?, minUptimePercent? },
149
+ maxSessionBudget?: number,
150
+ sessionDurationMs?: number,
151
+ metadata?: Record<string, any>
152
+ })
153
+ ```
154
+
155
+ **negotiate(endpoint, intent)**
156
+ ```typescript
157
+ const offer = await client.negotiate(
158
+ 'https://api.provider.com',
159
+ intent
160
+ );
161
+ ```
162
+
163
+ **createSession(offer, options?)**
164
+ ```typescript
165
+ const session = await client.createSession(offer, {
166
+ depositAmount?: number, // Custom deposit
167
+ anchorOnChain?: boolean // Store on Solana (optional)
168
+ });
169
+ ```
170
+
171
+ **executeRequest(sessionId, data)**
172
+ ```typescript
173
+ const result = await client.executeRequest(
174
+ sessionId,
175
+ { prompt: 'Hello' }
176
+ );
177
+ // Returns: { data, receipt }
178
+ ```
179
+
180
+ **closeSession(sessionId)**
181
+ ```typescript
182
+ const refund = await client.closeSession(sessionId);
183
+ // Returns: { refundAmount, txSignature }
184
+ ```
185
+
186
+ **getSession(sessionId)**
187
+ ```typescript
188
+ const session = client.getSession(sessionId);
189
+ ```
190
+
191
+ **getActiveSessions()**
192
+ ```typescript
193
+ const sessions = client.getActiveSessions();
194
+ ```
195
+
196
+ ## Examples
197
+
198
+ ### AI Inference
199
+ ```typescript
200
+ const intent = client.createIntent({
201
+ capability: 'gpt-4-inference',
202
+ maxPricePerRequest: 0.01,
203
+ token: 'USDC'
204
+ });
205
+
206
+ const offer = await client.negotiate('https://ai-api.com', intent);
207
+ const session = await client.createSession(offer);
208
+
209
+ const result = await client.executeRequest(session.sessionId, {
210
+ prompt: 'Write a poem about Solana'
211
+ });
212
+
213
+ console.log(result.data.text);
214
+ ```
215
+
216
+ ### Image Generation
217
+ ```typescript
218
+ const intent = client.createIntent({
219
+ capability: 'image-generation',
220
+ maxPricePerRequest: 0.05,
221
+ token: 'USDC'
222
+ });
223
+
224
+ const offer = await client.negotiate('https://image-api.com', intent);
225
+ const session = await client.createSession(offer);
226
+
227
+ const result = await client.executeRequest(session.sessionId, {
228
+ prompt: 'A futuristic city on Mars',
229
+ style: 'photorealistic'
230
+ });
231
+
232
+ console.log(result.data.imageUrl);
233
+ ```
234
+
235
+ ### Data Analysis
236
+ ```typescript
237
+ const intent = client.createIntent({
238
+ capability: 'data-analysis',
239
+ maxPricePerRequest: 0.001,
240
+ token: 'USDC'
241
+ });
242
+
243
+ const offer = await client.negotiate('https://data-api.com', intent);
244
+ const session = await client.createSession(offer);
245
+
246
+ const result = await client.executeRequest(session.sessionId, {
247
+ dataset: myData,
248
+ operation: 'statistical-summary'
249
+ });
250
+
251
+ console.log(result.data.analysis);
252
+ ```
253
+
254
+ ## Error Handling
255
+
256
+ ```typescript
257
+ try {
258
+ const offer = await client.negotiate(endpoint, intent);
259
+ const session = await client.createSession(offer);
260
+ const result = await client.executeRequest(session.sessionId, data);
261
+ } catch (error) {
262
+ if (error instanceof InvalidOfferError) {
263
+ console.error('Offer validation failed');
264
+ } else if (error instanceof SessionExpiredError) {
265
+ console.error('Session expired, create new one');
266
+ } else if (error instanceof InsufficientFundsError) {
267
+ console.error('Session balance depleted');
268
+ }
269
+ }
270
+ ```
271
+
272
+ ## Related Packages
273
+
274
+ - **[@gistplus/core](https://www.npmjs.com/package/@gistplus/core)** - Core protocol (auto-installed)
275
+ - **[@gistplus/server](https://www.npmjs.com/package/@gistplus/server)** - For API providers
276
+
277
+ ## License
278
+
279
+ Apache 2.0
280
+
@@ -0,0 +1,116 @@
1
+ /**
2
+ * GistClient - Main client interface for Gist Plus protocol
3
+ */
4
+ import { Connection, Keypair, PublicKey } from '@solana/web3.js';
5
+ import { Intent, Offer, Session, Receipt, SLA, SupportedToken } from '@gistplus/core';
6
+ export interface GistClientConfig {
7
+ /** Solana connection */
8
+ connection: Connection;
9
+ /** Agent's keypair for signing transactions */
10
+ wallet: Keypair;
11
+ /** Optional HTTP client config */
12
+ httpConfig?: {
13
+ timeout?: number;
14
+ headers?: Record<string, string>;
15
+ };
16
+ }
17
+ export interface CreateIntentOptions {
18
+ capability: string;
19
+ maxPricePerRequest: number;
20
+ token: SupportedToken;
21
+ maxSessionBudget?: number;
22
+ sessionDurationMs?: number;
23
+ sla?: SLA;
24
+ metadata?: Record<string, any>;
25
+ }
26
+ export interface NegotiateOptions {
27
+ /** Custom headers for the request */
28
+ headers?: Record<string, string>;
29
+ /** Timeout in milliseconds */
30
+ timeout?: number;
31
+ }
32
+ export interface CreateSessionOptions {
33
+ /** Custom deposit amount (defaults to maxSessionBudget from Intent) */
34
+ depositAmount?: number;
35
+ /** Whether to anchor session on-chain (costs extra transaction fee) */
36
+ anchorOnChain?: boolean;
37
+ }
38
+ /**
39
+ * GistClient - Primary interface for Gist Plus protocol
40
+ *
41
+ * Enables AI agents to:
42
+ * 1. Create Intents expressing their needs
43
+ * 2. Negotiate Offers with providers
44
+ * 3. Create prepaid Sessions
45
+ * 4. Execute requests and verify Receipts
46
+ */
47
+ export declare class GistClient {
48
+ private connection;
49
+ private wallet;
50
+ private httpClient;
51
+ private sessionManager;
52
+ constructor(config: GistClientConfig);
53
+ /**
54
+ * Create a new Intent
55
+ */
56
+ createIntent(options: CreateIntentOptions): Intent;
57
+ /**
58
+ * Negotiate an Offer with a provider
59
+ *
60
+ * Sends Intent to provider's endpoint and receives a signed Offer.
61
+ *
62
+ * @param providerEndpoint - Provider's endpoint URL
63
+ * @param intent - Intent object
64
+ * @param options - Negotiation options
65
+ * @returns Signed Offer from provider
66
+ */
67
+ negotiate(providerEndpoint: string, intent: Intent, options?: NegotiateOptions): Promise<Offer>;
68
+ /**
69
+ * Create a Session from an accepted Offer
70
+ *
71
+ * Transfers funds to the provider and creates a prepaid session.
72
+ *
73
+ * @param offer - Accepted Offer
74
+ * @param options - Session creation options
75
+ * @returns Active Session
76
+ */
77
+ createSession(offer: Offer, options?: CreateSessionOptions): Promise<Session>;
78
+ /**
79
+ * Get an active session by ID
80
+ */
81
+ getSession(sessionId: string): Session | undefined;
82
+ /**
83
+ * Execute a request within a Session
84
+ *
85
+ * @param sessionId - Session ID
86
+ * @param requestData - Request payload
87
+ * @returns Response data and Receipt
88
+ */
89
+ executeRequest(sessionId: string, requestData: any): Promise<{
90
+ data: any;
91
+ receipt: Receipt;
92
+ }>;
93
+ /**
94
+ * Close a session and claim refund for remaining balance
95
+ */
96
+ closeSession(sessionId: string): Promise<{
97
+ refundAmount: number;
98
+ txSignature: string;
99
+ }>;
100
+ /**
101
+ * Get all active sessions
102
+ */
103
+ getActiveSessions(): Session[];
104
+ /**
105
+ * Transfer funds to provider (SOL or SPL token)
106
+ */
107
+ private transferFunds;
108
+ /**
109
+ * Calculate default deposit amount from Offer
110
+ */
111
+ private calculateDefaultDeposit;
112
+ /**
113
+ * Get wallet public key
114
+ */
115
+ get publicKey(): PublicKey;
116
+ }
package/dist/client.js ADDED
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ /**
3
+ * GistClient - Main client interface for Gist Plus protocol
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.GistClient = void 0;
7
+ const web3_js_1 = require("@solana/web3.js");
8
+ const spl_token_1 = require("@solana/spl-token");
9
+ const core_1 = require("@gistplus/core");
10
+ const http_client_1 = require("./http-client");
11
+ const session_manager_1 = require("./session-manager");
12
+ /**
13
+ * GistClient - Primary interface for Gist Plus protocol
14
+ *
15
+ * Enables AI agents to:
16
+ * 1. Create Intents expressing their needs
17
+ * 2. Negotiate Offers with providers
18
+ * 3. Create prepaid Sessions
19
+ * 4. Execute requests and verify Receipts
20
+ */
21
+ class GistClient {
22
+ constructor(config) {
23
+ this.connection = config.connection;
24
+ this.wallet = config.wallet;
25
+ this.httpClient = new http_client_1.HttpClient(config.httpConfig);
26
+ this.sessionManager = new session_manager_1.SessionManager(this.connection, this.wallet);
27
+ }
28
+ /**
29
+ * Create a new Intent
30
+ */
31
+ createIntent(options) {
32
+ return (0, core_1.createIntent)({
33
+ ...options,
34
+ agentPubkey: this.wallet.publicKey,
35
+ });
36
+ }
37
+ /**
38
+ * Negotiate an Offer with a provider
39
+ *
40
+ * Sends Intent to provider's endpoint and receives a signed Offer.
41
+ *
42
+ * @param providerEndpoint - Provider's endpoint URL
43
+ * @param intent - Intent object
44
+ * @param options - Negotiation options
45
+ * @returns Signed Offer from provider
46
+ */
47
+ async negotiate(providerEndpoint, intent, options) {
48
+ // Send Intent to provider
49
+ const offer = await this.httpClient.sendIntent(providerEndpoint, intent, options);
50
+ // Verify Offer signature and validity
51
+ (0, core_1.verifyOffer)(offer);
52
+ return offer;
53
+ }
54
+ /**
55
+ * Create a Session from an accepted Offer
56
+ *
57
+ * Transfers funds to the provider and creates a prepaid session.
58
+ *
59
+ * @param offer - Accepted Offer
60
+ * @param options - Session creation options
61
+ * @returns Active Session
62
+ */
63
+ async createSession(offer, options) {
64
+ // Calculate deposit amount
65
+ const depositAmount = options?.depositAmount || this.calculateDefaultDeposit(offer);
66
+ // Transfer funds to provider
67
+ const txSignature = await this.transferFunds(offer.providerPubkey, offer.token, depositAmount);
68
+ // Create session with provider
69
+ const session = await this.httpClient.createSession(offer, depositAmount, txSignature);
70
+ // Register session with manager
71
+ this.sessionManager.registerSession(session);
72
+ return session;
73
+ }
74
+ /**
75
+ * Get an active session by ID
76
+ */
77
+ getSession(sessionId) {
78
+ return this.sessionManager.getSession(sessionId);
79
+ }
80
+ /**
81
+ * Execute a request within a Session
82
+ *
83
+ * @param sessionId - Session ID
84
+ * @param requestData - Request payload
85
+ * @returns Response data and Receipt
86
+ */
87
+ async executeRequest(sessionId, requestData) {
88
+ const session = this.sessionManager.getSession(sessionId);
89
+ if (!session) {
90
+ throw new Error(`Session ${sessionId} not found`);
91
+ }
92
+ // Execute request via HTTP client
93
+ const result = await this.httpClient.executeRequest(session, requestData);
94
+ // Update session state
95
+ this.sessionManager.updateSessionAfterRequest(sessionId, result.receipt);
96
+ return result;
97
+ }
98
+ /**
99
+ * Close a session and claim refund for remaining balance
100
+ */
101
+ async closeSession(sessionId) {
102
+ const session = this.sessionManager.getSession(sessionId);
103
+ if (!session) {
104
+ throw new Error(`Session ${sessionId} not found`);
105
+ }
106
+ // Request refund from provider
107
+ const refundResponse = await this.httpClient.closeSession(session);
108
+ // Mark session as closed
109
+ this.sessionManager.closeSession(sessionId);
110
+ return refundResponse;
111
+ }
112
+ /**
113
+ * Get all active sessions
114
+ */
115
+ getActiveSessions() {
116
+ return this.sessionManager.getActiveSessions();
117
+ }
118
+ /**
119
+ * Transfer funds to provider (SOL or SPL token)
120
+ */
121
+ async transferFunds(providerPubkey, token, amount) {
122
+ const provider = new web3_js_1.PublicKey(providerPubkey);
123
+ if (token === 'SOL') {
124
+ // Transfer SOL
125
+ const transaction = new web3_js_1.Transaction().add(web3_js_1.SystemProgram.transfer({
126
+ fromPubkey: this.wallet.publicKey,
127
+ toPubkey: provider,
128
+ lamports: amount * 1e9, // Convert SOL to lamports
129
+ }));
130
+ const signature = await (0, web3_js_1.sendAndConfirmTransaction)(this.connection, transaction, [this.wallet]);
131
+ return signature;
132
+ }
133
+ else {
134
+ // Transfer SPL token
135
+ const mintAddress = new web3_js_1.PublicKey(core_1.TOKEN_MINTS[token]);
136
+ // Get or create associated token accounts
137
+ const fromTokenAccount = await (0, spl_token_1.getOrCreateAssociatedTokenAccount)(this.connection, this.wallet, mintAddress, this.wallet.publicKey);
138
+ const toTokenAccount = await (0, spl_token_1.getOrCreateAssociatedTokenAccount)(this.connection, this.wallet, mintAddress, provider);
139
+ // Create transfer instruction
140
+ const transaction = new web3_js_1.Transaction().add((0, spl_token_1.createTransferInstruction)(fromTokenAccount.address, toTokenAccount.address, this.wallet.publicKey, amount * 1e6, // Assuming 6 decimals for USDC/USDT
141
+ [], spl_token_1.TOKEN_PROGRAM_ID));
142
+ const signature = await (0, web3_js_1.sendAndConfirmTransaction)(this.connection, transaction, [this.wallet]);
143
+ return signature;
144
+ }
145
+ }
146
+ /**
147
+ * Calculate default deposit amount from Offer
148
+ */
149
+ calculateDefaultDeposit(offer) {
150
+ // Default: enough for 10 requests or session duration worth
151
+ const minRequests = 10;
152
+ return offer.pricePerRequest * minRequests;
153
+ }
154
+ /**
155
+ * Get wallet public key
156
+ */
157
+ get publicKey() {
158
+ return this.wallet.publicKey;
159
+ }
160
+ }
161
+ exports.GistClient = GistClient;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * HTTP Client for Gist Plus protocol communication
3
+ */
4
+ import { Intent, Offer, Session, Receipt } from '@gistplus/core';
5
+ export interface HttpClientConfig {
6
+ timeout?: number;
7
+ headers?: Record<string, string>;
8
+ }
9
+ /**
10
+ * HttpClient handles HTTP communication with Gist Plus providers
11
+ */
12
+ export declare class HttpClient {
13
+ private axios;
14
+ constructor(config?: HttpClientConfig);
15
+ /**
16
+ * Send Intent to provider and receive Offer
17
+ *
18
+ * Makes a request to provider endpoint, receives 402 Quote Required,
19
+ * sends Intent, and receives signed Offer.
20
+ */
21
+ sendIntent(endpoint: string, intent: Intent, options?: {
22
+ headers?: Record<string, string>;
23
+ timeout?: number;
24
+ }): Promise<Offer>;
25
+ /**
26
+ * Create a Session with provider
27
+ */
28
+ createSession(offer: Offer, depositAmount: number, txSignature: string): Promise<Session>;
29
+ /**
30
+ * Execute a request within a Session
31
+ */
32
+ executeRequest(session: Session, requestData: any): Promise<{
33
+ data: any;
34
+ receipt: Receipt;
35
+ }>;
36
+ /**
37
+ * Close a session and request refund
38
+ */
39
+ closeSession(session: Session): Promise<{
40
+ refundAmount: number;
41
+ txSignature: string;
42
+ }>;
43
+ /**
44
+ * Get provider endpoint for session
45
+ */
46
+ private getSessionEndpoint;
47
+ }
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ /**
3
+ * HTTP Client for Gist Plus protocol communication
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.HttpClient = void 0;
10
+ const axios_1 = __importDefault(require("axios"));
11
+ const core_1 = require("@gistplus/core");
12
+ /**
13
+ * HttpClient handles HTTP communication with Gist Plus providers
14
+ */
15
+ class HttpClient {
16
+ constructor(config) {
17
+ this.axios = axios_1.default.create({
18
+ timeout: config?.timeout || 30000,
19
+ headers: {
20
+ 'Content-Type': 'application/json',
21
+ ...config?.headers,
22
+ },
23
+ });
24
+ }
25
+ /**
26
+ * Send Intent to provider and receive Offer
27
+ *
28
+ * Makes a request to provider endpoint, receives 402 Quote Required,
29
+ * sends Intent, and receives signed Offer.
30
+ */
31
+ async sendIntent(endpoint, intent, options) {
32
+ try {
33
+ // Send Intent to provider
34
+ const response = await this.axios.post(endpoint, {}, {
35
+ headers: {
36
+ [core_1.HEADERS.INTENT]: JSON.stringify(intent),
37
+ ...options?.headers,
38
+ },
39
+ timeout: options?.timeout,
40
+ });
41
+ // Provider should respond with Offer in header
42
+ const offerHeader = response.headers[core_1.HEADERS.OFFER.toLowerCase()];
43
+ if (!offerHeader) {
44
+ throw new Error('Provider did not return an Offer');
45
+ }
46
+ const offer = JSON.parse(offerHeader);
47
+ return offer;
48
+ }
49
+ catch (error) {
50
+ if (axios_1.default.isAxiosError(error) && error.response?.status === core_1.HTTP_STATUS.QUOTE_REQUIRED) {
51
+ // Expected 402 response with Offer
52
+ const offerHeader = error.response.headers[core_1.HEADERS.OFFER.toLowerCase()];
53
+ if (offerHeader) {
54
+ const offer = JSON.parse(offerHeader);
55
+ return offer;
56
+ }
57
+ }
58
+ throw new Error(`Failed to negotiate with provider: ${error}`);
59
+ }
60
+ }
61
+ /**
62
+ * Create a Session with provider
63
+ */
64
+ async createSession(offer, depositAmount, txSignature) {
65
+ try {
66
+ const response = await this.axios.post(`${offer.endpoint}/session/create`, {
67
+ offerId: offer.offerId,
68
+ depositAmount,
69
+ txSignature,
70
+ });
71
+ if (response.status !== core_1.HTTP_STATUS.SESSION_STARTED && response.status !== 201) {
72
+ throw new Error(`Unexpected status code: ${response.status}`);
73
+ }
74
+ const session = response.data;
75
+ return session;
76
+ }
77
+ catch (error) {
78
+ throw new Error(`Failed to create session: ${error}`);
79
+ }
80
+ }
81
+ /**
82
+ * Execute a request within a Session
83
+ */
84
+ async executeRequest(session, requestData) {
85
+ try {
86
+ // Get provider endpoint from session metadata or construct it
87
+ const endpoint = this.getSessionEndpoint(session);
88
+ const response = await this.axios.post(endpoint, requestData, {
89
+ headers: {
90
+ [core_1.HEADERS.SESSION_ID]: session.sessionId,
91
+ },
92
+ });
93
+ // Extract receipt from header
94
+ const receiptHeader = response.headers[core_1.HEADERS.RECEIPT.toLowerCase()];
95
+ if (!receiptHeader) {
96
+ throw new Error('Provider did not return a Receipt');
97
+ }
98
+ const receipt = JSON.parse(receiptHeader);
99
+ // Verify receipt signature
100
+ (0, core_1.verifyReceipt)(receipt);
101
+ return {
102
+ data: response.data,
103
+ receipt,
104
+ };
105
+ }
106
+ catch (error) {
107
+ throw new Error(`Failed to execute request: ${error}`);
108
+ }
109
+ }
110
+ /**
111
+ * Close a session and request refund
112
+ */
113
+ async closeSession(session) {
114
+ try {
115
+ const endpoint = this.getSessionEndpoint(session);
116
+ const response = await this.axios.post(`${endpoint}/close`, {
117
+ sessionId: session.sessionId,
118
+ }, {
119
+ headers: {
120
+ [core_1.HEADERS.SESSION_ID]: session.sessionId,
121
+ },
122
+ });
123
+ return response.data;
124
+ }
125
+ catch (error) {
126
+ throw new Error(`Failed to close session: ${error}`);
127
+ }
128
+ }
129
+ /**
130
+ * Get provider endpoint for session
131
+ */
132
+ getSessionEndpoint(session) {
133
+ // In a real implementation, this might be stored in session metadata
134
+ // For now, construct from provider's base endpoint
135
+ return session.metadata?.endpoint || `https://provider/${session.providerPubkey}`;
136
+ }
137
+ }
138
+ exports.HttpClient = HttpClient;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @gistplus/client
3
+ *
4
+ * Client SDK for AI agents and applications to interact with Gist Plus providers.
5
+ * Handles Intent creation, Offer negotiation, Session management, and Receipt verification.
6
+ */
7
+ export * from './client';
8
+ export * from './http-client';
9
+ export * from './session-manager';
10
+ export { Intent, Offer, Session, Receipt, SLA, SessionState, createIntent, verifyOffer, verifyReceipt, SUPPORTED_TOKENS, SupportedToken, } from '@gistplus/core';
package/dist/index.js ADDED
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ /**
3
+ * @gistplus/client
4
+ *
5
+ * Client SDK for AI agents and applications to interact with Gist Plus providers.
6
+ * Handles Intent creation, Offer negotiation, Session management, and Receipt verification.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
20
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.SUPPORTED_TOKENS = exports.verifyReceipt = exports.verifyOffer = exports.createIntent = exports.SessionState = void 0;
24
+ __exportStar(require("./client"), exports);
25
+ __exportStar(require("./http-client"), exports);
26
+ __exportStar(require("./session-manager"), exports);
27
+ // Re-export core types for convenience
28
+ var core_1 = require("@gistplus/core");
29
+ Object.defineProperty(exports, "SessionState", { enumerable: true, get: function () { return core_1.SessionState; } });
30
+ Object.defineProperty(exports, "createIntent", { enumerable: true, get: function () { return core_1.createIntent; } });
31
+ Object.defineProperty(exports, "verifyOffer", { enumerable: true, get: function () { return core_1.verifyOffer; } });
32
+ Object.defineProperty(exports, "verifyReceipt", { enumerable: true, get: function () { return core_1.verifyReceipt; } });
33
+ Object.defineProperty(exports, "SUPPORTED_TOKENS", { enumerable: true, get: function () { return core_1.SUPPORTED_TOKENS; } });
@@ -0,0 +1,50 @@
1
+ /**
2
+ * SessionManager - Manages active sessions and their state
3
+ */
4
+ import { Connection, Keypair } from '@solana/web3.js';
5
+ import { Session, Receipt } from '@gistplus/core';
6
+ /**
7
+ * SessionManager tracks and manages active Gist Plus sessions
8
+ */
9
+ export declare class SessionManager {
10
+ private sessions;
11
+ private connection;
12
+ private wallet;
13
+ constructor(connection: Connection, wallet: Keypair);
14
+ /**
15
+ * Register a new session
16
+ */
17
+ registerSession(session: Session): void;
18
+ /**
19
+ * Get a session by ID
20
+ */
21
+ getSession(sessionId: string): Session | undefined;
22
+ /**
23
+ * Update session after a request is completed
24
+ */
25
+ updateSessionAfterRequest(sessionId: string, receipt: Receipt): void;
26
+ /**
27
+ * Close a session
28
+ */
29
+ closeSession(sessionId: string): void;
30
+ /**
31
+ * Get all active sessions
32
+ */
33
+ getActiveSessions(): Session[];
34
+ /**
35
+ * Get all sessions
36
+ */
37
+ getAllSessions(): Session[];
38
+ /**
39
+ * Clean up expired sessions
40
+ */
41
+ private cleanup;
42
+ /**
43
+ * Start background cleanup task
44
+ */
45
+ private startCleanupTask;
46
+ /**
47
+ * Get session count
48
+ */
49
+ getSessionCount(): number;
50
+ }
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ /**
3
+ * SessionManager - Manages active sessions and their state
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SessionManager = void 0;
7
+ const core_1 = require("@gistplus/core");
8
+ /**
9
+ * SessionManager tracks and manages active Gist Plus sessions
10
+ */
11
+ class SessionManager {
12
+ constructor(connection, wallet) {
13
+ this.sessions = new Map();
14
+ this.connection = connection;
15
+ this.wallet = wallet;
16
+ // Start background cleanup task
17
+ this.startCleanupTask();
18
+ }
19
+ /**
20
+ * Register a new session
21
+ */
22
+ registerSession(session) {
23
+ this.sessions.set(session.sessionId, session);
24
+ }
25
+ /**
26
+ * Get a session by ID
27
+ */
28
+ getSession(sessionId) {
29
+ const session = this.sessions.get(sessionId);
30
+ if (!session) {
31
+ return undefined;
32
+ }
33
+ // Check if session has expired and update state
34
+ if (!(0, core_1.isSessionActive)(session) && session.state === core_1.SessionState.ACTIVE) {
35
+ const expiredSession = (0, core_1.expireSession)(session);
36
+ this.sessions.set(sessionId, expiredSession);
37
+ return expiredSession;
38
+ }
39
+ return session;
40
+ }
41
+ /**
42
+ * Update session after a request is completed
43
+ */
44
+ updateSessionAfterRequest(sessionId, receipt) {
45
+ const session = this.sessions.get(sessionId);
46
+ if (!session) {
47
+ throw new Error(`Session ${sessionId} not found`);
48
+ }
49
+ // Deduct amount from session
50
+ const updatedSession = (0, core_1.deductFromSession)(session, receipt.amountCharged);
51
+ this.sessions.set(sessionId, updatedSession);
52
+ }
53
+ /**
54
+ * Close a session
55
+ */
56
+ closeSession(sessionId) {
57
+ this.sessions.delete(sessionId);
58
+ }
59
+ /**
60
+ * Get all active sessions
61
+ */
62
+ getActiveSessions() {
63
+ const activeSessions = [];
64
+ for (const session of this.sessions.values()) {
65
+ if ((0, core_1.isSessionActive)(session)) {
66
+ activeSessions.push(session);
67
+ }
68
+ }
69
+ return activeSessions;
70
+ }
71
+ /**
72
+ * Get all sessions
73
+ */
74
+ getAllSessions() {
75
+ return Array.from(this.sessions.values());
76
+ }
77
+ /**
78
+ * Clean up expired sessions
79
+ */
80
+ cleanup() {
81
+ const now = Date.now();
82
+ for (const [sessionId, session] of this.sessions.entries()) {
83
+ if (session.state === core_1.SessionState.EXPIRED || now > session.expiresAt) {
84
+ // Keep expired sessions for a grace period (1 hour)
85
+ if (now > session.expiresAt + 3600000) {
86
+ this.sessions.delete(sessionId);
87
+ }
88
+ }
89
+ }
90
+ }
91
+ /**
92
+ * Start background cleanup task
93
+ */
94
+ startCleanupTask() {
95
+ // Clean up every 5 minutes
96
+ setInterval(() => {
97
+ this.cleanup();
98
+ }, 300000);
99
+ }
100
+ /**
101
+ * Get session count
102
+ */
103
+ getSessionCount() {
104
+ return this.sessions.size;
105
+ }
106
+ }
107
+ exports.SessionManager = SessionManager;
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@gistplus/client",
3
+ "version": "0.1.0",
4
+ "description": "Client SDK for Gist Plus - enables agents and applications to negotiate, transact, and verify with providers",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "test": "jest",
17
+ "clean": "rimraf dist"
18
+ },
19
+ "keywords": [
20
+ "gistplus",
21
+ "gist",
22
+ "client",
23
+ "solana",
24
+ "ai-agents",
25
+ "payments"
26
+ ],
27
+ "author": "Gist Plus",
28
+ "license": "Apache-2.0",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/gistplus/gistplus"
32
+ },
33
+ "homepage": "https://github.com/gistplus/gistplus#readme",
34
+ "bugs": {
35
+ "url": "https://github.com/gistplus/gistplus/issues"
36
+ },
37
+ "dependencies": {
38
+ "@gistplus/core": "^0.1.0",
39
+ "@solana/web3.js": "^1.87.6",
40
+ "@solana/spl-token": "^0.3.9",
41
+ "axios": "^1.6.5"
42
+ },
43
+ "devDependencies": {
44
+ "typescript": "^5.3.3",
45
+ "@types/node": "^20.10.6",
46
+ "jest": "^29.7.0",
47
+ "@types/jest": "^29.5.11",
48
+ "rimraf": "^5.0.5"
49
+ }
50
+ }