@nordsym/apiclaw 2.0.0 → 2.2.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/.claude/settings.local.json +5 -1
- package/convex/_generated/api.d.ts +8 -0
- package/convex/_listWorkspaces.ts +13 -0
- package/convex/crons.ts +15 -0
- package/convex/funnel.ts +431 -0
- package/convex/guards.ts +174 -0
- package/convex/http.ts +334 -8
- package/convex/nurture.ts +355 -0
- package/convex/schema.ts +70 -0
- package/convex/workspaces.ts +185 -0
- package/dist/funnel-client.d.ts +24 -0
- package/dist/funnel-client.d.ts.map +1 -0
- package/dist/funnel-client.js +131 -0
- package/dist/funnel-client.js.map +1 -0
- package/dist/funnel.test.d.ts +2 -0
- package/dist/funnel.test.d.ts.map +1 -0
- package/dist/funnel.test.js +145 -0
- package/dist/funnel.test.js.map +1 -0
- package/dist/index.js +338 -120
- package/dist/index.js.map +1 -1
- package/dist/postinstall.d.ts +0 -5
- package/dist/postinstall.d.ts.map +1 -1
- package/dist/postinstall.js +24 -3
- package/dist/postinstall.js.map +1 -1
- package/dist/registration-guard.d.ts +29 -0
- package/dist/registration-guard.d.ts.map +1 -0
- package/dist/registration-guard.js +87 -0
- package/dist/registration-guard.js.map +1 -0
- package/package.json +1 -1
- package/src/funnel-client.ts +168 -0
- package/src/funnel.test.ts +187 -0
- package/src/index.ts +381 -145
- package/src/postinstall.ts +24 -2
- package/src/registration-guard.ts +117 -0
package/src/postinstall.ts
CHANGED
|
@@ -1,14 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* APIClaw Postinstall Hook
|
|
4
|
-
* Prints a welcome message with links
|
|
5
|
-
*
|
|
4
|
+
* Prints a welcome message with links and fires ONE anonymous funnel
|
|
5
|
+
* event (install) so we can measure top-of-funnel truthfully.
|
|
6
|
+
*
|
|
7
|
+
* Disable telemetry: APICLAW_TELEMETRY=false
|
|
6
8
|
*/
|
|
9
|
+
import { emitFunnelEvent, hasLocalMarker, setLocalMarker } from './funnel-client.js';
|
|
10
|
+
import { getMachineFingerprint, detectMCPClient } from './session.js';
|
|
7
11
|
|
|
8
12
|
const CYAN = '\x1b[36m';
|
|
9
13
|
const RESET = '\x1b[0m';
|
|
10
14
|
const DIM = '\x1b[2m';
|
|
11
15
|
|
|
16
|
+
try {
|
|
17
|
+
const fp = getMachineFingerprint();
|
|
18
|
+
const dedupeKey = `install:${fp}`;
|
|
19
|
+
if (!hasLocalMarker(dedupeKey)) {
|
|
20
|
+
emitFunnelEvent({
|
|
21
|
+
event: 'install',
|
|
22
|
+
fingerprint: fp,
|
|
23
|
+
mcpClient: detectMCPClient(),
|
|
24
|
+
platform: process.platform,
|
|
25
|
+
version: process.env.npm_package_version || 'unknown',
|
|
26
|
+
dedupeKey,
|
|
27
|
+
});
|
|
28
|
+
setLocalMarker(dedupeKey);
|
|
29
|
+
}
|
|
30
|
+
} catch {
|
|
31
|
+
/* never block install */
|
|
32
|
+
}
|
|
33
|
+
|
|
12
34
|
console.log('');
|
|
13
35
|
console.log(` 🦞 APIClaw installed successfully!`);
|
|
14
36
|
console.log('');
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side registration guard — single source of truth for "does this
|
|
3
|
+
* workspaceContext pass the verified-owner check before an API call".
|
|
4
|
+
*
|
|
5
|
+
* Free paths (discover_apis, list_* , *_help) do NOT call this.
|
|
6
|
+
* Paying paths (call_api single + chain, capability, resume_chain) DO.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface WorkspaceContextLike {
|
|
10
|
+
sessionToken: string;
|
|
11
|
+
workspaceId: string;
|
|
12
|
+
email: string;
|
|
13
|
+
tier: string;
|
|
14
|
+
status: string;
|
|
15
|
+
usageRemaining: number;
|
|
16
|
+
usageCount: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type GuardResult =
|
|
20
|
+
| { ok: true; ctx: WorkspaceContextLike }
|
|
21
|
+
| { ok: false; reason: GuardReason; payload: Record<string, unknown> };
|
|
22
|
+
|
|
23
|
+
export type GuardReason =
|
|
24
|
+
| "no_session"
|
|
25
|
+
| "not_verified"
|
|
26
|
+
| "quota_exceeded"
|
|
27
|
+
| "pending_verification";
|
|
28
|
+
|
|
29
|
+
// Paths that are allowed without a verified owner.
|
|
30
|
+
export const FREE_CALL_PATHS = new Set<string>([
|
|
31
|
+
"discover_apis",
|
|
32
|
+
"list_categories",
|
|
33
|
+
"list_connected",
|
|
34
|
+
"list_capabilities",
|
|
35
|
+
"apiclaw_help",
|
|
36
|
+
"register_owner",
|
|
37
|
+
"verify_code",
|
|
38
|
+
"check_workspace_status",
|
|
39
|
+
"remind_owner",
|
|
40
|
+
"get_chain_status",
|
|
41
|
+
"setup_metered_billing",
|
|
42
|
+
"get_usage_summary",
|
|
43
|
+
"estimate_cost",
|
|
44
|
+
"check_balance",
|
|
45
|
+
"add_credits",
|
|
46
|
+
"get_api_details",
|
|
47
|
+
"purchase_access",
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
// Paths that MUST go through requireVerifiedOwner.
|
|
51
|
+
export const ENFORCED_CALL_PATHS = new Set<string>([
|
|
52
|
+
"call_api",
|
|
53
|
+
"capability",
|
|
54
|
+
"resume_chain",
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
export function requireVerifiedOwner(
|
|
58
|
+
workspaceContext: WorkspaceContextLike | null
|
|
59
|
+
): GuardResult {
|
|
60
|
+
if (!workspaceContext) {
|
|
61
|
+
return {
|
|
62
|
+
ok: false,
|
|
63
|
+
reason: "no_session",
|
|
64
|
+
payload: {
|
|
65
|
+
status: "registration_required",
|
|
66
|
+
error: "Registration required to call APIs.",
|
|
67
|
+
message:
|
|
68
|
+
"Ask the user for their email, then call register_owner({ email }). A 6-digit code will be sent. Then call verify_code with the code.",
|
|
69
|
+
action: "register_owner",
|
|
70
|
+
free_tier: "50 API calls/month -- completely free.",
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!workspaceContext.email) {
|
|
76
|
+
return {
|
|
77
|
+
ok: false,
|
|
78
|
+
reason: "pending_verification",
|
|
79
|
+
payload: {
|
|
80
|
+
status: "registration_required",
|
|
81
|
+
error: "Workspace is not linked to a verified email yet.",
|
|
82
|
+
message: "Run register_owner({ email }) and verify_code to activate.",
|
|
83
|
+
action: "register_owner",
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (workspaceContext.status !== "active") {
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
reason: "not_verified",
|
|
92
|
+
payload: {
|
|
93
|
+
status: "pending_verification",
|
|
94
|
+
error: `Workspace status: ${workspaceContext.status}. Please verify your email.`,
|
|
95
|
+
action: "verify_code",
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (workspaceContext.usageRemaining === 0) {
|
|
101
|
+
return {
|
|
102
|
+
ok: false,
|
|
103
|
+
reason: "quota_exceeded",
|
|
104
|
+
payload: {
|
|
105
|
+
status: "quota_exceeded",
|
|
106
|
+
error:
|
|
107
|
+
workspaceContext.tier === "free"
|
|
108
|
+
? "You've hit the free tier limit. Upgrade at https://apiclaw.cloud/upgrade."
|
|
109
|
+
: "Quota exceeded.",
|
|
110
|
+
upgrade_url: "https://apiclaw.cloud/upgrade",
|
|
111
|
+
action: "upgrade",
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { ok: true, ctx: workspaceContext };
|
|
117
|
+
}
|