@nordsym/apiclaw 1.2.2 → 1.2.3

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.
Files changed (77) hide show
  1. package/AGENTS.md +50 -33
  2. package/README.md +22 -12
  3. package/SOUL.md +60 -19
  4. package/STATUS.md +91 -169
  5. package/convex/_generated/api.d.ts +6 -0
  6. package/convex/directCall.ts +598 -0
  7. package/convex/providers.ts +341 -26
  8. package/convex/schema.ts +87 -0
  9. package/convex/usage.ts +260 -0
  10. package/convex/waitlist.ts +55 -0
  11. package/data/combined-02-26.json +22102 -0
  12. package/data/night-expansion-02-26-06-batch2.json +1898 -0
  13. package/data/night-expansion-02-26-06-batch3.json +1410 -0
  14. package/data/night-expansion-02-26-06.json +3146 -0
  15. package/data/night-expansion-02-26-full.json +9726 -0
  16. package/data/night-expansion-02-26-v2.json +330 -0
  17. package/data/night-expansion-02-26.json +171 -0
  18. package/dist/crypto.d.ts +7 -0
  19. package/dist/crypto.d.ts.map +1 -0
  20. package/dist/crypto.js +67 -0
  21. package/dist/crypto.js.map +1 -0
  22. package/dist/execute-dynamic.d.ts +116 -0
  23. package/dist/execute-dynamic.d.ts.map +1 -0
  24. package/dist/execute-dynamic.js +456 -0
  25. package/dist/execute-dynamic.js.map +1 -0
  26. package/dist/execute.d.ts +2 -1
  27. package/dist/execute.d.ts.map +1 -1
  28. package/dist/execute.js +35 -5
  29. package/dist/execute.js.map +1 -1
  30. package/dist/index.js +33 -4
  31. package/dist/index.js.map +1 -1
  32. package/dist/registry/apis.json +2081 -3
  33. package/docs/PRD-customer-key-passthrough.md +184 -0
  34. package/landing/public/badges/available-on-apiclaw.svg +14 -0
  35. package/landing/scripts/generate-stats.js +75 -4
  36. package/landing/src/app/admin/page.tsx +1 -1
  37. package/landing/src/app/api/auth/magic-link/route.ts +1 -1
  38. package/landing/src/app/api/auth/session/route.ts +1 -1
  39. package/landing/src/app/api/auth/verify/route.ts +1 -1
  40. package/landing/src/app/api/og/route.tsx +5 -3
  41. package/landing/src/app/docs/page.tsx +5 -4
  42. package/landing/src/app/earn/page.tsx +14 -11
  43. package/landing/src/app/globals.css +16 -15
  44. package/landing/src/app/layout.tsx +2 -2
  45. package/landing/src/app/page.tsx +425 -254
  46. package/landing/src/app/providers/dashboard/[apiId]/actions/[actionId]/edit/page.tsx +600 -0
  47. package/landing/src/app/providers/dashboard/[apiId]/actions/new/page.tsx +583 -0
  48. package/landing/src/app/providers/dashboard/[apiId]/actions/page.tsx +301 -0
  49. package/landing/src/app/providers/dashboard/[apiId]/direct-call/page.tsx +659 -0
  50. package/landing/src/app/providers/dashboard/[apiId]/page.tsx +381 -0
  51. package/landing/src/app/providers/dashboard/[apiId]/test/page.tsx +418 -0
  52. package/landing/src/app/providers/dashboard/layout.tsx +292 -0
  53. package/landing/src/app/providers/dashboard/page.tsx +353 -290
  54. package/landing/src/app/providers/register/page.tsx +87 -10
  55. package/landing/src/components/AiClientDropdown.tsx +85 -0
  56. package/landing/src/components/ConfigHelperModal.tsx +113 -0
  57. package/landing/src/components/HeroTabs.tsx +187 -0
  58. package/landing/src/components/ShareIntegrationModal.tsx +198 -0
  59. package/landing/src/hooks/useDashboardData.ts +53 -1
  60. package/landing/src/lib/apis.json +46554 -174
  61. package/landing/src/lib/convex-client.ts +22 -3
  62. package/landing/src/lib/stats.json +4 -4
  63. package/landing/tsconfig.tsbuildinfo +1 -1
  64. package/night-expansion-02-26-06-batch2.py +368 -0
  65. package/night-expansion-02-26-06-batch3.py +299 -0
  66. package/night-expansion-02-26-06.py +756 -0
  67. package/package.json +1 -1
  68. package/scripts/bulk-add-public-apis-v2.py +418 -0
  69. package/scripts/night-expansion-02-26-v2.py +296 -0
  70. package/scripts/night-expansion-02-26.py +890 -0
  71. package/scripts/seed-complete-api.js +181 -0
  72. package/scripts/seed-demo-api.sh +44 -0
  73. package/src/crypto.ts +75 -0
  74. package/src/execute-dynamic.ts +589 -0
  75. package/src/execute.ts +41 -5
  76. package/src/index.ts +38 -4
  77. package/src/registry/apis.json +2081 -3
