@nosana/kit 0.1.1 → 0.1.3
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/.gitlab-ci.yml +6 -5
- package/dist/config/defaultConfigs.js +15 -18
- package/dist/config/index.js +3 -19
- package/dist/config/types.d.ts +1 -3
- package/dist/config/types.js +4 -7
- package/dist/config/utils.js +8 -13
- package/dist/errors/NosanaError.d.ts +1 -0
- package/dist/errors/NosanaError.js +3 -6
- package/dist/generated_clients/jobs/accounts/index.js +3 -19
- package/dist/generated_clients/jobs/accounts/jobAccount.js +46 -59
- package/dist/generated_clients/jobs/accounts/marketAccount.js +45 -57
- package/dist/generated_clients/jobs/accounts/runAccount.js +36 -49
- package/dist/generated_clients/jobs/errors/index.js +1 -17
- package/dist/generated_clients/jobs/errors/nosanaJobs.js +43 -48
- package/dist/generated_clients/jobs/index.js +5 -21
- package/dist/generated_clients/jobs/instructions/claim.js +17 -26
- package/dist/generated_clients/jobs/instructions/clean.js +17 -26
- package/dist/generated_clients/jobs/instructions/cleanAdmin.js +17 -26
- package/dist/generated_clients/jobs/instructions/close.js +17 -26
- package/dist/generated_clients/jobs/instructions/closeAdmin.js +17 -26
- package/dist/generated_clients/jobs/instructions/complete.js +21 -30
- package/dist/generated_clients/jobs/instructions/delist.js +17 -26
- package/dist/generated_clients/jobs/instructions/end.js +17 -26
- package/dist/generated_clients/jobs/instructions/extend.js +21 -30
- package/dist/generated_clients/jobs/instructions/finish.js +21 -30
- package/dist/generated_clients/jobs/instructions/index.js +18 -34
- package/dist/generated_clients/jobs/instructions/list.js +23 -32
- package/dist/generated_clients/jobs/instructions/open.js +29 -38
- package/dist/generated_clients/jobs/instructions/quit.js +17 -26
- package/dist/generated_clients/jobs/instructions/quitAdmin.js +17 -26
- package/dist/generated_clients/jobs/instructions/recover.js +17 -26
- package/dist/generated_clients/jobs/instructions/stop.js +17 -26
- package/dist/generated_clients/jobs/instructions/update.js +29 -38
- package/dist/generated_clients/jobs/instructions/work.js +17 -26
- package/dist/generated_clients/jobs/programs/index.js +1 -17
- package/dist/generated_clients/jobs/programs/nosanaJobs.js +29 -34
- package/dist/generated_clients/jobs/shared/index.js +13 -21
- package/dist/generated_clients/jobs/types/index.js +3 -19
- package/dist/generated_clients/jobs/types/jobState.js +9 -15
- package/dist/generated_clients/jobs/types/jobType.js +9 -15
- package/dist/generated_clients/jobs/types/queueType.js +9 -15
- package/dist/index.d.ts +5 -1
- package/dist/index.js +152 -36
- package/dist/ipfs/IPFS.js +5 -12
- package/dist/logger/Logger.js +1 -5
- package/dist/programs/BaseProgram.js +1 -5
- package/dist/programs/JobsProgram.d.ts +2 -3
- package/dist/programs/JobsProgram.js +35 -99
- package/dist/solana/SolanaUtils.d.ts +15 -1
- package/dist/solana/SolanaUtils.js +78 -14
- package/dist/utils/index.js +1 -4
- package/examples/browser/.gitlab-ci.yml +78 -0
- package/examples/browser/FEATURES.md +141 -0
- package/examples/browser/QUICK_START.md +76 -0
- package/examples/browser/README.md +182 -0
- package/examples/browser/app.vue +1840 -0
- package/examples/browser/assets/css/main.css +7 -0
- package/examples/browser/nuxt.config.ts +24 -0
- package/examples/browser/package-lock.json +11467 -0
- package/examples/browser/package.json +31 -0
- package/examples/browser/public/favicon.ico +0 -0
- package/examples/browser/public/robots.txt +2 -0
- package/examples/browser/start.sh +38 -0
- package/examples/browser/tailwind.config.js +26 -0
- package/examples/node/README.md +146 -0
- package/examples/node/example-keypair.json +1 -0
- package/examples/node/package-lock.json +500 -156
- package/examples/node/package.json +5 -3
- package/examples/node/post-job.ts +160 -0
- package/examples/node/set-wallet.ts +87 -0
- package/package.json +3 -1
|
@@ -1,51 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.JobsProgram = void 0;
|
|
40
|
-
const BaseProgram_js_1 = require("./BaseProgram.js");
|
|
41
|
-
const gill_1 = require("gill");
|
|
42
|
-
const index_js_1 = require("../index.js");
|
|
43
|
-
const programClient = __importStar(require("../generated_clients/jobs/index.js"));
|
|
44
|
-
const token_1 = require("@solana-program/token");
|
|
45
|
-
const bs58_1 = __importDefault(require("bs58"));
|
|
46
|
-
const IPFS_js_1 = require("../ipfs/IPFS.js");
|
|
47
|
-
const index_js_2 = require("../utils/index.js");
|
|
48
|
-
class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
1
|
+
import { BaseProgram } from './BaseProgram.js';
|
|
2
|
+
import { generateKeyPairSigner, parseBase64RpcAccount } from 'gill';
|
|
3
|
+
import { ErrorCodes, NosanaError } from '../index.js';
|
|
4
|
+
import * as programClient from "../generated_clients/jobs/index.js";
|
|
5
|
+
import { findAssociatedTokenPda, TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';
|
|
6
|
+
import bs58 from 'bs58';
|
|
7
|
+
import { IPFS } from '../ipfs/IPFS.js';
|
|
8
|
+
import { convertBigIntToNumber } from '../utils/index.js';
|
|
9
|
+
export class JobsProgram extends BaseProgram {
|
|
49
10
|
constructor(sdk) {
|
|
50
11
|
super(sdk);
|
|
51
12
|
this.client = programClient;
|
|
@@ -144,7 +105,7 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
144
105
|
extraGPAFilters.push({
|
|
145
106
|
memcmp: {
|
|
146
107
|
offset: BigInt(208),
|
|
147
|
-
bytes:
|
|
108
|
+
bytes: bs58.encode(Buffer.from([filters.state])),
|
|
148
109
|
encoding: "base58",
|
|
149
110
|
},
|
|
150
111
|
});
|
|
@@ -184,7 +145,7 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
184
145
|
{
|
|
185
146
|
memcmp: {
|
|
186
147
|
offset: BigInt(0),
|
|
187
|
-
bytes:
|
|
148
|
+
bytes: bs58.encode(Buffer.from(programClient.JOB_ACCOUNT_DISCRIMINATOR)),
|
|
188
149
|
encoding: "base58",
|
|
189
150
|
},
|
|
190
151
|
},
|
|
@@ -195,7 +156,7 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
195
156
|
const jobs = getProgramAccountsResponse
|
|
196
157
|
.map((result) => {
|
|
197
158
|
try {
|
|
198
|
-
const jobAccount = programClient.decodeJobAccount(
|
|
159
|
+
const jobAccount = programClient.decodeJobAccount(parseBase64RpcAccount(result.pubkey, result.account));
|
|
199
160
|
return this.transformJobAccount(jobAccount);
|
|
200
161
|
}
|
|
201
162
|
catch (err) {
|
|
@@ -257,7 +218,7 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
257
218
|
{
|
|
258
219
|
memcmp: {
|
|
259
220
|
offset: BigInt(0),
|
|
260
|
-
bytes:
|
|
221
|
+
bytes: bs58.encode(Buffer.from(programClient.RUN_ACCOUNT_DISCRIMINATOR)),
|
|
261
222
|
encoding: "base58",
|
|
262
223
|
},
|
|
263
224
|
},
|
|
@@ -267,7 +228,7 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
267
228
|
const runAccounts = getProgramAccountsResponse
|
|
268
229
|
.map((result) => {
|
|
269
230
|
try {
|
|
270
|
-
const runAccount = programClient.decodeRunAccount(
|
|
231
|
+
const runAccount = programClient.decodeRunAccount(parseBase64RpcAccount(result.pubkey, result.account));
|
|
271
232
|
return this.transformRunAccount(runAccount);
|
|
272
233
|
}
|
|
273
234
|
catch (err) {
|
|
@@ -295,7 +256,7 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
295
256
|
{
|
|
296
257
|
memcmp: {
|
|
297
258
|
offset: BigInt(0),
|
|
298
|
-
bytes:
|
|
259
|
+
bytes: bs58.encode(Buffer.from(programClient.MARKET_ACCOUNT_DISCRIMINATOR)),
|
|
299
260
|
encoding: "base58",
|
|
300
261
|
},
|
|
301
262
|
},
|
|
@@ -305,7 +266,7 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
305
266
|
const marketAccounts = getProgramAccountsResponse
|
|
306
267
|
.map((result) => {
|
|
307
268
|
try {
|
|
308
|
-
const marketAccount = programClient.decodeMarketAccount(
|
|
269
|
+
const marketAccount = programClient.decodeMarketAccount(parseBase64RpcAccount(result.pubkey, result.account));
|
|
309
270
|
return this.transformMarketAccount(marketAccount);
|
|
310
271
|
}
|
|
311
272
|
catch (err) {
|
|
@@ -327,15 +288,12 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
327
288
|
* @returns The transaction signature
|
|
328
289
|
*/
|
|
329
290
|
async post(params) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const jobKey = await (0, gill_1.generateKeyPairSigner)();
|
|
334
|
-
const runKey = await (0, gill_1.generateKeyPairSigner)();
|
|
335
|
-
const [associatedTokenAddress] = await (0, token_1.findAssociatedTokenPda)({
|
|
291
|
+
const jobKey = await generateKeyPairSigner();
|
|
292
|
+
const runKey = await generateKeyPairSigner();
|
|
293
|
+
const [associatedTokenAddress] = await findAssociatedTokenPda({
|
|
336
294
|
mint: this.sdk.config.programs.nosTokenAddress,
|
|
337
|
-
owner: this.sdk.
|
|
338
|
-
tokenProgram:
|
|
295
|
+
owner: this.sdk.wallet.address,
|
|
296
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS
|
|
339
297
|
});
|
|
340
298
|
try {
|
|
341
299
|
const staticAccounts = await this.getStaticAccounts();
|
|
@@ -349,41 +307,20 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
349
307
|
params.market,
|
|
350
308
|
this.sdk.config.programs.nosTokenAddress,
|
|
351
309
|
], staticAccounts.jobsProgram),
|
|
352
|
-
payer: this.sdk.
|
|
310
|
+
payer: this.sdk.wallet,
|
|
353
311
|
rewardsReflection: staticAccounts.rewardsReflection,
|
|
354
312
|
rewardsVault: staticAccounts.rewardsVault,
|
|
355
|
-
authority: this.sdk.
|
|
313
|
+
authority: this.sdk.wallet,
|
|
356
314
|
rewardsProgram: staticAccounts.rewardsProgram,
|
|
357
|
-
ipfsJob:
|
|
315
|
+
ipfsJob: bs58.decode(params.ipfsHash).subarray(2),
|
|
358
316
|
timeout: params.timeout
|
|
359
317
|
});
|
|
360
|
-
|
|
361
|
-
return instruction;
|
|
362
|
-
// Create the transaction
|
|
363
|
-
const transaction = (0, gill_1.createTransaction)({
|
|
364
|
-
instructions: [instruction],
|
|
365
|
-
feePayer: this.sdk.config.wallet.signer,
|
|
366
|
-
latestBlockhash: await this.sdk.solana.getLatestBlockhash(),
|
|
367
|
-
version: 0,
|
|
368
|
-
});
|
|
369
|
-
// Sign the transaction with all required signers
|
|
370
|
-
const signedTransaction = await (0, gill_1.signTransactionMessageWithSigners)(transaction);
|
|
371
|
-
// Get the transaction signature for logging
|
|
372
|
-
const signature = (0, gill_1.getSignatureFromTransaction)(signedTransaction);
|
|
373
|
-
// Log the transaction explorer link
|
|
374
|
-
const explorerLink = (0, gill_1.getExplorerLink)({
|
|
375
|
-
cluster: this.sdk.config.solana.cluster,
|
|
376
|
-
transaction: signature
|
|
377
|
-
});
|
|
378
|
-
this.sdk.logger.info(`Sending list job transaction: ${explorerLink}`);
|
|
379
|
-
// Send and confirm the transaction
|
|
380
|
-
await this.sdk.solana.sendAndConfirmTransaction(signedTransaction);
|
|
381
|
-
this.sdk.logger.info("Job listing transaction confirmed!");
|
|
382
|
-
return signature;
|
|
318
|
+
return instruction;
|
|
383
319
|
}
|
|
384
320
|
catch (err) {
|
|
385
|
-
|
|
386
|
-
|
|
321
|
+
const errorMessage = `Failed to create list instruction: ${err instanceof Error ? err.message : String(err)}`;
|
|
322
|
+
this.sdk.logger.error(errorMessage);
|
|
323
|
+
throw new Error(errorMessage);
|
|
387
324
|
}
|
|
388
325
|
}
|
|
389
326
|
/**
|
|
@@ -462,7 +399,7 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
462
399
|
}
|
|
463
400
|
catch (error) {
|
|
464
401
|
this.sdk.logger.error(`Failed to start monitoring job program accounts: ${error}`);
|
|
465
|
-
throw new
|
|
402
|
+
throw new NosanaError('Failed to start monitoring job program accounts', ErrorCodes.RPC_ERROR, error);
|
|
466
403
|
}
|
|
467
404
|
}
|
|
468
405
|
/**
|
|
@@ -519,9 +456,9 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
519
456
|
const { discriminator: _, ...jobAccountData } = jobAccount.data;
|
|
520
457
|
return {
|
|
521
458
|
address: jobAccount.address,
|
|
522
|
-
...
|
|
523
|
-
ipfsJob:
|
|
524
|
-
ipfsResult:
|
|
459
|
+
...convertBigIntToNumber(jobAccountData),
|
|
460
|
+
ipfsJob: IPFS.solHashToIpfsHash(jobAccountData.ipfsJob),
|
|
461
|
+
ipfsResult: IPFS.solHashToIpfsHash(jobAccountData.ipfsResult),
|
|
525
462
|
};
|
|
526
463
|
}
|
|
527
464
|
transformRunAccount(runAccount) {
|
|
@@ -529,7 +466,7 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
529
466
|
const { discriminator: _, ...runAccountData } = runAccount.data;
|
|
530
467
|
return {
|
|
531
468
|
address: runAccount.address,
|
|
532
|
-
...
|
|
469
|
+
...convertBigIntToNumber(runAccountData),
|
|
533
470
|
};
|
|
534
471
|
}
|
|
535
472
|
transformMarketAccount(marketAccount) {
|
|
@@ -537,7 +474,7 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
537
474
|
const { discriminator: _, ...marketAccountData } = marketAccount.data;
|
|
538
475
|
return {
|
|
539
476
|
address: marketAccount.address,
|
|
540
|
-
...
|
|
477
|
+
...convertBigIntToNumber(marketAccountData),
|
|
541
478
|
};
|
|
542
479
|
}
|
|
543
480
|
/**
|
|
@@ -546,7 +483,7 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
546
483
|
async handleAccountUpdate(accountData, options, isMonitoring) {
|
|
547
484
|
try {
|
|
548
485
|
const { account, pubkey } = accountData;
|
|
549
|
-
const encodedAccount =
|
|
486
|
+
const encodedAccount = parseBase64RpcAccount(pubkey, account);
|
|
550
487
|
const accountType = programClient.identifyNosanaJobsAccount(encodedAccount);
|
|
551
488
|
switch (accountType) {
|
|
552
489
|
case programClient.NosanaJobsAccount.JobAccount:
|
|
@@ -608,4 +545,3 @@ class JobsProgram extends BaseProgram_js_1.BaseProgram {
|
|
|
608
545
|
this.sdk.logger.debug(`Processed run account ${runAccount.address.toString()}`);
|
|
609
546
|
}
|
|
610
547
|
}
|
|
611
|
-
exports.JobsProgram = JobsProgram;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Address, SolanaClient } from 'gill';
|
|
1
|
+
import { Address, SolanaClient, Signature, IInstruction, TransactionMessageWithBlockhashLifetime, CompilableTransactionMessage, FullySignedTransaction, TransactionWithBlockhashLifetime } from 'gill';
|
|
2
2
|
import { NosanaClient } from '../index.js';
|
|
3
3
|
export declare class SolanaUtils {
|
|
4
4
|
private readonly sdk;
|
|
@@ -12,4 +12,18 @@ export declare class SolanaUtils {
|
|
|
12
12
|
blockhash: import("gill").Blockhash;
|
|
13
13
|
lastValidBlockHeight: bigint;
|
|
14
14
|
}>>;
|
|
15
|
+
/**
|
|
16
|
+
* Type guard to check if the input is a transaction
|
|
17
|
+
*/
|
|
18
|
+
private isTransaction;
|
|
19
|
+
/**
|
|
20
|
+
* Type guard to check if the input is a signed transaction
|
|
21
|
+
*/
|
|
22
|
+
private isSignedTransaction;
|
|
23
|
+
/**
|
|
24
|
+
* Create, sign, and send a transaction with proper logging and error handling
|
|
25
|
+
* @param instructionsOrTransaction Single instruction, array of instructions, or pre-built transaction
|
|
26
|
+
* @returns The transaction signature
|
|
27
|
+
*/
|
|
28
|
+
send(instructionsOrTransaction: IInstruction | IInstruction[] | CompilableTransactionMessage & TransactionMessageWithBlockhashLifetime | FullySignedTransaction & TransactionWithBlockhashLifetime): Promise<Signature>;
|
|
15
29
|
}
|
|
@@ -1,22 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const gill_1 = require("gill");
|
|
5
|
-
const NosanaError_js_1 = require("../errors/NosanaError.js");
|
|
6
|
-
class SolanaUtils {
|
|
1
|
+
import { createSolanaClient, address, getProgramDerivedAddress, getAddressEncoder, createTransaction, signTransactionMessageWithSigners, getExplorerLink, getSignatureFromTransaction } from 'gill';
|
|
2
|
+
import { NosanaError, ErrorCodes } from '../errors/NosanaError.js';
|
|
3
|
+
export class SolanaUtils {
|
|
7
4
|
constructor(sdk) {
|
|
8
5
|
this.sdk = sdk;
|
|
9
6
|
const rpcEndpoint = this.sdk.config.solana.rpcEndpoint;
|
|
10
7
|
if (!rpcEndpoint)
|
|
11
|
-
throw new
|
|
12
|
-
const { rpc, rpcSubscriptions, sendAndConfirmTransaction } =
|
|
8
|
+
throw new NosanaError('RPC URL is required', ErrorCodes.INVALID_CONFIG);
|
|
9
|
+
const { rpc, rpcSubscriptions, sendAndConfirmTransaction } = createSolanaClient({ urlOrMoniker: rpcEndpoint });
|
|
13
10
|
this.rpc = rpc;
|
|
14
11
|
this.rpcSubscriptions = rpcSubscriptions;
|
|
15
12
|
this.sendAndConfirmTransaction = sendAndConfirmTransaction;
|
|
16
13
|
}
|
|
17
14
|
async pda(seeds, programId) {
|
|
18
|
-
const addressEncoder =
|
|
19
|
-
const [pda] = await
|
|
15
|
+
const addressEncoder = getAddressEncoder();
|
|
16
|
+
const [pda] = await getProgramDerivedAddress({
|
|
20
17
|
programAddress: programId,
|
|
21
18
|
seeds: seeds.map(seed => typeof seed !== 'string' ? addressEncoder.encode(seed) : seed),
|
|
22
19
|
});
|
|
@@ -25,13 +22,13 @@ class SolanaUtils {
|
|
|
25
22
|
async getBalance(addressStr) {
|
|
26
23
|
try {
|
|
27
24
|
this.sdk.logger.debug(`Getting balance for address: ${addressStr}`);
|
|
28
|
-
const addr =
|
|
25
|
+
const addr = address(addressStr);
|
|
29
26
|
const balance = await this.rpc.getBalance(addr).send();
|
|
30
27
|
return balance.value;
|
|
31
28
|
}
|
|
32
29
|
catch (error) {
|
|
33
30
|
this.sdk.logger.error(`Failed to get balance: ${error}`);
|
|
34
|
-
throw new
|
|
31
|
+
throw new NosanaError('Failed to get balance', ErrorCodes.RPC_ERROR, error);
|
|
35
32
|
}
|
|
36
33
|
}
|
|
37
34
|
async getLatestBlockhash() {
|
|
@@ -41,8 +38,75 @@ class SolanaUtils {
|
|
|
41
38
|
}
|
|
42
39
|
catch (error) {
|
|
43
40
|
this.sdk.logger.error(`Failed to get latest blockhash: ${error}`);
|
|
44
|
-
throw new
|
|
41
|
+
throw new NosanaError('Failed to get latest blockhash', ErrorCodes.RPC_ERROR, error);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Type guard to check if the input is a transaction
|
|
46
|
+
*/
|
|
47
|
+
isTransaction(input) {
|
|
48
|
+
return 'instructions' in input && 'version' in input && !('programAddress' in input);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Type guard to check if the input is a signed transaction
|
|
52
|
+
*/
|
|
53
|
+
isSignedTransaction(input) {
|
|
54
|
+
return 'signatures' in input && input.signatures && input.signatures.length > 0;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Create, sign, and send a transaction with proper logging and error handling
|
|
58
|
+
* @param instructionsOrTransaction Single instruction, array of instructions, or pre-built transaction
|
|
59
|
+
* @returns The transaction signature
|
|
60
|
+
*/
|
|
61
|
+
async send(instructionsOrTransaction) {
|
|
62
|
+
if (!this.sdk.wallet) {
|
|
63
|
+
throw new NosanaError('No wallet found', ErrorCodes.NO_WALLET);
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
let signedTransaction;
|
|
67
|
+
// Check if it's already a transaction or if we need to create one from instructions
|
|
68
|
+
if (this.isTransaction(instructionsOrTransaction)) {
|
|
69
|
+
// Check if it's already signed
|
|
70
|
+
if (this.isSignedTransaction(instructionsOrTransaction)) {
|
|
71
|
+
// Already signed, use it directly
|
|
72
|
+
signedTransaction = instructionsOrTransaction;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// Not signed yet, sign it
|
|
76
|
+
signedTransaction = await signTransactionMessageWithSigners(instructionsOrTransaction);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
// It's instructions, create and sign a transaction
|
|
81
|
+
const instructions = Array.isArray(instructionsOrTransaction)
|
|
82
|
+
? instructionsOrTransaction
|
|
83
|
+
: [instructionsOrTransaction];
|
|
84
|
+
const transaction = createTransaction({
|
|
85
|
+
instructions,
|
|
86
|
+
feePayer: this.sdk.wallet,
|
|
87
|
+
latestBlockhash: await this.getLatestBlockhash(),
|
|
88
|
+
version: 0,
|
|
89
|
+
});
|
|
90
|
+
// Sign the transaction with all required signers
|
|
91
|
+
signedTransaction = await signTransactionMessageWithSigners(transaction);
|
|
92
|
+
}
|
|
93
|
+
// Get the transaction signature for logging
|
|
94
|
+
const signature = getSignatureFromTransaction(signedTransaction);
|
|
95
|
+
// Log the transaction explorer link
|
|
96
|
+
const explorerLink = getExplorerLink({
|
|
97
|
+
cluster: this.sdk.config.solana.cluster,
|
|
98
|
+
transaction: signature
|
|
99
|
+
});
|
|
100
|
+
this.sdk.logger.info(`Sending transaction: ${explorerLink}`);
|
|
101
|
+
// Send and confirm the transaction
|
|
102
|
+
await this.sendAndConfirmTransaction(signedTransaction);
|
|
103
|
+
this.sdk.logger.info('Transaction confirmed!');
|
|
104
|
+
return signature;
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
const errorMessage = `Failed to send transaction: ${err instanceof Error ? err.message : String(err)}`;
|
|
108
|
+
this.sdk.logger.error(errorMessage);
|
|
109
|
+
throw new Error(errorMessage);
|
|
45
110
|
}
|
|
46
111
|
}
|
|
47
112
|
}
|
|
48
|
-
exports.SolanaUtils = SolanaUtils;
|
package/dist/utils/index.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.convertBigIntToNumber = convertBigIntToNumber;
|
|
4
1
|
/**
|
|
5
2
|
* Helper function to convert bigint values to numbers in an object
|
|
6
3
|
* @param obj Object that may contain bigint values
|
|
7
4
|
* @returns Object with all bigint values converted to numbers
|
|
8
5
|
*/
|
|
9
|
-
function convertBigIntToNumber(obj) {
|
|
6
|
+
export function convertBigIntToNumber(obj) {
|
|
10
7
|
const result = { ...obj };
|
|
11
8
|
for (const [key, value] of Object.entries(result)) {
|
|
12
9
|
if (typeof value === 'bigint') {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
include:
|
|
2
|
+
- project: nosana-ci/tools/cicd/gitlab-ci
|
|
3
|
+
file: templates/semver.yml
|
|
4
|
+
- project: nosana-ci/tools/cicd/gitlab-ci
|
|
5
|
+
file: templates/cacheflush.yml
|
|
6
|
+
|
|
7
|
+
variables:
|
|
8
|
+
NODE_VERSION: 22
|
|
9
|
+
OUTPUT_DIR: examples/browser/.output/public
|
|
10
|
+
PURGE_FILE: examples/browser/purge.json
|
|
11
|
+
|
|
12
|
+
.npm:
|
|
13
|
+
image: node:$NODE_VERSION
|
|
14
|
+
cache:
|
|
15
|
+
key:
|
|
16
|
+
files:
|
|
17
|
+
- examples/browser/package-lock.json
|
|
18
|
+
paths:
|
|
19
|
+
- examples/browser/node_modules
|
|
20
|
+
- examples/browser/.npm
|
|
21
|
+
|
|
22
|
+
build:
|
|
23
|
+
extends: .npm
|
|
24
|
+
stage: build
|
|
25
|
+
before_script:
|
|
26
|
+
- cd examples/browser
|
|
27
|
+
script: npm ci --cache .npm --prefer-offline
|
|
28
|
+
rules:
|
|
29
|
+
- if: $CI_MERGE_REQUEST_ID # merge requests
|
|
30
|
+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # main
|
|
31
|
+
- if: $DEPLOYMENT_BRANCH && $CI_COMMIT_BRANCH == $DEPLOYMENT_BRANCH # optional deployment branch
|
|
32
|
+
|
|
33
|
+
pages:
|
|
34
|
+
extends: .npm
|
|
35
|
+
stage: deploy
|
|
36
|
+
before_script:
|
|
37
|
+
- cd examples/browser
|
|
38
|
+
script:
|
|
39
|
+
- NODE_OPTIONS=--max_old_space_size=25384 npm run generate
|
|
40
|
+
- |
|
|
41
|
+
if [ -z ${SKIP_CACHEFLUSH} ] && [ -n ${FQDN} ]
|
|
42
|
+
then
|
|
43
|
+
apt update
|
|
44
|
+
apt install -y jq
|
|
45
|
+
find $OUTPUT_DIR -type f | sed "s/${OUTPUT_DIR//\//\\/}/https:\/\/$FQDN/g" | jq -R -s -c 'split("\n")[:-1]' > $PURGE_FILE
|
|
46
|
+
fi
|
|
47
|
+
- mv $OUTPUT_DIR public
|
|
48
|
+
artifacts:
|
|
49
|
+
paths:
|
|
50
|
+
- public
|
|
51
|
+
- $PURGE_FILE
|
|
52
|
+
rules:
|
|
53
|
+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $AUTO_DEPLOY != null # main
|
|
54
|
+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $AUTO_DEPLOY == null # main
|
|
55
|
+
when: manual
|
|
56
|
+
- if: $DEPLOYMENT_BRANCH && $CI_COMMIT_BRANCH == $DEPLOYMENT_BRANCH && $AUTO_DEPLOY != null # deployment branch
|
|
57
|
+
- if: $DEPLOYMENT_BRANCH && $CI_COMMIT_BRANCH == $DEPLOYMENT_BRANCH && $AUTO_DEPLOY == null # deployment branch
|
|
58
|
+
when: manual
|
|
59
|
+
|
|
60
|
+
release:
|
|
61
|
+
extends: .release
|
|
62
|
+
stage: .post
|
|
63
|
+
rules:
|
|
64
|
+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # main
|
|
65
|
+
- if: $DEPLOYMENT_BRANCH && $CI_COMMIT_BRANCH == $DEPLOYMENT_BRANCH # optional deployment branch
|
|
66
|
+
|
|
67
|
+
gitlab-release:
|
|
68
|
+
extends: .gitlab-release
|
|
69
|
+
stage: .post
|
|
70
|
+
|
|
71
|
+
cacheflush:
|
|
72
|
+
extends: .cacheflush
|
|
73
|
+
stage: .post
|
|
74
|
+
rules:
|
|
75
|
+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # main
|
|
76
|
+
- if: $DEPLOYMENT_BRANCH && $CI_COMMIT_BRANCH == $DEPLOYMENT_BRANCH # optional deployment branch
|
|
77
|
+
|
|
78
|
+
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Nosana SDK Browser Playground - Features
|
|
2
|
+
|
|
3
|
+
This interactive documentation site provides a comprehensive testing environment for the Nosana SDK with the following features:
|
|
4
|
+
|
|
5
|
+
## 🎯 Core Features
|
|
6
|
+
|
|
7
|
+
### 1. **Interactive SDK Testing**
|
|
8
|
+
- Test all major SDK functions through a user-friendly web interface
|
|
9
|
+
- No need to write code - just click buttons and see results
|
|
10
|
+
- Perfect for developers learning the SDK or testing specific functionality
|
|
11
|
+
|
|
12
|
+
### 2. **Network Management**
|
|
13
|
+
- **Mainnet/Devnet Switching**: Easily switch between networks with a dropdown
|
|
14
|
+
- **Connection Status**: Real-time connection indicator
|
|
15
|
+
- **Automatic Reinitialization**: SDK automatically reinitializes when switching networks
|
|
16
|
+
|
|
17
|
+
### 3. **Job Operations**
|
|
18
|
+
- **Individual Job Retrieval**: Get detailed information about specific jobs by address
|
|
19
|
+
- **Bulk Job Fetching**: Retrieve multiple jobs with optional filtering
|
|
20
|
+
- **State Filtering**: Filter jobs by state (Queued, Running, Stopped, Done)
|
|
21
|
+
- **Limit Control**: Control how many jobs to fetch (1-100)
|
|
22
|
+
|
|
23
|
+
### 4. **Market Operations**
|
|
24
|
+
- **Market Discovery**: Retrieve all available markets
|
|
25
|
+
- **Market Details**: View pricing, timeouts, and configuration
|
|
26
|
+
- **Market Monitoring**: Real-time updates for market changes
|
|
27
|
+
|
|
28
|
+
### 5. **Real-time Monitoring**
|
|
29
|
+
- **WebSocket Subscriptions**: Live updates for account changes
|
|
30
|
+
- **Multi-Account Types**: Monitor jobs, runs, and markets simultaneously
|
|
31
|
+
- **Automatic Reconnection**: Handles connection failures gracefully
|
|
32
|
+
- **Error Reporting**: Clear error messages and recovery
|
|
33
|
+
|
|
34
|
+
## 🖥️ User Interface Features
|
|
35
|
+
|
|
36
|
+
### 1. **Terminal-style Output**
|
|
37
|
+
- **Color-coded Logs**: Different colors for info, success, error, and warning messages
|
|
38
|
+
- **Timestamps**: Every log entry includes a timestamp
|
|
39
|
+
- **Auto-scroll**: Optional automatic scrolling to latest entries
|
|
40
|
+
- **Log Management**: Clear logs button for fresh starts
|
|
41
|
+
|
|
42
|
+
### 2. **Responsive Design**
|
|
43
|
+
- **Mobile-friendly**: Works on phones, tablets, and desktops
|
|
44
|
+
- **Grid Layout**: Adaptive layout that works on all screen sizes
|
|
45
|
+
- **Modern UI**: Clean, professional interface using Tailwind CSS
|
|
46
|
+
|
|
47
|
+
### 3. **Interactive Controls**
|
|
48
|
+
- **Form Validation**: Input validation and error handling
|
|
49
|
+
- **Loading States**: Visual feedback during operations
|
|
50
|
+
- **Disabled States**: Buttons disabled during loading to prevent conflicts
|
|
51
|
+
- **Status Indicators**: Visual indicators for connection and monitoring status
|
|
52
|
+
|
|
53
|
+
## 🔧 Technical Features
|
|
54
|
+
|
|
55
|
+
### 1. **Modern Web Technologies**
|
|
56
|
+
- **Nuxt 3**: Latest Vue.js framework for optimal performance
|
|
57
|
+
- **Vue 3 Composition API**: Modern reactive programming
|
|
58
|
+
- **TypeScript Support**: Full type safety and IntelliSense
|
|
59
|
+
- **Hot Module Replacement**: Instant updates during development
|
|
60
|
+
|
|
61
|
+
### 2. **Blockchain Integration**
|
|
62
|
+
- **Solana SDK Integration**: Full compatibility with Solana blockchain
|
|
63
|
+
- **WASM Support**: WebAssembly support for cryptographic operations
|
|
64
|
+
- **Address Validation**: Proper Solana address handling
|
|
65
|
+
- **Error Handling**: Comprehensive blockchain error handling
|
|
66
|
+
|
|
67
|
+
### 3. **Development Experience**
|
|
68
|
+
- **Fast Builds**: Optimized build process with Vite
|
|
69
|
+
- **Development Server**: Hot reload for rapid development
|
|
70
|
+
- **Dependency Optimization**: Pre-bundled dependencies for faster loading
|
|
71
|
+
- **SSR Disabled**: Client-side rendering for better SDK compatibility
|
|
72
|
+
|
|
73
|
+
## 📊 Monitoring Capabilities
|
|
74
|
+
|
|
75
|
+
### 1. **Account Monitoring**
|
|
76
|
+
- **Job Accounts**: Monitor job state changes, node assignments, and completion
|
|
77
|
+
- **Run Accounts**: Track job execution and node performance
|
|
78
|
+
- **Market Accounts**: Watch for pricing and configuration changes
|
|
79
|
+
|
|
80
|
+
### 2. **Real-time Updates**
|
|
81
|
+
- **Live Data**: Updates appear immediately as they happen on-chain
|
|
82
|
+
- **Detailed Information**: Full account data with formatted display
|
|
83
|
+
- **Historical View**: All updates are logged and preserved during session
|
|
84
|
+
|
|
85
|
+
### 3. **Error Handling**
|
|
86
|
+
- **Connection Recovery**: Automatic reconnection on WebSocket failures
|
|
87
|
+
- **Error Classification**: Different error types with appropriate handling
|
|
88
|
+
- **User Feedback**: Clear error messages and recovery suggestions
|
|
89
|
+
|
|
90
|
+
## 🎨 User Experience Features
|
|
91
|
+
|
|
92
|
+
### 1. **Intuitive Interface**
|
|
93
|
+
- **Logical Grouping**: Related functions grouped in clear sections
|
|
94
|
+
- **Progressive Disclosure**: Advanced options available but not overwhelming
|
|
95
|
+
- **Visual Hierarchy**: Clear information hierarchy with proper typography
|
|
96
|
+
|
|
97
|
+
### 2. **Helpful Defaults**
|
|
98
|
+
- **Example Data**: Pre-filled example job addresses for testing
|
|
99
|
+
- **Sensible Limits**: Default limits that work well for most use cases
|
|
100
|
+
- **Network Selection**: Starts with devnet for safer testing
|
|
101
|
+
|
|
102
|
+
### 3. **Documentation Integration**
|
|
103
|
+
- **Inline Help**: Helpful descriptions and tooltips
|
|
104
|
+
- **Example Usage**: Clear examples of how to use each feature
|
|
105
|
+
- **Troubleshooting**: Built-in error handling and user guidance
|
|
106
|
+
|
|
107
|
+
## 🚀 Performance Features
|
|
108
|
+
|
|
109
|
+
### 1. **Optimized Loading**
|
|
110
|
+
- **Dynamic Imports**: SDK loaded only when needed
|
|
111
|
+
- **Code Splitting**: Efficient bundle splitting for faster initial load
|
|
112
|
+
- **Dependency Optimization**: Pre-bundled common dependencies
|
|
113
|
+
|
|
114
|
+
### 2. **Efficient Updates**
|
|
115
|
+
- **Reactive State**: Efficient state management with Vue 3 reactivity
|
|
116
|
+
- **Minimal Re-renders**: Optimized component updates
|
|
117
|
+
- **Memory Management**: Proper cleanup of WebSocket connections
|
|
118
|
+
|
|
119
|
+
### 3. **Browser Compatibility**
|
|
120
|
+
- **Modern Browsers**: Optimized for Chrome, Firefox, Safari, Edge
|
|
121
|
+
- **WebSocket Support**: Fallback handling for connection issues
|
|
122
|
+
- **WASM Support**: WebAssembly for cryptographic operations
|
|
123
|
+
|
|
124
|
+
## 📱 Accessibility Features
|
|
125
|
+
|
|
126
|
+
### 1. **Keyboard Navigation**
|
|
127
|
+
- **Tab Order**: Logical tab order through interface elements
|
|
128
|
+
- **Keyboard Shortcuts**: Standard keyboard interactions
|
|
129
|
+
- **Focus Management**: Clear focus indicators
|
|
130
|
+
|
|
131
|
+
### 2. **Screen Reader Support**
|
|
132
|
+
- **Semantic HTML**: Proper HTML structure for screen readers
|
|
133
|
+
- **ARIA Labels**: Appropriate ARIA labels for interactive elements
|
|
134
|
+
- **Status Updates**: Screen reader announcements for status changes
|
|
135
|
+
|
|
136
|
+
### 3. **Visual Accessibility**
|
|
137
|
+
- **Color Contrast**: High contrast colors for readability
|
|
138
|
+
- **Font Sizes**: Readable font sizes across all devices
|
|
139
|
+
- **Visual Indicators**: Multiple ways to convey information (not just color)
|
|
140
|
+
|
|
141
|
+
This playground serves as both a learning tool for developers new to the Nosana SDK and a testing environment for experienced developers working with the platform.
|