@nosana/kit 1.0.7 โ 1.0.9
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/dist/services/SolanaService.js +23 -1
- package/package.json +7 -2
- package/.gitlab-ci.yml +0 -54
- package/.prettierignore +0 -17
- package/eslint.config.js +0 -47
- package/examples/browser/.gitlab-ci.yml +0 -78
- package/examples/browser/FEATURES.md +0 -141
- package/examples/browser/QUICK_START.md +0 -76
- package/examples/browser/README.md +0 -182
- package/examples/browser/app.vue +0 -1840
- package/examples/browser/assets/css/main.css +0 -7
- package/examples/browser/nuxt.config.ts +0 -30
- package/examples/browser/package-lock.json +0 -12230
- package/examples/browser/package.json +0 -31
- package/examples/browser/public/favicon.ico +0 -0
- package/examples/browser/public/robots.txt +0 -2
- package/examples/browser/start.sh +0 -38
- package/examples/browser/tailwind.config.js +0 -26
- package/examples/node/README.md +0 -261
- package/examples/node/example-keypair.json +0 -1
- package/examples/node/monitor.ts +0 -143
- package/examples/node/nos-service.ts +0 -117
- package/examples/node/package-lock.json +0 -589
- package/examples/node/package.json +0 -20
- package/examples/node/post-job.ts +0 -160
- package/examples/node/retrieve.ts +0 -18
- package/examples/node/set-wallet.ts +0 -87
- package/examples/node/stake-program.ts +0 -84
- package/scripts/generate-clients.ts +0 -33
- package/vitest.config.ts +0 -31
package/examples/browser/app.vue
DELETED
|
@@ -1,1840 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="min-h-screen bg-gradient-to-br from-gray-50 to-green-50">
|
|
3
|
-
<!-- Header -->
|
|
4
|
-
<header class="bg-white shadow-lg border-b sticky top-0 z-50 backdrop-blur-sm bg-white/95">
|
|
5
|
-
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
6
|
-
<div class="flex justify-between items-center py-4 flex-wrap">
|
|
7
|
-
<div class="flex items-center space-x-4 flex-shrink-0">
|
|
8
|
-
<div class="flex items-center">
|
|
9
|
-
<div
|
|
10
|
-
class="w-10 h-10 bg-gradient-to-br from-green-700 to-[#10e80c] rounded-lg flex items-center justify-center text-white font-bold text-lg mr-3">
|
|
11
|
-
N
|
|
12
|
-
</div>
|
|
13
|
-
<div>
|
|
14
|
-
<h1 class="text-2xl font-bold text-gray-900 leading-tight">Nosana Kit</h1>
|
|
15
|
-
<div class="flex items-center space-x-2 text-xs text-gray-500 h-4">
|
|
16
|
-
<span>Documentation</span>
|
|
17
|
-
<span>โข</span>
|
|
18
|
-
<a href="https://www.npmjs.com/package/@nosana/kit" target="_blank"
|
|
19
|
-
class="text-blue-600 hover:text-blue-800 transition-colors no-underline">
|
|
20
|
-
๐ฆ @nosana/kit
|
|
21
|
-
</a>
|
|
22
|
-
<span>โข</span>
|
|
23
|
-
<span class="bg-green-100 text-green-800 px-2 py-0.5 rounded-full whitespace-nowrap">v1.0.0</span>
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
<div class="flex items-center space-x-4 flex-shrink-0">
|
|
29
|
-
<div class="flex items-center bg-gray-50 rounded-lg px-3 py-2">
|
|
30
|
-
<label class="text-sm font-medium text-gray-700 mr-2 whitespace-nowrap">Network:</label>
|
|
31
|
-
<select v-model="selectedNetwork" @change="initializeClient"
|
|
32
|
-
class="bg-transparent border-0 text-sm font-medium focus:outline-none focus:ring-0 min-w-[100px]">
|
|
33
|
-
<option value="mainnet">๐ Mainnet</option>
|
|
34
|
-
<option value="devnet">๐งช Devnet</option>
|
|
35
|
-
</select>
|
|
36
|
-
</div>
|
|
37
|
-
<div class="flex items-center space-x-2 min-w-[120px]">
|
|
38
|
-
<div :class="[
|
|
39
|
-
'w-2 h-2 rounded-full flex-shrink-0',
|
|
40
|
-
isConnected ? 'bg-green-500 animate-pulse' : 'bg-red-500'
|
|
41
|
-
]"></div>
|
|
42
|
-
<span class="text-sm font-medium whitespace-nowrap"
|
|
43
|
-
:class="isConnected ? 'text-green-700' : 'text-red-700'">
|
|
44
|
-
{{ isConnected ? 'Connected' : 'Disconnected' }}
|
|
45
|
-
</span>
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
</div>
|
|
50
|
-
</header>
|
|
51
|
-
|
|
52
|
-
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
53
|
-
<!-- Installation Section -->
|
|
54
|
-
<div class="mb-8 bg-gradient-to-r from-green-700 to-[#10e80c] rounded-xl p-8 text-white">
|
|
55
|
-
<div class="grid lg:grid-cols-2 gap-8 items-center">
|
|
56
|
-
<div>
|
|
57
|
-
<h1 class="text-4xl font-bold mb-4">๐ Nosana Kit</h1>
|
|
58
|
-
<p class="text-green-100 text-lg mb-6">
|
|
59
|
-
Decentralized compute network SDK for AI inference and computational tasks.
|
|
60
|
-
Test APIs interactively and see real-time results.
|
|
61
|
-
</p>
|
|
62
|
-
<div class="flex flex-wrap gap-3">
|
|
63
|
-
<span class="bg-white/20 px-3 py-1 rounded-full text-sm">TypeScript Ready</span>
|
|
64
|
-
<span class="bg-white/20 px-3 py-1 rounded-full text-sm">Real-time Testing</span>
|
|
65
|
-
<span class="bg-white/20 px-3 py-1 rounded-full text-sm">Interactive Docs</span>
|
|
66
|
-
</div>
|
|
67
|
-
</div>
|
|
68
|
-
<div class="bg-gray-900 rounded-lg p-6">
|
|
69
|
-
<div class="flex items-center justify-between mb-4">
|
|
70
|
-
<h3 class="text-lg font-semibold">Installation</h3>
|
|
71
|
-
<button @click="copyInstallCommand" class="text-gray-400 hover:text-white transition-colors"
|
|
72
|
-
title="Copy to clipboard">
|
|
73
|
-
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
74
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
75
|
-
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z">
|
|
76
|
-
</path>
|
|
77
|
-
</svg>
|
|
78
|
-
</button>
|
|
79
|
-
</div>
|
|
80
|
-
<code class="text-green-400 font-mono text-sm">npm install @nosana/kit</code>
|
|
81
|
-
</div>
|
|
82
|
-
</div>
|
|
83
|
-
</div>
|
|
84
|
-
|
|
85
|
-
<div class="grid grid-cols-1 lg:grid-cols-5 gap-8">
|
|
86
|
-
<!-- Sidebar Navigation -->
|
|
87
|
-
<div class="lg:col-span-1">
|
|
88
|
-
<div class="bg-white rounded-xl shadow-lg sticky top-24">
|
|
89
|
-
<div class="p-6">
|
|
90
|
-
<h3 class="font-semibold text-gray-900 mb-4">๐ API Reference</h3>
|
|
91
|
-
<nav class="space-y-2">
|
|
92
|
-
<a href="#sdk-init" @click="scrollToSection('sdk-init')"
|
|
93
|
-
class="flex items-center space-x-2 text-sm text-gray-600 hover:text-blue-600 hover:bg-blue-50 px-3 py-2 rounded-lg transition-colors cursor-pointer">
|
|
94
|
-
<span>๐ง</span>
|
|
95
|
-
<span>SDK Initialization</span>
|
|
96
|
-
</a>
|
|
97
|
-
<a href="#job-retrieval" @click="scrollToSection('job-retrieval')"
|
|
98
|
-
class="flex items-center space-x-2 text-sm text-gray-600 hover:text-green-600 hover:bg-green-50 px-3 py-2 rounded-lg transition-colors cursor-pointer">
|
|
99
|
-
<span>๐</span>
|
|
100
|
-
<span>Job Retrieval</span>
|
|
101
|
-
</a>
|
|
102
|
-
<a href="#market-discovery" @click="scrollToSection('market-discovery')"
|
|
103
|
-
class="flex items-center space-x-2 text-sm text-gray-600 hover:text-orange-600 hover:bg-orange-50 px-3 py-2 rounded-lg transition-colors cursor-pointer">
|
|
104
|
-
<span>๐ช</span>
|
|
105
|
-
<span>Market Discovery</span>
|
|
106
|
-
</a>
|
|
107
|
-
<a href="#monitoring" @click="scrollToSection('monitoring')"
|
|
108
|
-
class="flex items-center space-x-2 text-sm text-gray-600 hover:text-purple-600 hover:bg-purple-50 px-3 py-2 rounded-lg transition-colors cursor-pointer">
|
|
109
|
-
<span>๐ก</span>
|
|
110
|
-
<span>Real-time Monitoring</span>
|
|
111
|
-
</a>
|
|
112
|
-
</nav>
|
|
113
|
-
</div>
|
|
114
|
-
</div>
|
|
115
|
-
</div>
|
|
116
|
-
|
|
117
|
-
<!-- Main Content -->
|
|
118
|
-
<div :class="[
|
|
119
|
-
'transition-all duration-300',
|
|
120
|
-
'lg:col-span-4'
|
|
121
|
-
]">
|
|
122
|
-
<div class="space-y-8">
|
|
123
|
-
<!-- 1. SDK Initialization -->
|
|
124
|
-
<div id="sdk-init" class="bg-white rounded-xl shadow-lg overflow-hidden border border-gray-100">
|
|
125
|
-
<div class="bg-gradient-to-r from-blue-500 to-blue-600 px-8 py-6">
|
|
126
|
-
<div class="flex items-center justify-between">
|
|
127
|
-
<h2 class="text-2xl font-bold text-white">๐ง SDK Initialization</h2>
|
|
128
|
-
<span class="bg-white/20 px-3 py-1 rounded-full text-sm text-blue-100">Core</span>
|
|
129
|
-
</div>
|
|
130
|
-
</div>
|
|
131
|
-
|
|
132
|
-
<div class="p-8">
|
|
133
|
-
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
134
|
-
<!-- Documentation -->
|
|
135
|
-
<div class="lg:col-span-2">
|
|
136
|
-
<div class="prose prose-blue max-w-none">
|
|
137
|
-
<h4 class="text-xl font-semibold text-gray-900 mb-4">๐ Documentation</h4>
|
|
138
|
-
|
|
139
|
-
<!-- Method Signature -->
|
|
140
|
-
<div class="bg-gray-50 rounded-lg p-4 mb-6">
|
|
141
|
-
<div class="flex items-center justify-between mb-2">
|
|
142
|
-
<h5 class="font-semibold text-gray-700">Constructor</h5>
|
|
143
|
-
<span class="text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded">TypeScript</span>
|
|
144
|
-
</div>
|
|
145
|
-
<code class="text-sm font-mono text-[#10e80c]">
|
|
146
|
-
new NosanaClient(network: NosanaNetwork, customConfig?: PartialClientConfig)
|
|
147
|
-
</code>
|
|
148
|
-
</div>
|
|
149
|
-
|
|
150
|
-
<!-- TypeScript Types -->
|
|
151
|
-
<div class="bg-gradient-to-r from-green-50 to-blue-50 rounded-lg p-4 mb-6">
|
|
152
|
-
<button @click="toggleTypeInfo('init')"
|
|
153
|
-
class="flex items-center justify-between w-full text-left">
|
|
154
|
-
<h5 class="font-semibold text-[#10e80c]">๐ TypeScript Types</h5>
|
|
155
|
-
<svg :class="['w-4 h-4 transition-transform', showTypeInfo.init ? 'rotate-180' : '']"
|
|
156
|
-
fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
157
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7">
|
|
158
|
-
</path>
|
|
159
|
-
</svg>
|
|
160
|
-
</button>
|
|
161
|
-
<div v-show="showTypeInfo.init" class="mt-4 space-y-3">
|
|
162
|
-
<div class="bg-white rounded p-3 text-sm font-mono">
|
|
163
|
-
<div class="text-blue-600">enum</div>
|
|
164
|
-
<div class="text-[#10e80c]">NosanaNetwork</div>
|
|
165
|
-
<div class="ml-4 text-gray-600">MAINNET = "mainnet"</div>
|
|
166
|
-
<div class="ml-4 text-gray-600">DEVNET = "devnet"</div>
|
|
167
|
-
</div>
|
|
168
|
-
<div class="bg-white rounded p-3 text-sm font-mono">
|
|
169
|
-
<div class="text-blue-600">interface</div>
|
|
170
|
-
<div class="text-[#10e80c]">NosanaClient</div>
|
|
171
|
-
<div class="ml-4 text-gray-600">config: ClientConfig</div>
|
|
172
|
-
<div class="ml-4 text-gray-600">solana: SolanaUtils</div>
|
|
173
|
-
<div class="ml-4 text-gray-600">jobs: JobsProgram</div>
|
|
174
|
-
<div class="ml-4 text-gray-600">logger: Logger</div>
|
|
175
|
-
<div class="ml-4 text-gray-600">wallet?: KeyPairSigner</div>
|
|
176
|
-
<div class="ml-4 text-gray-600">setWallet(config: WalletConfig):
|
|
177
|
-
Promise<KeyPairSigner></div>
|
|
178
|
-
</div>
|
|
179
|
-
<div class="bg-white rounded p-3 text-sm font-mono">
|
|
180
|
-
<div class="text-blue-600">interface</div>
|
|
181
|
-
<div class="text-[#10e80c]">ClientConfig</div>
|
|
182
|
-
<div class="ml-4 text-gray-600">solana: SolanaConfig</div>
|
|
183
|
-
<div class="ml-4 text-gray-600">programs: ProgramsConfig</div>
|
|
184
|
-
<div class="ml-4 text-gray-600">ipfs: IpfsConfig</div>
|
|
185
|
-
<div class="ml-4 text-gray-600">wallet?: WalletConfig</div>
|
|
186
|
-
</div>
|
|
187
|
-
<div class="bg-white rounded p-3 text-sm font-mono">
|
|
188
|
-
<div class="text-blue-600">type</div>
|
|
189
|
-
<div class="text-[#10e80c]">PartialClientConfig</div>
|
|
190
|
-
<div class="ml-4 text-gray-600">= Partial<ClientConfig></div>
|
|
191
|
-
<div class="ml-6 text-gray-500">// All properties optional for custom configuration</div>
|
|
192
|
-
</div>
|
|
193
|
-
<div class="bg-white rounded p-3 text-sm font-mono">
|
|
194
|
-
<div class="text-blue-600">interface</div>
|
|
195
|
-
<div class="text-[#10e80c]">SolanaConfig</div>
|
|
196
|
-
<div class="ml-4 text-gray-600">rpcEndpoint: string</div>
|
|
197
|
-
<div class="ml-4 text-gray-600">cluster: SolanaClusterMoniker</div>
|
|
198
|
-
</div>
|
|
199
|
-
<div class="bg-white rounded p-3 text-sm font-mono">
|
|
200
|
-
<div class="text-blue-600">interface</div>
|
|
201
|
-
<div class="text-[#10e80c]">ProgramsConfig</div>
|
|
202
|
-
<div class="ml-4 text-gray-600">jobsAddress: Address</div>
|
|
203
|
-
<div class="ml-4 text-gray-600">nosTokenAddress: Address</div>
|
|
204
|
-
<div class="ml-4 text-gray-600">rewardsAddress: Address</div>
|
|
205
|
-
</div>
|
|
206
|
-
<div class="bg-white rounded p-3 text-sm font-mono">
|
|
207
|
-
<div class="text-blue-600">interface</div>
|
|
208
|
-
<div class="text-[#10e80c]">IpfsConfig</div>
|
|
209
|
-
<div class="ml-4 text-gray-600">gatewayUrl: string</div>
|
|
210
|
-
<div class="ml-4 text-gray-600">pinataJwt?: string</div>
|
|
211
|
-
<div class="ml-4 text-gray-600">timeout?: number</div>
|
|
212
|
-
</div>
|
|
213
|
-
<div class="bg-white rounded p-3 text-sm font-mono">
|
|
214
|
-
<div class="text-blue-600">type</div>
|
|
215
|
-
<div class="text-[#10e80c]">WalletConfig</div>
|
|
216
|
-
<div class="ml-4 text-gray-600">= string | number[] | KeyPairSigner</div>
|
|
217
|
-
<div class="ml-6 text-gray-500">// JSON string, number array, or keypair instance</div>
|
|
218
|
-
</div>
|
|
219
|
-
</div>
|
|
220
|
-
</div>
|
|
221
|
-
|
|
222
|
-
<!-- Description -->
|
|
223
|
-
<p class="text-gray-700 mb-6">
|
|
224
|
-
Initialize a new Nosana client instance to interact with the decentralized compute network.
|
|
225
|
-
The network parameter determines which Solana cluster to connect to for blockchain operations.
|
|
226
|
-
You can optionally provide custom configuration to override default settings like RPC endpoints,
|
|
227
|
-
program addresses, or IPFS gateways. You can also set a wallet to enable transaction signing and
|
|
228
|
-
job posting.
|
|
229
|
-
</p>
|
|
230
|
-
|
|
231
|
-
<!-- Code Example -->
|
|
232
|
-
<div class="bg-gray-900 rounded-lg overflow-hidden mb-6">
|
|
233
|
-
<button @click="toggleCodeExample('init')"
|
|
234
|
-
class="w-full flex items-center justify-between bg-gray-800 px-4 py-2 hover:bg-gray-700 transition-colors">
|
|
235
|
-
<span class="text-gray-300 text-sm font-medium">Example Usage</span>
|
|
236
|
-
<svg
|
|
237
|
-
:class="['w-4 h-4 transition-transform text-gray-400', showCodeExample.init ? 'rotate-180' : '']"
|
|
238
|
-
fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
239
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7">
|
|
240
|
-
</path>
|
|
241
|
-
</svg>
|
|
242
|
-
</button>
|
|
243
|
-
<div v-show="showCodeExample.init" class="p-4">
|
|
244
|
-
<pre
|
|
245
|
-
class="text-sm"><code class="text-green-400">import</code> <code class="text-blue-400">{ NosanaClient, NosanaNetwork }</code> <code class="text-green-400">from</code> <code class="text-yellow-400">'@nosana/kit'</code>
|
|
246
|
-
|
|
247
|
-
<code class="text-gray-500">// Initialize for devnet (testing)</code>
|
|
248
|
-
<code class="text-green-400">const</code> <code class="text-blue-400">client</code> <code class="text-white">=</code> <code class="text-green-400">new</code> <code class="text-yellow-400">NosanaClient</code><code class="text-white">(</code><code class="text-blue-400">NosanaNetwork</code><code class="text-white">.</code><code class="text-blue-400">DEVNET</code><code class="text-white">)</code>
|
|
249
|
-
|
|
250
|
-
<code class="text-gray-500">// Initialize for mainnet with custom config</code>
|
|
251
|
-
<code class="text-green-400">const</code> <code class="text-blue-400">customConfig</code> <code class="text-white">=</code> <code class="text-white">{</code>
|
|
252
|
-
<code class="text-blue-400">solana</code><code class="text-white">:</code> <code class="text-white">{</code>
|
|
253
|
-
<code class="text-blue-400">rpcEndpoint</code><code class="text-white">:</code> <code class="text-yellow-400">'https://custom-rpc.com'</code>
|
|
254
|
-
<code class="text-white">}</code>
|
|
255
|
-
<code class="text-white">}</code>
|
|
256
|
-
<code class="text-green-400">const</code> <code class="text-blue-400">prodClient</code> <code class="text-white">=</code> <code class="text-green-400">new</code> <code class="text-yellow-400">NosanaClient</code><code class="text-white">(</code><code class="text-blue-400">NosanaNetwork</code><code class="text-white">.</code><code class="text-blue-400">MAINNET</code><code class="text-white">,</code> <code class="text-blue-400">customConfig</code><code class="text-white">)</code>
|
|
257
|
-
|
|
258
|
-
<code class="text-gray-500">// Access configuration</code>
|
|
259
|
-
<code class="text-blue-400">console</code><code class="text-white">.</code><code class="text-yellow-400">log</code><code class="text-white">(</code><code class="text-blue-400">client</code><code class="text-white">.</code><code class="text-blue-400">config</code><code class="text-white">.</code><code class="text-blue-400">solana</code><code class="text-white">.</code><code class="text-blue-400">rpcEndpoint</code><code class="text-white">)</code>
|
|
260
|
-
|
|
261
|
-
<code class="text-gray-500">// Set wallet for transaction signing</code>
|
|
262
|
-
<code class="text-green-400">const</code> <code class="text-blue-400">keypair</code> <code class="text-white">=</code> <code class="text-yellow-400">'[66,240,117,68,169,30...]'</code>
|
|
263
|
-
<code class="text-green-400">const</code> <code class="text-blue-400">wallet</code> <code class="text-white">=</code> <code class="text-green-400">await</code> <code class="text-blue-400">client</code><code class="text-white">.</code><code class="text-yellow-400">setWallet</code><code class="text-white">(</code><code class="text-blue-400">keypair</code><code class="text-white">)</code>
|
|
264
|
-
<code class="text-blue-400">console</code><code class="text-white">.</code><code class="text-yellow-400">log</code><code class="text-white">(</code><code class="text-yellow-400">'Wallet address:'</code><code class="text-white">,</code> <code class="text-blue-400">wallet</code><code class="text-white">.</code><code class="text-blue-400">address</code><code class="text-white">)</code></pre>
|
|
265
|
-
</div>
|
|
266
|
-
</div>
|
|
267
|
-
|
|
268
|
-
<!-- Network Info -->
|
|
269
|
-
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
270
|
-
<div class="bg-blue-50 border-l-4 border-blue-400 p-4 rounded">
|
|
271
|
-
<h6 class="font-semibold text-blue-900 mb-2">๐ Mainnet</h6>
|
|
272
|
-
<p class="text-blue-800 text-sm">Production environment with real SOL tokens and live compute
|
|
273
|
-
jobs.</p>
|
|
274
|
-
</div>
|
|
275
|
-
<div class="bg-green-50 border-l-4 border-green-400 p-4 rounded">
|
|
276
|
-
<h6 class="font-semibold text-green-900 mb-2">๐งช Devnet</h6>
|
|
277
|
-
<p class="text-green-800 text-sm">Testing environment with test tokens for development and
|
|
278
|
-
experimentation.</p>
|
|
279
|
-
</div>
|
|
280
|
-
</div>
|
|
281
|
-
</div>
|
|
282
|
-
</div>
|
|
283
|
-
|
|
284
|
-
<!-- Interactive Controls -->
|
|
285
|
-
<div class="lg:col-span-1">
|
|
286
|
-
<div class="bg-gradient-to-br from-blue-50 to-blue-100 rounded-xl p-6 sticky top-24">
|
|
287
|
-
<h4 class="font-semibold text-gray-900 mb-4">๐ฎ Try It Now</h4>
|
|
288
|
-
<div class="space-y-4">
|
|
289
|
-
<!-- Network Status -->
|
|
290
|
-
<div class="bg-white rounded-lg p-4 border border-blue-200">
|
|
291
|
-
<div class="flex items-center space-x-2 mb-3">
|
|
292
|
-
<div :class="[
|
|
293
|
-
'w-3 h-3 rounded-full',
|
|
294
|
-
isConnected ? 'bg-green-500 animate-pulse' : 'bg-gray-400'
|
|
295
|
-
]"></div>
|
|
296
|
-
<span class="text-sm font-medium text-gray-700">
|
|
297
|
-
{{ selectedNetwork.toUpperCase() }} Network
|
|
298
|
-
</span>
|
|
299
|
-
</div>
|
|
300
|
-
<p class="text-sm text-gray-600 mb-3">
|
|
301
|
-
SDK initialized and ready for {{ selectedNetwork }} operations
|
|
302
|
-
</p>
|
|
303
|
-
<p class="text-xs text-gray-500">
|
|
304
|
-
๐ก Switch networks using the dropdown in the header
|
|
305
|
-
</p>
|
|
306
|
-
</div>
|
|
307
|
-
|
|
308
|
-
<!-- Wallet Management -->
|
|
309
|
-
<div class="bg-white rounded-lg p-4 border border-blue-200">
|
|
310
|
-
<div class="flex items-center justify-between mb-3">
|
|
311
|
-
<span class="text-sm font-semibold text-gray-700">
|
|
312
|
-
๐ Wallet
|
|
313
|
-
</span>
|
|
314
|
-
<div class="flex items-center">
|
|
315
|
-
<div :class="[
|
|
316
|
-
'w-2 h-2 rounded-full mr-2',
|
|
317
|
-
currentWallet ? 'bg-green-500' : 'bg-gray-400'
|
|
318
|
-
]"></div>
|
|
319
|
-
<span class="text-xs font-medium"
|
|
320
|
-
:class="currentWallet ? 'text-green-700' : 'text-gray-600'">
|
|
321
|
-
{{ currentWallet ? 'Connected' : 'None' }}
|
|
322
|
-
</span>
|
|
323
|
-
</div>
|
|
324
|
-
</div>
|
|
325
|
-
|
|
326
|
-
<div v-if="currentWallet" class="mb-3 p-2 bg-green-50 rounded text-xs">
|
|
327
|
-
<div class="font-mono text-green-800 break-all">
|
|
328
|
-
{{ currentWallet.substring(0, 8) }}...{{ currentWallet.substring(currentWallet.length - 8)
|
|
329
|
-
}}
|
|
330
|
-
</div>
|
|
331
|
-
</div>
|
|
332
|
-
|
|
333
|
-
<!-- Wallet Input Method Selection -->
|
|
334
|
-
<select v-model="walletInputMethod"
|
|
335
|
-
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent mb-3">
|
|
336
|
-
<option value="browser">๐ Connect Browser Wallet</option>
|
|
337
|
-
<option value="paste">๐ Paste Private Key</option>
|
|
338
|
-
<option value="file">๐ Upload Keypair File</option>
|
|
339
|
-
</select>
|
|
340
|
-
|
|
341
|
-
<!-- Browser Wallet Connection -->
|
|
342
|
-
<div v-if="walletInputMethod === 'browser'" class="mb-3">
|
|
343
|
-
<div v-if="!browserWallet.connected" class="space-y-3">
|
|
344
|
-
<div class="text-center p-4 border-2 border-dashed border-gray-300 rounded-lg">
|
|
345
|
-
<p class="text-sm text-gray-600 mb-3">
|
|
346
|
-
Connect your browser wallet to use with the SDK
|
|
347
|
-
</p>
|
|
348
|
-
<div class="space-y-2">
|
|
349
|
-
<div class="grid grid-cols-2 gap-2">
|
|
350
|
-
<button @click="connectWallet('phantom')"
|
|
351
|
-
class="flex items-center justify-center px-3 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 text-xs font-medium">
|
|
352
|
-
๐ป Phantom
|
|
353
|
-
</button>
|
|
354
|
-
<button @click="connectWallet('solflare')"
|
|
355
|
-
class="flex items-center justify-center px-3 py-2 bg-orange-600 text-white rounded-lg hover:bg-orange-700 text-xs font-medium">
|
|
356
|
-
๐ฅ Solflare
|
|
357
|
-
</button>
|
|
358
|
-
</div>
|
|
359
|
-
<div class="flex justify-center">
|
|
360
|
-
<button @click="connectWallet('backpack')"
|
|
361
|
-
class="flex items-center justify-center px-3 py-2 bg-black text-white rounded-lg hover:bg-gray-800 text-xs font-medium w-32">
|
|
362
|
-
๐ Backpack
|
|
363
|
-
</button>
|
|
364
|
-
</div>
|
|
365
|
-
</div>
|
|
366
|
-
</div>
|
|
367
|
-
</div>
|
|
368
|
-
<div v-else class="p-3 bg-green-50 border border-green-200 rounded-lg">
|
|
369
|
-
<div class="flex items-center justify-between mb-2">
|
|
370
|
-
<div class="flex items-center space-x-2">
|
|
371
|
-
<div class="w-2 h-2 bg-green-500 rounded-full"></div>
|
|
372
|
-
<span class="text-sm font-medium text-green-800">
|
|
373
|
-
{{ browserWallet.name }}
|
|
374
|
-
</span>
|
|
375
|
-
</div>
|
|
376
|
-
<button @click="disconnectBrowserWallet"
|
|
377
|
-
class="text-xs text-green-600 hover:text-green-800 underline">
|
|
378
|
-
Disconnect
|
|
379
|
-
</button>
|
|
380
|
-
</div>
|
|
381
|
-
<div class="text-xs font-mono text-green-700 break-all">
|
|
382
|
-
{{ browserWallet.publicKey?.substring(0, 8) }}...{{
|
|
383
|
-
browserWallet.publicKey?.substring(browserWallet.publicKey.length - 8) }}
|
|
384
|
-
</div>
|
|
385
|
-
</div>
|
|
386
|
-
<p class="text-xs text-gray-500 mt-1">
|
|
387
|
-
๐ Connect popular Solana wallets like Phantom, Solflare, and Backpack!
|
|
388
|
-
</p>
|
|
389
|
-
</div>
|
|
390
|
-
|
|
391
|
-
<!-- Paste Private Key Input -->
|
|
392
|
-
<div v-if="walletInputMethod === 'paste'" class="mb-3">
|
|
393
|
-
<textarea v-model="walletInputs.privateKey"
|
|
394
|
-
placeholder="Paste your private key in any format: โข JSON Array: [66,240,117,68,169,30,179,62,...] โข Number Array: 66,240,117,68,169,30,179,62,... โข Base58: 2Ld9Q8E9TxsSPf9Zkxn55u2EuuXBZUiV..."
|
|
395
|
-
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-xs focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
396
|
-
rows="4"></textarea>
|
|
397
|
-
<p class="text-xs text-gray-500 mt-1">
|
|
398
|
-
๐ก Supports JSON array, number array, or Base58 format - the SDK will auto-detect!
|
|
399
|
-
</p>
|
|
400
|
-
</div>
|
|
401
|
-
|
|
402
|
-
<!-- File Upload -->
|
|
403
|
-
<div v-if="walletInputMethod === 'file'" class="mb-3">
|
|
404
|
-
<input ref="fileInput" type="file" accept=".json" @change="handleFileUpload"
|
|
405
|
-
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-xs focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" />
|
|
406
|
-
<p class="text-xs text-gray-500 mt-1">
|
|
407
|
-
๐ Upload a JSON keypair file (e.g., from Solana CLI)
|
|
408
|
-
</p>
|
|
409
|
-
</div>
|
|
410
|
-
|
|
411
|
-
<!-- Set Wallet Button -->
|
|
412
|
-
<button @click="setWallet" :disabled="loading || !canSetWallet"
|
|
413
|
-
class="w-full px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 font-medium text-sm shadow-lg hover:shadow-xl mb-2">
|
|
414
|
-
<span v-if="loading" class="flex items-center justify-center">
|
|
415
|
-
<svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" fill="none" viewBox="0 0 24 24">
|
|
416
|
-
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor"
|
|
417
|
-
stroke-width="4"></circle>
|
|
418
|
-
<path class="opacity-75" fill="currentColor"
|
|
419
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
|
|
420
|
-
</path>
|
|
421
|
-
</svg>
|
|
422
|
-
Setting...
|
|
423
|
-
</span>
|
|
424
|
-
<span v-else>๐ Set Wallet</span>
|
|
425
|
-
</button>
|
|
426
|
-
|
|
427
|
-
<!-- Clear Wallet Button -->
|
|
428
|
-
<button v-if="currentWallet" @click="clearWallet"
|
|
429
|
-
class="w-full px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-all duration-200 font-medium text-sm">
|
|
430
|
-
๐๏ธ Clear Wallet
|
|
431
|
-
</button>
|
|
432
|
-
|
|
433
|
-
<!-- Demo Keypair Button -->
|
|
434
|
-
<button @click="loadDemoKeypair"
|
|
435
|
-
class="w-full px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-all duration-200 font-medium text-sm mt-2">
|
|
436
|
-
๐ฏ Load Demo Keypair
|
|
437
|
-
</button>
|
|
438
|
-
</div>
|
|
439
|
-
|
|
440
|
-
<!-- Connection Test -->
|
|
441
|
-
<button @click="testConnection" :disabled="loading"
|
|
442
|
-
class="w-full px-4 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 font-medium shadow-lg hover:shadow-xl">
|
|
443
|
-
<span v-if="loading" class="flex items-center justify-center">
|
|
444
|
-
<svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" fill="none" viewBox="0 0 24 24">
|
|
445
|
-
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4">
|
|
446
|
-
</circle>
|
|
447
|
-
<path class="opacity-75" fill="currentColor"
|
|
448
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 714 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
|
|
449
|
-
</path>
|
|
450
|
-
</svg>
|
|
451
|
-
Testing...
|
|
452
|
-
</span>
|
|
453
|
-
<span v-else class="flex items-center justify-center">
|
|
454
|
-
๐ Test Connection
|
|
455
|
-
</span>
|
|
456
|
-
</button>
|
|
457
|
-
</div>
|
|
458
|
-
</div>
|
|
459
|
-
</div>
|
|
460
|
-
</div>
|
|
461
|
-
</div>
|
|
462
|
-
</div>
|
|
463
|
-
|
|
464
|
-
<!-- 2. Job Retrieval -->
|
|
465
|
-
<div id="job-retrieval" class="bg-white rounded-xl shadow-lg overflow-hidden border border-gray-100">
|
|
466
|
-
<div class="bg-gradient-to-r from-green-500 to-green-600 px-8 py-6">
|
|
467
|
-
<div class="flex items-center justify-between">
|
|
468
|
-
<h2 class="text-2xl font-bold text-white">๐ Job Retrieval</h2>
|
|
469
|
-
<span class="bg-white/20 px-3 py-1 rounded-full text-sm text-green-100">Jobs API</span>
|
|
470
|
-
</div>
|
|
471
|
-
</div>
|
|
472
|
-
|
|
473
|
-
<div class="p-8">
|
|
474
|
-
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
475
|
-
<!-- Documentation -->
|
|
476
|
-
<div class="lg:col-span-2">
|
|
477
|
-
<div class="prose prose-green max-w-none">
|
|
478
|
-
<h4 class="text-xl font-semibold text-gray-900 mb-4">๐ Documentation</h4>
|
|
479
|
-
|
|
480
|
-
<!-- Method Signatures -->
|
|
481
|
-
<div class="space-y-6">
|
|
482
|
-
<div class="bg-gray-50 rounded-lg p-4">
|
|
483
|
-
<div class="flex items-center justify-between mb-3">
|
|
484
|
-
<h5 class="font-semibold text-gray-700">Get Single Job</h5>
|
|
485
|
-
<span class="text-xs bg-green-100 text-green-800 px-2 py-1 rounded">async</span>
|
|
486
|
-
</div>
|
|
487
|
-
<code class="text-sm font-mono text-purple-600 block mb-3">
|
|
488
|
-
client.jobs.get(address: PublicKey): Promise<Job>
|
|
489
|
-
</code>
|
|
490
|
-
<p class="text-gray-700 text-sm">Retrieve a specific job by its blockchain address.</p>
|
|
491
|
-
</div>
|
|
492
|
-
|
|
493
|
-
<div class="bg-gray-50 rounded-lg p-4">
|
|
494
|
-
<div class="flex items-center justify-between mb-3">
|
|
495
|
-
<h5 class="font-semibold text-gray-700">Get Multiple Jobs</h5>
|
|
496
|
-
<span class="text-xs bg-green-100 text-green-800 px-2 py-1 rounded">async</span>
|
|
497
|
-
</div>
|
|
498
|
-
<code class="text-sm font-mono text-purple-600 block mb-3">
|
|
499
|
-
client.jobs.all(filters?: JobFilters): Promise<Job[]>
|
|
500
|
-
</code>
|
|
501
|
-
<p class="text-gray-700 text-sm">Retrieve multiple jobs with optional filtering capabilities.
|
|
502
|
-
The SDK also provides additional methods like <code
|
|
503
|
-
class="text-xs bg-gray-100 px-1 rounded">runs()</code>, <code
|
|
504
|
-
class="text-xs bg-gray-100 px-1 rounded">multiple()</code>, and <code
|
|
505
|
-
class="text-xs bg-gray-100 px-1 rounded">post()</code> for advanced use cases.
|
|
506
|
-
</p>
|
|
507
|
-
</div>
|
|
508
|
-
</div>
|
|
509
|
-
|
|
510
|
-
<!-- TypeScript Types -->
|
|
511
|
-
<div class="bg-gradient-to-r from-green-50 to-emerald-50 rounded-lg p-4 mt-6">
|
|
512
|
-
<button @click="toggleTypeInfo('jobs')"
|
|
513
|
-
class="flex items-center justify-between w-full text-left">
|
|
514
|
-
<h5 class="font-semibold text-green-900">๐ TypeScript Types</h5>
|
|
515
|
-
<svg :class="['w-4 h-4 transition-transform', showTypeInfo.jobs ? 'rotate-180' : '']"
|
|
516
|
-
fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
517
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7">
|
|
518
|
-
</path>
|
|
519
|
-
</svg>
|
|
520
|
-
</button>
|
|
521
|
-
<div v-show="showTypeInfo.jobs" class="mt-4 space-y-3">
|
|
522
|
-
<div class="bg-white rounded p-3 text-sm font-mono">
|
|
523
|
-
<div class="text-blue-600">interface</div>
|
|
524
|
-
<div class="text-purple-600">Job</div>
|
|
525
|
-
<div class="ml-4 text-gray-600">address: string</div>
|
|
526
|
-
<div class="ml-4 text-gray-600">state: number</div>
|
|
527
|
-
<div class="ml-4 text-gray-600">market: Address</div>
|
|
528
|
-
<div class="ml-4 text-gray-600">node: Address</div>
|
|
529
|
-
<div class="ml-4 text-gray-600">payer: Address</div>
|
|
530
|
-
<div class="ml-4 text-gray-600">project: Address</div>
|
|
531
|
-
<div class="ml-4 text-gray-600">price: number</div>
|
|
532
|
-
<div class="ml-4 text-gray-600">ipfsJob: string</div>
|
|
533
|
-
<div class="ml-4 text-gray-600">ipfsResult: string</div>
|
|
534
|
-
<div class="ml-4 text-gray-600">timeStart: number</div>
|
|
535
|
-
<div class="ml-4 text-gray-600">timeEnd: number</div>
|
|
536
|
-
<div class="ml-4 text-gray-600">timeout: number</div>
|
|
537
|
-
</div>
|
|
538
|
-
<div class="bg-white rounded p-3 text-sm font-mono">
|
|
539
|
-
<div class="text-blue-600">interface</div>
|
|
540
|
-
<div class="text-purple-600">JobFilters</div>
|
|
541
|
-
<div class="ml-4 text-gray-600">state?: number</div>
|
|
542
|
-
<div class="ml-4 text-gray-600">market?: Address</div>
|
|
543
|
-
<div class="ml-4 text-gray-600">node?: Address</div>
|
|
544
|
-
<div class="ml-4 text-gray-600">project?: Address</div>
|
|
545
|
-
</div>
|
|
546
|
-
</div>
|
|
547
|
-
</div>
|
|
548
|
-
|
|
549
|
-
<!-- Code Example -->
|
|
550
|
-
<div class="bg-gray-900 rounded-lg overflow-hidden mt-6">
|
|
551
|
-
<button @click="toggleCodeExample('jobs')"
|
|
552
|
-
class="w-full flex items-center justify-between bg-gray-800 px-4 py-2 hover:bg-gray-700 transition-colors">
|
|
553
|
-
<span class="text-gray-300 text-sm font-medium">Example Usage</span>
|
|
554
|
-
<svg
|
|
555
|
-
:class="['w-4 h-4 transition-transform text-gray-400', showCodeExample.jobs ? 'rotate-180' : '']"
|
|
556
|
-
fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
557
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7">
|
|
558
|
-
</path>
|
|
559
|
-
</svg>
|
|
560
|
-
</button>
|
|
561
|
-
<div v-show="showCodeExample.jobs" class="p-4">
|
|
562
|
-
<pre class="text-sm"><code class="text-green-400">import</code> <code class="text-blue-400">{ address }</code> <code class="text-green-400">from</code> <code class="text-yellow-400">'@nosana/kit'</code>
|
|
563
|
-
|
|
564
|
-
<code class="text-gray-500">// Get a specific job</code>
|
|
565
|
-
<code class="text-green-400">const</code> <code class="text-blue-400">jobAddress</code> <code class="text-white">=</code> <code class="text-yellow-400">'BwBURHTRMM3Ckzo2Dzmw99hv6gV8Ve12b6iw4sm9qeyR'</code>
|
|
566
|
-
<code class="text-green-400">const</code> <code class="text-blue-400">job</code> <code class="text-white">=</code> <code class="text-green-400">await</code> <code class="text-blue-400">client</code><code class="text-white">.</code><code class="text-blue-400">jobs</code><code class="text-white">.</code><code class="text-yellow-400">get</code><code class="text-white">(</code><code class="text-yellow-400">address</code><code class="text-white">(</code><code class="text-blue-400">jobAddress</code><code class="text-white">))</code>
|
|
567
|
-
|
|
568
|
-
<code class="text-gray-500">// Get all jobs with filters</code>
|
|
569
|
-
<code class="text-green-400">const</code> <code class="text-blue-400">runningJobs</code> <code class="text-white">=</code> <code class="text-green-400">await</code> <code class="text-blue-400">client</code><code class="text-white">.</code><code class="text-blue-400">jobs</code><code class="text-white">.</code><code class="text-yellow-400">all</code><code class="text-white">({</code>
|
|
570
|
-
<code class="text-blue-400">state</code><code class="text-white">:</code> <code class="text-orange-400">2</code><code class="text-gray-500">, // Completed</code>
|
|
571
|
-
<code class="text-blue-400">market</code><code class="text-white">:</code> <code class="text-yellow-400">'MarketAddress123...'</code>
|
|
572
|
-
<code class="text-white">})</code></pre>
|
|
573
|
-
</div>
|
|
574
|
-
</div>
|
|
575
|
-
|
|
576
|
-
<!-- Job States Reference -->
|
|
577
|
-
<div class="mt-6">
|
|
578
|
-
<h5 class="font-semibold text-gray-900 mb-4">Job State Reference</h5>
|
|
579
|
-
<div class="grid grid-cols-2 gap-3">
|
|
580
|
-
<div class="bg-yellow-50 border border-yellow-200 p-3 rounded-lg text-center">
|
|
581
|
-
<div class="text-2xl mb-1">๐ก</div>
|
|
582
|
-
<div class="font-semibold text-yellow-900">Queued</div>
|
|
583
|
-
<div class="text-xs text-yellow-700">State: 0</div>
|
|
584
|
-
</div>
|
|
585
|
-
<div class="bg-blue-50 border border-blue-200 p-3 rounded-lg text-center">
|
|
586
|
-
<div class="text-2xl mb-1">๐ต</div>
|
|
587
|
-
<div class="font-semibold text-blue-900">Running</div>
|
|
588
|
-
<div class="text-xs text-blue-700">State: 1</div>
|
|
589
|
-
</div>
|
|
590
|
-
<div class="bg-green-50 border border-green-200 p-3 rounded-lg text-center">
|
|
591
|
-
<div class="text-2xl mb-1">๐ข</div>
|
|
592
|
-
<div class="font-semibold text-green-900">Done</div>
|
|
593
|
-
<div class="text-xs text-green-700">State: 2</div>
|
|
594
|
-
</div>
|
|
595
|
-
<div class="bg-red-50 border border-red-200 p-3 rounded-lg text-center">
|
|
596
|
-
<div class="text-2xl mb-1">๐ด</div>
|
|
597
|
-
<div class="font-semibold text-red-900">Stopped</div>
|
|
598
|
-
<div class="text-xs text-red-700">State: 3</div>
|
|
599
|
-
</div>
|
|
600
|
-
</div>
|
|
601
|
-
</div>
|
|
602
|
-
</div>
|
|
603
|
-
</div>
|
|
604
|
-
|
|
605
|
-
<!-- Interactive Controls -->
|
|
606
|
-
<div class="lg:col-span-1">
|
|
607
|
-
<div class="bg-gradient-to-br from-green-50 to-emerald-100 rounded-xl p-6 sticky top-24">
|
|
608
|
-
<h4 class="font-semibold text-gray-900 mb-4">๐ฎ Try It Now</h4>
|
|
609
|
-
|
|
610
|
-
<div class="space-y-6">
|
|
611
|
-
<!-- Get Single Job -->
|
|
612
|
-
<div class="bg-white rounded-lg p-4 border border-green-200">
|
|
613
|
-
<label class="block text-sm font-semibold text-gray-700 mb-2">
|
|
614
|
-
๐ Get Job by Address
|
|
615
|
-
</label>
|
|
616
|
-
<input v-model="jobAddress" type="text" placeholder="Job address..."
|
|
617
|
-
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent mb-3" />
|
|
618
|
-
<button @click="getJob" :disabled="loading || !jobAddress"
|
|
619
|
-
class="w-full px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 font-medium text-sm shadow-lg hover:shadow-xl">
|
|
620
|
-
<span v-if="loading" class="flex items-center justify-center">
|
|
621
|
-
<svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" fill="none" viewBox="0 0 24 24">
|
|
622
|
-
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor"
|
|
623
|
-
stroke-width="4"></circle>
|
|
624
|
-
<path class="opacity-75" fill="currentColor"
|
|
625
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
|
|
626
|
-
</path>
|
|
627
|
-
</svg>
|
|
628
|
-
Loading...
|
|
629
|
-
</span>
|
|
630
|
-
<span v-else>๐ Get Job</span>
|
|
631
|
-
</button>
|
|
632
|
-
</div>
|
|
633
|
-
|
|
634
|
-
<!-- Get Multiple Jobs -->
|
|
635
|
-
<div class="bg-white rounded-lg p-4 border border-green-200">
|
|
636
|
-
<label class="block text-sm font-semibold text-gray-700 mb-2">
|
|
637
|
-
๐ Get Jobs with Filters
|
|
638
|
-
</label>
|
|
639
|
-
<select v-model="jobFilters.state"
|
|
640
|
-
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent mb-2">
|
|
641
|
-
<option value="">Any State</option>
|
|
642
|
-
<option value="0">๐ก Queued</option>
|
|
643
|
-
<option value="1">๐ต Running</option>
|
|
644
|
-
<option value="2">๐ข Done</option>
|
|
645
|
-
<option value="3">๐ด Stopped</option>
|
|
646
|
-
</select>
|
|
647
|
-
<input v-model="jobFilters.market" type="text" placeholder="Market Address (optional)"
|
|
648
|
-
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent mb-2" />
|
|
649
|
-
<input v-model="jobFilters.node" type="text" placeholder="Node Address (optional)"
|
|
650
|
-
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent mb-2" />
|
|
651
|
-
<input v-model="jobFilters.project" type="text" placeholder="Project Address (optional)"
|
|
652
|
-
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent mb-3" />
|
|
653
|
-
<button @click="getAllJobs" :disabled="loading"
|
|
654
|
-
class="w-full px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 font-medium text-sm shadow-lg hover:shadow-xl">
|
|
655
|
-
<span v-if="loading" class="flex items-center justify-center">
|
|
656
|
-
<svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" fill="none" viewBox="0 0 24 24">
|
|
657
|
-
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor"
|
|
658
|
-
stroke-width="4"></circle>
|
|
659
|
-
<path class="opacity-75" fill="currentColor"
|
|
660
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 714 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
|
|
661
|
-
</path>
|
|
662
|
-
</svg>
|
|
663
|
-
Fetching...
|
|
664
|
-
</span>
|
|
665
|
-
<span v-else>๐ Get Jobs</span>
|
|
666
|
-
</button>
|
|
667
|
-
</div>
|
|
668
|
-
</div>
|
|
669
|
-
</div>
|
|
670
|
-
</div>
|
|
671
|
-
</div>
|
|
672
|
-
</div>
|
|
673
|
-
</div>
|
|
674
|
-
|
|
675
|
-
<!-- 3. Market Discovery -->
|
|
676
|
-
<div id="market-discovery" class="bg-white rounded-xl shadow-lg overflow-hidden border border-gray-100">
|
|
677
|
-
<div class="bg-gradient-to-r from-orange-500 to-orange-600 px-8 py-6">
|
|
678
|
-
<div class="flex items-center justify-between">
|
|
679
|
-
<h2 class="text-2xl font-bold text-white">๐ช Market Discovery</h2>
|
|
680
|
-
<span class="bg-white/20 px-3 py-1 rounded-full text-sm text-orange-100">Markets API</span>
|
|
681
|
-
</div>
|
|
682
|
-
</div>
|
|
683
|
-
|
|
684
|
-
<div class="p-8">
|
|
685
|
-
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
686
|
-
<!-- Documentation -->
|
|
687
|
-
<div class="lg:col-span-2">
|
|
688
|
-
<div class="prose prose-orange max-w-none">
|
|
689
|
-
<h4 class="text-xl font-semibold text-gray-900 mb-4">๐ Documentation</h4>
|
|
690
|
-
|
|
691
|
-
<!-- Method Signature -->
|
|
692
|
-
<div class="bg-gray-50 rounded-lg p-4 mb-6">
|
|
693
|
-
<div class="flex items-center justify-between mb-3">
|
|
694
|
-
<h5 class="font-semibold text-gray-700">Get All Markets</h5>
|
|
695
|
-
<span class="text-xs bg-orange-100 text-orange-800 px-2 py-1 rounded">async</span>
|
|
696
|
-
</div>
|
|
697
|
-
<code class="text-sm font-mono text-purple-600 block mb-3">
|
|
698
|
-
client.jobs.markets(): Promise<Market[]>
|
|
699
|
-
</code>
|
|
700
|
-
<p class="text-gray-700 text-sm">
|
|
701
|
-
Retrieve all available compute markets with pricing and configuration details.
|
|
702
|
-
</p>
|
|
703
|
-
</div>
|
|
704
|
-
|
|
705
|
-
<!-- TypeScript Types -->
|
|
706
|
-
<div class="bg-gradient-to-r from-orange-50 to-red-50 rounded-lg p-4 mb-6">
|
|
707
|
-
<button @click="toggleTypeInfo('markets')"
|
|
708
|
-
class="flex items-center justify-between w-full text-left">
|
|
709
|
-
<h5 class="font-semibold text-orange-900">๐ TypeScript Types</h5>
|
|
710
|
-
<svg :class="['w-4 h-4 transition-transform', showTypeInfo.markets ? 'rotate-180' : '']"
|
|
711
|
-
fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
712
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7">
|
|
713
|
-
</path>
|
|
714
|
-
</svg>
|
|
715
|
-
</button>
|
|
716
|
-
<div v-show="showTypeInfo.markets" class="mt-4 space-y-3">
|
|
717
|
-
<div class="bg-white rounded p-3 text-sm font-mono">
|
|
718
|
-
<div class="text-blue-600">interface</div>
|
|
719
|
-
<div class="text-purple-600">Market</div>
|
|
720
|
-
<div class="ml-4 text-gray-600">address: string</div>
|
|
721
|
-
<div class="ml-4 text-gray-600">authority: Address</div>
|
|
722
|
-
<div class="ml-4 text-gray-600">jobExpiration: number</div>
|
|
723
|
-
<div class="ml-4 text-gray-600">jobPrice: number</div>
|
|
724
|
-
<div class="ml-4 text-gray-600">jobTimeout: number</div>
|
|
725
|
-
<div class="ml-4 text-gray-600">jobType: number</div>
|
|
726
|
-
<div class="ml-4 text-gray-600">vault: Address</div>
|
|
727
|
-
<div class="ml-4 text-gray-600">vaultBump: number</div>
|
|
728
|
-
<div class="ml-4 text-gray-600">nodeAccessKey: Address</div>
|
|
729
|
-
<div class="ml-4 text-gray-600">nodeXnosMinimum: number</div>
|
|
730
|
-
<div class="ml-4 text-gray-600">queueType: number</div>
|
|
731
|
-
<div class="ml-4 text-gray-600">queue: Address[]</div>
|
|
732
|
-
</div>
|
|
733
|
-
</div>
|
|
734
|
-
</div>
|
|
735
|
-
|
|
736
|
-
<!-- Code Example -->
|
|
737
|
-
<div class="bg-gray-900 rounded-lg overflow-hidden mb-6">
|
|
738
|
-
<button @click="toggleCodeExample('markets')"
|
|
739
|
-
class="w-full flex items-center justify-between bg-gray-800 px-4 py-2 hover:bg-gray-700 transition-colors">
|
|
740
|
-
<span class="text-gray-300 text-sm font-medium">Example Usage</span>
|
|
741
|
-
<svg
|
|
742
|
-
:class="['w-4 h-4 transition-transform text-gray-400', showCodeExample.markets ? 'rotate-180' : '']"
|
|
743
|
-
fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
744
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7">
|
|
745
|
-
</path>
|
|
746
|
-
</svg>
|
|
747
|
-
</button>
|
|
748
|
-
<div v-show="showCodeExample.markets" class="p-4">
|
|
749
|
-
<pre
|
|
750
|
-
class="text-sm"><code class="text-gray-500">// Get all available markets</code>
|
|
751
|
-
<code class="text-green-400">const</code> <code class="text-blue-400">markets</code> <code class="text-white">=</code> <code class="text-green-400">await</code> <code class="text-blue-400">client</code><code class="text-white">.</code><code class="text-blue-400">jobs</code><code class="text-white">.</code><code class="text-yellow-400">markets</code><code class="text-white">()</code>
|
|
752
|
-
|
|
753
|
-
<code class="text-gray-500">// Find cheapest market</code>
|
|
754
|
-
<code class="text-green-400">const</code> <code class="text-blue-400">cheapest</code> <code class="text-white">=</code> <code class="text-blue-400">markets</code><code class="text-white">.</code><code class="text-yellow-400">reduce</code><code class="text-white">((</code><code class="text-blue-400">min</code><code class="text-white">,</code> <code class="text-blue-400">market</code><code class="text-white">) =></code>
|
|
755
|
-
<code class="text-blue-400">market</code><code class="text-white">.</code><code class="text-blue-400">jobPrice</code> <code class="text-white"><</code> <code class="text-blue-400">min</code><code class="text-white">.</code><code class="text-blue-400">jobPrice</code> <code class="text-white">?</code> <code class="text-blue-400">market</code> <code class="text-white">:</code> <code class="text-blue-400">min</code>
|
|
756
|
-
<code class="text-white">)</code>
|
|
757
|
-
|
|
758
|
-
<code class="text-gray-500">// Filter by timeout</code>
|
|
759
|
-
<code class="text-green-400">const</code> <code class="text-blue-400">fastMarkets</code> <code class="text-white">=</code> <code class="text-blue-400">markets</code><code class="text-white">.</code><code class="text-yellow-400">filter</code><code class="text-white">(</code><code class="text-blue-400">m</code> <code class="text-white">=></code> <code class="text-blue-400">m</code><code class="text-white">.</code><code class="text-blue-400">jobTimeout</code> <code class="text-white"><</code> <code class="text-orange-400">300</code><code class="text-white">)</code></pre>
|
|
760
|
-
</div>
|
|
761
|
-
</div>
|
|
762
|
-
|
|
763
|
-
<!-- Market Info -->
|
|
764
|
-
<div class="bg-orange-50 border-l-4 border-orange-400 p-4 rounded">
|
|
765
|
-
<h6 class="font-semibold text-orange-900 mb-2">๐ก Market Insights</h6>
|
|
766
|
-
<p class="text-orange-800 text-sm mb-2">
|
|
767
|
-
Markets represent different compute environments with varying pricing, timeouts, and node
|
|
768
|
-
requirements.
|
|
769
|
-
</p>
|
|
770
|
-
<ul class="text-orange-700 text-sm space-y-1">
|
|
771
|
-
<li>โข <strong>Job Price:</strong> Cost in lamports per job execution</li>
|
|
772
|
-
<li>โข <strong>Job Timeout:</strong> Maximum execution time in seconds</li>
|
|
773
|
-
<li>โข <strong>Job Expiration:</strong> How long jobs remain in queue</li>
|
|
774
|
-
<li>โข <strong>Node Access Key:</strong> Required key for node participation</li>
|
|
775
|
-
</ul>
|
|
776
|
-
</div>
|
|
777
|
-
</div>
|
|
778
|
-
</div>
|
|
779
|
-
|
|
780
|
-
<!-- Interactive Controls -->
|
|
781
|
-
<div class="lg:col-span-1">
|
|
782
|
-
<div class="bg-gradient-to-br from-orange-50 to-red-100 rounded-xl p-6 sticky top-24">
|
|
783
|
-
<h4 class="font-semibold text-gray-900 mb-4">๐ฎ Try It Now</h4>
|
|
784
|
-
|
|
785
|
-
<div class="bg-white rounded-lg p-4 border border-orange-200">
|
|
786
|
-
<div class="text-center mb-4">
|
|
787
|
-
<div class="text-3xl mb-2">๐ช</div>
|
|
788
|
-
<p class="text-sm text-gray-600 mb-3">
|
|
789
|
-
Discover all available compute markets and their pricing models.
|
|
790
|
-
</p>
|
|
791
|
-
</div>
|
|
792
|
-
<button @click="getMarkets" :disabled="loading"
|
|
793
|
-
class="w-full px-4 py-3 bg-orange-600 text-white rounded-lg hover:bg-orange-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 font-medium shadow-lg hover:shadow-xl">
|
|
794
|
-
<span v-if="loading" class="flex items-center justify-center">
|
|
795
|
-
<svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" fill="none" viewBox="0 0 24 24">
|
|
796
|
-
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4">
|
|
797
|
-
</circle>
|
|
798
|
-
<path class="opacity-75" fill="currentColor"
|
|
799
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
|
|
800
|
-
</path>
|
|
801
|
-
</svg>
|
|
802
|
-
Loading...
|
|
803
|
-
</span>
|
|
804
|
-
<span v-else>๐ช Get Markets</span>
|
|
805
|
-
</button>
|
|
806
|
-
</div>
|
|
807
|
-
</div>
|
|
808
|
-
</div>
|
|
809
|
-
</div>
|
|
810
|
-
</div>
|
|
811
|
-
</div>
|
|
812
|
-
|
|
813
|
-
<!-- 4. Real-time Monitoring -->
|
|
814
|
-
<div id="monitoring" class="bg-white rounded-xl shadow-lg overflow-hidden border border-gray-100">
|
|
815
|
-
<div class="bg-gradient-to-r from-purple-500 to-purple-600 px-8 py-6">
|
|
816
|
-
<div class="flex items-center justify-between">
|
|
817
|
-
<h2 class="text-2xl font-bold text-white">๐ก Real-time Monitoring</h2>
|
|
818
|
-
<span class="bg-white/20 px-3 py-1 rounded-full text-sm text-purple-100">Monitor API</span>
|
|
819
|
-
</div>
|
|
820
|
-
</div>
|
|
821
|
-
|
|
822
|
-
<div class="p-8">
|
|
823
|
-
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
824
|
-
<!-- Documentation -->
|
|
825
|
-
<div class="lg:col-span-2">
|
|
826
|
-
<div class="prose prose-purple max-w-none">
|
|
827
|
-
<h4 class="text-xl font-semibold text-gray-900 mb-4">๐ Documentation</h4>
|
|
828
|
-
|
|
829
|
-
<!-- Method Signature -->
|
|
830
|
-
<div class="bg-gray-50 rounded-lg p-4 mb-6">
|
|
831
|
-
<div class="flex items-center justify-between mb-3">
|
|
832
|
-
<h5 class="font-semibold text-gray-700">Monitor Blockchain Events</h5>
|
|
833
|
-
<span class="text-xs bg-purple-100 text-purple-800 px-2 py-1 rounded">async</span>
|
|
834
|
-
</div>
|
|
835
|
-
<code class="text-sm font-mono text-purple-600 block mb-3">
|
|
836
|
-
client.jobs.monitor(callbacks: MonitorCallbacks): Promise<() => void>
|
|
837
|
-
</code>
|
|
838
|
-
<p class="text-gray-700 text-sm">
|
|
839
|
-
Start real-time monitoring of blockchain events for jobs, runs, and markets.
|
|
840
|
-
</p>
|
|
841
|
-
</div>
|
|
842
|
-
|
|
843
|
-
<!-- TypeScript Types -->
|
|
844
|
-
<div class="bg-gradient-to-r from-purple-50 to-indigo-50 rounded-lg p-4 mb-6">
|
|
845
|
-
<button @click="toggleTypeInfo('monitoring')"
|
|
846
|
-
class="flex items-center justify-between w-full text-left">
|
|
847
|
-
<h5 class="font-semibold text-purple-900">๐ TypeScript Types</h5>
|
|
848
|
-
<svg :class="['w-4 h-4 transition-transform', showTypeInfo.monitoring ? 'rotate-180' : '']"
|
|
849
|
-
fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
850
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7">
|
|
851
|
-
</path>
|
|
852
|
-
</svg>
|
|
853
|
-
</button>
|
|
854
|
-
<div v-show="showTypeInfo.monitoring" class="mt-4 space-y-3">
|
|
855
|
-
<div class="bg-white rounded p-3 text-sm font-mono">
|
|
856
|
-
<div class="text-blue-600">interface</div>
|
|
857
|
-
<div class="text-purple-600">MonitorCallbacks</div>
|
|
858
|
-
<div class="ml-4 text-gray-600">onJobAccount?: (job: Job) => Promise<void></div>
|
|
859
|
-
<div class="ml-4 text-gray-600">onRunAccount?: (run: Run) => Promise<void></div>
|
|
860
|
-
<div class="ml-4 text-gray-600">onMarketAccount?: (market: Market) => Promise<void>
|
|
861
|
-
</div>
|
|
862
|
-
<div class="ml-4 text-gray-600">onError?: (error: Error, type: string) =>
|
|
863
|
-
Promise<void></div>
|
|
864
|
-
</div>
|
|
865
|
-
</div>
|
|
866
|
-
</div>
|
|
867
|
-
|
|
868
|
-
<!-- Code Example -->
|
|
869
|
-
<div class="bg-gray-900 rounded-lg overflow-hidden mb-6">
|
|
870
|
-
<button @click="toggleCodeExample('monitoring')"
|
|
871
|
-
class="w-full flex items-center justify-between bg-gray-800 px-4 py-2 hover:bg-gray-700 transition-colors">
|
|
872
|
-
<span class="text-gray-300 text-sm font-medium">Example Usage</span>
|
|
873
|
-
<svg
|
|
874
|
-
:class="['w-4 h-4 transition-transform text-gray-400', showCodeExample.monitoring ? 'rotate-180' : '']"
|
|
875
|
-
fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
876
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7">
|
|
877
|
-
</path>
|
|
878
|
-
</svg>
|
|
879
|
-
</button>
|
|
880
|
-
<div v-show="showCodeExample.monitoring" class="p-4">
|
|
881
|
-
<pre class="text-sm"><code class="text-gray-500">// Start monitoring with callbacks</code>
|
|
882
|
-
<code class="text-green-400">const</code> <code class="text-blue-400">stopMonitoring</code> <code class="text-white">=</code> <code class="text-green-400">await</code> <code class="text-blue-400">client</code><code class="text-white">.</code><code class="text-blue-400">jobs</code><code class="text-white">.</code><code class="text-yellow-400">monitor</code><code class="text-white">({</code>
|
|
883
|
-
<code class="text-blue-400">onJobAccount</code><code class="text-white">:</code> <code class="text-green-400">async</code> <code class="text-white">(</code><code class="text-blue-400">job</code><code class="text-white">) =></code> <code class="text-white">{</code>
|
|
884
|
-
<code class="text-blue-400">console</code><code class="text-white">.</code><code class="text-yellow-400">log</code><code class="text-white">(</code><code class="text-yellow-400">'Job updated:'</code><code class="text-white">,</code> <code class="text-blue-400">job</code><code class="text-white">.</code><code class="text-blue-400">address</code><code class="text-white">)</code>
|
|
885
|
-
<code class="text-white">},</code>
|
|
886
|
-
<code class="text-blue-400">onRunAccount</code><code class="text-white">:</code> <code class="text-green-400">async</code> <code class="text-white">(</code><code class="text-blue-400">run</code><code class="text-white">) =></code> <code class="text-white">{</code>
|
|
887
|
-
<code class="text-blue-400">console</code><code class="text-white">.</code><code class="text-yellow-400">log</code><code class="text-white">(</code><code class="text-yellow-400">'Run updated:'</code><code class="text-white">,</code> <code class="text-blue-400">run</code><code class="text-white">.</code><code class="text-blue-400">address</code><code class="text-white">)</code>
|
|
888
|
-
<code class="text-white">},</code>
|
|
889
|
-
<code class="text-blue-400">onError</code><code class="text-white">:</code> <code class="text-green-400">async</code> <code class="text-white">(</code><code class="text-blue-400">error</code><code class="text-white">) =></code> <code class="text-white">{</code>
|
|
890
|
-
<code class="text-blue-400">console</code><code class="text-white">.</code><code class="text-red-400">error</code><code class="text-white">(</code><code class="text-yellow-400">'Monitor error:'</code><code class="text-white">,</code> <code class="text-blue-400">error</code><code class="text-white">)</code>
|
|
891
|
-
<code class="text-white">}</code>
|
|
892
|
-
<code class="text-white">})</code>
|
|
893
|
-
|
|
894
|
-
<code class="text-gray-500">// Stop monitoring when done</code>
|
|
895
|
-
<code class="text-blue-400">stopMonitoring</code><code class="text-white">()</code></pre>
|
|
896
|
-
</div>
|
|
897
|
-
</div>
|
|
898
|
-
|
|
899
|
-
<!-- Monitor Info -->
|
|
900
|
-
<div class="bg-purple-50 border-l-4 border-purple-400 p-4 rounded">
|
|
901
|
-
<h6 class="font-semibold text-purple-900 mb-2">โก Real-time Updates</h6>
|
|
902
|
-
<p class="text-purple-800 text-sm mb-2">
|
|
903
|
-
Monitor blockchain events in real-time to track job progress, run status, and market changes.
|
|
904
|
-
</p>
|
|
905
|
-
<ul class="text-purple-700 text-sm space-y-1">
|
|
906
|
-
<li>โข <strong>Job Events:</strong> State changes, node assignments, completions</li>
|
|
907
|
-
<li>โข <strong>Run Events:</strong> Execution start/stop, result updates</li>
|
|
908
|
-
<li>โข <strong>Market Events:</strong> Price changes, configuration updates</li>
|
|
909
|
-
<li>โข <strong>Error Handling:</strong> Connection issues, parsing errors</li>
|
|
910
|
-
</ul>
|
|
911
|
-
</div>
|
|
912
|
-
</div>
|
|
913
|
-
</div>
|
|
914
|
-
|
|
915
|
-
<!-- Interactive Controls -->
|
|
916
|
-
<div class="lg:col-span-1">
|
|
917
|
-
<div class="bg-gradient-to-br from-purple-50 to-indigo-100 rounded-xl p-6 sticky top-24">
|
|
918
|
-
<h4 class="font-semibold text-gray-900 mb-4">๐ฎ Try It Now</h4>
|
|
919
|
-
|
|
920
|
-
<div class="space-y-4">
|
|
921
|
-
<div class="bg-white rounded-lg p-4 border border-purple-200">
|
|
922
|
-
<div class="flex items-center justify-between mb-3">
|
|
923
|
-
<span class="text-sm font-semibold text-gray-700">
|
|
924
|
-
Monitor Status
|
|
925
|
-
</span>
|
|
926
|
-
<div class="flex items-center">
|
|
927
|
-
<div :class="[
|
|
928
|
-
'w-3 h-3 rounded-full mr-2',
|
|
929
|
-
isMonitoring ? 'bg-green-500 animate-pulse' : 'bg-gray-400'
|
|
930
|
-
]"></div>
|
|
931
|
-
<span class="text-sm font-medium"
|
|
932
|
-
:class="isMonitoring ? 'text-green-700' : 'text-gray-600'">
|
|
933
|
-
{{ isMonitoring ? 'Active' : 'Inactive' }}
|
|
934
|
-
</span>
|
|
935
|
-
</div>
|
|
936
|
-
</div>
|
|
937
|
-
|
|
938
|
-
<div class="text-center mb-4">
|
|
939
|
-
<div class="text-3xl mb-2">{{ isMonitoring ? '๐ก' : '๐ด' }}</div>
|
|
940
|
-
<p class="text-xs text-gray-500">
|
|
941
|
-
{{ isMonitoring ? 'Watching for blockchain events' : 'Ready to start monitoring' }}
|
|
942
|
-
</p>
|
|
943
|
-
</div>
|
|
944
|
-
|
|
945
|
-
<button @click="toggleMonitoring" :disabled="loading" :class="[
|
|
946
|
-
'w-full px-4 py-3 rounded-lg disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 font-medium shadow-lg hover:shadow-xl',
|
|
947
|
-
isMonitoring
|
|
948
|
-
? 'bg-red-600 text-white hover:bg-red-700'
|
|
949
|
-
: 'bg-purple-600 text-white hover:bg-purple-700'
|
|
950
|
-
]">
|
|
951
|
-
<span v-if="loading" class="flex items-center justify-center">
|
|
952
|
-
<svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" fill="none" viewBox="0 0 24 24">
|
|
953
|
-
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor"
|
|
954
|
-
stroke-width="4"></circle>
|
|
955
|
-
<path class="opacity-75" fill="currentColor"
|
|
956
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
|
|
957
|
-
</path>
|
|
958
|
-
</svg>
|
|
959
|
-
Processing...
|
|
960
|
-
</span>
|
|
961
|
-
<span v-else>
|
|
962
|
-
{{ isMonitoring ? '๐ Stop Monitoring' : '๐ Start Monitoring' }}
|
|
963
|
-
</span>
|
|
964
|
-
</button>
|
|
965
|
-
|
|
966
|
-
<p class="text-xs text-gray-500 mt-3 text-center">
|
|
967
|
-
Monitor real-time blockchain events and see updates in the terminal
|
|
968
|
-
</p>
|
|
969
|
-
</div>
|
|
970
|
-
</div>
|
|
971
|
-
</div>
|
|
972
|
-
</div>
|
|
973
|
-
</div>
|
|
974
|
-
</div>
|
|
975
|
-
</div>
|
|
976
|
-
</div>
|
|
977
|
-
</div>
|
|
978
|
-
|
|
979
|
-
<!-- Terminal Output - Right Sidebar -->
|
|
980
|
-
<div :class="[
|
|
981
|
-
'transition-all duration-300',
|
|
982
|
-
isFullscreenTerminal ? 'fixed inset-0 z-50' : 'lg:col-span-5'
|
|
983
|
-
]">
|
|
984
|
-
<div :class="[
|
|
985
|
-
'shadow-lg flex flex-col',
|
|
986
|
-
isFullscreenTerminal
|
|
987
|
-
? 'bg-gray-900 h-full w-full'
|
|
988
|
-
: 'bg-white rounded-xl sticky top-24 max-h-[80vh] border border-gray-100'
|
|
989
|
-
]">
|
|
990
|
-
<div class="bg-gradient-to-r from-gray-800 to-gray-900 px-6 py-4 flex items-center justify-between"
|
|
991
|
-
:class="isFullscreenTerminal ? 'rounded-none' : 'rounded-t-xl'">
|
|
992
|
-
<div class="flex items-center space-x-3">
|
|
993
|
-
<!-- <div class="flex space-x-1">
|
|
994
|
-
<div class="w-3 h-3 bg-red-500 rounded-full"></div>
|
|
995
|
-
<div class="w-3 h-3 bg-yellow-500 rounded-full"></div>
|
|
996
|
-
<div class="w-3 h-3 bg-green-500 rounded-full"></div>
|
|
997
|
-
</div> -->
|
|
998
|
-
<h3 class="text-white font-semibold">๐ป Terminal Output</h3>
|
|
999
|
-
</div>
|
|
1000
|
-
<div class="flex items-center space-x-3">
|
|
1001
|
-
<span class="text-gray-300 text-sm">{{ logs.length }} lines</span>
|
|
1002
|
-
<button @click="autoScroll = !autoScroll" :class="[
|
|
1003
|
-
'px-3 py-1 text-xs rounded-full transition-all duration-200',
|
|
1004
|
-
autoScroll ? 'bg-green-600 text-white' : 'bg-gray-600 text-gray-200'
|
|
1005
|
-
]">
|
|
1006
|
-
Auto: {{ autoScroll ? 'ON' : 'OFF' }}
|
|
1007
|
-
</button>
|
|
1008
|
-
<button @click="toggleFullscreenTerminal"
|
|
1009
|
-
class="p-2 text-gray-300 hover:text-white hover:bg-gray-700 rounded-lg transition-colors"
|
|
1010
|
-
:title="isFullscreenTerminal ? 'Exit Fullscreen' : 'Enter Fullscreen'">
|
|
1011
|
-
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
1012
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" :d="isFullscreenTerminal
|
|
1013
|
-
? 'M9 9l6 6m0-6l-6 6M21 3l-6 6m0 0V4m0 5h5M3 21l6-6m0 0v5m0-5H4'
|
|
1014
|
-
: 'M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4'">
|
|
1015
|
-
</path>
|
|
1016
|
-
</svg>
|
|
1017
|
-
</button>
|
|
1018
|
-
</div>
|
|
1019
|
-
</div>
|
|
1020
|
-
|
|
1021
|
-
<div ref="terminal" :class="[
|
|
1022
|
-
'terminal flex-1 overflow-y-auto overflow-x-auto p-6',
|
|
1023
|
-
isFullscreenTerminal ? 'min-h-[calc(100vh-8.3rem)]' : 'min-h-[400px] max-h-[400px]'
|
|
1024
|
-
]">
|
|
1025
|
-
<div v-for="(log, index) in logs" :key="index" class="terminal-line whitespace-nowrap mb-2">
|
|
1026
|
-
<span class="terminal-timestamp">{{ log.timestamp }}</span>
|
|
1027
|
-
<span :class="getLogClass(log.type)">{{ log.message }}</span>
|
|
1028
|
-
</div>
|
|
1029
|
-
<div v-if="logs.length === 0" class="text-gray-400 italic text-center mt-12">
|
|
1030
|
-
<div class="text-4xl mb-4">๐ป</div>
|
|
1031
|
-
<p class="text-lg font-medium mb-2">Terminal Ready</p>
|
|
1032
|
-
<p class="text-sm">Output will appear here when you test the API methods</p>
|
|
1033
|
-
</div>
|
|
1034
|
-
</div>
|
|
1035
|
-
|
|
1036
|
-
<div class="p-4 border-t border-gray-200 bg-gray-50"
|
|
1037
|
-
:class="isFullscreenTerminal ? 'rounded-none' : 'rounded-b-xl'">
|
|
1038
|
-
<div class="flex space-x-2">
|
|
1039
|
-
<button @click="clearLogs"
|
|
1040
|
-
class="flex-1 px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 text-sm transition-all duration-200 font-medium shadow-lg hover:shadow-xl">
|
|
1041
|
-
๐๏ธ Clear Terminal
|
|
1042
|
-
</button>
|
|
1043
|
-
<button @click="exportLogs"
|
|
1044
|
-
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm transition-all duration-200 font-medium shadow-lg hover:shadow-xl">
|
|
1045
|
-
๐พ Export
|
|
1046
|
-
</button>
|
|
1047
|
-
</div>
|
|
1048
|
-
</div>
|
|
1049
|
-
</div>
|
|
1050
|
-
</div>
|
|
1051
|
-
</div>
|
|
1052
|
-
</div>
|
|
1053
|
-
</div>
|
|
1054
|
-
</template>
|
|
1055
|
-
|
|
1056
|
-
<script setup>
|
|
1057
|
-
import { ref, computed, onMounted, nextTick } from 'vue'
|
|
1058
|
-
const { NosanaClient, NosanaNetwork, address } = await import('@nosana/kit')
|
|
1059
|
-
// Reactive state
|
|
1060
|
-
const selectedNetwork = ref('mainnet')
|
|
1061
|
-
const isConnected = ref(false)
|
|
1062
|
-
const loading = ref(false)
|
|
1063
|
-
const jobAddress = ref()
|
|
1064
|
-
const jobFilters = ref({
|
|
1065
|
-
state: '',
|
|
1066
|
-
market: '',
|
|
1067
|
-
node: '',
|
|
1068
|
-
project: ''
|
|
1069
|
-
})
|
|
1070
|
-
const isMonitoring = ref(false)
|
|
1071
|
-
const autoScroll = ref(true)
|
|
1072
|
-
const logs = ref([])
|
|
1073
|
-
const terminal = ref(null)
|
|
1074
|
-
const isFullscreenTerminal = ref(false)
|
|
1075
|
-
|
|
1076
|
-
// Wallet state
|
|
1077
|
-
const currentWallet = ref(null)
|
|
1078
|
-
const walletInputMethod = ref('browser')
|
|
1079
|
-
const walletInputs = ref({
|
|
1080
|
-
privateKey: '',
|
|
1081
|
-
fileContent: null
|
|
1082
|
-
})
|
|
1083
|
-
const fileInput = ref(null)
|
|
1084
|
-
|
|
1085
|
-
// Browser wallet state
|
|
1086
|
-
const browserWallet = ref({
|
|
1087
|
-
connected: false,
|
|
1088
|
-
connecting: false,
|
|
1089
|
-
name: null,
|
|
1090
|
-
publicKey: null,
|
|
1091
|
-
adapter: null
|
|
1092
|
-
})
|
|
1093
|
-
|
|
1094
|
-
// Documentation visibility
|
|
1095
|
-
const showTypeInfo = ref({
|
|
1096
|
-
init: false,
|
|
1097
|
-
jobs: false,
|
|
1098
|
-
markets: false,
|
|
1099
|
-
monitoring: false
|
|
1100
|
-
})
|
|
1101
|
-
const showCodeExample = ref({
|
|
1102
|
-
init: false,
|
|
1103
|
-
jobs: false,
|
|
1104
|
-
markets: false,
|
|
1105
|
-
monitoring: false
|
|
1106
|
-
})
|
|
1107
|
-
|
|
1108
|
-
// SDK client
|
|
1109
|
-
let client = null
|
|
1110
|
-
let stopMonitoring = null
|
|
1111
|
-
|
|
1112
|
-
// Computed properties
|
|
1113
|
-
const canSetWallet = computed(() => {
|
|
1114
|
-
switch (walletInputMethod.value) {
|
|
1115
|
-
case 'browser':
|
|
1116
|
-
return browserWallet.value.connected
|
|
1117
|
-
case 'paste':
|
|
1118
|
-
return walletInputs.value.privateKey.trim().length > 0
|
|
1119
|
-
case 'file':
|
|
1120
|
-
return walletInputs.value.fileContent !== null
|
|
1121
|
-
default:
|
|
1122
|
-
return false
|
|
1123
|
-
}
|
|
1124
|
-
})
|
|
1125
|
-
|
|
1126
|
-
// Log types
|
|
1127
|
-
const LogType = {
|
|
1128
|
-
INFO: 'info',
|
|
1129
|
-
SUCCESS: 'success',
|
|
1130
|
-
ERROR: 'error',
|
|
1131
|
-
WARNING: 'warning'
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
// Utility functions
|
|
1135
|
-
const addLog = (message, type = LogType.INFO) => {
|
|
1136
|
-
const timestamp = new Date().toLocaleTimeString()
|
|
1137
|
-
logs.value.push({ timestamp, message, type })
|
|
1138
|
-
|
|
1139
|
-
// Always auto-scroll to bottom if autoScroll is enabled
|
|
1140
|
-
nextTick(() => {
|
|
1141
|
-
if (terminal.value && autoScroll.value) {
|
|
1142
|
-
terminal.value.scrollTop = terminal.value.scrollHeight
|
|
1143
|
-
}
|
|
1144
|
-
})
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
const getLogClass = (type) => {
|
|
1148
|
-
switch (type) {
|
|
1149
|
-
case LogType.ERROR: return 'terminal-error'
|
|
1150
|
-
case LogType.SUCCESS: return 'terminal-success'
|
|
1151
|
-
case LogType.WARNING: return 'terminal-warning'
|
|
1152
|
-
default: return 'terminal-info'
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
const clearLogs = () => {
|
|
1157
|
-
logs.value = []
|
|
1158
|
-
addLog('Logs cleared', LogType.INFO)
|
|
1159
|
-
}
|
|
1160
|
-
|
|
1161
|
-
const exportLogs = () => {
|
|
1162
|
-
const logText = logs.value.map(log => `[${log.timestamp}] ${log.message}`).join('\n')
|
|
1163
|
-
const blob = new Blob([logText], { type: 'text/plain' })
|
|
1164
|
-
const url = URL.createObjectURL(blob)
|
|
1165
|
-
const a = document.createElement('a')
|
|
1166
|
-
a.href = url
|
|
1167
|
-
a.download = `nosana-kit-logs-${new Date().toISOString().slice(0, 10)}.txt`
|
|
1168
|
-
document.body.appendChild(a)
|
|
1169
|
-
a.click()
|
|
1170
|
-
document.body.removeChild(a)
|
|
1171
|
-
URL.revokeObjectURL(url)
|
|
1172
|
-
addLog('๐ Logs exported to file', LogType.SUCCESS)
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
const copyInstallCommand = () => {
|
|
1176
|
-
navigator.clipboard.writeText('npm install @nosana/kit')
|
|
1177
|
-
addLog('๐ Installation command copied to clipboard', LogType.SUCCESS)
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
const toggleFullscreenTerminal = () => {
|
|
1181
|
-
isFullscreenTerminal.value = !isFullscreenTerminal.value
|
|
1182
|
-
addLog(`๐ฅ๏ธ Terminal ${isFullscreenTerminal.value ? 'expanded to' : 'exited'} fullscreen`, LogType.INFO)
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
const toggleTypeInfo = (section) => {
|
|
1186
|
-
showTypeInfo.value[section] = !showTypeInfo.value[section]
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
const toggleCodeExample = (section) => {
|
|
1190
|
-
showCodeExample.value[section] = !showCodeExample.value[section]
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
const scrollToSection = (sectionId) => {
|
|
1194
|
-
const element = document.getElementById(sectionId)
|
|
1195
|
-
if (element) {
|
|
1196
|
-
element.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
|
1197
|
-
addLog(`๐ Navigated to ${sectionId} section`, LogType.INFO)
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
const scrollToTerminal = () => {
|
|
1202
|
-
if (terminal.value) {
|
|
1203
|
-
terminal.value.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
|
1204
|
-
}
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
// Wallet operations
|
|
1208
|
-
const handleFileUpload = (event) => {
|
|
1209
|
-
const file = event.target.files[0]
|
|
1210
|
-
if (file) {
|
|
1211
|
-
const reader = new FileReader()
|
|
1212
|
-
reader.onload = (e) => {
|
|
1213
|
-
try {
|
|
1214
|
-
const content = e.target.result
|
|
1215
|
-
JSON.parse(content) // Validate JSON
|
|
1216
|
-
walletInputs.value.fileContent = content
|
|
1217
|
-
addLog(`๐ File loaded: ${file.name}`, LogType.SUCCESS)
|
|
1218
|
-
} catch (error) {
|
|
1219
|
-
addLog(`โ Invalid JSON file: ${error.message}`, LogType.ERROR)
|
|
1220
|
-
walletInputs.value.fileContent = null
|
|
1221
|
-
if (fileInput.value) {
|
|
1222
|
-
fileInput.value.value = ''
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
reader.readAsText(file)
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
const setWallet = async () => {
|
|
1231
|
-
if (!client) {
|
|
1232
|
-
addLog('โ SDK not initialized', LogType.ERROR)
|
|
1233
|
-
scrollToTerminal()
|
|
1234
|
-
return
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
try {
|
|
1238
|
-
loading.value = true
|
|
1239
|
-
|
|
1240
|
-
let walletData
|
|
1241
|
-
let inputType = 'unknown'
|
|
1242
|
-
|
|
1243
|
-
switch (walletInputMethod.value) {
|
|
1244
|
-
case 'browser':
|
|
1245
|
-
if (!browserWallet.value.connected || !browserWallet.value.adapter) {
|
|
1246
|
-
throw new Error('Browser wallet not connected')
|
|
1247
|
-
}
|
|
1248
|
-
// For browser wallets, we'll use the adapter directly
|
|
1249
|
-
// The SDK's setWallet method should accept a wallet adapter
|
|
1250
|
-
walletData = browserWallet.value.adapter
|
|
1251
|
-
inputType = `${browserWallet.value.name} browser wallet`
|
|
1252
|
-
break
|
|
1253
|
-
case 'paste':
|
|
1254
|
-
walletData = walletInputs.value.privateKey.trim()
|
|
1255
|
-
// Try to detect the format for better logging
|
|
1256
|
-
if (walletData.startsWith('[') && walletData.endsWith(']')) {
|
|
1257
|
-
inputType = 'JSON array'
|
|
1258
|
-
} else if (walletData.includes(',') && !walletData.includes('[')) {
|
|
1259
|
-
inputType = 'number array'
|
|
1260
|
-
} else if (walletData.length > 80 && !walletData.includes(',')) {
|
|
1261
|
-
inputType = 'Base58'
|
|
1262
|
-
} else {
|
|
1263
|
-
inputType = 'auto-detected format'
|
|
1264
|
-
}
|
|
1265
|
-
break
|
|
1266
|
-
case 'file':
|
|
1267
|
-
walletData = walletInputs.value.fileContent
|
|
1268
|
-
inputType = 'keypair file'
|
|
1269
|
-
break
|
|
1270
|
-
default:
|
|
1271
|
-
throw new Error('Invalid wallet input method')
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
addLog(`๐ Setting wallet from ${inputType}...`, LogType.INFO)
|
|
1275
|
-
scrollToTerminal()
|
|
1276
|
-
|
|
1277
|
-
const wallet = await client.setWallet(walletData)
|
|
1278
|
-
|
|
1279
|
-
if (wallet && wallet.address) {
|
|
1280
|
-
currentWallet.value = wallet.address
|
|
1281
|
-
addLog(`โ
Wallet set successfully!`, LogType.SUCCESS)
|
|
1282
|
-
addLog(`๐ Address: ${wallet.address}`, LogType.INFO)
|
|
1283
|
-
addLog(`๐ Source: ${inputType}`, LogType.INFO)
|
|
1284
|
-
|
|
1285
|
-
// For browser wallets, also show the wallet name
|
|
1286
|
-
if (walletInputMethod.value === 'browser') {
|
|
1287
|
-
addLog(`๐ฆ Connected via: ${browserWallet.value.name}`, LogType.INFO)
|
|
1288
|
-
}
|
|
1289
|
-
} else {
|
|
1290
|
-
throw new Error('Wallet set but no address returned')
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
} catch (error) {
|
|
1294
|
-
addLog(`โ Failed to set wallet: ${error.message}`, LogType.ERROR)
|
|
1295
|
-
currentWallet.value = null
|
|
1296
|
-
} finally {
|
|
1297
|
-
loading.value = false
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
|
|
1301
|
-
const clearWallet = async () => {
|
|
1302
|
-
currentWallet.value = null
|
|
1303
|
-
if (client) {
|
|
1304
|
-
client.wallet = undefined
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
// Also disconnect browser wallet if it's connected
|
|
1308
|
-
if (browserWallet.value.connected) {
|
|
1309
|
-
await disconnectBrowserWallet()
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
addLog('๐๏ธ Wallet cleared', LogType.INFO)
|
|
1313
|
-
scrollToTerminal()
|
|
1314
|
-
}
|
|
1315
|
-
|
|
1316
|
-
const loadDemoKeypair = () => {
|
|
1317
|
-
const demoKeypair = '[66,240,117,68,169,30,179,62,57,123,28,249,122,218,186,173,196,222,208,58,126,168,32,91,126,64,102,33,220,51,49,97,6,197,228,206,210,117,23,184,89,48,217,110,194,137,242,129,112,23,140,120,148,249,210,18,105,192,40,197,250,132,40,149]'
|
|
1318
|
-
|
|
1319
|
-
walletInputMethod.value = 'paste'
|
|
1320
|
-
walletInputs.value.privateKey = demoKeypair
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
// Browser wallet operations
|
|
1324
|
-
const connectWallet = async (walletName) => {
|
|
1325
|
-
try {
|
|
1326
|
-
browserWallet.value.connecting = true
|
|
1327
|
-
addLog(`๐ Connecting to ${walletName} wallet...`, LogType.INFO)
|
|
1328
|
-
|
|
1329
|
-
let adapter
|
|
1330
|
-
|
|
1331
|
-
switch (walletName) {
|
|
1332
|
-
case 'phantom':
|
|
1333
|
-
if (process.client && window.phantom?.solana) {
|
|
1334
|
-
adapter = window.phantom.solana
|
|
1335
|
-
}
|
|
1336
|
-
break
|
|
1337
|
-
case 'solflare':
|
|
1338
|
-
if (process.client && window.solflare) {
|
|
1339
|
-
adapter = window.solflare
|
|
1340
|
-
}
|
|
1341
|
-
break
|
|
1342
|
-
case 'backpack':
|
|
1343
|
-
if (process.client && window.backpack) {
|
|
1344
|
-
adapter = window.backpack
|
|
1345
|
-
}
|
|
1346
|
-
break
|
|
1347
|
-
default:
|
|
1348
|
-
throw new Error('Unsupported wallet')
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
|
-
if (!adapter) {
|
|
1352
|
-
throw new Error(`${walletName} wallet not found. Please install the ${walletName} browser extension and refresh the page.`)
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
// Request connection
|
|
1356
|
-
const connection = await adapter.connect()
|
|
1357
|
-
|
|
1358
|
-
if (adapter.publicKey) {
|
|
1359
|
-
browserWallet.value = {
|
|
1360
|
-
connected: true,
|
|
1361
|
-
connecting: false,
|
|
1362
|
-
name: walletName.charAt(0).toUpperCase() + walletName.slice(1),
|
|
1363
|
-
publicKey: adapter.publicKey.toString(),
|
|
1364
|
-
adapter: adapter
|
|
1365
|
-
}
|
|
1366
|
-
|
|
1367
|
-
addLog(`โ
Successfully connected to ${walletName}!`, LogType.SUCCESS)
|
|
1368
|
-
addLog(`๐ Public Key: ${adapter.publicKey.toString()}`, LogType.INFO)
|
|
1369
|
-
addLog(`๐ Connection: ${connection ? 'Established' : 'Ready'}`, LogType.INFO)
|
|
1370
|
-
} else {
|
|
1371
|
-
throw new Error('Failed to get public key from wallet')
|
|
1372
|
-
}
|
|
1373
|
-
|
|
1374
|
-
} catch (error) {
|
|
1375
|
-
addLog(`โ Failed to connect to ${walletName}: ${error.message}`, LogType.ERROR)
|
|
1376
|
-
browserWallet.value.connecting = false
|
|
1377
|
-
browserWallet.value.connected = false
|
|
1378
|
-
} finally {
|
|
1379
|
-
browserWallet.value.connecting = false
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1382
|
-
|
|
1383
|
-
const disconnectBrowserWallet = async () => {
|
|
1384
|
-
try {
|
|
1385
|
-
if (browserWallet.value.adapter && browserWallet.value.adapter.disconnect) {
|
|
1386
|
-
console.log('bro', browserWallet.value.adapter, browserWallet.value)
|
|
1387
|
-
await browserWallet.value.adapter.disconnect()
|
|
1388
|
-
}
|
|
1389
|
-
|
|
1390
|
-
browserWallet.value = {
|
|
1391
|
-
connected: false,
|
|
1392
|
-
connecting: false,
|
|
1393
|
-
name: null,
|
|
1394
|
-
publicKey: null,
|
|
1395
|
-
adapter: null
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
// Clear the current wallet if it was set from browser wallet
|
|
1399
|
-
if (currentWallet.value && currentWallet.value === browserWallet.value.publicKey) {
|
|
1400
|
-
currentWallet.value = null
|
|
1401
|
-
if (client) {
|
|
1402
|
-
client.wallet = undefined
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
addLog('๐ Browser wallet disconnected', LogType.INFO)
|
|
1407
|
-
scrollToTerminal()
|
|
1408
|
-
|
|
1409
|
-
} catch (error) {
|
|
1410
|
-
addLog(`โ Error disconnecting wallet: ${error.message}`, LogType.ERROR)
|
|
1411
|
-
}
|
|
1412
|
-
}
|
|
1413
|
-
|
|
1414
|
-
// SDK operations
|
|
1415
|
-
const initializeClient = async () => {
|
|
1416
|
-
try {
|
|
1417
|
-
// Stop monitoring if active before switching networks
|
|
1418
|
-
if (isMonitoring.value) {
|
|
1419
|
-
if (stopMonitoring) {
|
|
1420
|
-
stopMonitoring()
|
|
1421
|
-
stopMonitoring = null
|
|
1422
|
-
}
|
|
1423
|
-
isMonitoring.value = false
|
|
1424
|
-
addLog('๐ Stopped monitoring due to network switch', LogType.WARNING)
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
|
-
// Clear wallet when switching networks
|
|
1428
|
-
if (currentWallet.value) {
|
|
1429
|
-
currentWallet.value = null
|
|
1430
|
-
addLog('๐ Wallet cleared due to network switch', LogType.WARNING)
|
|
1431
|
-
}
|
|
1432
|
-
|
|
1433
|
-
loading.value = true
|
|
1434
|
-
addLog(`Initializing Nosana SDK for ${selectedNetwork.value}...`, LogType.INFO)
|
|
1435
|
-
|
|
1436
|
-
const network = selectedNetwork.value === 'mainnet'
|
|
1437
|
-
? NosanaNetwork.MAINNET
|
|
1438
|
-
: NosanaNetwork.DEVNET
|
|
1439
|
-
|
|
1440
|
-
client = new NosanaClient(network)
|
|
1441
|
-
isConnected.value = true
|
|
1442
|
-
|
|
1443
|
-
addLog(`โ
SDK initialized successfully for ${selectedNetwork.value}`, LogType.SUCCESS)
|
|
1444
|
-
addLog(`๐ก RPC Endpoint: ${client.config.solana.rpcEndpoint}`, LogType.INFO)
|
|
1445
|
-
addLog(`๐ช Jobs Program: ${client.config.programs.jobsAddress}`, LogType.INFO)
|
|
1446
|
-
|
|
1447
|
-
} catch (error) {
|
|
1448
|
-
addLog(`โ Failed to initialize SDK: ${error.message}`, LogType.ERROR)
|
|
1449
|
-
isConnected.value = false
|
|
1450
|
-
} finally {
|
|
1451
|
-
loading.value = false
|
|
1452
|
-
}
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
const testConnection = async () => {
|
|
1456
|
-
if (!client) {
|
|
1457
|
-
addLog('โ SDK not initialized', LogType.ERROR)
|
|
1458
|
-
scrollToTerminal()
|
|
1459
|
-
return
|
|
1460
|
-
}
|
|
1461
|
-
|
|
1462
|
-
try {
|
|
1463
|
-
loading.value = true
|
|
1464
|
-
addLog('๐ Testing connection...', LogType.INFO)
|
|
1465
|
-
scrollToTerminal()
|
|
1466
|
-
|
|
1467
|
-
// Test by getting the latest blockhash
|
|
1468
|
-
const latestBlockhash = await client.solana.getLatestBlockhash()
|
|
1469
|
-
addLog(`โ
Connection successful! Latest blockhash: ${latestBlockhash.blockhash}`, LogType.SUCCESS)
|
|
1470
|
-
|
|
1471
|
-
} catch (error) {
|
|
1472
|
-
addLog(`โ Connection test failed: ${error.message}`, LogType.ERROR)
|
|
1473
|
-
} finally {
|
|
1474
|
-
loading.value = false
|
|
1475
|
-
}
|
|
1476
|
-
}
|
|
1477
|
-
|
|
1478
|
-
const getJob = async () => {
|
|
1479
|
-
if (!client || !jobAddress.value) {
|
|
1480
|
-
addLog('โ SDK not initialized or no job address provided', LogType.ERROR)
|
|
1481
|
-
scrollToTerminal()
|
|
1482
|
-
return
|
|
1483
|
-
}
|
|
1484
|
-
|
|
1485
|
-
try {
|
|
1486
|
-
loading.value = true
|
|
1487
|
-
addLog(`๐ Fetching job: ${jobAddress.value}`, LogType.INFO)
|
|
1488
|
-
scrollToTerminal()
|
|
1489
|
-
|
|
1490
|
-
const job = await client.jobs.get(address(jobAddress.value))
|
|
1491
|
-
|
|
1492
|
-
addLog(`โ
Job retrieved successfully!`, LogType.SUCCESS)
|
|
1493
|
-
addLog(`๐ Job Details:`, LogType.INFO)
|
|
1494
|
-
addLog(` Address: ${job.address}`, LogType.INFO)
|
|
1495
|
-
addLog(` State: ${getJobStateName(job.state)}`, LogType.INFO)
|
|
1496
|
-
addLog(` Market: ${job.market}`, LogType.INFO)
|
|
1497
|
-
addLog(` Price: ${job.price}`, LogType.INFO)
|
|
1498
|
-
addLog(` IPFS Job: ${job.ipfsJob}`, LogType.INFO)
|
|
1499
|
-
if (job.node) addLog(` Node: ${job.node}`, LogType.INFO)
|
|
1500
|
-
if (job.timeStart) addLog(` Start Time: ${new Date(job.timeStart * 1000).toLocaleString()}`, LogType.INFO)
|
|
1501
|
-
|
|
1502
|
-
} catch (error) {
|
|
1503
|
-
addLog(`โ Failed to fetch job: ${error.message}`, LogType.ERROR)
|
|
1504
|
-
} finally {
|
|
1505
|
-
loading.value = false
|
|
1506
|
-
}
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
|
-
const getAllJobs = async () => {
|
|
1510
|
-
if (!client) {
|
|
1511
|
-
addLog('โ SDK not initialized', LogType.ERROR)
|
|
1512
|
-
scrollToTerminal()
|
|
1513
|
-
return
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
try {
|
|
1517
|
-
loading.value = true
|
|
1518
|
-
addLog('๐ Fetching jobs with filters...', LogType.INFO)
|
|
1519
|
-
scrollToTerminal()
|
|
1520
|
-
|
|
1521
|
-
const filters = {}
|
|
1522
|
-
if (jobFilters.value.state !== '') {
|
|
1523
|
-
filters.state = parseInt(jobFilters.value.state)
|
|
1524
|
-
}
|
|
1525
|
-
if (jobFilters.value.market !== '') {
|
|
1526
|
-
filters.market = address(jobFilters.value.market)
|
|
1527
|
-
}
|
|
1528
|
-
if (jobFilters.value.node !== '') {
|
|
1529
|
-
filters.node = address(jobFilters.value.node)
|
|
1530
|
-
}
|
|
1531
|
-
if (jobFilters.value.project !== '') {
|
|
1532
|
-
filters.project = address(jobFilters.value.project)
|
|
1533
|
-
}
|
|
1534
|
-
const jobs = await client.jobs.all(filters)
|
|
1535
|
-
// Show first 20 jobs to avoid overwhelming the terminal
|
|
1536
|
-
const limitedJobs = jobs.slice(0, 20)
|
|
1537
|
-
|
|
1538
|
-
addLog(`โ
Retrieved ${limitedJobs.length} jobs (total: ${jobs.length})`, LogType.SUCCESS)
|
|
1539
|
-
|
|
1540
|
-
limitedJobs.forEach((job, index) => {
|
|
1541
|
-
addLog(`๐ Job ${index + 1}:`, LogType.INFO)
|
|
1542
|
-
addLog(job, LogType.INFO)
|
|
1543
|
-
})
|
|
1544
|
-
|
|
1545
|
-
} catch (error) {
|
|
1546
|
-
addLog(`โ Failed to fetch jobs: ${error.message}`, LogType.ERROR)
|
|
1547
|
-
} finally {
|
|
1548
|
-
loading.value = false
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
|
-
|
|
1552
|
-
const getMarkets = async () => {
|
|
1553
|
-
if (!client) {
|
|
1554
|
-
addLog('โ SDK not initialized', LogType.ERROR)
|
|
1555
|
-
scrollToTerminal()
|
|
1556
|
-
return
|
|
1557
|
-
}
|
|
1558
|
-
|
|
1559
|
-
try {
|
|
1560
|
-
loading.value = true
|
|
1561
|
-
addLog('๐ Fetching all markets...', LogType.INFO)
|
|
1562
|
-
scrollToTerminal()
|
|
1563
|
-
|
|
1564
|
-
const markets = await client.jobs.markets()
|
|
1565
|
-
|
|
1566
|
-
addLog(`โ
Retrieved ${markets.length} markets`, LogType.SUCCESS)
|
|
1567
|
-
|
|
1568
|
-
markets.forEach((market, index) => {
|
|
1569
|
-
addLog(`๐ช Market ${index + 1}:`, LogType.INFO)
|
|
1570
|
-
addLog(market, LogType.INFO)
|
|
1571
|
-
})
|
|
1572
|
-
|
|
1573
|
-
} catch (error) {
|
|
1574
|
-
addLog(`โ Failed to fetch markets: ${error.message}`, LogType.ERROR)
|
|
1575
|
-
} finally {
|
|
1576
|
-
loading.value = false
|
|
1577
|
-
}
|
|
1578
|
-
}
|
|
1579
|
-
|
|
1580
|
-
const toggleMonitoring = async () => {
|
|
1581
|
-
if (!client) {
|
|
1582
|
-
addLog('โ SDK not initialized', LogType.ERROR)
|
|
1583
|
-
scrollToTerminal()
|
|
1584
|
-
return
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
|
-
if (isMonitoring.value) {
|
|
1588
|
-
// Stop monitoring
|
|
1589
|
-
if (stopMonitoring) {
|
|
1590
|
-
stopMonitoring()
|
|
1591
|
-
stopMonitoring = null
|
|
1592
|
-
}
|
|
1593
|
-
isMonitoring.value = false
|
|
1594
|
-
addLog('๐ Stopped monitoring account updates', LogType.WARNING)
|
|
1595
|
-
scrollToTerminal()
|
|
1596
|
-
} else {
|
|
1597
|
-
// Start monitoring
|
|
1598
|
-
try {
|
|
1599
|
-
loading.value = true
|
|
1600
|
-
addLog('๐ Starting real-time monitoring...', LogType.INFO)
|
|
1601
|
-
scrollToTerminal()
|
|
1602
|
-
|
|
1603
|
-
stopMonitoring = await client.jobs.monitor({
|
|
1604
|
-
onJobAccount: async (jobAccount) => {
|
|
1605
|
-
addLog(`๐ Job account updated: ${jobAccount.address}`, LogType.SUCCESS)
|
|
1606
|
-
addLog(` State: ${getJobStateName(jobAccount.state)}`, LogType.INFO)
|
|
1607
|
-
if (jobAccount.node) addLog(` Node: ${jobAccount.node}`, LogType.INFO)
|
|
1608
|
-
},
|
|
1609
|
-
|
|
1610
|
-
onRunAccount: async (runAccount) => {
|
|
1611
|
-
addLog(`๐ Run account updated: ${runAccount.address}`, LogType.SUCCESS)
|
|
1612
|
-
addLog(` Job: ${runAccount.job}`, LogType.INFO)
|
|
1613
|
-
addLog(` Node: ${runAccount.node}`, LogType.INFO)
|
|
1614
|
-
},
|
|
1615
|
-
|
|
1616
|
-
onMarketAccount: async (marketAccount) => {
|
|
1617
|
-
addLog(`๐ช Market account updated: ${marketAccount.address}`, LogType.SUCCESS)
|
|
1618
|
-
addLog(` Job Price: ${marketAccount.jobPrice}`, LogType.INFO)
|
|
1619
|
-
},
|
|
1620
|
-
|
|
1621
|
-
onError: async (error, accountType) => {
|
|
1622
|
-
addLog(`โ Monitor error (${accountType}): ${error.message}`, LogType.ERROR)
|
|
1623
|
-
}
|
|
1624
|
-
})
|
|
1625
|
-
|
|
1626
|
-
isMonitoring.value = true
|
|
1627
|
-
addLog('โ
Real-time monitoring started successfully!', LogType.SUCCESS)
|
|
1628
|
-
addLog('๐ Watching for job, run, and market account updates...', LogType.INFO)
|
|
1629
|
-
|
|
1630
|
-
} catch (error) {
|
|
1631
|
-
addLog(`โ Failed to start monitoring: ${error.message}`, LogType.ERROR)
|
|
1632
|
-
} finally {
|
|
1633
|
-
loading.value = false
|
|
1634
|
-
}
|
|
1635
|
-
}
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
const getJobStateName = (state) => {
|
|
1639
|
-
const states = {
|
|
1640
|
-
0: 'Queued',
|
|
1641
|
-
1: 'Running',
|
|
1642
|
-
2: 'Done',
|
|
1643
|
-
3: 'Stopped'
|
|
1644
|
-
}
|
|
1645
|
-
return states[state] || `Unknown (${state})`
|
|
1646
|
-
}
|
|
1647
|
-
|
|
1648
|
-
// Initialize on mount
|
|
1649
|
-
onMounted(() => {
|
|
1650
|
-
addLog('๐ Nosana SDK Playground initialized', LogType.SUCCESS)
|
|
1651
|
-
addLog('๐ This is an interactive documentation and testing environment', LogType.INFO)
|
|
1652
|
-
addLog('๐ง Use the controls on the left to test SDK functionality', LogType.INFO)
|
|
1653
|
-
initializeClient()
|
|
1654
|
-
})
|
|
1655
|
-
</script>
|
|
1656
|
-
|
|
1657
|
-
<style scoped>
|
|
1658
|
-
.terminal {
|
|
1659
|
-
background-color: #1a1a1a;
|
|
1660
|
-
border-radius: 6px;
|
|
1661
|
-
padding: 16px;
|
|
1662
|
-
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
1663
|
-
}
|
|
1664
|
-
|
|
1665
|
-
.terminal-line {
|
|
1666
|
-
margin-bottom: 8px;
|
|
1667
|
-
line-height: 1.4;
|
|
1668
|
-
}
|
|
1669
|
-
|
|
1670
|
-
.terminal-timestamp {
|
|
1671
|
-
color: #6b7280;
|
|
1672
|
-
font-size: 12px;
|
|
1673
|
-
margin-right: 8px;
|
|
1674
|
-
}
|
|
1675
|
-
|
|
1676
|
-
.terminal-info {
|
|
1677
|
-
color: #e5e7eb;
|
|
1678
|
-
}
|
|
1679
|
-
|
|
1680
|
-
.terminal-success {
|
|
1681
|
-
color: #10b981;
|
|
1682
|
-
font-weight: 500;
|
|
1683
|
-
}
|
|
1684
|
-
|
|
1685
|
-
.terminal-error {
|
|
1686
|
-
color: #ef4444;
|
|
1687
|
-
font-weight: 500;
|
|
1688
|
-
}
|
|
1689
|
-
|
|
1690
|
-
.terminal-warning {
|
|
1691
|
-
color: #f59e0b;
|
|
1692
|
-
font-weight: 500;
|
|
1693
|
-
}
|
|
1694
|
-
|
|
1695
|
-
/* Scrollbar styling */
|
|
1696
|
-
.terminal::-webkit-scrollbar {
|
|
1697
|
-
width: 8px;
|
|
1698
|
-
}
|
|
1699
|
-
|
|
1700
|
-
.terminal::-webkit-scrollbar-track {
|
|
1701
|
-
background: #374151;
|
|
1702
|
-
border-radius: 4px;
|
|
1703
|
-
}
|
|
1704
|
-
|
|
1705
|
-
.terminal::-webkit-scrollbar-thumb {
|
|
1706
|
-
background: #6b7280;
|
|
1707
|
-
border-radius: 4px;
|
|
1708
|
-
}
|
|
1709
|
-
|
|
1710
|
-
.terminal::-webkit-scrollbar-thumb:hover {
|
|
1711
|
-
background: #9ca3af;
|
|
1712
|
-
}
|
|
1713
|
-
|
|
1714
|
-
/* Code blocks */
|
|
1715
|
-
pre code {
|
|
1716
|
-
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
1717
|
-
line-height: 1.5;
|
|
1718
|
-
}
|
|
1719
|
-
|
|
1720
|
-
/* Tab transitions */
|
|
1721
|
-
.tab-content {
|
|
1722
|
-
animation: fadeIn 0.3s ease-in-out;
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
|
-
@keyframes fadeIn {
|
|
1726
|
-
from {
|
|
1727
|
-
opacity: 0;
|
|
1728
|
-
transform: translateY(10px);
|
|
1729
|
-
}
|
|
1730
|
-
|
|
1731
|
-
to {
|
|
1732
|
-
opacity: 1;
|
|
1733
|
-
transform: translateY(0);
|
|
1734
|
-
}
|
|
1735
|
-
}
|
|
1736
|
-
|
|
1737
|
-
/* Enhanced buttons */
|
|
1738
|
-
button:focus {
|
|
1739
|
-
outline: none;
|
|
1740
|
-
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
1741
|
-
}
|
|
1742
|
-
|
|
1743
|
-
/* Loading states */
|
|
1744
|
-
.loading-pulse {
|
|
1745
|
-
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
1746
|
-
}
|
|
1747
|
-
|
|
1748
|
-
@keyframes pulse {
|
|
1749
|
-
|
|
1750
|
-
0%,
|
|
1751
|
-
100% {
|
|
1752
|
-
opacity: 1;
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
50% {
|
|
1756
|
-
opacity: 0.5;
|
|
1757
|
-
}
|
|
1758
|
-
}
|
|
1759
|
-
|
|
1760
|
-
/* Status indicators */
|
|
1761
|
-
.status-indicator {
|
|
1762
|
-
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
1763
|
-
}
|
|
1764
|
-
|
|
1765
|
-
/* Documentation section styling */
|
|
1766
|
-
.prose {
|
|
1767
|
-
max-width: none;
|
|
1768
|
-
}
|
|
1769
|
-
|
|
1770
|
-
.prose h3 {
|
|
1771
|
-
margin-top: 2rem;
|
|
1772
|
-
margin-bottom: 1rem;
|
|
1773
|
-
}
|
|
1774
|
-
|
|
1775
|
-
.prose p {
|
|
1776
|
-
margin-bottom: 1rem;
|
|
1777
|
-
}
|
|
1778
|
-
|
|
1779
|
-
.prose ul {
|
|
1780
|
-
margin-bottom: 1rem;
|
|
1781
|
-
}
|
|
1782
|
-
|
|
1783
|
-
.prose li {
|
|
1784
|
-
margin-bottom: 0.5rem;
|
|
1785
|
-
}
|
|
1786
|
-
|
|
1787
|
-
.terminal {
|
|
1788
|
-
background-color: #1a202c;
|
|
1789
|
-
color: #68d391;
|
|
1790
|
-
font-family: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace;
|
|
1791
|
-
font-size: 0.875rem;
|
|
1792
|
-
padding: 1rem;
|
|
1793
|
-
border-radius: 0.5rem;
|
|
1794
|
-
overflow: auto;
|
|
1795
|
-
scrollbar-width: thin;
|
|
1796
|
-
scrollbar-color: #4a5568 #1a202c;
|
|
1797
|
-
}
|
|
1798
|
-
|
|
1799
|
-
.terminal::-webkit-scrollbar {
|
|
1800
|
-
width: 8px;
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
.terminal::-webkit-scrollbar-track {
|
|
1804
|
-
background: #1a202c;
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1807
|
-
.terminal::-webkit-scrollbar-thumb {
|
|
1808
|
-
background: #4a5568;
|
|
1809
|
-
border-radius: 4px;
|
|
1810
|
-
}
|
|
1811
|
-
|
|
1812
|
-
.terminal::-webkit-scrollbar-thumb:hover {
|
|
1813
|
-
background: #718096;
|
|
1814
|
-
}
|
|
1815
|
-
|
|
1816
|
-
.terminal-line {
|
|
1817
|
-
margin-bottom: 0.25rem;
|
|
1818
|
-
}
|
|
1819
|
-
|
|
1820
|
-
.terminal-timestamp {
|
|
1821
|
-
color: #9ca3af;
|
|
1822
|
-
margin-right: 0.5rem;
|
|
1823
|
-
}
|
|
1824
|
-
|
|
1825
|
-
.terminal-error {
|
|
1826
|
-
color: #f87171;
|
|
1827
|
-
}
|
|
1828
|
-
|
|
1829
|
-
.terminal-success {
|
|
1830
|
-
color: #68d391;
|
|
1831
|
-
}
|
|
1832
|
-
|
|
1833
|
-
.terminal-info {
|
|
1834
|
-
color: #60a5fa;
|
|
1835
|
-
}
|
|
1836
|
-
|
|
1837
|
-
.terminal-warning {
|
|
1838
|
-
color: #fbbf24;
|
|
1839
|
-
}
|
|
1840
|
-
</style>
|