@nordsym/apiclaw 1.8.1 → 1.8.2
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/LICENSE +21 -0
- package/apiclaw-README.md +106 -6
- package/dist/index.js +114 -111
- package/package.json +2 -1
- package/src/bin.ts +15 -0
- package/src/index.ts +5 -4
- package/src/postinstall.ts +18 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 NordSym AB
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/apiclaw-README.md
CHANGED
|
@@ -12,12 +12,18 @@ The API layer for AI agents. 18 providers → 1000s of capabilities. Workspace
|
|
|
12
12
|
[](https://www.npmjs.com/package/@nordsym/apiclaw)
|
|
13
13
|
[](LICENSE)
|
|
14
14
|
[](https://modelcontextprotocol.io)
|
|
15
|
+
[](https://github.com/nordsym/apiclaw)
|
|
16
|
+
[](https://modelcontextprotocol.io)
|
|
17
|
+
|
|
18
|
+
> **If APIClaw saves you time, [⭐ star the repo](https://github.com/nordsym/apiclaw) — it helps more developers find us.**
|
|
19
|
+
|
|
20
|
+

|
|
15
21
|
|
|
16
22
|
---
|
|
17
23
|
|
|
18
24
|
## The Platform
|
|
19
25
|
|
|
20
|
-
**[apiclaw.com](https://apiclaw.com)** — Your workspace for API-powered agents.
|
|
26
|
+
**[apiclaw.nordsym.com](https://apiclaw.nordsym.com)** — Your workspace for API-powered agents.
|
|
21
27
|
|
|
22
28
|
| Layer | What You Get |
|
|
23
29
|
|-------|--------------|
|
|
@@ -51,12 +57,52 @@ That's it. All 18 Direct Call providers work instantly through NordSym's infrast
|
|
|
51
57
|
**Usage Limits:**
|
|
52
58
|
- **Anonymous:** 10 calls/week (no registration)
|
|
53
59
|
- **Registered:** 50 calls/week (5x more)
|
|
54
|
-
- **Upgrade:**
|
|
60
|
+
- **Upgrade:** See [Pricing](#pricing) below
|
|
55
61
|
|
|
56
62
|
Start calling APIs immediately. No setup, no API keys, no configuration.
|
|
57
63
|
|
|
58
64
|
---
|
|
59
65
|
|
|
66
|
+
## End-to-End Example
|
|
67
|
+
|
|
68
|
+
Here's a complete agent workflow — send an SMS, generate an image, and search the web in one session:
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
// 1. Register for 50 calls/week
|
|
72
|
+
register_owner({ email: "you@example.com" })
|
|
73
|
+
|
|
74
|
+
// 2. Send an SMS via 46elks
|
|
75
|
+
call_api({
|
|
76
|
+
provider: "46elks",
|
|
77
|
+
action: "send_sms",
|
|
78
|
+
params: {
|
|
79
|
+
to: "+46701234567",
|
|
80
|
+
message: "APIClaw is live! 🦞"
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
// 3. Generate an image via Replicate
|
|
85
|
+
call_api({
|
|
86
|
+
provider: "replicate",
|
|
87
|
+
action: "run",
|
|
88
|
+
params: {
|
|
89
|
+
model: "stability-ai/sdxl",
|
|
90
|
+
input: { prompt: "a lobster wearing a top hat, digital art" }
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
// 4. Search the web via Brave
|
|
95
|
+
call_api({
|
|
96
|
+
provider: "brave",
|
|
97
|
+
action: "search",
|
|
98
|
+
params: { q: "MCP protocol AI agents 2025", count: 5 }
|
|
99
|
+
})
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
All three calls go through APIClaw's proxy — zero API keys, zero configuration.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
60
106
|
## What You Get
|
|
61
107
|
|
|
62
108
|
### Instant API Access
|
|
@@ -148,7 +194,7 @@ Public APIs, instantly callable. No API keys needed.
|
|
|
148
194
|
- Food & Recipes
|
|
149
195
|
- Science & Education
|
|
150
196
|
|
|
151
|
-
Browse at [apiclaw.com/open-apis](https://apiclaw.com/open-apis)
|
|
197
|
+
Browse at [apiclaw.nordsym.com/open-apis](https://apiclaw.nordsym.com/open-apis)
|
|
152
198
|
|
|
153
199
|
---
|
|
154
200
|
|
|
@@ -163,7 +209,7 @@ Use `discover_apis` to search:
|
|
|
163
209
|
"What APIs exist for recipe data?"
|
|
164
210
|
```
|
|
165
211
|
|
|
166
|
-
Browse at [apiclaw.com/discover](https://apiclaw.com/discover)
|
|
212
|
+
Browse at [apiclaw.nordsym.com/discover](https://apiclaw.nordsym.com/discover)
|
|
167
213
|
|
|
168
214
|
---
|
|
169
215
|
|
|
@@ -358,7 +404,7 @@ You don't manage API keys. You don't configure auth. You don't worry about rate
|
|
|
358
404
|
- Usage analytics in your workspace
|
|
359
405
|
- Production-ready from day one
|
|
360
406
|
|
|
361
|
-
**Want higher limits?**
|
|
407
|
+
**Want higher limits?** See [Pricing](#pricing) below or upgrade at [apiclaw.nordsym.com](https://apiclaw.nordsym.com).
|
|
362
408
|
|
|
363
409
|
---
|
|
364
410
|
|
|
@@ -379,12 +425,66 @@ Returns the exact request that *would* be sent, with mock response data.
|
|
|
379
425
|
|
|
380
426
|
---
|
|
381
427
|
|
|
428
|
+
## Why APIClaw?
|
|
429
|
+
|
|
430
|
+
| | **APIClaw** | **RapidAPI** | **Direct API Keys** | **Kong / custom gateway** |
|
|
431
|
+
|---|---|---|---|---|
|
|
432
|
+
| **Setup time** | `curl \| bash` (30 sec) | Account + per-API signup | Per-provider signup | Hours of config |
|
|
433
|
+
| **API keys to manage** | 0 | Per API | 1 per provider | 1 per provider |
|
|
434
|
+
| **Providers covered** | 18 premium + 1,636 open | 40,000+ (DIY) | 1 at a time | Any (DIY) |
|
|
435
|
+
| **MCP-native** | ✅ First-class | ❌ | ❌ | ❌ |
|
|
436
|
+
| **Works in AI agents** | ✅ Out of the box | ⚠️ Manual wiring | ⚠️ Manual wiring | ⚠️ Manual wiring |
|
|
437
|
+
| **Free tier** | ✅ 50 calls/week | ✅ Limited | Varies | ❌ |
|
|
438
|
+
| **Self-hosted option** | ✅ | ❌ | — | ✅ |
|
|
439
|
+
|
|
440
|
+
APIClaw is purpose-built for AI agents and MCP clients. No glue code, no key juggling — just call the API.
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## Social Proof
|
|
445
|
+
|
|
446
|
+
**9,000+ npm installs** · 88 versions shipped · Used in Claude Agents, GPT Builders, and Codex workflows worldwide.
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## Pricing
|
|
451
|
+
|
|
452
|
+
| Plan | Price | Calls/month | Best for |
|
|
453
|
+
|------|-------|-------------|----------|
|
|
454
|
+
| **Free** | $0 | 50 | Exploring, prototyping |
|
|
455
|
+
| **Pro** | $79/mo | 5,000 | Solo builders & small teams |
|
|
456
|
+
| **Scale** | $249/mo | 25,000 | Production agents |
|
|
457
|
+
| **Enterprise** | Custom | Unlimited | Large teams & custom SLAs |
|
|
458
|
+
|
|
459
|
+
→ [Upgrade at apiclaw.nordsym.com](https://apiclaw.nordsym.com) · Enterprise: [book a call](https://apiclaw.nordsym.com/contact)
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
## AI Discoverability
|
|
464
|
+
|
|
465
|
+
APIClaw is optimized for discovery by AI agents and LLM tooling:
|
|
466
|
+
|
|
467
|
+
- **llms.txt:** [apiclaw.nordsym.com/llms.txt](https://apiclaw.nordsym.com/llms.txt) — Machine-readable API index
|
|
468
|
+
- **llms-full.txt:** [apiclaw.nordsym.com/llms-full.txt](https://apiclaw.nordsym.com/llms-full.txt) — Full capability descriptions
|
|
469
|
+
- **ai-plugin.json:** [apiclaw.nordsym.com/.well-known/ai-plugin.json](https://apiclaw.nordsym.com/.well-known/ai-plugin.json) — OpenAI plugin manifest
|
|
470
|
+
- **MCP:** Install with one command and any MCP-compatible agent can use APIClaw immediately
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## Contributing & Changelog
|
|
475
|
+
|
|
476
|
+
- [CONTRIBUTING.md](apiclaw-CONTRIBUTING.md) — How to contribute
|
|
477
|
+
- [CHANGELOG.md](apiclaw-CHANGELOG.md) — Release history
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
382
481
|
## Links
|
|
383
482
|
|
|
384
|
-
- **Platform:** [apiclaw.com](https://apiclaw.com)
|
|
483
|
+
- **Platform:** [apiclaw.nordsym.com](https://apiclaw.nordsym.com)
|
|
385
484
|
- **Docs:** [apiclaw.nordsym.com/docs](https://apiclaw.nordsym.com/docs)
|
|
386
485
|
- **GitHub:** [github.com/nordsym/apiclaw](https://github.com/nordsym/apiclaw)
|
|
387
486
|
- **npm:** [@nordsym/apiclaw](https://www.npmjs.com/package/@nordsym/apiclaw)
|
|
487
|
+
- **Security:** [SECURITY.md](SECURITY.md)
|
|
388
488
|
|
|
389
489
|
---
|
|
390
490
|
|
package/dist/index.js
CHANGED
|
@@ -1,49 +1,48 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
var import_chainExecutor = require("./chainExecutor.js");
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import {
|
|
5
|
+
CallToolRequestSchema,
|
|
6
|
+
ListToolsRequestSchema
|
|
7
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
+
import { discoverAPIs, getAPIDetails, getCategories, getAllAPIs } from "./discovery.js";
|
|
9
|
+
import { trackStartup, trackSearch } from "./telemetry.js";
|
|
10
|
+
import {
|
|
11
|
+
addCredits,
|
|
12
|
+
purchaseAPIAccess,
|
|
13
|
+
getBalanceSummary
|
|
14
|
+
} from "./credits.js";
|
|
15
|
+
import { hasRealCredentials } from "./credentials.js";
|
|
16
|
+
import { getConnectedProviders } from "./execute.js";
|
|
17
|
+
import { executeMetered } from "./metered.js";
|
|
18
|
+
import { logAPICall } from "./mcp-analytics.js";
|
|
19
|
+
import { isOpenAPI, executeOpenAPI, listOpenAPIs } from "./open-apis.js";
|
|
20
|
+
import { PROXY_PROVIDERS } from "./proxy.js";
|
|
21
|
+
import {
|
|
22
|
+
requiresConfirmationAsync,
|
|
23
|
+
createPendingAction,
|
|
24
|
+
consumePendingAction,
|
|
25
|
+
generatePreview,
|
|
26
|
+
validateParams
|
|
27
|
+
} from "./confirmation.js";
|
|
28
|
+
import { executeCapability, listCapabilities, hasCapability } from "./capability-router.js";
|
|
29
|
+
import { readSession, writeSession, clearSession, getMachineFingerprint, detectMCPClient } from "./session.js";
|
|
30
|
+
import { ConvexHttpClient } from "convex/browser";
|
|
31
|
+
import {
|
|
32
|
+
getOrCreateCustomer,
|
|
33
|
+
createMeteredCheckoutSession,
|
|
34
|
+
getUsageSummary,
|
|
35
|
+
METERED_BILLING
|
|
36
|
+
} from "./stripe.js";
|
|
37
|
+
import { estimateCost } from "./metered.js";
|
|
38
|
+
import {
|
|
39
|
+
executeChain,
|
|
40
|
+
getChainStatus,
|
|
41
|
+
resumeChain
|
|
42
|
+
} from "./chainExecutor.js";
|
|
44
43
|
const DEFAULT_AGENT_ID = "agent_default";
|
|
45
44
|
const CONVEX_URL = process.env.CONVEX_URL || "https://adventurous-avocet-799.convex.cloud";
|
|
46
|
-
const convex = new
|
|
45
|
+
const convex = new ConvexHttpClient(CONVEX_URL);
|
|
47
46
|
let workspaceContext = null;
|
|
48
47
|
let currentAgentId = null;
|
|
49
48
|
const anonymousRateLimits = /* @__PURE__ */ new Map();
|
|
@@ -100,9 +99,11 @@ function checkAnonymousRateLimit(fingerprint) {
|
|
|
100
99
|
allowed: false,
|
|
101
100
|
error: JSON.stringify({
|
|
102
101
|
success: false,
|
|
103
|
-
error:
|
|
104
|
-
|
|
102
|
+
error: `\u26A1 You've hit your free tier limit (${ANONYMOUS_WEEKLY_LIMIT} calls/week).
|
|
103
|
+
Upgrade: https://apiclaw.nordsym.com/upgrade`,
|
|
104
|
+
hint: "Register for 50 calls/week, or upgrade for unlimited",
|
|
105
105
|
action: "Run: register_owner({ email: 'you@example.com' })",
|
|
106
|
+
upgrade_url: "https://apiclaw.nordsym.com/upgrade",
|
|
106
107
|
retry_after: getNextMonthUTC()
|
|
107
108
|
}, null, 2)
|
|
108
109
|
};
|
|
@@ -112,7 +113,7 @@ function checkAnonymousRateLimit(fingerprint) {
|
|
|
112
113
|
return { allowed: true };
|
|
113
114
|
}
|
|
114
115
|
async function validateSession() {
|
|
115
|
-
const session =
|
|
116
|
+
const session = readSession();
|
|
116
117
|
if (!session) {
|
|
117
118
|
console.error("[APIClaw] No session found. Use register_owner to authenticate.");
|
|
118
119
|
return false;
|
|
@@ -123,7 +124,7 @@ async function validateSession() {
|
|
|
123
124
|
});
|
|
124
125
|
if (!result.authenticated) {
|
|
125
126
|
console.error("[APIClaw] Session invalid or expired. Clearing...");
|
|
126
|
-
|
|
127
|
+
clearSession();
|
|
127
128
|
return false;
|
|
128
129
|
}
|
|
129
130
|
if (result.status !== "active") {
|
|
@@ -167,9 +168,9 @@ async function trackEarnProgress(workspaceId, provider, action) {
|
|
|
167
168
|
const rateLimitStore = /* @__PURE__ */ new Map();
|
|
168
169
|
const UNREGISTERED_CALL_LIMIT = 5;
|
|
169
170
|
function checkWorkspaceAccess(providerId) {
|
|
170
|
-
if (providerId &&
|
|
171
|
+
if (providerId && PROXY_PROVIDERS.includes(providerId)) {
|
|
171
172
|
if (!workspaceContext) {
|
|
172
|
-
const fingerprint =
|
|
173
|
+
const fingerprint = getMachineFingerprint();
|
|
173
174
|
const rateLimitCheck = checkAnonymousRateLimit(fingerprint);
|
|
174
175
|
if (!rateLimitCheck.allowed) {
|
|
175
176
|
return {
|
|
@@ -211,7 +212,8 @@ function checkWorkspaceAccess(providerId) {
|
|
|
211
212
|
allowed: false,
|
|
212
213
|
error: JSON.stringify({
|
|
213
214
|
success: false,
|
|
214
|
-
error:
|
|
215
|
+
error: `\u26A1 You've hit your free tier limit (${FREE_MONTHLY_LIMIT} calls/week).
|
|
216
|
+
Upgrade: https://apiclaw.nordsym.com/upgrade`,
|
|
215
217
|
hint: "Upgrade to Backer for unlimited calls",
|
|
216
218
|
upgrade_url: "https://apiclaw.nordsym.com/upgrade",
|
|
217
219
|
retry_after: getNextMonthUTC()
|
|
@@ -220,7 +222,8 @@ function checkWorkspaceAccess(providerId) {
|
|
|
220
222
|
}
|
|
221
223
|
return {
|
|
222
224
|
allowed: false,
|
|
223
|
-
error:
|
|
225
|
+
error: `\u26A1 You've hit your free tier limit (${FREE_MONTHLY_LIMIT} calls/week).
|
|
226
|
+
Upgrade: https://apiclaw.nordsym.com/upgrade`
|
|
224
227
|
};
|
|
225
228
|
}
|
|
226
229
|
return { allowed: true, isAnonymous: false };
|
|
@@ -664,7 +667,7 @@ Example chain:
|
|
|
664
667
|
}
|
|
665
668
|
}
|
|
666
669
|
];
|
|
667
|
-
const server = new
|
|
670
|
+
const server = new Server(
|
|
668
671
|
{
|
|
669
672
|
name: "apivault",
|
|
670
673
|
version: "0.1.0"
|
|
@@ -675,10 +678,10 @@ const server = new import_server.Server(
|
|
|
675
678
|
}
|
|
676
679
|
}
|
|
677
680
|
);
|
|
678
|
-
server.setRequestHandler(
|
|
681
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
679
682
|
return { tools };
|
|
680
683
|
});
|
|
681
|
-
server.setRequestHandler(
|
|
684
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
682
685
|
const { name, arguments: args } = request.params;
|
|
683
686
|
try {
|
|
684
687
|
switch (name) {
|
|
@@ -729,10 +732,10 @@ Docs: https://apiclaw.nordsym.com
|
|
|
729
732
|
const subagentId = args?.subagent_id;
|
|
730
733
|
const aiBackend = args?.ai_backend;
|
|
731
734
|
const startTime = Date.now();
|
|
732
|
-
const results =
|
|
735
|
+
const results = discoverAPIs(query, { category, maxResults, region });
|
|
733
736
|
const responseTimeMs = Date.now() - startTime;
|
|
734
|
-
|
|
735
|
-
const analyticsUserId = workspaceContext?.workspaceId || `anon:${
|
|
737
|
+
trackSearch(query, results.length, responseTimeMs);
|
|
738
|
+
const analyticsUserId = workspaceContext?.workspaceId || `anon:${getMachineFingerprint()}`;
|
|
736
739
|
const convexUrl = CONVEX_URL;
|
|
737
740
|
if (convexUrl) {
|
|
738
741
|
fetch(`${convexUrl}/api/mutation`, {
|
|
@@ -822,7 +825,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
822
825
|
text: JSON.stringify({
|
|
823
826
|
status: "no_results",
|
|
824
827
|
message: `No APIs found matching "${query}". Try broader terms or check available categories with list_categories.`,
|
|
825
|
-
available_categories:
|
|
828
|
+
available_categories: getCategories()
|
|
826
829
|
}, null, 2)
|
|
827
830
|
}
|
|
828
831
|
]
|
|
@@ -856,7 +859,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
856
859
|
case "get_api_details": {
|
|
857
860
|
const apiId = args?.api_id;
|
|
858
861
|
const compact = args?.compact || false;
|
|
859
|
-
const api =
|
|
862
|
+
const api = getAPIDetails(apiId, { compact });
|
|
860
863
|
if (!api) {
|
|
861
864
|
return {
|
|
862
865
|
content: [
|
|
@@ -897,7 +900,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
897
900
|
const apiId = args?.api_id;
|
|
898
901
|
const amountUsd = args?.amount_usd;
|
|
899
902
|
const agentId = args?.agent_id || DEFAULT_AGENT_ID;
|
|
900
|
-
const result =
|
|
903
|
+
const result = purchaseAPIAccess(agentId, apiId, amountUsd);
|
|
901
904
|
if (!result.success) {
|
|
902
905
|
return {
|
|
903
906
|
content: [
|
|
@@ -911,7 +914,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
911
914
|
]
|
|
912
915
|
};
|
|
913
916
|
}
|
|
914
|
-
const api =
|
|
917
|
+
const api = getAPIDetails(apiId);
|
|
915
918
|
return {
|
|
916
919
|
content: [
|
|
917
920
|
{
|
|
@@ -925,7 +928,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
925
928
|
amount_paid_usd: amountUsd,
|
|
926
929
|
credits_received: result.purchase.credits_purchased,
|
|
927
930
|
status: result.purchase.status,
|
|
928
|
-
real_credentials:
|
|
931
|
+
real_credentials: hasRealCredentials(apiId)
|
|
929
932
|
},
|
|
930
933
|
credentials: result.purchase.credentials,
|
|
931
934
|
access: {
|
|
@@ -940,7 +943,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
940
943
|
}
|
|
941
944
|
case "check_balance": {
|
|
942
945
|
const agentId = args?.agent_id || DEFAULT_AGENT_ID;
|
|
943
|
-
const summary =
|
|
946
|
+
const summary = getBalanceSummary(agentId);
|
|
944
947
|
return {
|
|
945
948
|
content: [
|
|
946
949
|
{
|
|
@@ -957,7 +960,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
957
960
|
provider: p.provider_id,
|
|
958
961
|
credits_remaining: p.credits_purchased,
|
|
959
962
|
status: p.status,
|
|
960
|
-
real_credentials:
|
|
963
|
+
real_credentials: hasRealCredentials(p.provider_id)
|
|
961
964
|
}))
|
|
962
965
|
}, null, 2)
|
|
963
966
|
}
|
|
@@ -967,7 +970,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
967
970
|
case "add_credits": {
|
|
968
971
|
const amountUsd = args?.amount_usd;
|
|
969
972
|
const agentId = args?.agent_id || DEFAULT_AGENT_ID;
|
|
970
|
-
const credits =
|
|
973
|
+
const credits = addCredits(agentId, amountUsd);
|
|
971
974
|
return {
|
|
972
975
|
content: [
|
|
973
976
|
{
|
|
@@ -982,10 +985,10 @@ Docs: https://apiclaw.nordsym.com
|
|
|
982
985
|
};
|
|
983
986
|
}
|
|
984
987
|
case "list_categories": {
|
|
985
|
-
const categories =
|
|
988
|
+
const categories = getCategories();
|
|
986
989
|
const apisByCategory = {};
|
|
987
990
|
for (const cat of categories) {
|
|
988
|
-
apisByCategory[cat] =
|
|
991
|
+
apisByCategory[cat] = getAllAPIs().filter((a) => a.category === cat).map((a) => a.id);
|
|
989
992
|
}
|
|
990
993
|
return {
|
|
991
994
|
content: [
|
|
@@ -1064,7 +1067,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1064
1067
|
const chainOptions = {
|
|
1065
1068
|
verbose: false
|
|
1066
1069
|
};
|
|
1067
|
-
const chainResult = await
|
|
1070
|
+
const chainResult = await executeChain(
|
|
1068
1071
|
chainDefinition,
|
|
1069
1072
|
chainCredentials,
|
|
1070
1073
|
{},
|
|
@@ -1142,7 +1145,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1142
1145
|
}]
|
|
1143
1146
|
};
|
|
1144
1147
|
}
|
|
1145
|
-
const isFreeAPI =
|
|
1148
|
+
const isFreeAPI = isOpenAPI(provider);
|
|
1146
1149
|
if (!isFreeAPI) {
|
|
1147
1150
|
const access = checkWorkspaceAccess(provider);
|
|
1148
1151
|
if (!access.allowed) {
|
|
@@ -1163,7 +1166,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1163
1166
|
let result;
|
|
1164
1167
|
let apiType;
|
|
1165
1168
|
if (confirmToken) {
|
|
1166
|
-
const pending =
|
|
1169
|
+
const pending = consumePendingAction(confirmToken);
|
|
1167
1170
|
if (!pending) {
|
|
1168
1171
|
return {
|
|
1169
1172
|
content: [{
|
|
@@ -1179,13 +1182,13 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1179
1182
|
apiType = "direct";
|
|
1180
1183
|
const customerKey = args?.customer_key || getCustomerKey(pending.provider);
|
|
1181
1184
|
const stripeCustomerId = args?.stripe_customer_id || process.env.APICLAW_STRIPE_CUSTOMER_ID;
|
|
1182
|
-
result = await
|
|
1185
|
+
result = await executeMetered(pending.provider, pending.action, pending.params, {
|
|
1183
1186
|
customerId: stripeCustomerId,
|
|
1184
1187
|
customerKey,
|
|
1185
1188
|
userId: DEFAULT_AGENT_ID
|
|
1186
1189
|
});
|
|
1187
|
-
const analyticsUserId2 = workspaceContext ? workspaceContext.workspaceId : `anon:${
|
|
1188
|
-
|
|
1190
|
+
const analyticsUserId2 = workspaceContext ? workspaceContext.workspaceId : `anon:${getMachineFingerprint()}`;
|
|
1191
|
+
logAPICall({
|
|
1189
1192
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1190
1193
|
provider: pending.provider,
|
|
1191
1194
|
action: pending.action,
|
|
@@ -1212,10 +1215,10 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1212
1215
|
isError: !result.success
|
|
1213
1216
|
};
|
|
1214
1217
|
}
|
|
1215
|
-
const confirmCheck = await
|
|
1218
|
+
const confirmCheck = await requiresConfirmationAsync(provider, action);
|
|
1216
1219
|
if (confirmCheck.required) {
|
|
1217
1220
|
if (!confirmCheck.isDynamic) {
|
|
1218
|
-
const validation =
|
|
1221
|
+
const validation = validateParams(provider, action, params);
|
|
1219
1222
|
if (!validation.valid) {
|
|
1220
1223
|
return {
|
|
1221
1224
|
content: [{
|
|
@@ -1231,11 +1234,11 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1231
1234
|
};
|
|
1232
1235
|
}
|
|
1233
1236
|
}
|
|
1234
|
-
const preview =
|
|
1237
|
+
const preview = generatePreview(provider, action, params);
|
|
1235
1238
|
if (confirmCheck.estimatedCost) {
|
|
1236
1239
|
preview.estimated_cost = confirmCheck.estimatedCost;
|
|
1237
1240
|
}
|
|
1238
|
-
const pending =
|
|
1241
|
+
const pending = createPendingAction(provider, action, params, preview, DEFAULT_AGENT_ID);
|
|
1239
1242
|
return {
|
|
1240
1243
|
content: [{
|
|
1241
1244
|
type: "text",
|
|
@@ -1250,21 +1253,21 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1250
1253
|
}]
|
|
1251
1254
|
};
|
|
1252
1255
|
}
|
|
1253
|
-
if (
|
|
1256
|
+
if (isOpenAPI(provider)) {
|
|
1254
1257
|
apiType = "open";
|
|
1255
|
-
result = await
|
|
1258
|
+
result = await executeOpenAPI(provider, action, params);
|
|
1256
1259
|
} else {
|
|
1257
1260
|
apiType = "direct";
|
|
1258
1261
|
const customerKey = args?.customer_key || getCustomerKey(provider);
|
|
1259
1262
|
const stripeCustomerId = args?.stripe_customer_id || process.env.APICLAW_STRIPE_CUSTOMER_ID;
|
|
1260
|
-
result = await
|
|
1263
|
+
result = await executeMetered(provider, action, params, {
|
|
1261
1264
|
customerId: stripeCustomerId,
|
|
1262
1265
|
customerKey,
|
|
1263
1266
|
userId: DEFAULT_AGENT_ID
|
|
1264
1267
|
});
|
|
1265
1268
|
}
|
|
1266
|
-
const analyticsUserId = workspaceContext ? workspaceContext.workspaceId : `anon:${
|
|
1267
|
-
|
|
1269
|
+
const analyticsUserId = workspaceContext ? workspaceContext.workspaceId : `anon:${getMachineFingerprint()}`;
|
|
1270
|
+
logAPICall({
|
|
1268
1271
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1269
1272
|
provider,
|
|
1270
1273
|
action,
|
|
@@ -1338,8 +1341,8 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1338
1341
|
};
|
|
1339
1342
|
}
|
|
1340
1343
|
case "list_connected": {
|
|
1341
|
-
const directProviders =
|
|
1342
|
-
const openProviders =
|
|
1344
|
+
const directProviders = getConnectedProviders();
|
|
1345
|
+
const openProviders = listOpenAPIs();
|
|
1343
1346
|
return {
|
|
1344
1347
|
content: [
|
|
1345
1348
|
{
|
|
@@ -1383,9 +1386,9 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1383
1386
|
}).catch(() => {
|
|
1384
1387
|
});
|
|
1385
1388
|
}
|
|
1386
|
-
const exists = await
|
|
1389
|
+
const exists = await hasCapability(capabilityId);
|
|
1387
1390
|
if (!exists) {
|
|
1388
|
-
const available = await
|
|
1391
|
+
const available = await listCapabilities();
|
|
1389
1392
|
return {
|
|
1390
1393
|
content: [{
|
|
1391
1394
|
type: "text",
|
|
@@ -1399,7 +1402,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1399
1402
|
isError: true
|
|
1400
1403
|
};
|
|
1401
1404
|
}
|
|
1402
|
-
const result = await
|
|
1405
|
+
const result = await executeCapability(
|
|
1403
1406
|
capabilityId,
|
|
1404
1407
|
action,
|
|
1405
1408
|
params,
|
|
@@ -1425,7 +1428,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1425
1428
|
};
|
|
1426
1429
|
}
|
|
1427
1430
|
case "list_capabilities": {
|
|
1428
|
-
const capabilities = await
|
|
1431
|
+
const capabilities = await listCapabilities();
|
|
1429
1432
|
return {
|
|
1430
1433
|
content: [{
|
|
1431
1434
|
type: "text",
|
|
@@ -1458,13 +1461,13 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1458
1461
|
try {
|
|
1459
1462
|
const existing = await convex.query("workspaces:getByEmail", { email });
|
|
1460
1463
|
if (existing && existing.status === "active") {
|
|
1461
|
-
const fingerprint2 =
|
|
1464
|
+
const fingerprint2 = getMachineFingerprint();
|
|
1462
1465
|
const sessionResult = await convex.mutation("workspaces:createAgentSession", {
|
|
1463
1466
|
workspaceId: existing.id,
|
|
1464
1467
|
fingerprint: fingerprint2
|
|
1465
1468
|
});
|
|
1466
1469
|
if (sessionResult.success) {
|
|
1467
|
-
|
|
1470
|
+
writeSession(sessionResult.sessionToken, existing.id, email);
|
|
1468
1471
|
try {
|
|
1469
1472
|
const claimResult = await convex.mutation("workspaces:claimAnonymousUsage", {
|
|
1470
1473
|
workspaceId: existing.id,
|
|
@@ -1511,7 +1514,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1511
1514
|
} else {
|
|
1512
1515
|
throw new Error(createResult.error);
|
|
1513
1516
|
}
|
|
1514
|
-
const fingerprint =
|
|
1517
|
+
const fingerprint = getMachineFingerprint();
|
|
1515
1518
|
const magicLinkResult = await convex.mutation("workspaces:createMagicLink", {
|
|
1516
1519
|
email,
|
|
1517
1520
|
fingerprint
|
|
@@ -1560,7 +1563,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1560
1563
|
}
|
|
1561
1564
|
}
|
|
1562
1565
|
case "check_workspace_status": {
|
|
1563
|
-
const session =
|
|
1566
|
+
const session = readSession();
|
|
1564
1567
|
if (!session) {
|
|
1565
1568
|
return {
|
|
1566
1569
|
content: [{
|
|
@@ -1577,7 +1580,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1577
1580
|
sessionToken: session.sessionToken
|
|
1578
1581
|
});
|
|
1579
1582
|
if (!result.authenticated) {
|
|
1580
|
-
|
|
1583
|
+
clearSession();
|
|
1581
1584
|
workspaceContext = null;
|
|
1582
1585
|
return {
|
|
1583
1586
|
content: [{
|
|
@@ -1632,7 +1635,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1632
1635
|
}
|
|
1633
1636
|
}
|
|
1634
1637
|
case "remind_owner": {
|
|
1635
|
-
const session =
|
|
1638
|
+
const session = readSession();
|
|
1636
1639
|
if (!session) {
|
|
1637
1640
|
return {
|
|
1638
1641
|
content: [{
|
|
@@ -1661,7 +1664,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1661
1664
|
}]
|
|
1662
1665
|
};
|
|
1663
1666
|
}
|
|
1664
|
-
const fingerprint =
|
|
1667
|
+
const fingerprint = getMachineFingerprint();
|
|
1665
1668
|
const magicLinkResult = await convex.mutation("workspaces:createMagicLink", {
|
|
1666
1669
|
email: session.email,
|
|
1667
1670
|
fingerprint
|
|
@@ -1705,7 +1708,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1705
1708
|
isError: true
|
|
1706
1709
|
};
|
|
1707
1710
|
}
|
|
1708
|
-
const customerResult = await
|
|
1711
|
+
const customerResult = await getOrCreateCustomer(email, email);
|
|
1709
1712
|
if ("error" in customerResult) {
|
|
1710
1713
|
return {
|
|
1711
1714
|
content: [{
|
|
@@ -1715,7 +1718,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1715
1718
|
isError: true
|
|
1716
1719
|
};
|
|
1717
1720
|
}
|
|
1718
|
-
const checkoutResult = await
|
|
1721
|
+
const checkoutResult = await createMeteredCheckoutSession(
|
|
1719
1722
|
email,
|
|
1720
1723
|
success_url || "https://apiclaw.nordsym.com/billing/success",
|
|
1721
1724
|
cancel_url || "https://apiclaw.nordsym.com/billing/cancel"
|
|
@@ -1758,7 +1761,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1758
1761
|
isError: true
|
|
1759
1762
|
};
|
|
1760
1763
|
}
|
|
1761
|
-
const usage = await
|
|
1764
|
+
const usage = await getUsageSummary(subscription_id);
|
|
1762
1765
|
if ("error" in usage) {
|
|
1763
1766
|
return {
|
|
1764
1767
|
content: [{
|
|
@@ -1779,7 +1782,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1779
1782
|
},
|
|
1780
1783
|
usage: {
|
|
1781
1784
|
total_calls: usage.totalCalls,
|
|
1782
|
-
price_per_call:
|
|
1785
|
+
price_per_call: METERED_BILLING.pricePerCall,
|
|
1783
1786
|
estimated_cost: `$${usage.totalCost.toFixed(4)}`
|
|
1784
1787
|
}
|
|
1785
1788
|
}, null, 2)
|
|
@@ -1797,7 +1800,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1797
1800
|
isError: true
|
|
1798
1801
|
};
|
|
1799
1802
|
}
|
|
1800
|
-
const estimate =
|
|
1803
|
+
const estimate = estimateCost(call_count);
|
|
1801
1804
|
return {
|
|
1802
1805
|
content: [{
|
|
1803
1806
|
type: "text",
|
|
@@ -1810,9 +1813,9 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1810
1813
|
currency: estimate.currency
|
|
1811
1814
|
},
|
|
1812
1815
|
examples: {
|
|
1813
|
-
"100 calls": `$${(100 *
|
|
1814
|
-
"1,000 calls": `$${(1e3 *
|
|
1815
|
-
"10,000 calls": `$${(1e4 *
|
|
1816
|
+
"100 calls": `$${(100 * METERED_BILLING.pricePerCall).toFixed(2)}`,
|
|
1817
|
+
"1,000 calls": `$${(1e3 * METERED_BILLING.pricePerCall).toFixed(2)}`,
|
|
1818
|
+
"10,000 calls": `$${(1e4 * METERED_BILLING.pricePerCall).toFixed(2)}`
|
|
1816
1819
|
}
|
|
1817
1820
|
}, null, 2)
|
|
1818
1821
|
}]
|
|
@@ -1835,7 +1838,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1835
1838
|
isError: true
|
|
1836
1839
|
};
|
|
1837
1840
|
}
|
|
1838
|
-
const chainStatus = await
|
|
1841
|
+
const chainStatus = await getChainStatus(chainId);
|
|
1839
1842
|
if (chainStatus.status === "not_found") {
|
|
1840
1843
|
return {
|
|
1841
1844
|
content: [{
|
|
@@ -1929,7 +1932,7 @@ Docs: https://apiclaw.nordsym.com
|
|
|
1929
1932
|
if (customerKey) {
|
|
1930
1933
|
chainCredentials.customerKeys = { default: customerKey };
|
|
1931
1934
|
}
|
|
1932
|
-
const result = await
|
|
1935
|
+
const result = await resumeChain(
|
|
1933
1936
|
resumeToken,
|
|
1934
1937
|
chainDefinition,
|
|
1935
1938
|
chainCredentials,
|
|
@@ -2012,14 +2015,14 @@ async function main() {
|
|
|
2012
2015
|
await startCLI();
|
|
2013
2016
|
return;
|
|
2014
2017
|
}
|
|
2015
|
-
const transport = new
|
|
2018
|
+
const transport = new StdioServerTransport();
|
|
2016
2019
|
await server.connect(transport);
|
|
2017
|
-
|
|
2020
|
+
trackStartup();
|
|
2018
2021
|
const hasValidSession = await validateSession();
|
|
2019
2022
|
try {
|
|
2020
|
-
const fingerprint =
|
|
2021
|
-
const mcpClient =
|
|
2022
|
-
const existingSession =
|
|
2023
|
+
const fingerprint = getMachineFingerprint();
|
|
2024
|
+
const mcpClient = detectMCPClient();
|
|
2025
|
+
const existingSession = readSession();
|
|
2023
2026
|
const result = await convex.mutation("agents:ensureAgent", {
|
|
2024
2027
|
fingerprint,
|
|
2025
2028
|
mcpClient,
|
|
@@ -2030,7 +2033,7 @@ async function main() {
|
|
|
2030
2033
|
currentAgentId = result.agentId;
|
|
2031
2034
|
}
|
|
2032
2035
|
if (result?.isNew && result?.sessionToken && !hasValidSession) {
|
|
2033
|
-
|
|
2036
|
+
writeSession(result.sessionToken, result.workspaceId, "");
|
|
2034
2037
|
}
|
|
2035
2038
|
} catch (e) {
|
|
2036
2039
|
console.error("[APIClaw] Agent registration failed (non-blocking):", e);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nordsym/apiclaw",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.2",
|
|
4
4
|
"description": "The API layer for AI agents. Dashboard + 22K APIs + 18 Direct Call providers. MCP native.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
16
|
"build": "tsc && cp -r src/registry dist/",
|
|
17
|
+
"postinstall": "node dist/postinstall.js || true",
|
|
17
18
|
"dev": "tsx watch src/index.ts",
|
|
18
19
|
"start": "node dist/index.js",
|
|
19
20
|
"start:http": "tsx src/http-server-minimal.ts",
|
package/src/bin.ts
CHANGED
|
@@ -6,11 +6,26 @@
|
|
|
6
6
|
* - setup/doctor/restore/uninstall → Run CLI
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { existsSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
|
|
9
12
|
const cliCommands = ['setup', 'mcp-install', 'mcp-uninstall', 'doctor', 'restore', 'uninstall', 'help', '--help', '-h', '--version', '-V'];
|
|
10
13
|
|
|
11
14
|
const firstArg = process.argv[2];
|
|
12
15
|
|
|
13
16
|
if (!firstArg || !cliCommands.includes(firstArg)) {
|
|
17
|
+
// First-run nudge: non-blocking hint if no workspace is configured
|
|
18
|
+
try {
|
|
19
|
+
const sessionFile = join(process.env.HOME ?? '~', '.apiclaw', 'session');
|
|
20
|
+
if (!existsSync(sessionFile)) {
|
|
21
|
+
process.stderr.write(
|
|
22
|
+
'\x1b[33m💡 No workspace linked. Get one free: https://apiclaw.nordsym.com/workspace\x1b[0m\n'
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
// Never let this block server startup
|
|
27
|
+
}
|
|
28
|
+
|
|
14
29
|
// Run MCP server
|
|
15
30
|
import('./index.js');
|
|
16
31
|
} else {
|
package/src/index.ts
CHANGED
|
@@ -170,9 +170,10 @@ function checkAnonymousRateLimit(fingerprint: string): { allowed: boolean; error
|
|
|
170
170
|
allowed: false,
|
|
171
171
|
error: JSON.stringify({
|
|
172
172
|
success: false,
|
|
173
|
-
error:
|
|
174
|
-
hint: "Register
|
|
173
|
+
error: `⚡ You've hit your free tier limit (${ANONYMOUS_WEEKLY_LIMIT} calls/week).\n Upgrade: https://apiclaw.nordsym.com/upgrade`,
|
|
174
|
+
hint: "Register for 50 calls/week, or upgrade for unlimited",
|
|
175
175
|
action: "Run: register_owner({ email: 'you@example.com' })",
|
|
176
|
+
upgrade_url: "https://apiclaw.nordsym.com/upgrade",
|
|
176
177
|
retry_after: getNextMonthUTC()
|
|
177
178
|
}, null, 2)
|
|
178
179
|
};
|
|
@@ -335,7 +336,7 @@ function checkWorkspaceAccess(providerId?: string): { allowed: boolean; error?:
|
|
|
335
336
|
allowed: false,
|
|
336
337
|
error: JSON.stringify({
|
|
337
338
|
success: false,
|
|
338
|
-
error:
|
|
339
|
+
error: `⚡ You've hit your free tier limit (${FREE_MONTHLY_LIMIT} calls/week).\n Upgrade: https://apiclaw.nordsym.com/upgrade`,
|
|
339
340
|
hint: "Upgrade to Backer for unlimited calls",
|
|
340
341
|
upgrade_url: "https://apiclaw.nordsym.com/upgrade",
|
|
341
342
|
retry_after: getNextMonthUTC()
|
|
@@ -346,7 +347,7 @@ function checkWorkspaceAccess(providerId?: string): { allowed: boolean; error?:
|
|
|
346
347
|
// Other tiers (shouldn't happen, but handle gracefully)
|
|
347
348
|
return {
|
|
348
349
|
allowed: false,
|
|
349
|
-
error:
|
|
350
|
+
error: `⚡ You've hit your free tier limit (${FREE_MONTHLY_LIMIT} calls/week).\n Upgrade: https://apiclaw.nordsym.com/upgrade`
|
|
350
351
|
};
|
|
351
352
|
}
|
|
352
353
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* APIClaw Postinstall Hook
|
|
4
|
+
* Prints a welcome message with links after install.
|
|
5
|
+
* No network calls. No side effects.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const CYAN = '\x1b[36m';
|
|
9
|
+
const RESET = '\x1b[0m';
|
|
10
|
+
const DIM = '\x1b[2m';
|
|
11
|
+
|
|
12
|
+
console.log('');
|
|
13
|
+
console.log(` 🦞 APIClaw installed successfully!`);
|
|
14
|
+
console.log('');
|
|
15
|
+
console.log(` → Create your free workspace: ${CYAN}https://apiclaw.nordsym.com/workspace${RESET}`);
|
|
16
|
+
console.log(` → Quick setup: ${CYAN}npx @nordsym/apiclaw setup${RESET}`);
|
|
17
|
+
console.log(` ⭐ Star us: ${CYAN}https://github.com/nordsym/apiclaw${RESET} ${DIM}(helps more devs find us)${RESET}`);
|
|
18
|
+
console.log('');
|