@nordsym/apiclaw 1.5.0 → 1.5.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/convex/http.ts +104 -29
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +12 -2
- package/dist/proxy.js.map +1 -1
- package/landing/src/app/api/billing/checkout/route.ts +2 -2
- package/landing/src/app/page.tsx +1 -1
- package/landing/src/lib/stats.json +1 -1
- package/package.json +1 -1
- package/src/proxy.ts +14 -2
package/convex/http.ts
CHANGED
|
@@ -118,42 +118,38 @@ async function validateAndLogProxyCall(
|
|
|
118
118
|
provider: string,
|
|
119
119
|
action: string
|
|
120
120
|
): Promise<{ valid: boolean; workspaceId?: string; subagentId?: string; error?: string }> {
|
|
121
|
-
const
|
|
122
|
-
const subagentId = request.headers.get("X-APIClaw-Subagent") || "
|
|
123
|
-
|
|
124
|
-
if (!sessionToken) {
|
|
125
|
-
// Allow calls without session but don't log to workspace
|
|
126
|
-
return { valid: true, subagentId };
|
|
127
|
-
}
|
|
121
|
+
const identifier = request.headers.get("X-APIClaw-Identifier") || "unknown";
|
|
122
|
+
const subagentId = request.headers.get("X-APIClaw-Subagent") || "main";
|
|
128
123
|
|
|
129
124
|
try {
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (!session) {
|
|
134
|
-
// Allow call anyway but log warning
|
|
135
|
-
console.warn("[Proxy] Invalid session token, allowing call but not logging");
|
|
136
|
-
return { valid: true, subagentId };
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Log the API call
|
|
140
|
-
await ctx.runMutation(api.logs.createProxyLog, {
|
|
141
|
-
workspaceId: session.workspaceId,
|
|
125
|
+
// Always log to analytics (anonymous or authenticated)
|
|
126
|
+
await ctx.runMutation(api.analytics.log, {
|
|
127
|
+
event: "api_call",
|
|
142
128
|
provider,
|
|
143
|
-
|
|
144
|
-
subagentId,
|
|
145
|
-
sessionToken,
|
|
129
|
+
identifier,
|
|
130
|
+
metadata: { action, subagentId },
|
|
146
131
|
});
|
|
147
132
|
|
|
148
|
-
//
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
133
|
+
// If authenticated (workspace ID format), increment usage
|
|
134
|
+
if (identifier.startsWith("anon:")) {
|
|
135
|
+
// Anonymous user - track for rate limiting but don't increment workspace usage
|
|
136
|
+
return { valid: true, subagentId };
|
|
137
|
+
}
|
|
152
138
|
|
|
153
|
-
|
|
139
|
+
// Try to increment workspace usage
|
|
140
|
+
try {
|
|
141
|
+
await ctx.runMutation(api.workspaces.incrementUsage, {
|
|
142
|
+
workspaceId: identifier,
|
|
143
|
+
});
|
|
144
|
+
return { valid: true, workspaceId: identifier, subagentId };
|
|
145
|
+
} catch (e) {
|
|
146
|
+
// Workspace doesn't exist or error - allow call anyway
|
|
147
|
+
console.warn("[Proxy] Could not increment workspace usage:", e);
|
|
148
|
+
return { valid: true, subagentId };
|
|
149
|
+
}
|
|
154
150
|
} catch (e: any) {
|
|
155
|
-
console.error("[Proxy]
|
|
156
|
-
//
|
|
151
|
+
console.error("[Proxy] Logging error:", e);
|
|
152
|
+
// Always allow call even if logging fails
|
|
157
153
|
return { valid: true, subagentId };
|
|
158
154
|
}
|
|
159
155
|
}
|
|
@@ -701,6 +697,85 @@ http.route({
|
|
|
701
697
|
handler: httpAction(async () => new Response(null, { headers: corsHeaders })),
|
|
702
698
|
});
|
|
703
699
|
|
|
700
|
+
// GitHub API proxy
|
|
701
|
+
http.route({
|
|
702
|
+
path: "/proxy/github",
|
|
703
|
+
method: "POST",
|
|
704
|
+
handler: httpAction(async (ctx, request) => {
|
|
705
|
+
// Validate session and log usage
|
|
706
|
+
const body = await request.json();
|
|
707
|
+
const action = body.action || "search_repos";
|
|
708
|
+
await validateAndLogProxyCall(ctx, request, "github", action);
|
|
709
|
+
|
|
710
|
+
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
|
|
711
|
+
if (!GITHUB_TOKEN) {
|
|
712
|
+
return jsonResponse({ error: "GitHub not configured" }, 500);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
try {
|
|
716
|
+
const { action, ...params } = body;
|
|
717
|
+
let url: string;
|
|
718
|
+
let method = "GET";
|
|
719
|
+
let fetchBody: string | undefined;
|
|
720
|
+
|
|
721
|
+
// Route based on action
|
|
722
|
+
switch (action) {
|
|
723
|
+
case "search_repos":
|
|
724
|
+
const { query, sort = "stars", limit = 10 } = params;
|
|
725
|
+
url = `https://api.github.com/search/repositories?q=${encodeURIComponent(query)}&sort=${sort}&per_page=${limit}`;
|
|
726
|
+
break;
|
|
727
|
+
|
|
728
|
+
case "get_repo":
|
|
729
|
+
const { owner, repo } = params;
|
|
730
|
+
url = `https://api.github.com/repos/${owner}/${repo}`;
|
|
731
|
+
break;
|
|
732
|
+
|
|
733
|
+
case "list_issues":
|
|
734
|
+
const { owner: issueOwner, repo: issueRepo, state = "open", limit: issueLimit = 10 } = params;
|
|
735
|
+
url = `https://api.github.com/repos/${issueOwner}/${issueRepo}/issues?state=${state}&per_page=${issueLimit}`;
|
|
736
|
+
break;
|
|
737
|
+
|
|
738
|
+
case "create_issue":
|
|
739
|
+
const { owner: createOwner, repo: createRepo, title, body: issueBody = "" } = params;
|
|
740
|
+
url = `https://api.github.com/repos/${createOwner}/${createRepo}/issues`;
|
|
741
|
+
method = "POST";
|
|
742
|
+
fetchBody = JSON.stringify({ title, body: issueBody });
|
|
743
|
+
break;
|
|
744
|
+
|
|
745
|
+
case "get_file":
|
|
746
|
+
const { owner: fileOwner, repo: fileRepo, path } = params;
|
|
747
|
+
url = `https://api.github.com/repos/${fileOwner}/${fileRepo}/contents/${path}`;
|
|
748
|
+
break;
|
|
749
|
+
|
|
750
|
+
default:
|
|
751
|
+
return jsonResponse({ error: `Unknown action: ${action}` }, 400);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
const response = await fetch(url, {
|
|
755
|
+
method,
|
|
756
|
+
headers: {
|
|
757
|
+
"Authorization": `Bearer ${GITHUB_TOKEN}`,
|
|
758
|
+
"Accept": "application/vnd.github+json",
|
|
759
|
+
"User-Agent": "APIClaw",
|
|
760
|
+
...(fetchBody ? { "Content-Type": "application/json" } : {}),
|
|
761
|
+
},
|
|
762
|
+
...(fetchBody ? { body: fetchBody } : {}),
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
const data = await response.json();
|
|
766
|
+
return jsonResponse(data, response.status);
|
|
767
|
+
} catch (e: any) {
|
|
768
|
+
return jsonResponse({ error: e.message }, 500);
|
|
769
|
+
}
|
|
770
|
+
}),
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
http.route({
|
|
774
|
+
path: "/proxy/github",
|
|
775
|
+
method: "OPTIONS",
|
|
776
|
+
handler: httpAction(async () => new Response(null, { headers: corsHeaders })),
|
|
777
|
+
});
|
|
778
|
+
|
|
704
779
|
// ==============================================
|
|
705
780
|
// WORKSPACE / MAGIC LINK ENDPOINTS
|
|
706
781
|
// ==============================================
|
package/dist/proxy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAyB3E;AAED,eAAO,MAAM,eAAe,UAAkN,CAAC"}
|
package/dist/proxy.js
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* APIClaw Proxy - Fallback to hosted API when no local credentials
|
|
3
3
|
*/
|
|
4
|
+
import { readSession, getMachineFingerprint } from './session.js';
|
|
4
5
|
const PROXY_BASE = "https://adventurous-avocet-799.convex.site/proxy";
|
|
5
6
|
export async function callProxy(provider, params) {
|
|
6
7
|
const url = `${PROXY_BASE}/${provider}`;
|
|
8
|
+
// Get session and fingerprint for tracking
|
|
9
|
+
const session = readSession();
|
|
10
|
+
const fingerprint = getMachineFingerprint();
|
|
11
|
+
const identifier = session?.workspaceId || `anon:${fingerprint}`;
|
|
7
12
|
const response = await fetch(url, {
|
|
8
13
|
method: "POST",
|
|
9
|
-
headers: {
|
|
14
|
+
headers: {
|
|
15
|
+
"Content-Type": "application/json",
|
|
16
|
+
"X-APIClaw-Identifier": identifier,
|
|
17
|
+
"X-APIClaw-Provider": provider,
|
|
18
|
+
"X-APIClaw-Action": params.action || "call",
|
|
19
|
+
},
|
|
10
20
|
body: JSON.stringify(params),
|
|
11
21
|
});
|
|
12
22
|
if (!response.ok) {
|
|
@@ -15,5 +25,5 @@ export async function callProxy(provider, params) {
|
|
|
15
25
|
}
|
|
16
26
|
return response.json();
|
|
17
27
|
}
|
|
18
|
-
export const PROXY_PROVIDERS = ["openrouter", "brave_search", "resend", "elevenlabs", "46elks", "twilio", "replicate", "firecrawl", "e2b", "groq", "deepgram", "serper", "mistral", "cohere", "together", "stability", "assemblyai"];
|
|
28
|
+
export const PROXY_PROVIDERS = ["openrouter", "brave_search", "resend", "elevenlabs", "46elks", "twilio", "replicate", "firecrawl", "e2b", "groq", "deepgram", "serper", "mistral", "cohere", "together", "stability", "assemblyai", "github"];
|
|
19
29
|
//# sourceMappingURL=proxy.js.map
|
package/dist/proxy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,UAAU,GAAG,kDAAkD,CAAC;AAEtE,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,MAAW;IAC3D,MAAM,GAAG,GAAG,GAAG,UAAU,IAAI,QAAQ,EAAE,CAAC;IAExC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAElE,MAAM,UAAU,GAAG,kDAAkD,CAAC;AAEtE,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,MAAW;IAC3D,MAAM,GAAG,GAAG,GAAG,UAAU,IAAI,QAAQ,EAAE,CAAC;IAExC,2CAA2C;IAC3C,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,MAAM,WAAW,GAAG,qBAAqB,EAAE,CAAC;IAC5C,MAAM,UAAU,GAAG,OAAO,EAAE,WAAW,IAAI,QAAQ,WAAW,EAAE,CAAC;IAEjE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,sBAAsB,EAAE,UAAU;YAClC,oBAAoB,EAAE,QAAQ;YAC9B,kBAAkB,EAAE,MAAM,CAAC,MAAM,IAAI,MAAM;SAC5C;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;KAC7B,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAuB,CAAC;QAC/G,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,KAAK,IAAI,gBAAgB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC"}
|
|
@@ -26,8 +26,8 @@ export async function POST(req: NextRequest) {
|
|
|
26
26
|
method: "POST",
|
|
27
27
|
headers: { "Content-Type": "application/json" },
|
|
28
28
|
body: JSON.stringify({
|
|
29
|
-
path: "workspaces:
|
|
30
|
-
args: { token },
|
|
29
|
+
path: "workspaces:verifySession",
|
|
30
|
+
args: { sessionToken: token },
|
|
31
31
|
}),
|
|
32
32
|
});
|
|
33
33
|
|
package/landing/src/app/page.tsx
CHANGED
|
@@ -14,7 +14,7 @@ import { PhoneDemo } from "@/components/demo";
|
|
|
14
14
|
import { AITestimonials } from "@/components/AITestimonials";
|
|
15
15
|
|
|
16
16
|
const stats = [
|
|
17
|
-
{ number:
|
|
17
|
+
{ number: "4,232+", label: "Installs", live: true },
|
|
18
18
|
{ number: statsData.apiCount.toLocaleString(), label: "APIs Indexed", live: true },
|
|
19
19
|
{ number: statsData.openApiCount.toLocaleString(), label: "Open APIs", live: true },
|
|
20
20
|
{ number: statsData.directCallCount.toString(), label: "Direct Call", live: true },
|
package/package.json
CHANGED
package/src/proxy.ts
CHANGED
|
@@ -2,14 +2,26 @@
|
|
|
2
2
|
* APIClaw Proxy - Fallback to hosted API when no local credentials
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { readSession, getMachineFingerprint } from './session.js';
|
|
6
|
+
|
|
5
7
|
const PROXY_BASE = "https://adventurous-avocet-799.convex.site/proxy";
|
|
6
8
|
|
|
7
9
|
export async function callProxy(provider: string, params: any): Promise<any> {
|
|
8
10
|
const url = `${PROXY_BASE}/${provider}`;
|
|
9
11
|
|
|
12
|
+
// Get session and fingerprint for tracking
|
|
13
|
+
const session = readSession();
|
|
14
|
+
const fingerprint = getMachineFingerprint();
|
|
15
|
+
const identifier = session?.workspaceId || `anon:${fingerprint}`;
|
|
16
|
+
|
|
10
17
|
const response = await fetch(url, {
|
|
11
18
|
method: "POST",
|
|
12
|
-
headers: {
|
|
19
|
+
headers: {
|
|
20
|
+
"Content-Type": "application/json",
|
|
21
|
+
"X-APIClaw-Identifier": identifier,
|
|
22
|
+
"X-APIClaw-Provider": provider,
|
|
23
|
+
"X-APIClaw-Action": params.action || "call",
|
|
24
|
+
},
|
|
13
25
|
body: JSON.stringify(params),
|
|
14
26
|
});
|
|
15
27
|
|
|
@@ -21,4 +33,4 @@ export async function callProxy(provider: string, params: any): Promise<any> {
|
|
|
21
33
|
return response.json();
|
|
22
34
|
}
|
|
23
35
|
|
|
24
|
-
export const PROXY_PROVIDERS = ["openrouter", "brave_search", "resend", "elevenlabs", "46elks", "twilio", "replicate", "firecrawl", "e2b", "groq", "deepgram", "serper", "mistral", "cohere", "together", "stability", "assemblyai"];
|
|
36
|
+
export const PROXY_PROVIDERS = ["openrouter", "brave_search", "resend", "elevenlabs", "46elks", "twilio", "replicate", "firecrawl", "e2b", "groq", "deepgram", "serper", "mistral", "cohere", "together", "stability", "assemblyai", "github"];
|