@kelpi/mcp 0.1.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.
Files changed (195) hide show
  1. package/README.md +312 -0
  2. package/bin/kelpi-mcp +3 -0
  3. package/dist/__tests__/integration-api/fixtures.d.ts +382 -0
  4. package/dist/__tests__/integration-api/fixtures.d.ts.map +1 -0
  5. package/dist/__tests__/integration-api/fixtures.js +478 -0
  6. package/dist/__tests__/integration-api/fixtures.js.map +1 -0
  7. package/dist/__tests__/integration-api/index.d.ts +19 -0
  8. package/dist/__tests__/integration-api/index.d.ts.map +1 -0
  9. package/dist/__tests__/integration-api/index.js +33 -0
  10. package/dist/__tests__/integration-api/index.js.map +1 -0
  11. package/dist/__tests__/integration-api/setup.d.ts +176 -0
  12. package/dist/__tests__/integration-api/setup.d.ts.map +1 -0
  13. package/dist/__tests__/integration-api/setup.js +329 -0
  14. package/dist/__tests__/integration-api/setup.js.map +1 -0
  15. package/dist/__tests__/setup.d.ts +2 -0
  16. package/dist/__tests__/setup.d.ts.map +1 -0
  17. package/dist/__tests__/setup.js +11 -0
  18. package/dist/__tests__/setup.js.map +1 -0
  19. package/dist/__tests__/unit/test-utils.d.ts +46 -0
  20. package/dist/__tests__/unit/test-utils.d.ts.map +1 -0
  21. package/dist/__tests__/unit/test-utils.js +50 -0
  22. package/dist/__tests__/unit/test-utils.js.map +1 -0
  23. package/dist/index.d.ts +6 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +34 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/lib/api-client.d.ts +17 -0
  28. package/dist/lib/api-client.d.ts.map +1 -0
  29. package/dist/lib/api-client.js +169 -0
  30. package/dist/lib/api-client.js.map +1 -0
  31. package/dist/lib/auth-state.d.ts +54 -0
  32. package/dist/lib/auth-state.d.ts.map +1 -0
  33. package/dist/lib/auth-state.js +131 -0
  34. package/dist/lib/auth-state.js.map +1 -0
  35. package/dist/lib/config.d.ts +39 -0
  36. package/dist/lib/config.d.ts.map +1 -0
  37. package/dist/lib/config.js +170 -0
  38. package/dist/lib/config.js.map +1 -0
  39. package/dist/lib/error-formatter.d.ts +40 -0
  40. package/dist/lib/error-formatter.d.ts.map +1 -0
  41. package/dist/lib/error-formatter.js +149 -0
  42. package/dist/lib/error-formatter.js.map +1 -0
  43. package/dist/lib/errors.d.ts +44 -0
  44. package/dist/lib/errors.d.ts.map +1 -0
  45. package/dist/lib/errors.js +56 -0
  46. package/dist/lib/errors.js.map +1 -0
  47. package/dist/lib/tool-helpers.d.ts +49 -0
  48. package/dist/lib/tool-helpers.d.ts.map +1 -0
  49. package/dist/lib/tool-helpers.js +101 -0
  50. package/dist/lib/tool-helpers.js.map +1 -0
  51. package/dist/lib/tool-registry.d.ts +111 -0
  52. package/dist/lib/tool-registry.d.ts.map +1 -0
  53. package/dist/lib/tool-registry.js +112 -0
  54. package/dist/lib/tool-registry.js.map +1 -0
  55. package/dist/lib/version.d.ts +13 -0
  56. package/dist/lib/version.d.ts.map +1 -0
  57. package/dist/lib/version.js +13 -0
  58. package/dist/lib/version.js.map +1 -0
  59. package/dist/prompts/flow-generator.d.ts +45 -0
  60. package/dist/prompts/flow-generator.d.ts.map +1 -0
  61. package/dist/prompts/flow-generator.js +177 -0
  62. package/dist/prompts/flow-generator.js.map +1 -0
  63. package/dist/prompts/index.d.ts +7 -0
  64. package/dist/prompts/index.d.ts.map +1 -0
  65. package/dist/prompts/index.js +7 -0
  66. package/dist/prompts/index.js.map +1 -0
  67. package/dist/server.d.ts +66 -0
  68. package/dist/server.d.ts.map +1 -0
  69. package/dist/server.js +140 -0
  70. package/dist/server.js.map +1 -0
  71. package/dist/tools/auth/index.d.ts +18 -0
  72. package/dist/tools/auth/index.d.ts.map +1 -0
  73. package/dist/tools/auth/index.js +50 -0
  74. package/dist/tools/auth/index.js.map +1 -0
  75. package/dist/tools/auth/login.d.ts +37 -0
  76. package/dist/tools/auth/login.d.ts.map +1 -0
  77. package/dist/tools/auth/login.js +257 -0
  78. package/dist/tools/auth/login.js.map +1 -0
  79. package/dist/tools/auth/schemas.d.ts +69 -0
  80. package/dist/tools/auth/schemas.d.ts.map +1 -0
  81. package/dist/tools/auth/schemas.js +36 -0
  82. package/dist/tools/auth/schemas.js.map +1 -0
  83. package/dist/tools/auth/status.d.ts +11 -0
  84. package/dist/tools/auth/status.d.ts.map +1 -0
  85. package/dist/tools/auth/status.js +50 -0
  86. package/dist/tools/auth/status.js.map +1 -0
  87. package/dist/tools/contacts/create.d.ts +11 -0
  88. package/dist/tools/contacts/create.d.ts.map +1 -0
  89. package/dist/tools/contacts/create.js +47 -0
  90. package/dist/tools/contacts/create.js.map +1 -0
  91. package/dist/tools/contacts/index.d.ts +10 -0
  92. package/dist/tools/contacts/index.d.ts.map +1 -0
  93. package/dist/tools/contacts/index.js +40 -0
  94. package/dist/tools/contacts/index.js.map +1 -0
  95. package/dist/tools/contacts/schemas.d.ts +37 -0
  96. package/dist/tools/contacts/schemas.d.ts.map +1 -0
  97. package/dist/tools/contacts/schemas.js +15 -0
  98. package/dist/tools/contacts/schemas.js.map +1 -0
  99. package/dist/tools/events/index.d.ts +10 -0
  100. package/dist/tools/events/index.d.ts.map +1 -0
  101. package/dist/tools/events/index.js +42 -0
  102. package/dist/tools/events/index.js.map +1 -0
  103. package/dist/tools/events/schemas.d.ts +37 -0
  104. package/dist/tools/events/schemas.d.ts.map +1 -0
  105. package/dist/tools/events/schemas.js +17 -0
  106. package/dist/tools/events/schemas.js.map +1 -0
  107. package/dist/tools/events/track.d.ts +11 -0
  108. package/dist/tools/events/track.d.ts.map +1 -0
  109. package/dist/tools/events/track.js +41 -0
  110. package/dist/tools/events/track.js.map +1 -0
  111. package/dist/tools/flows/activate.d.ts +11 -0
  112. package/dist/tools/flows/activate.d.ts.map +1 -0
  113. package/dist/tools/flows/activate.js +46 -0
  114. package/dist/tools/flows/activate.js.map +1 -0
  115. package/dist/tools/flows/create.d.ts +11 -0
  116. package/dist/tools/flows/create.d.ts.map +1 -0
  117. package/dist/tools/flows/create.js +72 -0
  118. package/dist/tools/flows/create.js.map +1 -0
  119. package/dist/tools/flows/index.d.ts +24 -0
  120. package/dist/tools/flows/index.d.ts.map +1 -0
  121. package/dist/tools/flows/index.js +183 -0
  122. package/dist/tools/flows/index.js.map +1 -0
  123. package/dist/tools/flows/list.d.ts +11 -0
  124. package/dist/tools/flows/list.d.ts.map +1 -0
  125. package/dist/tools/flows/list.js +34 -0
  126. package/dist/tools/flows/list.js.map +1 -0
  127. package/dist/tools/flows/schemas.d.ts +621 -0
  128. package/dist/tools/flows/schemas.d.ts.map +1 -0
  129. package/dist/tools/flows/schemas.js +135 -0
  130. package/dist/tools/flows/schemas.js.map +1 -0
  131. package/dist/tools/flows/transform.d.ts +39 -0
  132. package/dist/tools/flows/transform.d.ts.map +1 -0
  133. package/dist/tools/flows/transform.js +139 -0
  134. package/dist/tools/flows/transform.js.map +1 -0
  135. package/dist/tools/index.d.ts +34 -0
  136. package/dist/tools/index.d.ts.map +1 -0
  137. package/dist/tools/index.js +46 -0
  138. package/dist/tools/index.js.map +1 -0
  139. package/dist/tools/sdk/index.d.ts +18 -0
  140. package/dist/tools/sdk/index.d.ts.map +1 -0
  141. package/dist/tools/sdk/index.js +69 -0
  142. package/dist/tools/sdk/index.js.map +1 -0
  143. package/dist/tools/sdk/public-key.d.ts +11 -0
  144. package/dist/tools/sdk/public-key.d.ts.map +1 -0
  145. package/dist/tools/sdk/public-key.js +24 -0
  146. package/dist/tools/sdk/public-key.js.map +1 -0
  147. package/dist/tools/sdk/schemas.d.ts +48 -0
  148. package/dist/tools/sdk/schemas.d.ts.map +1 -0
  149. package/dist/tools/sdk/schemas.js +35 -0
  150. package/dist/tools/sdk/schemas.js.map +1 -0
  151. package/dist/tools/sdk/snippet.d.ts +11 -0
  152. package/dist/tools/sdk/snippet.d.ts.map +1 -0
  153. package/dist/tools/sdk/snippet.js +50 -0
  154. package/dist/tools/sdk/snippet.js.map +1 -0
  155. package/dist/tools/sdk/templates/index.d.ts +5 -0
  156. package/dist/tools/sdk/templates/index.d.ts.map +1 -0
  157. package/dist/tools/sdk/templates/index.js +5 -0
  158. package/dist/tools/sdk/templates/index.js.map +1 -0
  159. package/dist/tools/sdk/templates/nextjs.d.ts +5 -0
  160. package/dist/tools/sdk/templates/nextjs.d.ts.map +1 -0
  161. package/dist/tools/sdk/templates/nextjs.js +71 -0
  162. package/dist/tools/sdk/templates/nextjs.js.map +1 -0
  163. package/dist/tools/sdk/templates/node.d.ts +9 -0
  164. package/dist/tools/sdk/templates/node.d.ts.map +1 -0
  165. package/dist/tools/sdk/templates/node.js +170 -0
  166. package/dist/tools/sdk/templates/node.js.map +1 -0
  167. package/dist/tools/sdk/templates/react.d.ts +5 -0
  168. package/dist/tools/sdk/templates/react.d.ts.map +1 -0
  169. package/dist/tools/sdk/templates/react.js +54 -0
  170. package/dist/tools/sdk/templates/react.js.map +1 -0
  171. package/dist/tools/sdk/templates/vanilla.d.ts +5 -0
  172. package/dist/tools/sdk/templates/vanilla.d.ts.map +1 -0
  173. package/dist/tools/sdk/templates/vanilla.js +61 -0
  174. package/dist/tools/sdk/templates/vanilla.js.map +1 -0
  175. package/dist/tools/templates/create.d.ts +11 -0
  176. package/dist/tools/templates/create.d.ts.map +1 -0
  177. package/dist/tools/templates/create.js +39 -0
  178. package/dist/tools/templates/create.js.map +1 -0
  179. package/dist/tools/templates/index.d.ts +17 -0
  180. package/dist/tools/templates/index.d.ts.map +1 -0
  181. package/dist/tools/templates/index.js +68 -0
  182. package/dist/tools/templates/index.js.map +1 -0
  183. package/dist/tools/templates/list.d.ts +11 -0
  184. package/dist/tools/templates/list.d.ts.map +1 -0
  185. package/dist/tools/templates/list.js +31 -0
  186. package/dist/tools/templates/list.js.map +1 -0
  187. package/dist/tools/templates/schemas.d.ts +90 -0
  188. package/dist/tools/templates/schemas.d.ts.map +1 -0
  189. package/dist/tools/templates/schemas.js +37 -0
  190. package/dist/tools/templates/schemas.js.map +1 -0
  191. package/dist/types.d.ts +55 -0
  192. package/dist/types.d.ts.map +1 -0
  193. package/dist/types.js +2 -0
  194. package/dist/types.js.map +1 -0
  195. package/package.json +76 -0
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Integration test setup for MCP API tests.
3
+ *
4
+ * Provides utilities for testing MCP tools against the real Kelpi HTTP API.
5
+ * These tests require both local Supabase and Next.js server running.
6
+ *
7
+ * CRITICAL: Tests only run against localhost to prevent accidents with prod/staging.
8
+ */
9
+ import { SupabaseClient } from '@supabase/supabase-js';
10
+ /**
11
+ * Validate that we're running against localhost.
12
+ * CRITICAL safety feature to prevent accidental production/staging data access.
13
+ *
14
+ * @throws Error if Supabase URL or API URL is not localhost
15
+ */
16
+ export declare function validateLocalhost(): void;
17
+ /**
18
+ * Get the Supabase client for integration tests.
19
+ * Uses service role key to bypass RLS for test setup/teardown.
20
+ *
21
+ * @returns Supabase client instance
22
+ */
23
+ export declare function getTestSupabase(): SupabaseClient;
24
+ /**
25
+ * Get the API base URL for tests.
26
+ *
27
+ * @returns API base URL (default: http://localhost:3000/api/v1)
28
+ */
29
+ export declare function getTestApiUrl(): string;
30
+ /**
31
+ * Workspace type for test context
32
+ */
33
+ export interface TestWorkspace {
34
+ id: string;
35
+ name: string;
36
+ created_at: string;
37
+ }
38
+ /**
39
+ * Create a test workspace with a unique name.
40
+ *
41
+ * @param namePrefix - Optional prefix for workspace name (default: 'MCP Test')
42
+ * @returns Created workspace
43
+ */
44
+ export declare function createTestWorkspace(namePrefix?: string): Promise<TestWorkspace>;
45
+ /**
46
+ * Delete a workspace and all related data (cascade).
47
+ * Safe to call even if workspace doesn't exist.
48
+ *
49
+ * @param workspaceId - ID of workspace to delete
50
+ */
51
+ export declare function cleanupWorkspace(workspaceId: string): Promise<void>;
52
+ /**
53
+ * API key type constants
54
+ */
55
+ export declare const KeyType: {
56
+ readonly PUBLIC: "public";
57
+ readonly SECRET: "secret";
58
+ };
59
+ export type KeyType = (typeof KeyType)[keyof typeof KeyType];
60
+ /**
61
+ * Generated API key result
62
+ */
63
+ export interface GeneratedApiKey {
64
+ /** Raw API key to use in requests */
65
+ plaintext: string;
66
+ /** Key prefix for display/debugging */
67
+ prefix: string;
68
+ /** SHA-256 hash stored in database */
69
+ hash: string;
70
+ }
71
+ /**
72
+ * Create a test API key for a workspace.
73
+ * Returns the raw (unhashed) key for use in API requests.
74
+ *
75
+ * @param workspaceId - Workspace to create key for
76
+ * @param options - Key options (type, name, revoked)
77
+ * @returns Raw API key string
78
+ */
79
+ export declare function createTestApiKey(workspaceId: string, options?: {
80
+ keyType?: KeyType;
81
+ name?: string;
82
+ revoked?: boolean;
83
+ }): Promise<string>;
84
+ /**
85
+ * Test context with workspace and API keys.
86
+ * Use this to set up and tear down test state.
87
+ */
88
+ export interface TestContext {
89
+ workspace: TestWorkspace;
90
+ secretKey: string;
91
+ publicKey: string;
92
+ cleanup: () => Promise<void>;
93
+ }
94
+ /**
95
+ * Create a complete test context with workspace and both API key types.
96
+ * Call cleanup() in afterAll/afterEach to clean up resources.
97
+ *
98
+ * @param namePrefix - Optional prefix for workspace name
99
+ * @returns Test context with workspace, keys, and cleanup function
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * describe('My tests', () => {
104
+ * let ctx: TestContext;
105
+ *
106
+ * beforeAll(async () => {
107
+ * ctx = await createTestContext();
108
+ * });
109
+ *
110
+ * afterAll(async () => {
111
+ * await ctx.cleanup();
112
+ * });
113
+ *
114
+ * it('should work', async () => {
115
+ * const response = await fetch(`${getTestApiUrl()}/contacts`, {
116
+ * headers: { Authorization: `Bearer ${ctx.secretKey}` }
117
+ * });
118
+ * });
119
+ * });
120
+ * ```
121
+ */
122
+ export declare function createTestContext(namePrefix?: string): Promise<TestContext>;
123
+ /**
124
+ * Make an authenticated API request.
125
+ *
126
+ * @param method - HTTP method
127
+ * @param path - API path (without base URL)
128
+ * @param apiKey - API key for authentication
129
+ * @param body - Optional request body
130
+ * @returns Fetch response
131
+ */
132
+ export declare function apiRequest(method: string, path: string, apiKey: string, body?: unknown): Promise<Response>;
133
+ /**
134
+ * Parse JSON response body.
135
+ * Handles non-JSON responses gracefully.
136
+ *
137
+ * @param response - Fetch response
138
+ * @returns Parsed JSON or null if not JSON
139
+ */
140
+ export declare function parseJsonResponse<T = unknown>(response: Response): Promise<T | null>;
141
+ /**
142
+ * Wait for a condition to be true, with timeout.
143
+ * Useful for testing async operations.
144
+ *
145
+ * @param condition - Async function returning boolean
146
+ * @param options - Timeout and polling interval
147
+ * @throws Error if condition not met within timeout
148
+ */
149
+ export declare function waitFor(condition: () => Promise<boolean>, options?: {
150
+ timeout?: number;
151
+ interval?: number;
152
+ }): Promise<void>;
153
+ /**
154
+ * Sleep for a specified duration.
155
+ *
156
+ * @param ms - Milliseconds to sleep
157
+ */
158
+ export declare function sleep(ms: number): Promise<void>;
159
+ /**
160
+ * Get a record by ID from any table.
161
+ *
162
+ * @param table - Table name
163
+ * @param id - Record ID
164
+ * @param workspaceId - Optional workspace ID for scoped queries
165
+ * @returns Record or null if not found
166
+ */
167
+ export declare function getById<T = unknown>(table: string, id: string, workspaceId?: string): Promise<T | null>;
168
+ /**
169
+ * Count records in a table within a workspace.
170
+ *
171
+ * @param table - Table name
172
+ * @param workspaceId - Workspace ID
173
+ * @returns Record count
174
+ */
175
+ export declare function countInWorkspace(table: string, workspaceId: string): Promise<number>;
176
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration-api/setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,329 @@
1
+ /**
2
+ * Integration test setup for MCP API tests.
3
+ *
4
+ * Provides utilities for testing MCP tools against the real Kelpi HTTP API.
5
+ * These tests require both local Supabase and Next.js server running.
6
+ *
7
+ * CRITICAL: Tests only run against localhost to prevent accidents with prod/staging.
8
+ */
9
+ import { createClient } from '@supabase/supabase-js';
10
+ import crypto from 'crypto';
11
+ // =============================================================================
12
+ // Environment validation - fail fast if misconfigured
13
+ // =============================================================================
14
+ const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL;
15
+ const SUPABASE_SERVICE_KEY = process.env.SUPABASE_SERVICE_ROLE_KEY;
16
+ const API_BASE_URL = process.env.TEST_API_URL || 'http://localhost:3000/api/v1';
17
+ /**
18
+ * Validate that we're running against localhost.
19
+ * CRITICAL safety feature to prevent accidental production/staging data access.
20
+ *
21
+ * @throws Error if Supabase URL or API URL is not localhost
22
+ */
23
+ export function validateLocalhost() {
24
+ // Validate Supabase URL
25
+ if (!SUPABASE_URL) {
26
+ throw new Error('NEXT_PUBLIC_SUPABASE_URL must be set for integration tests.\n' +
27
+ 'Make sure you have a .env or .env.local file with this variable.');
28
+ }
29
+ if (!SUPABASE_URL.includes('127.0.0.1') && !SUPABASE_URL.includes('localhost')) {
30
+ throw new Error('CRITICAL: Integration tests can only run against local Supabase.\n' +
31
+ `Got: ${SUPABASE_URL}\n\n` +
32
+ 'This safety check prevents accidental modification of production or staging data.\n' +
33
+ 'To run integration tests:\n' +
34
+ ' 1. Start local Supabase: pnpm supabase:start\n' +
35
+ ' 2. Ensure NEXT_PUBLIC_SUPABASE_URL points to localhost');
36
+ }
37
+ // Validate API URL
38
+ const apiUrl = new URL(API_BASE_URL);
39
+ if (apiUrl.hostname !== 'localhost' && apiUrl.hostname !== '127.0.0.1') {
40
+ throw new Error('CRITICAL: Integration tests can only run against local API server.\n' +
41
+ `Got: ${API_BASE_URL}\n\n` +
42
+ 'Set TEST_API_URL to a localhost URL or leave unset to use default.');
43
+ }
44
+ // Validate service key exists
45
+ if (!SUPABASE_SERVICE_KEY) {
46
+ throw new Error('SUPABASE_SERVICE_ROLE_KEY must be set for integration tests.\n' +
47
+ 'This key is needed to bypass RLS for test setup/teardown.');
48
+ }
49
+ }
50
+ // Run validation immediately when this module is imported
51
+ validateLocalhost();
52
+ // =============================================================================
53
+ // Supabase client singleton
54
+ // =============================================================================
55
+ let supabaseClient = null;
56
+ /**
57
+ * Get the Supabase client for integration tests.
58
+ * Uses service role key to bypass RLS for test setup/teardown.
59
+ *
60
+ * @returns Supabase client instance
61
+ */
62
+ export function getTestSupabase() {
63
+ if (!supabaseClient) {
64
+ supabaseClient = createClient(SUPABASE_URL, SUPABASE_SERVICE_KEY);
65
+ }
66
+ return supabaseClient;
67
+ }
68
+ /**
69
+ * Get the API base URL for tests.
70
+ *
71
+ * @returns API base URL (default: http://localhost:3000/api/v1)
72
+ */
73
+ export function getTestApiUrl() {
74
+ return API_BASE_URL;
75
+ }
76
+ /**
77
+ * Create a test workspace with a unique name.
78
+ *
79
+ * @param namePrefix - Optional prefix for workspace name (default: 'MCP Test')
80
+ * @returns Created workspace
81
+ */
82
+ export async function createTestWorkspace(namePrefix = 'MCP Test') {
83
+ const supabase = getTestSupabase();
84
+ const uniqueName = `${namePrefix} ${Date.now()}`;
85
+ const { data, error } = await supabase
86
+ .from('workspaces')
87
+ .insert({ name: uniqueName, user_id: null })
88
+ .select('id, name, created_at')
89
+ .single();
90
+ if (error) {
91
+ throw new Error(`Failed to create test workspace: ${error.message}`);
92
+ }
93
+ return data;
94
+ }
95
+ /**
96
+ * Delete a workspace and all related data (cascade).
97
+ * Safe to call even if workspace doesn't exist.
98
+ *
99
+ * @param workspaceId - ID of workspace to delete
100
+ */
101
+ export async function cleanupWorkspace(workspaceId) {
102
+ const supabase = getTestSupabase();
103
+ const { error } = await supabase.from('workspaces').delete().eq('id', workspaceId);
104
+ if (error) {
105
+ // Log but don't throw - cleanup errors shouldn't fail tests
106
+ console.error(`Warning: Failed to cleanup workspace ${workspaceId}: ${error.message}`);
107
+ }
108
+ }
109
+ // =============================================================================
110
+ // API key management
111
+ // =============================================================================
112
+ /**
113
+ * API key type constants
114
+ */
115
+ export const KeyType = {
116
+ PUBLIC: 'public',
117
+ SECRET: 'secret',
118
+ };
119
+ /**
120
+ * Hash an API key using SHA-256.
121
+ * Matches production hashing algorithm.
122
+ */
123
+ function hashApiKey(key) {
124
+ return crypto.createHash('sha256').update(key).digest('hex');
125
+ }
126
+ /**
127
+ * Generate an API key with proper format and hash.
128
+ * Matches production key generation.
129
+ *
130
+ * @param type - Key type: 'public' (klp_pk_*) or 'secret' (klp_sk_*)
131
+ * @param orgSlug - Optional org slug to embed in key
132
+ * @returns Generated key with plaintext, prefix, and hash
133
+ */
134
+ function generateApiKey(type, orgSlug) {
135
+ const keyPrefix = type === KeyType.PUBLIC ? 'klp_pk' : 'klp_sk';
136
+ const random = crypto.randomBytes(24).toString('base64url');
137
+ const sanitizedOrgSlug = orgSlug
138
+ ? orgSlug
139
+ .toLowerCase()
140
+ .replace(/[^a-z0-9]/g, '')
141
+ .slice(0, 8)
142
+ : '';
143
+ const plaintext = sanitizedOrgSlug ? `${keyPrefix}_${sanitizedOrgSlug}_${random}` : `${keyPrefix}_${random}`;
144
+ const hash = hashApiKey(plaintext);
145
+ const prefixEnd = sanitizedOrgSlug ? `${keyPrefix}_${sanitizedOrgSlug}_`.length + 4 : 16;
146
+ const displayPrefix = plaintext.substring(0, prefixEnd) + '...';
147
+ return { plaintext, prefix: displayPrefix, hash };
148
+ }
149
+ /**
150
+ * Create a test API key for a workspace.
151
+ * Returns the raw (unhashed) key for use in API requests.
152
+ *
153
+ * @param workspaceId - Workspace to create key for
154
+ * @param options - Key options (type, name, revoked)
155
+ * @returns Raw API key string
156
+ */
157
+ export async function createTestApiKey(workspaceId, options = {}) {
158
+ const supabase = getTestSupabase();
159
+ const keyType = options.keyType ?? KeyType.SECRET;
160
+ const { plaintext, prefix, hash } = generateApiKey(keyType, 'test');
161
+ // Default scopes based on key type
162
+ const scopes = keyType === KeyType.PUBLIC ? ['track'] : ['read', 'write', 'track'];
163
+ const { error } = await supabase.from('api_keys').insert({
164
+ workspace_id: workspaceId,
165
+ key_hash: hash,
166
+ key_prefix: prefix,
167
+ key_type: keyType,
168
+ scopes,
169
+ name: options.name ?? `Test ${keyType} API Key`,
170
+ revoked_at: options.revoked ? new Date().toISOString() : null,
171
+ });
172
+ if (error) {
173
+ throw new Error(`Failed to create test API key: ${error.message}`);
174
+ }
175
+ return plaintext;
176
+ }
177
+ /**
178
+ * Create a complete test context with workspace and both API key types.
179
+ * Call cleanup() in afterAll/afterEach to clean up resources.
180
+ *
181
+ * @param namePrefix - Optional prefix for workspace name
182
+ * @returns Test context with workspace, keys, and cleanup function
183
+ *
184
+ * @example
185
+ * ```ts
186
+ * describe('My tests', () => {
187
+ * let ctx: TestContext;
188
+ *
189
+ * beforeAll(async () => {
190
+ * ctx = await createTestContext();
191
+ * });
192
+ *
193
+ * afterAll(async () => {
194
+ * await ctx.cleanup();
195
+ * });
196
+ *
197
+ * it('should work', async () => {
198
+ * const response = await fetch(`${getTestApiUrl()}/contacts`, {
199
+ * headers: { Authorization: `Bearer ${ctx.secretKey}` }
200
+ * });
201
+ * });
202
+ * });
203
+ * ```
204
+ */
205
+ export async function createTestContext(namePrefix = 'MCP Test') {
206
+ const workspace = await createTestWorkspace(namePrefix);
207
+ const [secretKey, publicKey] = await Promise.all([
208
+ createTestApiKey(workspace.id, { keyType: KeyType.SECRET }),
209
+ createTestApiKey(workspace.id, { keyType: KeyType.PUBLIC }),
210
+ ]);
211
+ return {
212
+ workspace,
213
+ secretKey,
214
+ publicKey,
215
+ cleanup: async () => {
216
+ await cleanupWorkspace(workspace.id);
217
+ },
218
+ };
219
+ }
220
+ // =============================================================================
221
+ // API request helpers
222
+ // =============================================================================
223
+ /**
224
+ * Make an authenticated API request.
225
+ *
226
+ * @param method - HTTP method
227
+ * @param path - API path (without base URL)
228
+ * @param apiKey - API key for authentication
229
+ * @param body - Optional request body
230
+ * @returns Fetch response
231
+ */
232
+ export async function apiRequest(method, path, apiKey, body) {
233
+ const url = `${API_BASE_URL}${path}`;
234
+ return fetch(url, {
235
+ method,
236
+ headers: {
237
+ 'Content-Type': 'application/json',
238
+ Authorization: `Bearer ${apiKey}`,
239
+ },
240
+ body: body ? JSON.stringify(body) : undefined,
241
+ });
242
+ }
243
+ /**
244
+ * Parse JSON response body.
245
+ * Handles non-JSON responses gracefully.
246
+ *
247
+ * @param response - Fetch response
248
+ * @returns Parsed JSON or null if not JSON
249
+ */
250
+ export async function parseJsonResponse(response) {
251
+ try {
252
+ return (await response.json());
253
+ }
254
+ catch {
255
+ return null;
256
+ }
257
+ }
258
+ // =============================================================================
259
+ // Wait utilities
260
+ // =============================================================================
261
+ /**
262
+ * Wait for a condition to be true, with timeout.
263
+ * Useful for testing async operations.
264
+ *
265
+ * @param condition - Async function returning boolean
266
+ * @param options - Timeout and polling interval
267
+ * @throws Error if condition not met within timeout
268
+ */
269
+ export async function waitFor(condition, options = {}) {
270
+ const { timeout = 5000, interval = 100 } = options;
271
+ const start = Date.now();
272
+ while (Date.now() - start < timeout) {
273
+ if (await condition()) {
274
+ return;
275
+ }
276
+ await new Promise((resolve) => setTimeout(resolve, interval));
277
+ }
278
+ throw new Error(`waitFor timed out after ${timeout}ms`);
279
+ }
280
+ /**
281
+ * Sleep for a specified duration.
282
+ *
283
+ * @param ms - Milliseconds to sleep
284
+ */
285
+ export function sleep(ms) {
286
+ return new Promise((resolve) => setTimeout(resolve, ms));
287
+ }
288
+ // =============================================================================
289
+ // Database query helpers
290
+ // =============================================================================
291
+ /**
292
+ * Get a record by ID from any table.
293
+ *
294
+ * @param table - Table name
295
+ * @param id - Record ID
296
+ * @param workspaceId - Optional workspace ID for scoped queries
297
+ * @returns Record or null if not found
298
+ */
299
+ export async function getById(table, id, workspaceId) {
300
+ const supabase = getTestSupabase();
301
+ let query = supabase.from(table).select('*').eq('id', id);
302
+ if (workspaceId) {
303
+ query = query.eq('workspace_id', workspaceId);
304
+ }
305
+ const { data, error } = await query.single();
306
+ if (error && error.code !== 'PGRST116') {
307
+ throw new Error(`Failed to get ${table} by ID: ${error.message}`);
308
+ }
309
+ return data;
310
+ }
311
+ /**
312
+ * Count records in a table within a workspace.
313
+ *
314
+ * @param table - Table name
315
+ * @param workspaceId - Workspace ID
316
+ * @returns Record count
317
+ */
318
+ export async function countInWorkspace(table, workspaceId) {
319
+ const supabase = getTestSupabase();
320
+ const { count, error } = await supabase
321
+ .from(table)
322
+ .select('*', { count: 'exact', head: true })
323
+ .eq('workspace_id', workspaceId);
324
+ if (error) {
325
+ throw new Error(`Failed to count ${table}: ${error.message}`);
326
+ }
327
+ return count ?? 0;
328
+ }
329
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/__tests__/integration-api/setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/__tests__/setup.ts"],"names":[],"mappings":""}
@@ -0,0 +1,11 @@
1
+ import { vi, beforeEach, afterEach } from 'vitest';
2
+ beforeEach(() => {
3
+ vi.clearAllMocks();
4
+ });
5
+ afterEach(() => {
6
+ // Clean up any environment variables set during tests
7
+ delete process.env.KELPI_API_KEY;
8
+ delete process.env.KELPI_API_URL;
9
+ delete process.env.KELPI_CONFIG_PATH;
10
+ });
11
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/__tests__/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEnD,UAAU,CAAC,GAAG,EAAE;IACd,EAAE,CAAC,aAAa,EAAE,CAAC;AACrB,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,GAAG,EAAE;IACb,sDAAsD;IACtD,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IACjC,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IACjC,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACvC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { vi } from 'vitest';
2
+ /**
3
+ * Type for mocked API client methods
4
+ */
5
+ export type MockApiClient = {
6
+ get: ReturnType<typeof vi.fn>;
7
+ post: ReturnType<typeof vi.fn>;
8
+ put: ReturnType<typeof vi.fn>;
9
+ patch: ReturnType<typeof vi.fn>;
10
+ delete: ReturnType<typeof vi.fn>;
11
+ };
12
+ /**
13
+ * Creates a fresh mock API client with all methods as vi.fn()
14
+ */
15
+ export declare function createMockApiClient(): MockApiClient;
16
+ /**
17
+ * Standard config path for tests
18
+ */
19
+ export declare const CONFIG_PATH: string;
20
+ /**
21
+ * Clears all Kelpi-related environment variables
22
+ */
23
+ export declare function clearKelpiEnv(): void;
24
+ /**
25
+ * Sets up a mock config file with the given API key
26
+ */
27
+ export declare function setupMockConfig(apiKey: string, extraConfig?: Record<string, unknown>): void;
28
+ /**
29
+ * Parses the text content from a tool result as JSON
30
+ */
31
+ export declare function parseToolResultJson<T = unknown>(result: {
32
+ content: Array<{
33
+ type: string;
34
+ text?: string;
35
+ }>;
36
+ }): T;
37
+ /**
38
+ * Gets the raw text content from a tool result
39
+ */
40
+ export declare function getToolResultText(result: {
41
+ content: Array<{
42
+ type: string;
43
+ text?: string;
44
+ }>;
45
+ }): string;
46
+ //# sourceMappingURL=test-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/test-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAK5B;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/B,GAAG,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,KAAK,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAChC,MAAM,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;CAClC,CAAC;AAEF;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,aAAa,CAQnD;AAED;;GAEG;AACH,eAAO,MAAM,WAAW,QAAgD,CAAC;AAEzE;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAIpC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI,CAI/F;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE;IACvD,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjD,GAAG,CAAC,CAGJ;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjD,GAAG,MAAM,CAET"}
@@ -0,0 +1,50 @@
1
+ import { vi } from 'vitest';
2
+ import { vol } from 'memfs';
3
+ import path from 'path';
4
+ import { homedir } from 'os';
5
+ /**
6
+ * Creates a fresh mock API client with all methods as vi.fn()
7
+ */
8
+ export function createMockApiClient() {
9
+ return {
10
+ get: vi.fn(),
11
+ post: vi.fn(),
12
+ put: vi.fn(),
13
+ patch: vi.fn(),
14
+ delete: vi.fn(),
15
+ };
16
+ }
17
+ /**
18
+ * Standard config path for tests
19
+ */
20
+ export const CONFIG_PATH = path.join(homedir(), '.kelpi', 'config.json');
21
+ /**
22
+ * Clears all Kelpi-related environment variables
23
+ */
24
+ export function clearKelpiEnv() {
25
+ delete process.env.KELPI_API_KEY;
26
+ delete process.env.KELPI_API_URL;
27
+ delete process.env.KELPI_CONFIG_PATH;
28
+ }
29
+ /**
30
+ * Sets up a mock config file with the given API key
31
+ */
32
+ export function setupMockConfig(apiKey, extraConfig = {}) {
33
+ vol.fromJSON({
34
+ [CONFIG_PATH]: JSON.stringify({ api_key: apiKey, ...extraConfig }),
35
+ });
36
+ }
37
+ /**
38
+ * Parses the text content from a tool result as JSON
39
+ */
40
+ export function parseToolResultJson(result) {
41
+ const textContent = result.content[0]?.text ?? '';
42
+ return JSON.parse(textContent);
43
+ }
44
+ /**
45
+ * Gets the raw text content from a tool result
46
+ */
47
+ export function getToolResultText(result) {
48
+ return result.content[0]?.text ?? '';
49
+ }
50
+ //# sourceMappingURL=test-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../../src/__tests__/unit/test-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAa7B;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;QACZ,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;QACb,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;QACZ,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;QACd,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE;KAChB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;AAEzE;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IACjC,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IACjC,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,cAAuC,EAAE;IACvF,GAAG,CAAC,QAAQ,CAAC;QACX,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;KACnE,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAc,MAEhD;IACC,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;IAClD,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAM,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAEjC;IACC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;AACvC,CAAC"}
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ export { KelpiMcpServer, createServer, type ServerOptions } from './server.js';
3
+ export { ToolRegistry, ToolRegistryError } from './lib/tool-registry.js';
4
+ export type { ToolDefinition, ToolHandler, ToolResult, McpTool, RegisteredTool, ValidationResult, } from './lib/tool-registry.js';
5
+ export { ALL_TOOLS, TOOL_DEFINITIONS, TOOL_NAMES, type ToolWithHandler, } from './tools/index.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAoCA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AACzE,YAAY,EACV,cAAc,EACd,WAAW,EACX,UAAU,EACV,OAAO,EACP,cAAc,EACd,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC"}