@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 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 sessionToken = request.headers.get("X-APIClaw-Session");
122
- const subagentId = request.headers.get("X-APIClaw-Subagent") || "unknown";
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
- // Validate session
131
- const session = await ctx.runQuery(api.workspaces.getSession, { token: sessionToken });
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
- action,
144
- subagentId,
145
- sessionToken,
129
+ identifier,
130
+ metadata: { action, subagentId },
146
131
  });
147
132
 
148
- // Increment usage
149
- await ctx.runMutation(api.workspaces.incrementUsage, {
150
- workspaceId: session.workspaceId,
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
- return { valid: true, workspaceId: session.workspaceId, subagentId };
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] Session validation error:", e);
156
- // Allow call but don't log on error
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
  // ==============================================
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAe3E;AAED,eAAO,MAAM,eAAe,UAAwM,CAAC"}
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: { "Content-Type": "application/json" },
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,cAAc,EAAE,kBAAkB,EAAE;QAC/C,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,CAAC,CAAC"}
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:getSessionWorkspace",
30
- args: { token },
29
+ path: "workspaces:verifySession",
30
+ args: { sessionToken: token },
31
31
  }),
32
32
  });
33
33
 
@@ -14,7 +14,7 @@ import { PhoneDemo } from "@/components/demo";
14
14
  import { AITestimonials } from "@/components/AITestimonials";
15
15
 
16
16
  const stats = [
17
- { number: ((statsData as any).npmDownloads || 3000).toLocaleString() + "+", label: "Installs", live: true },
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 },
@@ -3,7 +3,7 @@
3
3
  "openApiCount": 1636,
4
4
  "directCallCount": 18,
5
5
  "categoryCount": 13,
6
- "npmDownloads": 3396,
6
+ "npmDownloads": 4232,
7
7
  "lastUpdated": "2026-02-27T09:10:41.344767",
8
8
  "generatedAt": "2026-03-05T09:30:00.000Z",
9
9
  "categoryBreakdown": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nordsym/apiclaw",
3
- "version": "1.5.0",
3
+ "version": "1.5.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",
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: { "Content-Type": "application/json" },
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"];