@@ -0,0 +1,301 @@
1
+ "use client";
2
+
3
+ import { useState, useEffect } from "react";
4
+ import { useParams, useRouter } from "next/navigation";
5
+ import Link from "next/link";
6
+ import {
7
+ Plus,
8
+ Settings,
9
+ Trash2,
10
+ Loader2,
11
+ AlertCircle,
12
+ Check,
13
+ X,
14
+ ArrowLeft,
15
+ PlayCircle,
16
+ } from "lucide-react";
17
+
18
+ interface ActionParam {
19
+ name: string;
20
+ type: string;
21
+ required: boolean;
22
+ description: string;
23
+ in: string;
24
+ }
25
+
26
+ interface ProviderAction {
27
+ _id: string;
28
+ name: string;
29
+ displayName: string;
30
+ description: string;
31
+ method: string;
32
+ path: string;
33
+ params: ActionParam[];
34
+ enabled: boolean;
35
+ }
36
+
37
+ const CONVEX_URL = process.env.NEXT_PUBLIC_CONVEX_URL || 'https://adventurous-avocet-799.convex.cloud';
38
+
39
+ export default function ActionsPage() {
40
+ const params = useParams();
41
+ const router = useRouter();
42
+ const apiId = params.apiId as string;
43
+
44
+ const [actions, setActions] = useState<ProviderAction[]>([]);
45
+ const [isLoading, setIsLoading] = useState(true);
46
+ const [error, setError] = useState<string | null>(null);
47
+ const [directCallId, setDirectCallId] = useState<string | null>(null);
48
+
49
+ useEffect(() => {
50
+ const loadActions = async () => {
51
+ const token = localStorage.getItem("apiclaw_session");
52
+ if (!token) {
53
+ router.push("/providers/dashboard/login");
54
+ return;
55
+ }
56
+
57
+ try {
58
+ // First get the direct call config to get directCallId
59
+ const configRes = await fetch(`${CONVEX_URL}/api/query`, {
60
+ method: 'POST',
61
+ headers: { 'Content-Type': 'application/json' },
62
+ body: JSON.stringify({
63
+ path: 'directCall:getDirectCallConfigByApiId',
64
+ args: { apiId }
65
+ })
66
+ });
67
+ const configData = await configRes.json();
68
+
69
+ if (!configData || !configData._id) {
70
+ setError("Direct Call not configured. Please set up Direct Call first.");
71
+ setIsLoading(false);
72
+ return;
73
+ }
74
+
75
+ setDirectCallId(configData._id);
76
+
77
+ // Then get actions
78
+ const actionsRes = await fetch(`${CONVEX_URL}/api/query`, {
79
+ method: 'POST',
80
+ headers: { 'Content-Type': 'application/json' },
81
+ body: JSON.stringify({
82
+ path: 'directCall:getActions',
83
+ args: { directCallId: configData._id }
84
+ })
85
+ });
86
+ const actionsData = await actionsRes.json();
87
+ setActions(actionsData || []);
88
+ } catch (err) {
89
+ console.error("Failed to load actions:", err);
90
+ setError(err instanceof Error ? err.message : "Failed to load actions");
91
+ } finally {
92
+ setIsLoading(false);
93
+ }
94
+ };
95
+
96
+ loadActions();
97
+ }, [apiId, router]);
98
+
99
+ const deleteAction = async (actionId: string) => {
100
+ if (!confirm("Are you sure you want to delete this action?")) return;
101
+
102
+ try {
103
+ await fetch(`${CONVEX_URL}/api/mutation`, {
104
+ method: 'POST',
105
+ headers: { 'Content-Type': 'application/json' },
106
+ body: JSON.stringify({
107
+ path: 'directCall:deleteAction',
108
+ args: { actionId }
109
+ })
110
+ });
111
+ setActions(actions.filter(a => a._id !== actionId));
112
+ } catch (err) {
113
+ alert("Failed to delete action");
114
+ }
115
+ };
116
+
117
+ const toggleAction = async (actionId: string, enabled: boolean) => {
118
+ try {
119
+ await fetch(`${CONVEX_URL}/api/mutation`, {
120
+ method: 'POST',
121
+ headers: { 'Content-Type': 'application/json' },
122
+ body: JSON.stringify({
123
+ path: 'directCall:saveAction',
124
+ args: {
125
+ directCallId,
126
+ action: { _id: actionId, enabled: !enabled }
127
+ }
128
+ })
129
+ });
130
+ setActions(actions.map(a =>
131
+ a._id === actionId ? { ...a, enabled: !enabled } : a
132
+ ));
133
+ } catch (err) {
134
+ alert("Failed to update action");
135
+ }
136
+ };
137
+
138
+ const getMethodColor = (method: string) => {
139
+ switch (method.toUpperCase()) {
140
+ case 'GET': return 'bg-green-500/20 text-green-500';
141
+ case 'POST': return 'bg-blue-500/20 text-blue-500';
142
+ case 'PUT': return 'bg-yellow-500/20 text-yellow-600';
143
+ case 'PATCH': return 'bg-orange-500/20 text-orange-500';
144
+ case 'DELETE': return 'bg-red-500/20 text-red-500';
145
+ default: return 'bg-gray-500/20 text-gray-500';
146
+ }
147
+ };
148
+
149
+ if (isLoading) {
150
+ return (
151
+ <div className="flex items-center justify-center py-24">
152
+ <Loader2 className="w-8 h-8 text-accent animate-spin" />
153
+ </div>
154
+ );
155
+ }
156
+
157
+ if (error) {
158
+ return (
159
+ <div className="text-center py-24">
160
+ <AlertCircle className="w-16 h-16 text-yellow-500 mx-auto mb-4" />
161
+ <h1 className="text-2xl font-bold mb-2">Setup Required</h1>
162
+ <p className="text-text-muted mb-6">{error}</p>
163
+ <Link href={`/providers/dashboard/${apiId}/direct-call`} className="btn-primary">
164
+ Set Up Direct Call
165
+ </Link>
166
+ </div>
167
+ );
168
+ }
169
+
170
+ return (
171
+ <div className="space-y-6">
172
+ {/* Header */}
173
+ <div className="flex items-center justify-between">
174
+ <div className="flex items-center gap-4">
175
+ <Link
176
+ href={`/providers/dashboard/${apiId}`}
177
+ className="p-2 hover:bg-surface rounded-lg transition"
178
+ >
179
+ <ArrowLeft className="w-5 h-5" />
180
+ </Link>
181
+ <div>
182
+ <h1 className="text-2xl font-bold">Actions</h1>
183
+ <p className="text-text-muted">Define the endpoints agents can call</p>
184
+ </div>
185
+ </div>
186
+ <Link
187
+ href={`/providers/dashboard/${apiId}/actions/new`}
188
+ className="btn-primary"
189
+ >
190
+ <Plus className="w-4 h-4" />
191
+ Add Action
192
+ </Link>
193
+ </div>
194
+
195
+ {/* Actions List */}
196
+ {actions.length === 0 ? (
197
+ <div className="text-center py-16 rounded-2xl border border-dashed border-border">
198
+ <Settings className="w-12 h-12 text-text-muted mx-auto mb-4" />
199
+ <h2 className="text-xl font-semibold mb-2">No actions yet</h2>
200
+ <p className="text-text-muted mb-6">
201
+ Define your first action to let agents call your API
202
+ </p>
203
+ <Link
204
+ href={`/providers/dashboard/${apiId}/actions/new`}
205
+ className="btn-primary"
206
+ >
207
+ <Plus className="w-4 h-4" />
208
+ Add First Action
209
+ </Link>
210
+ </div>
211
+ ) : (
212
+ <div className="space-y-3">
213
+ {actions.map((action) => (
214
+ <div
215
+ key={action._id}
216
+ className="rounded-xl border border-border bg-surface-elevated p-4 hover:border-accent/30 transition"
217
+ >
218
+ <div className="flex items-center justify-between">
219
+ <div className="flex items-center gap-4">
220
+ <span className={`px-2.5 py-1 rounded text-xs font-bold ${getMethodColor(action.method)}`}>
221
+ {action.method}
222
+ </span>
223
+ <div>
224
+ <div className="flex items-center gap-2">
225
+ <h3 className="font-semibold">{action.displayName}</h3>
226
+ <code className="text-xs text-text-muted bg-surface px-2 py-0.5 rounded">
227
+ {action.name}
228
+ </code>
229
+ </div>
230
+ <p className="text-sm text-text-muted font-mono">{action.path}</p>
231
+ </div>
232
+ </div>
233
+ <div className="flex items-center gap-2">
234
+ <button
235
+ onClick={() => toggleAction(action._id, action.enabled)}
236
+ className={`p-2 rounded-lg transition ${
237
+ action.enabled
238
+ ? 'bg-green-500/20 text-green-500 hover:bg-green-500/30'
239
+ : 'bg-gray-500/20 text-gray-500 hover:bg-gray-500/30'
240
+ }`}
241
+ title={action.enabled ? 'Disable' : 'Enable'}
242
+ >
243
+ {action.enabled ? <Check className="w-4 h-4" /> : <X className="w-4 h-4" />}
244
+ </button>
245
+ <Link
246
+ href={`/providers/dashboard/${apiId}/actions/${action._id}/edit`}
247
+ className="p-2 rounded-lg hover:bg-surface transition"
248
+ title="Edit"
249
+ >
250
+ <Settings className="w-4 h-4" />
251
+ </Link>
252
+ <button
253
+ onClick={() => deleteAction(action._id)}
254
+ className="p-2 rounded-lg hover:bg-red-500/20 text-text-muted hover:text-red-500 transition"
255
+ title="Delete"
256
+ >
257
+ <Trash2 className="w-4 h-4" />
258
+ </button>
259
+ </div>
260
+ </div>
261
+ {action.description && (
262
+ <p className="text-sm text-text-muted mt-2 ml-[72px]">{action.description}</p>
263
+ )}
264
+ {action.params.length > 0 && (
265
+ <div className="flex items-center gap-2 mt-3 ml-[72px]">
266
+ <span className="text-xs text-text-muted">Params:</span>
267
+ {action.params.slice(0, 5).map((p, i) => (
268
+ <span
269
+ key={i}
270
+ className={`text-xs px-2 py-0.5 rounded ${
271
+ p.required ? 'bg-accent/20 text-accent' : 'bg-surface text-text-muted'
272
+ }`}
273
+ >
274
+ {p.name}
275
+ </span>
276
+ ))}
277
+ {action.params.length > 5 && (
278
+ <span className="text-xs text-text-muted">+{action.params.length - 5} more</span>
279
+ )}
280
+ </div>
281
+ )}
282
+ </div>
283
+ ))}
284
+ </div>
285
+ )}
286
+
287
+ {/* Test Console Link */}
288
+ {actions.length > 0 && (
289
+ <div className="flex justify-center pt-4">
290
+ <Link
291
+ href={`/providers/dashboard/${apiId}/test`}
292
+ className="btn-secondary"
293
+ >
294
+ <PlayCircle className="w-4 h-4" />
295
+ Test Actions
296
+ </Link>
297
+ </div>
298
+ )}
299
+ </div>
300
+ );
301
+ }