@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.
@@ -0,0 +1,131 @@
1
+ /**
2
+ * APIClaw Funnel — client-side emitter for MCP server.
3
+ *
4
+ * Fire-and-forget POST to Convex funnel:recordEvent. Never throws, never
5
+ * blocks. See convex/funnel.ts for schema and classification rules.
6
+ */
7
+ import * as fs from "fs";
8
+ import * as path from "path";
9
+ import * as os from "os";
10
+ const CONVEX_URL = process.env.CONVEX_URL || "https://adventurous-avocet-799.convex.cloud";
11
+ const CI_ENV_KEYS = [
12
+ "CI",
13
+ "GITHUB_ACTIONS",
14
+ "GITLAB_CI",
15
+ "CIRCLECI",
16
+ "BUILDKITE",
17
+ "JENKINS_URL",
18
+ "TEAMCITY_VERSION",
19
+ "TRAVIS",
20
+ "BITBUCKET_BUILD_NUMBER",
21
+ ];
22
+ const BOT_UA_MARKERS = [
23
+ "bot",
24
+ "crawl",
25
+ "spider",
26
+ "scanner",
27
+ "curl/",
28
+ "wget/",
29
+ "httpclient",
30
+ "python-requests",
31
+ "go-http-client",
32
+ "okhttp",
33
+ "java/",
34
+ "httrack",
35
+ "headlesschrome",
36
+ "phantomjs",
37
+ ];
38
+ const INTERNAL_EMAIL_DOMAINS = ["nordsym.com", "apiclaw.cloud"];
39
+ const INTERNAL_EMAIL_EXACT = ["gustav@nordsym.com", "gustavnordsync@gmail.com"];
40
+ export function classifyLocalSource(input) {
41
+ const email = (input.email || "").toLowerCase().trim();
42
+ if (email) {
43
+ if (INTERNAL_EMAIL_EXACT.includes(email))
44
+ return "internal";
45
+ const domain = email.split("@")[1] || "";
46
+ if (INTERNAL_EMAIL_DOMAINS.includes(domain))
47
+ return "internal";
48
+ }
49
+ const env = input.env || process.env;
50
+ for (const key of CI_ENV_KEYS) {
51
+ const val = env[key];
52
+ if (val && val !== "false" && val !== "0")
53
+ return "ci";
54
+ }
55
+ const ua = (input.userAgent || "").toLowerCase();
56
+ if (ua) {
57
+ for (const m of BOT_UA_MARKERS) {
58
+ if (ua.includes(m))
59
+ return "bot";
60
+ }
61
+ }
62
+ return "human";
63
+ }
64
+ // Persistent first-run marker stored alongside the session file.
65
+ const MARKER_DIR = path.join(os.homedir(), ".apiclaw");
66
+ const MARKER_FILE = path.join(MARKER_DIR, "funnel-markers.json");
67
+ function readMarkers() {
68
+ try {
69
+ if (!fs.existsSync(MARKER_FILE))
70
+ return {};
71
+ return JSON.parse(fs.readFileSync(MARKER_FILE, "utf8")) || {};
72
+ }
73
+ catch {
74
+ return {};
75
+ }
76
+ }
77
+ function writeMarkers(m) {
78
+ try {
79
+ if (!fs.existsSync(MARKER_DIR))
80
+ fs.mkdirSync(MARKER_DIR, { mode: 0o700 });
81
+ fs.writeFileSync(MARKER_FILE, JSON.stringify(m), { mode: 0o600 });
82
+ }
83
+ catch {
84
+ /* ignore */
85
+ }
86
+ }
87
+ export function hasLocalMarker(key) {
88
+ return !!readMarkers()[key];
89
+ }
90
+ export function setLocalMarker(key) {
91
+ const m = readMarkers();
92
+ m[key] = Date.now();
93
+ writeMarkers(m);
94
+ }
95
+ export function emitFunnelEvent(args) {
96
+ if (process.env.APICLAW_TELEMETRY === "false")
97
+ return;
98
+ const classification = classifyLocalSource({
99
+ email: args.email,
100
+ fingerprint: args.fingerprint,
101
+ });
102
+ const payload = {
103
+ path: "funnel:recordEvent",
104
+ args: {
105
+ event: args.event,
106
+ classification,
107
+ workspaceId: args.workspaceId,
108
+ fingerprint: args.fingerprint,
109
+ sessionToken: args.sessionToken,
110
+ email: args.email,
111
+ userAgent: `apiclaw-mcp/${args.version || "unknown"}`,
112
+ mcpClient: args.mcpClient,
113
+ platform: args.platform || process.platform,
114
+ version: args.version,
115
+ dedupeKey: args.dedupeKey,
116
+ props: args.props,
117
+ },
118
+ };
119
+ // Fire and forget.
120
+ try {
121
+ fetch(`${CONVEX_URL}/api/mutation`, {
122
+ method: "POST",
123
+ headers: { "Content-Type": "application/json" },
124
+ body: JSON.stringify(payload),
125
+ }).catch(() => { });
126
+ }
127
+ catch {
128
+ /* ignore */
129
+ }
130
+ }
131
+ //# sourceMappingURL=funnel-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"funnel-client.js","sourceRoot":"","sources":["../src/funnel-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,6CAA6C,CAAC;AAkB3F,MAAM,WAAW,GAAG;IAClB,IAAI;IACJ,gBAAgB;IAChB,WAAW;IACX,UAAU;IACV,WAAW;IACX,aAAa;IACb,kBAAkB;IAClB,QAAQ;IACR,wBAAwB;CACzB,CAAC;AAEF,MAAM,cAAc,GAAG;IACrB,KAAK;IACL,OAAO;IACP,QAAQ;IACR,SAAS;IACT,OAAO;IACP,OAAO;IACP,YAAY;IACZ,iBAAiB;IACjB,gBAAgB;IAChB,QAAQ;IACR,OAAO;IACP,SAAS;IACT,gBAAgB;IAChB,WAAW;CACZ,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;AAChE,MAAM,oBAAoB,GAAG,CAAC,oBAAoB,EAAE,0BAA0B,CAAC,CAAC;AAEhF,MAAM,UAAU,mBAAmB,CAAC,KAKnC;IACC,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IACvD,IAAI,KAAK,EAAE,CAAC;QACV,IAAI,oBAAoB,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,UAAU,CAAC;QAC5D,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,IAAI,sBAAsB,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,UAAU,CAAC;IACjE,CAAC;IACD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACrC,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACrB,IAAI,GAAG,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;IACzD,CAAC;IACD,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,IAAI,EAAE,EAAE,CAAC;QACP,KAAK,MAAM,CAAC,IAAI,cAAc,EAAE,CAAC;YAC/B,IAAI,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;QACnC,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AACvD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,qBAAqB,CAAC,CAAC;AAEjE,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC;YAAE,OAAO,EAAE,CAAC;QAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,CAAyB;IAC7C,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1E,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,YAAY;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,MAAM,CAAC,GAAG,WAAW,EAAE,CAAC;IACxB,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACpB,YAAY,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAeD,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,OAAO;QAAE,OAAO;IAEtD,MAAM,cAAc,GAAG,mBAAmB,CAAC;QACzC,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,WAAW,EAAE,IAAI,CAAC,WAAW;KAC9B,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG;QACd,IAAI,EAAE,oBAAoB;QAC1B,IAAI,EAAE;YACJ,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,cAAc;YACd,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,SAAS,EAAE,eAAe,IAAI,CAAC,OAAO,IAAI,SAAS,EAAE;YACrD,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ;YAC3C,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB;KACF,CAAC;IAEF,mBAAmB;IACnB,IAAI,CAAC;QACH,KAAK,CAAC,GAAG,UAAU,eAAe,EAAE;YAClC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;SAC9B,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,YAAY;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=funnel.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"funnel.test.d.ts","sourceRoot":"","sources":["../src/funnel.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Tests for funnel classification + registration guard + event canon.
3
+ * Run: npx tsx src/funnel.test.ts
4
+ */
5
+ import { strict as assert } from 'node:assert';
6
+ import { classifyLocalSource } from './funnel-client.js';
7
+ import { requireVerifiedOwner, FREE_CALL_PATHS, ENFORCED_CALL_PATHS, } from './registration-guard.js';
8
+ let failed = 0;
9
+ let passed = 0;
10
+ function test(name, fn) {
11
+ try {
12
+ fn();
13
+ console.log(`✅ ${name}`);
14
+ passed++;
15
+ }
16
+ catch (e) {
17
+ console.log(`❌ ${name}`);
18
+ console.log(` ${e.message || e}`);
19
+ failed++;
20
+ }
21
+ }
22
+ // ------------------------------------------------------------------
23
+ // Classification
24
+ // ------------------------------------------------------------------
25
+ test('classify: human is default', () => {
26
+ assert.equal(classifyLocalSource({ env: {} }), 'human');
27
+ });
28
+ test('classify: CI env flag → ci', () => {
29
+ assert.equal(classifyLocalSource({ env: { CI: 'true' } }), 'ci');
30
+ assert.equal(classifyLocalSource({ env: { GITHUB_ACTIONS: '1' } }), 'ci');
31
+ assert.equal(classifyLocalSource({ env: { CIRCLECI: 'true' } }), 'ci');
32
+ });
33
+ test('classify: CI=false is NOT ci', () => {
34
+ assert.equal(classifyLocalSource({ env: { CI: 'false' } }), 'human');
35
+ assert.equal(classifyLocalSource({ env: { CI: '0' } }), 'human');
36
+ });
37
+ test('classify: bot UA → bot', () => {
38
+ assert.equal(classifyLocalSource({ env: {}, userAgent: 'curl/7.88' }), 'bot');
39
+ assert.equal(classifyLocalSource({ env: {}, userAgent: 'Mozilla/5.0 (compatible; Googlebot/2.1)' }), 'bot');
40
+ assert.equal(classifyLocalSource({ env: {}, userAgent: 'python-requests/2.31' }), 'bot');
41
+ });
42
+ test('classify: internal email domain → internal', () => {
43
+ assert.equal(classifyLocalSource({ env: {}, email: 'someone@nordsym.com' }), 'internal');
44
+ assert.equal(classifyLocalSource({ env: {}, email: 'test@apiclaw.cloud' }), 'internal');
45
+ });
46
+ test('classify: internal exact email → internal (even with CI set)', () => {
47
+ assert.equal(classifyLocalSource({
48
+ env: { CI: 'true' },
49
+ email: 'gustavnordsync@gmail.com',
50
+ }), 'internal');
51
+ });
52
+ test('classify: precedence internal > ci > bot > human', () => {
53
+ // internal wins over CI
54
+ assert.equal(classifyLocalSource({ env: { CI: 'true' }, email: 'x@nordsym.com' }), 'internal');
55
+ // ci wins over bot
56
+ assert.equal(classifyLocalSource({ env: { CI: 'true' }, userAgent: 'curl/8' }), 'ci');
57
+ });
58
+ // ------------------------------------------------------------------
59
+ // requireVerifiedOwner
60
+ // ------------------------------------------------------------------
61
+ const good = {
62
+ sessionToken: 'tok',
63
+ workspaceId: 'ws_1',
64
+ email: 'user@example.com',
65
+ tier: 'free',
66
+ status: 'active',
67
+ usageRemaining: 42,
68
+ usageCount: 8,
69
+ };
70
+ test('guard: no workspace → no_session', () => {
71
+ const r = requireVerifiedOwner(null);
72
+ assert.equal(r.ok, false);
73
+ if (!r.ok)
74
+ assert.equal(r.reason, 'no_session');
75
+ });
76
+ test('guard: workspace without email → pending_verification', () => {
77
+ const r = requireVerifiedOwner({ ...good, email: '' });
78
+ assert.equal(r.ok, false);
79
+ if (!r.ok)
80
+ assert.equal(r.reason, 'pending_verification');
81
+ });
82
+ test('guard: workspace status pending → not_verified', () => {
83
+ const r = requireVerifiedOwner({ ...good, status: 'pending' });
84
+ assert.equal(r.ok, false);
85
+ if (!r.ok)
86
+ assert.equal(r.reason, 'not_verified');
87
+ });
88
+ test('guard: quota exhausted → quota_exceeded', () => {
89
+ const r = requireVerifiedOwner({ ...good, usageRemaining: 0 });
90
+ assert.equal(r.ok, false);
91
+ if (!r.ok)
92
+ assert.equal(r.reason, 'quota_exceeded');
93
+ });
94
+ test('guard: happy path → ok', () => {
95
+ const r = requireVerifiedOwner(good);
96
+ assert.equal(r.ok, true);
97
+ if (r.ok)
98
+ assert.equal(r.ctx.email, 'user@example.com');
99
+ });
100
+ test('guard: unlimited (usageRemaining=-1) → ok', () => {
101
+ const r = requireVerifiedOwner({ ...good, usageRemaining: -1 });
102
+ assert.equal(r.ok, true);
103
+ });
104
+ // ------------------------------------------------------------------
105
+ // Enforcement matrix coverage
106
+ // ------------------------------------------------------------------
107
+ test('matrix: discover_apis is free', () => {
108
+ assert.equal(FREE_CALL_PATHS.has('discover_apis'), true);
109
+ assert.equal(ENFORCED_CALL_PATHS.has('discover_apis'), false);
110
+ });
111
+ test('matrix: call_api / capability / resume_chain are enforced', () => {
112
+ for (const p of ['call_api', 'capability', 'resume_chain']) {
113
+ assert.equal(ENFORCED_CALL_PATHS.has(p), true, `${p} should be enforced`);
114
+ }
115
+ });
116
+ test('matrix: register_owner + verify_code are free (they BECOME the auth)', () => {
117
+ assert.equal(FREE_CALL_PATHS.has('register_owner'), true);
118
+ assert.equal(FREE_CALL_PATHS.has('verify_code'), true);
119
+ });
120
+ test('matrix: free and enforced sets are disjoint', () => {
121
+ for (const p of FREE_CALL_PATHS) {
122
+ assert.equal(ENFORCED_CALL_PATHS.has(p), false, `${p} is in both sets`);
123
+ }
124
+ });
125
+ test('event canon: all 11 approved events are typed', () => {
126
+ const names = [
127
+ 'install',
128
+ 'first_run',
129
+ 'register_owner',
130
+ 'verify_code',
131
+ 'first_call_api_success',
132
+ 'register_owner_failed',
133
+ 'verify_code_failed',
134
+ 'call_api_blocked',
135
+ 'call_api_error',
136
+ 'quota_hit',
137
+ 'gateway_retry',
138
+ ];
139
+ assert.equal(names.length, 11);
140
+ });
141
+ console.log('');
142
+ console.log(`Results: ${passed} passed, ${failed} failed`);
143
+ if (failed > 0)
144
+ process.exit(1);
145
+ //# sourceMappingURL=funnel.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"funnel.test.js","sourceRoot":"","sources":["../src/funnel.test.ts"],"names":[],"mappings":"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"}