0g-orbit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/cli.d.ts +3 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/cli/cli.js +59 -0
- package/dist/cli/cli.js.map +1 -0
- package/dist/cli/commands/account.d.ts +6 -0
- package/dist/cli/commands/account.d.ts.map +1 -0
- package/dist/cli/commands/account.js +23 -0
- package/dist/cli/commands/account.js.map +1 -0
- package/dist/cli/commands/inference.d.ts +15 -0
- package/dist/cli/commands/inference.d.ts.map +1 -0
- package/dist/cli/commands/inference.js +70 -0
- package/dist/cli/commands/inference.js.map +1 -0
- package/dist/cli/commands/init.d.ts +7 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +60 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/storage.d.ts +19 -0
- package/dist/cli/commands/storage.d.ts.map +1 -0
- package/dist/cli/commands/storage.js +62 -0
- package/dist/cli/commands/storage.js.map +1 -0
- package/dist/cli/utils.d.ts +4 -0
- package/dist/cli/utils.d.ts.map +1 -0
- package/dist/cli/utils.js +20 -0
- package/dist/cli/utils.js.map +1 -0
- package/dist/errors.d.ts +26 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +51 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/inference.d.ts +17 -0
- package/dist/inference.d.ts.map +1 -0
- package/dist/inference.js +179 -0
- package/dist/inference.js.map +1 -0
- package/dist/networks.d.ts +16 -0
- package/dist/networks.d.ts.map +1 -0
- package/dist/networks.js +48 -0
- package/dist/networks.js.map +1 -0
- package/dist/orbit.d.ts +27 -0
- package/dist/orbit.d.ts.map +1 -0
- package/dist/orbit.js +108 -0
- package/dist/orbit.js.map +1 -0
- package/dist/retry.d.ts +23 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +90 -0
- package/dist/retry.js.map +1 -0
- package/dist/storage.d.ts +26 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +121 -0
- package/dist/storage.js.map +1 -0
- package/dist/types.d.ts +81 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/examples/ai-chatbot/index.ts +74 -0
- package/examples/model-registry/index.ts +137 -0
- package/examples/quick-start/index.ts +65 -0
- package/package.json +42 -0
- package/packages/cli/package.json +30 -0
- package/packages/cli/src/cli.ts +69 -0
- package/packages/cli/src/commands/account.ts +29 -0
- package/packages/cli/src/commands/inference.ts +103 -0
- package/packages/cli/src/commands/init.ts +71 -0
- package/packages/cli/src/commands/storage.ts +91 -0
- package/packages/cli/src/utils.ts +21 -0
- package/packages/cli/tsconfig.json +8 -0
- package/packages/core/package.json +35 -0
- package/packages/core/src/errors.test.ts +99 -0
- package/packages/core/src/errors.ts +79 -0
- package/packages/core/src/index.ts +37 -0
- package/packages/core/src/inference.ts +256 -0
- package/packages/core/src/networks.test.ts +62 -0
- package/packages/core/src/networks.ts +62 -0
- package/packages/core/src/orbit.test.ts +153 -0
- package/packages/core/src/orbit.ts +159 -0
- package/packages/core/src/retry.test.ts +99 -0
- package/packages/core/src/retry.ts +99 -0
- package/packages/core/src/storage.test.ts +199 -0
- package/packages/core/src/storage.ts +158 -0
- package/packages/core/src/types.ts +85 -0
- package/packages/core/tsconfig.json +8 -0
- package/packages/core/vitest.config.ts +7 -0
- package/src/cli/cli.ts +69 -0
- package/src/cli/commands/account.ts +29 -0
- package/src/cli/commands/inference.ts +103 -0
- package/src/cli/commands/init.ts +71 -0
- package/src/cli/commands/storage.ts +91 -0
- package/src/cli/utils.ts +21 -0
- package/src/errors.test.ts +99 -0
- package/src/errors.ts +79 -0
- package/src/index.ts +37 -0
- package/src/inference.ts +256 -0
- package/src/networks.test.ts +62 -0
- package/src/networks.ts +62 -0
- package/src/orbit.test.ts +153 -0
- package/src/orbit.ts +159 -0
- package/src/retry.test.ts +99 -0
- package/src/retry.ts +99 -0
- package/src/storage.test.ts +199 -0
- package/src/storage.ts +158 -0
- package/src/types.ts +85 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +7 -0
package/src/cli/cli.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { storeCommand, storeDataCommand, retrieveCommand } from './commands/storage.js'
|
|
5
|
+
import { inferCommand, listServicesCommand } from './commands/inference.js'
|
|
6
|
+
import { statusCommand } from './commands/account.js'
|
|
7
|
+
import { initCommand } from './commands/init.js'
|
|
8
|
+
|
|
9
|
+
const program = new Command()
|
|
10
|
+
|
|
11
|
+
program
|
|
12
|
+
.name('orbit')
|
|
13
|
+
.description('The developer toolkit for 0G')
|
|
14
|
+
.version('0.1.0')
|
|
15
|
+
|
|
16
|
+
program
|
|
17
|
+
.command('init')
|
|
18
|
+
.description('Initialize a new 0G project')
|
|
19
|
+
.option('-t, --template <name>', 'template to use', 'default')
|
|
20
|
+
.option('-d, --dir <path>', 'directory to create', '.')
|
|
21
|
+
.action(initCommand)
|
|
22
|
+
|
|
23
|
+
program
|
|
24
|
+
.command('store <file>')
|
|
25
|
+
.description('Upload a file to 0G Storage')
|
|
26
|
+
.option('-n, --network <name>', 'network (testnet|mainnet)', 'testnet')
|
|
27
|
+
.option('--tags <hex>', 'custom tags (hex string)')
|
|
28
|
+
.option('--replicas <n>', 'number of replicas', '1')
|
|
29
|
+
.action(storeCommand)
|
|
30
|
+
|
|
31
|
+
program
|
|
32
|
+
.command('store-data <text>')
|
|
33
|
+
.description('Upload a text string to 0G Storage')
|
|
34
|
+
.option('-n, --network <name>', 'network (testnet|mainnet)', 'testnet')
|
|
35
|
+
.option('--tags <hex>', 'custom tags (hex string)')
|
|
36
|
+
.option('--replicas <n>', 'number of replicas', '1')
|
|
37
|
+
.action(storeDataCommand)
|
|
38
|
+
|
|
39
|
+
program
|
|
40
|
+
.command('retrieve <rootHash> <output>')
|
|
41
|
+
.description('Download a file from 0G Storage')
|
|
42
|
+
.option('-n, --network <name>', 'network (testnet|mainnet)', 'testnet')
|
|
43
|
+
.option('--proof', 'verify merkle proofs during download')
|
|
44
|
+
.action(retrieveCommand)
|
|
45
|
+
|
|
46
|
+
program
|
|
47
|
+
.command('infer <model>')
|
|
48
|
+
.description('Run AI inference on the 0G Compute Network')
|
|
49
|
+
.option('-n, --network <name>', 'network (testnet|mainnet)', 'testnet')
|
|
50
|
+
.option('-m, --message <text>', 'message to send')
|
|
51
|
+
.option('-s, --system <text>', 'system prompt')
|
|
52
|
+
.option('-t, --temperature <n>', 'sampling temperature', '0.7')
|
|
53
|
+
.option('--max-tokens <n>', 'maximum tokens to generate')
|
|
54
|
+
.option('--provider <address>', 'specific provider address')
|
|
55
|
+
.action(inferCommand)
|
|
56
|
+
|
|
57
|
+
program
|
|
58
|
+
.command('services')
|
|
59
|
+
.description('List available AI services on the network')
|
|
60
|
+
.option('-n, --network <name>', 'network (testnet|mainnet)', 'testnet')
|
|
61
|
+
.action(listServicesCommand)
|
|
62
|
+
|
|
63
|
+
program
|
|
64
|
+
.command('status')
|
|
65
|
+
.description('Show account status and balance')
|
|
66
|
+
.option('-n, --network <name>', 'network (testnet|mainnet)', 'testnet')
|
|
67
|
+
.action(statusCommand)
|
|
68
|
+
|
|
69
|
+
program.parse()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import ora from 'ora'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import { connectOrbit, formatError } from '../utils.js'
|
|
4
|
+
|
|
5
|
+
interface StatusOpts {
|
|
6
|
+
network: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function statusCommand(opts: StatusOpts) {
|
|
10
|
+
const spinner = ora('Checking status...').start()
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const orbit = await connectOrbit(opts.network)
|
|
14
|
+
const status = await orbit.status()
|
|
15
|
+
|
|
16
|
+
spinner.stop()
|
|
17
|
+
|
|
18
|
+
console.log()
|
|
19
|
+
console.log(chalk.bold(' 0G Orbit'))
|
|
20
|
+
console.log(` ${chalk.dim('Network:')} ${status.network}`)
|
|
21
|
+
console.log(` ${chalk.dim('Address:')} ${status.address}`)
|
|
22
|
+
console.log(` ${chalk.dim('Balance:')} ${chalk.cyan(status.balance)} OG`)
|
|
23
|
+
console.log()
|
|
24
|
+
} catch (err) {
|
|
25
|
+
spinner.fail(chalk.red('Failed to get status'))
|
|
26
|
+
console.error(chalk.dim(` ${formatError(err)}`))
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import ora from 'ora'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import { connectOrbit, formatError } from '../utils.js'
|
|
4
|
+
|
|
5
|
+
interface InferOpts {
|
|
6
|
+
network: string
|
|
7
|
+
message?: string
|
|
8
|
+
system?: string
|
|
9
|
+
temperature: string
|
|
10
|
+
maxTokens?: string
|
|
11
|
+
provider?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function inferCommand(model: string, opts: InferOpts) {
|
|
15
|
+
if (!opts.message) {
|
|
16
|
+
console.error(chalk.red('Error: --message is required'))
|
|
17
|
+
console.error(chalk.dim(' orbit infer meta-llama/Llama-3.3-70B -m "Hello!"'))
|
|
18
|
+
process.exit(1)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const spinner = ora('Connecting to 0G...').start()
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const orbit = await connectOrbit(opts.network)
|
|
25
|
+
spinner.text = `Sending to ${model}...`
|
|
26
|
+
|
|
27
|
+
const messages: Array<{ role: 'system' | 'user'; content: string }> = []
|
|
28
|
+
if (opts.system) {
|
|
29
|
+
messages.push({ role: 'system', content: opts.system })
|
|
30
|
+
}
|
|
31
|
+
messages.push({ role: 'user', content: opts.message })
|
|
32
|
+
|
|
33
|
+
const result = await orbit.infer(model, {
|
|
34
|
+
messages,
|
|
35
|
+
temperature: parseFloat(opts.temperature),
|
|
36
|
+
maxTokens: opts.maxTokens ? parseInt(opts.maxTokens, 10) : undefined,
|
|
37
|
+
provider: opts.provider,
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
spinner.succeed('Response received')
|
|
41
|
+
console.log()
|
|
42
|
+
console.log(result.content)
|
|
43
|
+
console.log()
|
|
44
|
+
|
|
45
|
+
if (result.usage) {
|
|
46
|
+
console.log(
|
|
47
|
+
chalk.dim(
|
|
48
|
+
` tokens: ${result.usage.promptTokens} in / ${result.usage.completionTokens} out` +
|
|
49
|
+
` | model: ${result.model}` +
|
|
50
|
+
(result.verified !== null
|
|
51
|
+
? ` | verified: ${result.verified ? chalk.green('yes') : chalk.red('no')}`
|
|
52
|
+
: '')
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
} catch (err) {
|
|
57
|
+
spinner.fail(chalk.red('Inference failed'))
|
|
58
|
+
console.error(chalk.dim(` ${formatError(err)}`))
|
|
59
|
+
process.exit(1)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface ServicesOpts {
|
|
64
|
+
network: string
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function listServicesCommand(opts: ServicesOpts) {
|
|
68
|
+
const spinner = ora('Fetching services...').start()
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const orbit = await connectOrbit(opts.network)
|
|
72
|
+
const services = await orbit.listServices()
|
|
73
|
+
|
|
74
|
+
spinner.stop()
|
|
75
|
+
|
|
76
|
+
if (services.length === 0) {
|
|
77
|
+
console.log(chalk.dim('No services found on this network.'))
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(chalk.bold(`\n ${services.length} services on ${opts.network}\n`))
|
|
82
|
+
|
|
83
|
+
for (const svc of services) {
|
|
84
|
+
const verTag = svc.verifiable
|
|
85
|
+
? chalk.green(' [TEE]')
|
|
86
|
+
: ''
|
|
87
|
+
console.log(
|
|
88
|
+
` ${chalk.cyan(svc.model)}${verTag}`
|
|
89
|
+
)
|
|
90
|
+
console.log(
|
|
91
|
+
chalk.dim(
|
|
92
|
+
` provider: ${svc.provider.slice(0, 10)}...${svc.provider.slice(-6)}` +
|
|
93
|
+
` | in: ${svc.inputPrice} neuron | out: ${svc.outputPrice} neuron`
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
console.log()
|
|
98
|
+
} catch (err) {
|
|
99
|
+
spinner.fail(chalk.red('Failed to list services'))
|
|
100
|
+
console.error(chalk.dim(` ${formatError(err)}`))
|
|
101
|
+
process.exit(1)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
import { writeFileSync, mkdirSync, existsSync } from 'node:fs'
|
|
3
|
+
import { join, resolve } from 'node:path'
|
|
4
|
+
|
|
5
|
+
interface InitOpts {
|
|
6
|
+
template: string
|
|
7
|
+
dir: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function initCommand(opts: InitOpts) {
|
|
11
|
+
const dir = resolve(opts.dir)
|
|
12
|
+
|
|
13
|
+
if (!existsSync(dir)) {
|
|
14
|
+
mkdirSync(dir, { recursive: true })
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Create package.json
|
|
18
|
+
const pkg = {
|
|
19
|
+
name: 'my-0g-app',
|
|
20
|
+
version: '0.1.0',
|
|
21
|
+
type: 'module',
|
|
22
|
+
scripts: {
|
|
23
|
+
start: 'node index.js',
|
|
24
|
+
},
|
|
25
|
+
dependencies: {
|
|
26
|
+
'0g-orbit': '^0.1.0',
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
writeFileSync(join(dir, 'package.json'), JSON.stringify(pkg, null, 2) + '\n')
|
|
30
|
+
|
|
31
|
+
// Create index.js with example
|
|
32
|
+
const example = `import { Orbit } from '0g-orbit'
|
|
33
|
+
|
|
34
|
+
const orbit = await Orbit.connect({
|
|
35
|
+
network: 'testnet',
|
|
36
|
+
privateKey: process.env.PRIVATE_KEY,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
// Check account status
|
|
40
|
+
const status = await orbit.status()
|
|
41
|
+
console.log(\`Connected: \${status.address} on \${status.network}\`)
|
|
42
|
+
console.log(\`Balance: \${status.balance} OG\`)
|
|
43
|
+
|
|
44
|
+
// Upload a file
|
|
45
|
+
// const { root } = await orbit.store('./my-file.txt')
|
|
46
|
+
// console.log('Stored at:', root)
|
|
47
|
+
|
|
48
|
+
// Run inference
|
|
49
|
+
// const result = await orbit.infer('meta-llama/Llama-3.3-70B', {
|
|
50
|
+
// messages: [{ role: 'user', content: 'What is 0G?' }],
|
|
51
|
+
// })
|
|
52
|
+
// console.log(result.content)
|
|
53
|
+
`
|
|
54
|
+
writeFileSync(join(dir, 'index.js'), example)
|
|
55
|
+
|
|
56
|
+
// Create .env.example
|
|
57
|
+
writeFileSync(join(dir, '.env.example'), 'PRIVATE_KEY=0x...\n')
|
|
58
|
+
|
|
59
|
+
// Create .gitignore
|
|
60
|
+
writeFileSync(join(dir, '.gitignore'), 'node_modules/\n.env\n')
|
|
61
|
+
|
|
62
|
+
console.log()
|
|
63
|
+
console.log(chalk.bold(' 0G Orbit project initialized'))
|
|
64
|
+
console.log()
|
|
65
|
+
console.log(chalk.dim(' Next steps:'))
|
|
66
|
+
console.log(` 1. ${chalk.cyan('cd ' + (opts.dir === '.' ? '.' : opts.dir))}`)
|
|
67
|
+
console.log(` 2. ${chalk.cyan('cp .env.example .env')} and add your private key`)
|
|
68
|
+
console.log(` 3. ${chalk.cyan('npm install')}`)
|
|
69
|
+
console.log(` 4. ${chalk.cyan('node index.js')}`)
|
|
70
|
+
console.log()
|
|
71
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import ora from 'ora'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import { connectOrbit, formatError } from '../utils.js'
|
|
4
|
+
|
|
5
|
+
interface StoreOpts {
|
|
6
|
+
network: string
|
|
7
|
+
tags?: string
|
|
8
|
+
replicas: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function storeCommand(file: string, opts: StoreOpts) {
|
|
12
|
+
const spinner = ora('Connecting to 0G...').start()
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const orbit = await connectOrbit(opts.network)
|
|
16
|
+
spinner.text = `Uploading ${file}...`
|
|
17
|
+
|
|
18
|
+
const result = await orbit.store(file, {
|
|
19
|
+
tags: opts.tags,
|
|
20
|
+
replicas: parseInt(opts.replicas, 10),
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
spinner.succeed('Upload complete')
|
|
24
|
+
console.log()
|
|
25
|
+
console.log(chalk.bold(' Root hash: ') + chalk.cyan(result.root))
|
|
26
|
+
console.log(chalk.bold(' Tx hash: ') + chalk.dim(result.txHash))
|
|
27
|
+
console.log()
|
|
28
|
+
console.log(chalk.dim(` Retrieve with: orbit retrieve ${result.root} ./output`))
|
|
29
|
+
} catch (err) {
|
|
30
|
+
spinner.fail(chalk.red('Upload failed'))
|
|
31
|
+
console.error(chalk.dim(` ${formatError(err)}`))
|
|
32
|
+
process.exit(1)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface StoreDataOpts {
|
|
37
|
+
network: string
|
|
38
|
+
tags?: string
|
|
39
|
+
replicas: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function storeDataCommand(text: string, opts: StoreDataOpts) {
|
|
43
|
+
const spinner = ora('Connecting to 0G...').start()
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const orbit = await connectOrbit(opts.network)
|
|
47
|
+
spinner.text = 'Uploading data...'
|
|
48
|
+
|
|
49
|
+
const result = await orbit.storeData(text, {
|
|
50
|
+
tags: opts.tags,
|
|
51
|
+
replicas: parseInt(opts.replicas, 10),
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
spinner.succeed('Upload complete')
|
|
55
|
+
console.log()
|
|
56
|
+
console.log(chalk.bold(' Root hash: ') + chalk.cyan(result.root))
|
|
57
|
+
console.log(chalk.bold(' Tx hash: ') + chalk.dim(result.txHash))
|
|
58
|
+
console.log()
|
|
59
|
+
console.log(chalk.dim(` Retrieve with: orbit retrieve ${result.root} ./output`))
|
|
60
|
+
} catch (err) {
|
|
61
|
+
spinner.fail(chalk.red('Upload failed'))
|
|
62
|
+
console.error(chalk.dim(` ${formatError(err)}`))
|
|
63
|
+
process.exit(1)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface RetrieveOpts {
|
|
68
|
+
network: string
|
|
69
|
+
proof?: boolean
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function retrieveCommand(
|
|
73
|
+
rootHash: string,
|
|
74
|
+
output: string,
|
|
75
|
+
opts: RetrieveOpts
|
|
76
|
+
) {
|
|
77
|
+
const spinner = ora('Connecting to 0G...').start()
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const orbit = await connectOrbit(opts.network)
|
|
81
|
+
spinner.text = `Downloading to ${output}...`
|
|
82
|
+
|
|
83
|
+
await orbit.retrieve(rootHash, output, { proof: opts.proof })
|
|
84
|
+
|
|
85
|
+
spinner.succeed(`Downloaded to ${output}`)
|
|
86
|
+
} catch (err) {
|
|
87
|
+
spinner.fail(chalk.red('Download failed'))
|
|
88
|
+
console.error(chalk.dim(` ${formatError(err)}`))
|
|
89
|
+
process.exit(1)
|
|
90
|
+
}
|
|
91
|
+
}
|
package/src/cli/utils.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Orbit, OrbitError } from '../index.js'
|
|
2
|
+
import type { NetworkName } from '../index.js'
|
|
3
|
+
import chalk from 'chalk'
|
|
4
|
+
|
|
5
|
+
export async function connectOrbit(network: string): Promise<Orbit> {
|
|
6
|
+
return Orbit.connect({
|
|
7
|
+
network: network as NetworkName,
|
|
8
|
+
})
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function formatError(err: unknown): string {
|
|
12
|
+
if (err instanceof OrbitError) {
|
|
13
|
+
let msg = err.message
|
|
14
|
+
if (err.suggestion) {
|
|
15
|
+
msg += '\n ' + chalk.yellow('Hint: ') + err.suggestion
|
|
16
|
+
}
|
|
17
|
+
return msg
|
|
18
|
+
}
|
|
19
|
+
if (err instanceof Error) return err.message
|
|
20
|
+
return String(err)
|
|
21
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import {
|
|
3
|
+
OrbitError,
|
|
4
|
+
ConnectionError,
|
|
5
|
+
StorageError,
|
|
6
|
+
InferenceError,
|
|
7
|
+
InsufficientBalanceError,
|
|
8
|
+
ProviderNotFoundError,
|
|
9
|
+
TimeoutError,
|
|
10
|
+
} from './errors.js'
|
|
11
|
+
|
|
12
|
+
describe('OrbitError', () => {
|
|
13
|
+
it('has code and suggestion', () => {
|
|
14
|
+
const err = new OrbitError('test', 'TEST_CODE', 'try this')
|
|
15
|
+
expect(err.message).toBe('test')
|
|
16
|
+
expect(err.code).toBe('TEST_CODE')
|
|
17
|
+
expect(err.suggestion).toBe('try this')
|
|
18
|
+
expect(err.name).toBe('OrbitError')
|
|
19
|
+
expect(err).toBeInstanceOf(Error)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('suggestion is optional', () => {
|
|
23
|
+
const err = new OrbitError('test', 'CODE')
|
|
24
|
+
expect(err.suggestion).toBeUndefined()
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe('ConnectionError', () => {
|
|
29
|
+
it('has default suggestion', () => {
|
|
30
|
+
const err = new ConnectionError('failed')
|
|
31
|
+
expect(err.code).toBe('CONNECTION_ERROR')
|
|
32
|
+
expect(err.suggestion).toContain('RPC')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('accepts custom suggestion', () => {
|
|
36
|
+
const err = new ConnectionError('failed', 'custom hint')
|
|
37
|
+
expect(err.suggestion).toBe('custom hint')
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
describe('StorageError', () => {
|
|
42
|
+
it('has default suggestion', () => {
|
|
43
|
+
const err = new StorageError('upload broke')
|
|
44
|
+
expect(err.code).toBe('STORAGE_ERROR')
|
|
45
|
+
expect(err.suggestion).toContain('file exists')
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
describe('InferenceError', () => {
|
|
50
|
+
it('has default suggestion', () => {
|
|
51
|
+
const err = new InferenceError('inference broke')
|
|
52
|
+
expect(err.code).toBe('INFERENCE_ERROR')
|
|
53
|
+
expect(err.suggestion).toContain('listServices')
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
describe('InsufficientBalanceError', () => {
|
|
58
|
+
it('includes required and available amounts', () => {
|
|
59
|
+
const err = new InsufficientBalanceError(1.5, 0.1)
|
|
60
|
+
expect(err.required).toBe(1.5)
|
|
61
|
+
expect(err.available).toBe(0.1)
|
|
62
|
+
expect(err.message).toContain('1.5')
|
|
63
|
+
expect(err.message).toContain('0.1')
|
|
64
|
+
expect(err.suggestion).toContain('faucet')
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
describe('ProviderNotFoundError', () => {
|
|
69
|
+
it('has suggestion about listServices', () => {
|
|
70
|
+
const err = new ProviderNotFoundError('No provider for model "gpt-5"')
|
|
71
|
+
expect(err.message).toContain('gpt-5')
|
|
72
|
+
expect(err.suggestion).toContain('listServices')
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
describe('TimeoutError', () => {
|
|
77
|
+
it('has timeout-specific suggestion', () => {
|
|
78
|
+
const err = new TimeoutError('timed out after 30s')
|
|
79
|
+
expect(err.code).toBe('TIMEOUT')
|
|
80
|
+
expect(err.suggestion).toContain('timeout')
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
describe('error hierarchy', () => {
|
|
85
|
+
it('all errors are instanceof OrbitError and Error', () => {
|
|
86
|
+
const errors = [
|
|
87
|
+
new ConnectionError('a'),
|
|
88
|
+
new StorageError('b'),
|
|
89
|
+
new InferenceError('c'),
|
|
90
|
+
new InsufficientBalanceError(1, 0),
|
|
91
|
+
new ProviderNotFoundError('d'),
|
|
92
|
+
new TimeoutError('e'),
|
|
93
|
+
]
|
|
94
|
+
for (const err of errors) {
|
|
95
|
+
expect(err).toBeInstanceOf(OrbitError)
|
|
96
|
+
expect(err).toBeInstanceOf(Error)
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
})
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export class OrbitError extends Error {
|
|
2
|
+
constructor(
|
|
3
|
+
message: string,
|
|
4
|
+
public readonly code: string,
|
|
5
|
+
public readonly suggestion?: string
|
|
6
|
+
) {
|
|
7
|
+
super(message)
|
|
8
|
+
this.name = 'OrbitError'
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class ConnectionError extends OrbitError {
|
|
13
|
+
constructor(message: string, suggestion?: string) {
|
|
14
|
+
super(
|
|
15
|
+
message,
|
|
16
|
+
'CONNECTION_ERROR',
|
|
17
|
+
suggestion ?? 'Check your RPC URL and network connection. Try a different RPC endpoint with the rpcUrl option.'
|
|
18
|
+
)
|
|
19
|
+
this.name = 'ConnectionError'
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class StorageError extends OrbitError {
|
|
24
|
+
constructor(message: string, suggestion?: string) {
|
|
25
|
+
super(
|
|
26
|
+
message,
|
|
27
|
+
'STORAGE_ERROR',
|
|
28
|
+
suggestion ?? 'Check that your file exists and you have sufficient OG balance for gas fees.'
|
|
29
|
+
)
|
|
30
|
+
this.name = 'StorageError'
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class InferenceError extends OrbitError {
|
|
35
|
+
constructor(message: string, suggestion?: string) {
|
|
36
|
+
super(
|
|
37
|
+
message,
|
|
38
|
+
'INFERENCE_ERROR',
|
|
39
|
+
suggestion ?? 'Run orbit.listServices() to check available models and provider status.'
|
|
40
|
+
)
|
|
41
|
+
this.name = 'InferenceError'
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class InsufficientBalanceError extends OrbitError {
|
|
46
|
+
constructor(
|
|
47
|
+
public readonly required: number,
|
|
48
|
+
public readonly available: number
|
|
49
|
+
) {
|
|
50
|
+
super(
|
|
51
|
+
`Insufficient balance: need ${required} OG but have ${available} OG`,
|
|
52
|
+
'INSUFFICIENT_BALANCE',
|
|
53
|
+
'Get testnet OG from the faucet: https://faucet.0g.ai'
|
|
54
|
+
)
|
|
55
|
+
this.name = 'InsufficientBalanceError'
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export class ProviderNotFoundError extends OrbitError {
|
|
60
|
+
constructor(message: string) {
|
|
61
|
+
super(
|
|
62
|
+
message,
|
|
63
|
+
'PROVIDER_NOT_FOUND',
|
|
64
|
+
'Run orbit.listServices() to see available models and their providers.'
|
|
65
|
+
)
|
|
66
|
+
this.name = 'ProviderNotFoundError'
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export class TimeoutError extends OrbitError {
|
|
71
|
+
constructor(message: string) {
|
|
72
|
+
super(
|
|
73
|
+
message,
|
|
74
|
+
'TIMEOUT',
|
|
75
|
+
'The request timed out. Try increasing the timeout option or check if the provider is responsive.'
|
|
76
|
+
)
|
|
77
|
+
this.name = 'TimeoutError'
|
|
78
|
+
}
|
|
79
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Main entry point
|
|
2
|
+
export { Orbit } from './orbit.js'
|
|
3
|
+
|
|
4
|
+
// Clients (for direct access)
|
|
5
|
+
export { StorageClient } from './storage.js'
|
|
6
|
+
export { InferenceClient } from './inference.js'
|
|
7
|
+
|
|
8
|
+
// Types
|
|
9
|
+
export type {
|
|
10
|
+
OrbitConfig,
|
|
11
|
+
StoreResult,
|
|
12
|
+
StoreOptions,
|
|
13
|
+
RetrieveOptions,
|
|
14
|
+
InferResult,
|
|
15
|
+
InferOptions,
|
|
16
|
+
ServiceInfo,
|
|
17
|
+
AccountStatus,
|
|
18
|
+
} from './types.js'
|
|
19
|
+
|
|
20
|
+
// Network config
|
|
21
|
+
export type { NetworkName, NetworkConfig } from './networks.js'
|
|
22
|
+
export { NETWORKS, getNetwork } from './networks.js'
|
|
23
|
+
|
|
24
|
+
// Retry utilities
|
|
25
|
+
export { withRetry, isTransientError } from './retry.js'
|
|
26
|
+
export type { RetryOptions } from './retry.js'
|
|
27
|
+
|
|
28
|
+
// Errors
|
|
29
|
+
export {
|
|
30
|
+
OrbitError,
|
|
31
|
+
ConnectionError,
|
|
32
|
+
StorageError,
|
|
33
|
+
InferenceError,
|
|
34
|
+
InsufficientBalanceError,
|
|
35
|
+
ProviderNotFoundError,
|
|
36
|
+
TimeoutError,
|
|
37
|
+
} from './errors.js'
|