apinow-sdk 0.22.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -0
- package/dist/cli.js +226 -1
- package/dist/index.d.ts +72 -0
- package/dist/index.js +100 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,6 +56,13 @@ Returns:
|
|
|
56
56
|
| `listWorkflows(opts?)` | List workflows (free) |
|
|
57
57
|
| `getWorkflow(id)` | Get workflow details (free) |
|
|
58
58
|
| `runWorkflow(id, input)` | Run a workflow with automatic x402 payment |
|
|
59
|
+
| `generateUI(opts)` | Start AI UI generation for an endpoint (async) |
|
|
60
|
+
| `generateUIAndWait(opts)` | Generate UI and poll until complete |
|
|
61
|
+
| `getGeneratedUI(id)` | Get a generated UI by ID |
|
|
62
|
+
| `listGeneratedUIs(key, sort?)` | List generated UIs for an endpoint |
|
|
63
|
+
| `checkFreeUI()` | Check free-tier generation eligibility |
|
|
64
|
+
| `reactToUI(id, action, comment?)` | Like/dislike/comment on a generated UI |
|
|
65
|
+
| `deleteGeneratedUI(id)` | Delete a generated UI |
|
|
59
66
|
| `wallet` | Your wallet address |
|
|
60
67
|
| `fetch` | Raw x402-wrapped `fetch` for advanced use |
|
|
61
68
|
|
|
@@ -77,6 +84,38 @@ const result = await apinow.runWorkflow('90931d9c8fb94df9', {
|
|
|
77
84
|
});
|
|
78
85
|
```
|
|
79
86
|
|
|
87
|
+
### AI UI Generation
|
|
88
|
+
|
|
89
|
+
Generate interactive Arrow JS sandbox UIs for any endpoint — ideal for AI agents that need a visual interface.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// generate a UI and wait for it to complete
|
|
93
|
+
const ui = await apinow.generateUIAndWait({
|
|
94
|
+
endpointName: 'horoscope',
|
|
95
|
+
namespace: 'gg402',
|
|
96
|
+
description: 'Get daily horoscope for a zodiac sign',
|
|
97
|
+
querySchema: { properties: { sign: { type: 'string' } } },
|
|
98
|
+
responseSchema: { properties: { horoscope: { type: 'string' } } },
|
|
99
|
+
customPrompt: 'Use a starry night theme',
|
|
100
|
+
});
|
|
101
|
+
console.log(ui.status); // 'complete'
|
|
102
|
+
console.log(ui.source); // { "main.ts": "...", "main.css": "..." }
|
|
103
|
+
|
|
104
|
+
// or fire-and-forget + poll yourself
|
|
105
|
+
const { id } = await apinow.generateUI({ endpointName: 'translate', namespace: 'apinowfun' });
|
|
106
|
+
const doc = await apinow.getGeneratedUI(id); // poll until doc.status !== 'generating'
|
|
107
|
+
|
|
108
|
+
// list existing UIs for an endpoint
|
|
109
|
+
const { uis } = await apinow.listGeneratedUIs('gg402/horoscope', 'popular');
|
|
110
|
+
|
|
111
|
+
// social
|
|
112
|
+
await apinow.reactToUI(ui._id, 'like');
|
|
113
|
+
await apinow.reactToUI(ui._id, 'comment', 'Great UI!');
|
|
114
|
+
|
|
115
|
+
// check free-tier
|
|
116
|
+
const { free, remaining } = await apinow.checkFreeUI();
|
|
117
|
+
```
|
|
118
|
+
|
|
80
119
|
## CLI
|
|
81
120
|
|
|
82
121
|
```bash
|
|
@@ -144,6 +183,57 @@ APINOW_WALLET_PKEY=0x... npx apinow run-workflow 90931d9c8fb94df9 -d '{"query":"
|
|
|
144
183
|
| `-d, --data <json>` | JSON input (default: `{"query":"hello world"}`) |
|
|
145
184
|
| `-k, --key <privateKey>` | Wallet key (or set `APINOW_WALLET_PKEY`) |
|
|
146
185
|
|
|
186
|
+
### `ui-generate` — generate an AI UI for an endpoint
|
|
187
|
+
|
|
188
|
+
Generates an interactive Arrow JS sandbox UI. Automatically fetches the endpoint's schema and examples, sends the generation request, and polls until complete.
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
APINOW_WALLET_PKEY=0x... npx apinow ui-generate gg402/horoscope
|
|
192
|
+
APINOW_WALLET_PKEY=0x... npx apinow ui-generate gg402/horoscope --prompt "dark theme with animations"
|
|
193
|
+
npx apinow ui-generate ns/endpoint --no-wait -k 0xKEY # returns immediately with ID
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
| Flag | Description |
|
|
197
|
+
|------|-------------|
|
|
198
|
+
| `-p, --prompt <text>` | Custom instructions for the UI |
|
|
199
|
+
| `--no-wait` | Return immediately without polling |
|
|
200
|
+
| `--timeout <ms>` | Polling timeout (default: 120000) |
|
|
201
|
+
| `-k, --key <privateKey>` | Wallet key (or set `APINOW_WALLET_PKEY`) |
|
|
202
|
+
|
|
203
|
+
### `ui-list` — list generated UIs
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
npx apinow ui-list gg402/horoscope
|
|
207
|
+
npx apinow ui-list gg402/horoscope --sort recent
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### `ui-get` — get a generated UI by ID
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
npx apinow ui-get 665a1b2c3d4e5f6a7b8c9d0e
|
|
214
|
+
npx apinow ui-get 665a1b2c3d4e5f6a7b8c9d0e --source-only # just the Arrow JS source
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### `ui-like` / `ui-dislike` / `ui-comment` — social actions
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
APINOW_WALLET_PKEY=0x... npx apinow ui-like <id>
|
|
221
|
+
APINOW_WALLET_PKEY=0x... npx apinow ui-dislike <id>
|
|
222
|
+
APINOW_WALLET_PKEY=0x... npx apinow ui-comment <id> -m "Nice UI!"
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### `ui-delete` — delete a generated UI
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
APINOW_WALLET_PKEY=0x... npx apinow ui-delete <id>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### `ui-free-check` — check free-tier eligibility
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
APINOW_WALLET_PKEY=0x... npx apinow ui-free-check
|
|
235
|
+
```
|
|
236
|
+
|
|
147
237
|
### `discover` — check the x402 price of any URL (free)
|
|
148
238
|
|
|
149
239
|
```bash
|
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ const program = new Command();
|
|
|
7
7
|
program
|
|
8
8
|
.name('apinow')
|
|
9
9
|
.description('CLI for APINow.fun — search, inspect, and call pay-per-request APIs')
|
|
10
|
-
.version('0.
|
|
10
|
+
.version('0.23.0');
|
|
11
11
|
// ─── Helpers ───
|
|
12
12
|
function getPrivateKey(opts) {
|
|
13
13
|
const raw = opts.key || process.env.APINOW_WALLET_PKEY || process.env.PRIVATE_KEY;
|
|
@@ -560,6 +560,231 @@ program
|
|
|
560
560
|
process.exit(1);
|
|
561
561
|
}
|
|
562
562
|
});
|
|
563
|
+
// ─── ui-generate ───
|
|
564
|
+
program
|
|
565
|
+
.command('ui-generate <endpoint>')
|
|
566
|
+
.description('Generate an AI UI for an endpoint (namespace/name). Polls until complete.')
|
|
567
|
+
.option('-p, --prompt <prompt>', 'Custom prompt / instructions for the UI')
|
|
568
|
+
.option('--no-wait', 'Return immediately without polling')
|
|
569
|
+
.option('--timeout <ms>', 'Polling timeout in ms', '120000')
|
|
570
|
+
.option('-k, --key <privateKey>', 'Wallet private key')
|
|
571
|
+
.action(async (endpoint, opts) => {
|
|
572
|
+
try {
|
|
573
|
+
if (!endpoint.includes('/'))
|
|
574
|
+
throw new Error('Format: namespace/endpoint-name');
|
|
575
|
+
const [ns, ep] = endpoint.split('/');
|
|
576
|
+
const { address } = getWallet(opts);
|
|
577
|
+
const details = await fetchJson(`${API_BASE}/api/endpoints/${ns}/${ep}/details`);
|
|
578
|
+
const body = {
|
|
579
|
+
endpointName: ep,
|
|
580
|
+
namespace: ns,
|
|
581
|
+
description: details.description || '',
|
|
582
|
+
querySchema: details.querySchema || {},
|
|
583
|
+
responseSchema: details.responseSchema || {},
|
|
584
|
+
walletAddress: address,
|
|
585
|
+
};
|
|
586
|
+
if (details.exampleQuery || details.exampleOutput) {
|
|
587
|
+
body.examples = [{ input: details.exampleQuery, output: details.exampleOutput }];
|
|
588
|
+
}
|
|
589
|
+
if (opts.prompt)
|
|
590
|
+
body.customPrompt = opts.prompt;
|
|
591
|
+
console.error(`Generating UI for ${ns}/${ep}…`);
|
|
592
|
+
const { id } = await fetchJson(`${API_BASE}/api/ai/generate-ui`, {
|
|
593
|
+
method: 'POST',
|
|
594
|
+
headers: { 'Content-Type': 'application/json' },
|
|
595
|
+
body: JSON.stringify(body),
|
|
596
|
+
});
|
|
597
|
+
if (!opts.wait) {
|
|
598
|
+
console.log(JSON.stringify({ id, status: 'generating' }, null, 2));
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
const timeout = Number(opts.timeout);
|
|
602
|
+
const deadline = Date.now() + timeout;
|
|
603
|
+
process.stderr.write(' Polling');
|
|
604
|
+
while (Date.now() < deadline) {
|
|
605
|
+
await new Promise((r) => setTimeout(r, 3000));
|
|
606
|
+
process.stderr.write('.');
|
|
607
|
+
const doc = await fetchJson(`${API_BASE}/api/ai/generate-ui?id=${encodeURIComponent(id)}`);
|
|
608
|
+
if (doc.status === 'complete') {
|
|
609
|
+
console.error(' done!');
|
|
610
|
+
console.log(JSON.stringify({
|
|
611
|
+
id: doc._id,
|
|
612
|
+
status: doc.status,
|
|
613
|
+
endpointKey: doc.endpointKey,
|
|
614
|
+
model: doc.model,
|
|
615
|
+
files: Object.keys(doc.source || {}),
|
|
616
|
+
source: doc.source,
|
|
617
|
+
viewUrl: `https://apinow.fun/try/${ns}/${ep}`,
|
|
618
|
+
}, null, 2));
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
if (doc.status === 'error') {
|
|
622
|
+
console.error(' failed!');
|
|
623
|
+
console.error(`Error: ${doc.errorMessage}`);
|
|
624
|
+
process.exit(1);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
console.error(` timed out after ${timeout / 1000}s`);
|
|
628
|
+
console.log(JSON.stringify({ id, status: 'generating', note: 'Still generating — poll with: apinow ui-get ' + id }));
|
|
629
|
+
}
|
|
630
|
+
catch (err) {
|
|
631
|
+
console.error(`Error: ${err.message}`);
|
|
632
|
+
process.exit(1);
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
// ─── ui-list ───
|
|
636
|
+
program
|
|
637
|
+
.command('ui-list <endpoint>')
|
|
638
|
+
.description('List generated UIs for an endpoint (namespace/name)')
|
|
639
|
+
.option('-s, --sort <sort>', 'Sort: popular | recent', 'popular')
|
|
640
|
+
.action(async (endpoint, opts) => {
|
|
641
|
+
try {
|
|
642
|
+
if (!endpoint.includes('/'))
|
|
643
|
+
throw new Error('Format: namespace/endpoint-name');
|
|
644
|
+
const params = new URLSearchParams({ endpointKey: endpoint, sort: opts.sort });
|
|
645
|
+
const data = await fetchJson(`${API_BASE}/api/ai/generate-ui?${params}`);
|
|
646
|
+
const uis = data.uis || [];
|
|
647
|
+
if (!uis.length) {
|
|
648
|
+
console.log('No generated UIs found.');
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
const rows = [['ID', 'STATUS', 'MODEL', 'OPENS', 'LIKES', 'PROMPT', 'CREATED']];
|
|
652
|
+
for (const ui of uis) {
|
|
653
|
+
rows.push([
|
|
654
|
+
ui._id,
|
|
655
|
+
ui.status,
|
|
656
|
+
ui.model || '—',
|
|
657
|
+
String(ui.openCount || 0),
|
|
658
|
+
String((ui.likes || []).length),
|
|
659
|
+
truncate(ui.customPrompt || '(default)', 30),
|
|
660
|
+
new Date(ui.createdAt).toLocaleDateString(),
|
|
661
|
+
]);
|
|
662
|
+
}
|
|
663
|
+
printTable(rows);
|
|
664
|
+
}
|
|
665
|
+
catch (err) {
|
|
666
|
+
console.error(`Error: ${err.message}`);
|
|
667
|
+
process.exit(1);
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
// ─── ui-get ───
|
|
671
|
+
program
|
|
672
|
+
.command('ui-get <id>')
|
|
673
|
+
.description('Get a generated UI by ID (includes source code)')
|
|
674
|
+
.option('--source-only', 'Print only the source JSON')
|
|
675
|
+
.action(async (id, opts) => {
|
|
676
|
+
try {
|
|
677
|
+
const doc = await fetchJson(`${API_BASE}/api/ai/generate-ui?id=${encodeURIComponent(id)}`);
|
|
678
|
+
if (opts.sourceOnly) {
|
|
679
|
+
console.log(JSON.stringify(doc.source, null, 2));
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
console.log(JSON.stringify(doc, null, 2));
|
|
683
|
+
}
|
|
684
|
+
catch (err) {
|
|
685
|
+
console.error(`Error: ${err.message}`);
|
|
686
|
+
process.exit(1);
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
// ─── ui-delete ───
|
|
690
|
+
program
|
|
691
|
+
.command('ui-delete <id>')
|
|
692
|
+
.description('Delete a generated UI (must be creator)')
|
|
693
|
+
.option('-k, --key <privateKey>', 'Wallet private key')
|
|
694
|
+
.action(async (id, opts) => {
|
|
695
|
+
try {
|
|
696
|
+
const { address } = getWallet(opts);
|
|
697
|
+
const data = await fetchJson(`${API_BASE}/api/ai/generate-ui`, {
|
|
698
|
+
method: 'DELETE',
|
|
699
|
+
headers: { 'Content-Type': 'application/json' },
|
|
700
|
+
body: JSON.stringify({ id, wallet: address }),
|
|
701
|
+
});
|
|
702
|
+
console.log(JSON.stringify(data, null, 2));
|
|
703
|
+
}
|
|
704
|
+
catch (err) {
|
|
705
|
+
console.error(`Error: ${err.message}`);
|
|
706
|
+
process.exit(1);
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
// ─── ui-like / ui-dislike ───
|
|
710
|
+
program
|
|
711
|
+
.command('ui-like <id>')
|
|
712
|
+
.description('Like a generated UI')
|
|
713
|
+
.option('-k, --key <privateKey>', 'Wallet private key')
|
|
714
|
+
.action(async (id, opts) => {
|
|
715
|
+
try {
|
|
716
|
+
const { address } = getWallet(opts);
|
|
717
|
+
const data = await fetchJson(`${API_BASE}/api/ai/generate-ui`, {
|
|
718
|
+
method: 'PATCH',
|
|
719
|
+
headers: { 'Content-Type': 'application/json' },
|
|
720
|
+
body: JSON.stringify({ id, action: 'like', wallet: address }),
|
|
721
|
+
});
|
|
722
|
+
console.log(`Likes: ${data.likes} Dislikes: ${data.dislikes}`);
|
|
723
|
+
}
|
|
724
|
+
catch (err) {
|
|
725
|
+
console.error(`Error: ${err.message}`);
|
|
726
|
+
process.exit(1);
|
|
727
|
+
}
|
|
728
|
+
});
|
|
729
|
+
program
|
|
730
|
+
.command('ui-dislike <id>')
|
|
731
|
+
.description('Dislike a generated UI')
|
|
732
|
+
.option('-k, --key <privateKey>', 'Wallet private key')
|
|
733
|
+
.action(async (id, opts) => {
|
|
734
|
+
try {
|
|
735
|
+
const { address } = getWallet(opts);
|
|
736
|
+
const data = await fetchJson(`${API_BASE}/api/ai/generate-ui`, {
|
|
737
|
+
method: 'PATCH',
|
|
738
|
+
headers: { 'Content-Type': 'application/json' },
|
|
739
|
+
body: JSON.stringify({ id, action: 'dislike', wallet: address }),
|
|
740
|
+
});
|
|
741
|
+
console.log(`Likes: ${data.likes} Dislikes: ${data.dislikes}`);
|
|
742
|
+
}
|
|
743
|
+
catch (err) {
|
|
744
|
+
console.error(`Error: ${err.message}`);
|
|
745
|
+
process.exit(1);
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
// ─── ui-comment ───
|
|
749
|
+
program
|
|
750
|
+
.command('ui-comment <id>')
|
|
751
|
+
.description('Comment on a generated UI')
|
|
752
|
+
.requiredOption('-m, --message <text>', 'Comment text')
|
|
753
|
+
.option('-k, --key <privateKey>', 'Wallet private key')
|
|
754
|
+
.action(async (id, opts) => {
|
|
755
|
+
try {
|
|
756
|
+
const { address } = getWallet(opts);
|
|
757
|
+
const data = await fetchJson(`${API_BASE}/api/ai/generate-ui`, {
|
|
758
|
+
method: 'PATCH',
|
|
759
|
+
headers: { 'Content-Type': 'application/json' },
|
|
760
|
+
body: JSON.stringify({ id, action: 'comment', wallet: address, comment: opts.message }),
|
|
761
|
+
});
|
|
762
|
+
console.log(`Comments: ${(data.comments || []).length}`);
|
|
763
|
+
}
|
|
764
|
+
catch (err) {
|
|
765
|
+
console.error(`Error: ${err.message}`);
|
|
766
|
+
process.exit(1);
|
|
767
|
+
}
|
|
768
|
+
});
|
|
769
|
+
// ─── ui-free-check ───
|
|
770
|
+
program
|
|
771
|
+
.command('ui-free-check')
|
|
772
|
+
.description('Check free-tier UI generation eligibility')
|
|
773
|
+
.option('-k, --key <privateKey>', 'Wallet private key')
|
|
774
|
+
.action(async (opts) => {
|
|
775
|
+
try {
|
|
776
|
+
const { address } = getWallet(opts);
|
|
777
|
+
const params = new URLSearchParams({ checkFree: '1', wallet: address });
|
|
778
|
+
const data = await fetchJson(`${API_BASE}/api/ai/generate-ui?${params}`);
|
|
779
|
+
console.log(`\n Wallet: ${address}`);
|
|
780
|
+
console.log(` Free tier: ${data.free ? 'YES' : 'NO'}`);
|
|
781
|
+
console.log(` Remaining: ${data.remaining === Infinity ? '∞' : data.remaining}\n`);
|
|
782
|
+
}
|
|
783
|
+
catch (err) {
|
|
784
|
+
console.error(`Error: ${err.message}`);
|
|
785
|
+
process.exit(1);
|
|
786
|
+
}
|
|
787
|
+
});
|
|
563
788
|
// ─── factory-balance ───
|
|
564
789
|
program
|
|
565
790
|
.command('factory-balance')
|
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,36 @@ export interface ApinowConfig {
|
|
|
23
23
|
baseUrl?: string;
|
|
24
24
|
fetch?: typeof globalThis.fetch;
|
|
25
25
|
}
|
|
26
|
+
export interface GenerateUIOptions {
|
|
27
|
+
endpointName: string;
|
|
28
|
+
namespace: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
querySchema?: any;
|
|
31
|
+
responseSchema?: any;
|
|
32
|
+
examples?: any[];
|
|
33
|
+
customPrompt?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface GeneratedUI {
|
|
36
|
+
_id: string;
|
|
37
|
+
endpointKey: string;
|
|
38
|
+
endpointName: string;
|
|
39
|
+
namespace: string;
|
|
40
|
+
source: Record<string, string> | null;
|
|
41
|
+
status: 'generating' | 'complete' | 'error';
|
|
42
|
+
errorMessage?: string;
|
|
43
|
+
customPrompt: string;
|
|
44
|
+
model: string;
|
|
45
|
+
generatedBy: string | null;
|
|
46
|
+
openCount: number;
|
|
47
|
+
likes: string[];
|
|
48
|
+
dislikes: string[];
|
|
49
|
+
comments: Array<{
|
|
50
|
+
wallet: string;
|
|
51
|
+
text: string;
|
|
52
|
+
createdAt: string;
|
|
53
|
+
}>;
|
|
54
|
+
createdAt: string;
|
|
55
|
+
}
|
|
26
56
|
export declare function createClient(config: ApinowConfig): {
|
|
27
57
|
wallet: `0x${string}`;
|
|
28
58
|
/**
|
|
@@ -202,6 +232,48 @@ export declare function createClient(config: ApinowConfig): {
|
|
|
202
232
|
testOutput: any;
|
|
203
233
|
workflow: any;
|
|
204
234
|
}>;
|
|
235
|
+
/**
|
|
236
|
+
* Start generating an AI UI for an endpoint. Returns immediately with a doc ID.
|
|
237
|
+
* Poll with getGeneratedUI() or use generateUIAndWait() for convenience.
|
|
238
|
+
*/
|
|
239
|
+
generateUI(opts: GenerateUIOptions): Promise<{
|
|
240
|
+
id: string;
|
|
241
|
+
status: string;
|
|
242
|
+
}>;
|
|
243
|
+
/**
|
|
244
|
+
* Get a generated UI by ID (use to poll status after generateUI).
|
|
245
|
+
*/
|
|
246
|
+
getGeneratedUI(id: string): Promise<GeneratedUI>;
|
|
247
|
+
/**
|
|
248
|
+
* List generated UIs for an endpoint.
|
|
249
|
+
*/
|
|
250
|
+
listGeneratedUIs(endpointKey: string, sort?: "popular" | "recent"): Promise<{
|
|
251
|
+
uis: GeneratedUI[];
|
|
252
|
+
}>;
|
|
253
|
+
/**
|
|
254
|
+
* Check free-tier UI generation eligibility for a wallet.
|
|
255
|
+
*/
|
|
256
|
+
checkFreeUI(): Promise<{
|
|
257
|
+
free: boolean;
|
|
258
|
+
remaining: number;
|
|
259
|
+
}>;
|
|
260
|
+
/**
|
|
261
|
+
* Like, dislike, or comment on a generated UI.
|
|
262
|
+
*/
|
|
263
|
+
reactToUI(id: string, action: "like" | "dislike" | "comment", comment?: string): Promise<any>;
|
|
264
|
+
/**
|
|
265
|
+
* Delete a generated UI (must be creator or admin).
|
|
266
|
+
*/
|
|
267
|
+
deleteGeneratedUI(id: string): Promise<{
|
|
268
|
+
deleted: boolean;
|
|
269
|
+
}>;
|
|
270
|
+
/**
|
|
271
|
+
* Generate a UI and poll until complete or error. Returns the final GeneratedUI doc.
|
|
272
|
+
* @param opts - generation params
|
|
273
|
+
* @param pollIntervalMs - polling interval (default 3000ms)
|
|
274
|
+
* @param timeoutMs - max wait time (default 120000ms)
|
|
275
|
+
*/
|
|
276
|
+
generateUIAndWait(opts: GenerateUIOptions, pollIntervalMs?: number, timeoutMs?: number): Promise<GeneratedUI>;
|
|
205
277
|
/**
|
|
206
278
|
* Discover the x402 price for any external URL without executing it.
|
|
207
279
|
* Free — no payment required.
|
package/dist/index.js
CHANGED
|
@@ -343,6 +343,106 @@ export function createClient(config) {
|
|
|
343
343
|
}
|
|
344
344
|
return { draft, endpoint, testOutput, workflow };
|
|
345
345
|
},
|
|
346
|
+
// ─── AI UI Generation ───
|
|
347
|
+
/**
|
|
348
|
+
* Start generating an AI UI for an endpoint. Returns immediately with a doc ID.
|
|
349
|
+
* Poll with getGeneratedUI() or use generateUIAndWait() for convenience.
|
|
350
|
+
*/
|
|
351
|
+
async generateUI(opts) {
|
|
352
|
+
const res = await fetch(`${baseUrl}/api/ai/generate-ui`, {
|
|
353
|
+
method: 'POST',
|
|
354
|
+
headers: { 'Content-Type': 'application/json' },
|
|
355
|
+
body: JSON.stringify({ ...opts, walletAddress: account.address }),
|
|
356
|
+
});
|
|
357
|
+
if (!res.ok) {
|
|
358
|
+
const text = await res.text();
|
|
359
|
+
throw new Error(`Failed to generate UI: ${res.status} ${text}`);
|
|
360
|
+
}
|
|
361
|
+
return res.json();
|
|
362
|
+
},
|
|
363
|
+
/**
|
|
364
|
+
* Get a generated UI by ID (use to poll status after generateUI).
|
|
365
|
+
*/
|
|
366
|
+
async getGeneratedUI(id) {
|
|
367
|
+
const res = await fetch(`${baseUrl}/api/ai/generate-ui?id=${encodeURIComponent(id)}`);
|
|
368
|
+
if (!res.ok) {
|
|
369
|
+
const text = await res.text();
|
|
370
|
+
throw new Error(`Failed to get generated UI: ${res.status} ${text}`);
|
|
371
|
+
}
|
|
372
|
+
return res.json();
|
|
373
|
+
},
|
|
374
|
+
/**
|
|
375
|
+
* List generated UIs for an endpoint.
|
|
376
|
+
*/
|
|
377
|
+
async listGeneratedUIs(endpointKey, sort = 'popular') {
|
|
378
|
+
const params = new URLSearchParams({ endpointKey, sort });
|
|
379
|
+
const res = await fetch(`${baseUrl}/api/ai/generate-ui?${params}`);
|
|
380
|
+
if (!res.ok) {
|
|
381
|
+
const text = await res.text();
|
|
382
|
+
throw new Error(`Failed to list generated UIs: ${res.status} ${text}`);
|
|
383
|
+
}
|
|
384
|
+
return res.json();
|
|
385
|
+
},
|
|
386
|
+
/**
|
|
387
|
+
* Check free-tier UI generation eligibility for a wallet.
|
|
388
|
+
*/
|
|
389
|
+
async checkFreeUI() {
|
|
390
|
+
const params = new URLSearchParams({ checkFree: '1', wallet: account.address });
|
|
391
|
+
const res = await fetch(`${baseUrl}/api/ai/generate-ui?${params}`);
|
|
392
|
+
if (!res.ok)
|
|
393
|
+
throw new Error(`Failed to check free tier: ${res.status}`);
|
|
394
|
+
return res.json();
|
|
395
|
+
},
|
|
396
|
+
/**
|
|
397
|
+
* Like, dislike, or comment on a generated UI.
|
|
398
|
+
*/
|
|
399
|
+
async reactToUI(id, action, comment) {
|
|
400
|
+
const body = { id, action, wallet: account.address };
|
|
401
|
+
if (comment)
|
|
402
|
+
body.comment = comment;
|
|
403
|
+
const res = await fetch(`${baseUrl}/api/ai/generate-ui`, {
|
|
404
|
+
method: 'PATCH',
|
|
405
|
+
headers: { 'Content-Type': 'application/json' },
|
|
406
|
+
body: JSON.stringify(body),
|
|
407
|
+
});
|
|
408
|
+
if (!res.ok) {
|
|
409
|
+
const text = await res.text();
|
|
410
|
+
throw new Error(`Failed to react to UI: ${res.status} ${text}`);
|
|
411
|
+
}
|
|
412
|
+
return res.json();
|
|
413
|
+
},
|
|
414
|
+
/**
|
|
415
|
+
* Delete a generated UI (must be creator or admin).
|
|
416
|
+
*/
|
|
417
|
+
async deleteGeneratedUI(id) {
|
|
418
|
+
const res = await fetch(`${baseUrl}/api/ai/generate-ui`, {
|
|
419
|
+
method: 'DELETE',
|
|
420
|
+
headers: { 'Content-Type': 'application/json' },
|
|
421
|
+
body: JSON.stringify({ id, wallet: account.address }),
|
|
422
|
+
});
|
|
423
|
+
if (!res.ok) {
|
|
424
|
+
const text = await res.text();
|
|
425
|
+
throw new Error(`Failed to delete UI: ${res.status} ${text}`);
|
|
426
|
+
}
|
|
427
|
+
return res.json();
|
|
428
|
+
},
|
|
429
|
+
/**
|
|
430
|
+
* Generate a UI and poll until complete or error. Returns the final GeneratedUI doc.
|
|
431
|
+
* @param opts - generation params
|
|
432
|
+
* @param pollIntervalMs - polling interval (default 3000ms)
|
|
433
|
+
* @param timeoutMs - max wait time (default 120000ms)
|
|
434
|
+
*/
|
|
435
|
+
async generateUIAndWait(opts, pollIntervalMs = 3000, timeoutMs = 120000) {
|
|
436
|
+
const { id } = await this.generateUI(opts);
|
|
437
|
+
const deadline = Date.now() + timeoutMs;
|
|
438
|
+
while (Date.now() < deadline) {
|
|
439
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
440
|
+
const doc = await this.getGeneratedUI(id);
|
|
441
|
+
if (doc.status === 'complete' || doc.status === 'error')
|
|
442
|
+
return doc;
|
|
443
|
+
}
|
|
444
|
+
throw new Error(`UI generation timed out after ${timeoutMs / 1000}s (id: ${id})`);
|
|
445
|
+
},
|
|
346
446
|
// ─── External x402 Proxy ───
|
|
347
447
|
/**
|
|
348
448
|
* Discover the x402 price for any external URL without executing it.
|
package/package.json
CHANGED