@quarri/claude-data-tools 1.0.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,19 @@
1
+ {
2
+ "name": "quarri",
3
+ "displayName": "Quarri Data Assistant",
4
+ "version": "1.0.0",
5
+ "description": "Natural language data analysis with Quarri. Query databases, create visualizations, and get insights using plain English.",
6
+ "publisher": "quarri",
7
+ "repository": "https://github.com/quarri-ai/quarri-claude-plugin",
8
+ "homepage": "https://quarri.ai",
9
+ "icon": "https://quarri.ai/logo.png",
10
+ "categories": ["Data & Analytics", "Developer Tools"],
11
+ "keywords": ["sql", "data", "analytics", "visualization", "database"],
12
+ "mcpServers": {
13
+ "quarri": {
14
+ "command": "node",
15
+ "args": ["${pluginDir}/dist/index.js"]
16
+ }
17
+ },
18
+ "skills": ["quarri-guide"]
19
+ }
package/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # Quarri Claude Code Plugin
2
+
3
+ Natural language data analysis with Quarri. Query databases, create visualizations, and get insights using plain English.
4
+
5
+ ## Installation
6
+
7
+ ### Via Claude Code Marketplace
8
+
9
+ ```bash
10
+ claude /install quarri
11
+ ```
12
+
13
+ ### Manual Installation
14
+
15
+ ```bash
16
+ npm install -g @anthropic/quarri
17
+ ```
18
+
19
+ Then add to your Claude Code configuration:
20
+
21
+ ```json
22
+ {
23
+ "mcpServers": {
24
+ "quarri": {
25
+ "command": "quarri-mcp"
26
+ }
27
+ }
28
+ }
29
+ ```
30
+
31
+ ## Authentication
32
+
33
+ On first use, you'll be prompted to authenticate:
34
+
35
+ ### Existing Quarri Users
36
+
37
+ 1. Enter your email address
38
+ 2. Check your email for a 6-digit verification code
39
+ 3. Enter the code to complete authentication
40
+
41
+ ### New Users (with invitation)
42
+
43
+ 1. Select "invite" when prompted
44
+ 2. Enter your email address
45
+ 3. Enter the invitation token from your admin's email
46
+ 4. Your account will be created automatically
47
+
48
+ ## Features
49
+
50
+ ### 47 Tools for Data Analysis
51
+
52
+ **Sub-Agents (12):**
53
+ - `quarri_query_agent` - Generate SQL from natural language
54
+ - `quarri_explain_agent` - Explain SQL queries
55
+ - `quarri_chart_agent` - Generate visualizations
56
+ - `quarri_metric_builder_agent` - Define metrics interactively
57
+ - `quarri_planning_agent` - Create analysis plans
58
+ - `quarri_insight_agent` - Generate actionable insights
59
+ - `quarri_stats_agent` - Statistical analysis
60
+ - `quarri_staging_agent` - Stage raw data
61
+ - `quarri_modeling_agent` - Design data models
62
+ - `quarri_transformers_agent` - Generate transformation SQL
63
+ - `quarri_extraction_agent` - Create data pipelines
64
+ - `quarri_query_with_analysis` - Full analysis pipeline
65
+
66
+ **Data Tools (8):**
67
+ - `quarri_execute_sql` - Run SQL queries
68
+ - `quarri_get_schema` - View database schema
69
+ - `quarri_search_values` - Semantic search
70
+ - `quarri_get_metrics`, `quarri_create_metric`, `quarri_approve_metric`
71
+ - `quarri_get_metric_detail`, `quarri_search_metrics`
72
+
73
+ **Configuration (8):**
74
+ - `quarri_list_agent_prompts`, `quarri_update_agent_prompt`
75
+ - `quarri_list_rules`, `quarri_create_rule`, `quarri_update_rule`, `quarri_delete_rule`
76
+ - `quarri_vectorize_column_values`, `quarri_list_searchable_columns`
77
+
78
+ **Canvas (5):**
79
+ - `quarri_list_canvases`, `quarri_get_canvas`
80
+ - `quarri_create_chart_panel`, `quarri_update_chart_panel`
81
+ - `quarri_export_canvas`
82
+
83
+ **Team (3):**
84
+ - `quarri_list_teams`, `quarri_get_team_filters`, `quarri_get_team_restrictions`
85
+
86
+ **Extraction (7):**
87
+ - `quarri_list_extraction_sources`, `quarri_configure_extraction`
88
+ - `quarri_discover_tables`, `quarri_propose_transformation`
89
+ - `quarri_upload_csv`, `quarri_generate_quarri_schema`, `quarri_list_raw_tables`
90
+
91
+ **Debug (3):**
92
+ - `quarri_read_server_logs`, `quarri_query_repl_activity`, `quarri_read_fly_logs`
93
+
94
+ **Session (2):**
95
+ - `quarri_list_databases`, `quarri_select_database`
96
+
97
+ ## Usage Examples
98
+
99
+ ### Ask a Data Question
100
+
101
+ ```
102
+ What were our top 10 products by revenue last month?
103
+ ```
104
+
105
+ Claude will use `quarri_query_with_analysis` to:
106
+ 1. Generate SQL from your question
107
+ 2. Execute the query
108
+ 3. Perform statistical analysis
109
+ 4. Generate a chart
110
+ 5. Provide key insights
111
+
112
+ ### Create a Metric
113
+
114
+ ```
115
+ Help me define a metric for customer lifetime value
116
+ ```
117
+
118
+ Claude will guide you through defining the metric using `quarri_metric_builder_agent`.
119
+
120
+ ### Configure Semantic Search
121
+
122
+ ```
123
+ Enable semantic search on the product_name column
124
+ ```
125
+
126
+ Claude will use `quarri_vectorize_column_values` to enable natural language search.
127
+
128
+ ## Configuration
129
+
130
+ Credentials are stored in `~/.quarri/credentials` with secure permissions (0600).
131
+
132
+ ### Environment Variables
133
+
134
+ - `QUARRI_API_URL` - API endpoint (default: https://app.quarri.ai)
135
+
136
+ ## Development
137
+
138
+ ### Building
139
+
140
+ ```bash
141
+ npm install
142
+ npm run build
143
+ ```
144
+
145
+ ### Testing
146
+
147
+ ```bash
148
+ npm test
149
+ ```
150
+
151
+ ### Local Development
152
+
153
+ ```bash
154
+ npm run dev
155
+ ```
156
+
157
+ ## License
158
+
159
+ MIT
160
+
161
+ ## Support
162
+
163
+ - GitHub Issues: https://github.com/quarri-ai/quarri-claude-plugin/issues
164
+ - Documentation: https://docs.quarri.ai
165
+ - Email: support@quarri.ai
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Quarri API Client
3
+ * HTTP client for communicating with the Quarri backend
4
+ */
5
+ interface ApiResponse<T = unknown> {
6
+ success: boolean;
7
+ error?: string;
8
+ data?: T;
9
+ }
10
+ interface AuthResponse {
11
+ success: boolean;
12
+ error?: string;
13
+ token?: string;
14
+ expiresAt?: string;
15
+ user?: {
16
+ email: string;
17
+ role: string;
18
+ user_id?: number;
19
+ };
20
+ databases?: Array<{
21
+ database_name: string;
22
+ display_name: string;
23
+ access_level: string;
24
+ }>;
25
+ }
26
+ interface ToolResult {
27
+ success: boolean;
28
+ error?: string;
29
+ [key: string]: unknown;
30
+ }
31
+ export declare class QuarriApiClient {
32
+ private baseUrl;
33
+ private token;
34
+ constructor(baseUrl?: string);
35
+ /**
36
+ * Set the authentication token
37
+ */
38
+ setToken(token: string): void;
39
+ /**
40
+ * Make an HTTP request to the API
41
+ */
42
+ private request;
43
+ /**
44
+ * Request a verification code for CLI authentication
45
+ */
46
+ requestVerificationCode(email: string): Promise<AuthResponse>;
47
+ /**
48
+ * Verify a code and get an API token
49
+ */
50
+ verifyCode(email: string, code: string): Promise<AuthResponse>;
51
+ /**
52
+ * Verify an invitation token for new users
53
+ */
54
+ verifyInvite(email: string, inviteToken: string): Promise<AuthResponse>;
55
+ /**
56
+ * Validate an existing token
57
+ */
58
+ validateToken(token: string): Promise<AuthResponse>;
59
+ /**
60
+ * List available tools
61
+ */
62
+ listTools(): Promise<ApiResponse<{
63
+ tools: unknown[];
64
+ count: number;
65
+ }>>;
66
+ /**
67
+ * Get tool schema
68
+ */
69
+ getToolSchema(toolName: string): Promise<ApiResponse<{
70
+ tool: unknown;
71
+ }>>;
72
+ /**
73
+ * Execute a tool
74
+ */
75
+ executeTool(toolName: string, args: Record<string, unknown>, databaseName?: string): Promise<ToolResult>;
76
+ /**
77
+ * List user's databases
78
+ */
79
+ listDatabases(): Promise<ApiResponse<{
80
+ databases: Array<{
81
+ database_name: string;
82
+ display_name: string;
83
+ access_level: string;
84
+ }>;
85
+ }>>;
86
+ /**
87
+ * Execute multiple tools in batch
88
+ */
89
+ executeBatch(tools: Array<{
90
+ name: string;
91
+ args: Record<string, unknown>;
92
+ }>, databaseName?: string, stopOnError?: boolean): Promise<ApiResponse<{
93
+ results: ToolResult[];
94
+ }>>;
95
+ /**
96
+ * Health check
97
+ */
98
+ healthCheck(): Promise<ApiResponse<{
99
+ tool_count: number;
100
+ }>>;
101
+ }
102
+ export {};
103
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,UAAU,WAAW,CAAC,CAAC,GAAG,OAAO;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,CAAC,CAAC;CACV;AAED,UAAU,YAAY;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,SAAS,CAAC,EAAE,KAAK,CAAC;QAChB,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;CACJ;AAED,UAAU,UAAU;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAuB;gBAExB,OAAO,CAAC,EAAE,MAAM;IAI5B;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7B;;OAEG;YACW,OAAO;IAwCrB;;OAEG;IACG,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAenE;;OAEG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAsBpE;;OAEG;IACG,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAsB7E;;OAEG;IACG,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IA2BzD;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,WAAW,CAAC;QAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAI5E;;OAEG;IACG,aAAa,CACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAI1C;;OAEG;IACG,WAAW,CACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,UAAU,CAAC;IAmBtB;;OAEG;IACG,aAAa,IAAI,OAAO,CAC5B,WAAW,CAAC;QACV,SAAS,EAAE,KAAK,CAAC;YACf,aAAa,EAAE,MAAM,CAAC;YACtB,YAAY,EAAE,MAAM,CAAC;YACrB,YAAY,EAAE,MAAM,CAAC;SACtB,CAAC,CAAC;KACJ,CAAC,CACH;IAID;;OAEG;IACG,YAAY,CAChB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,EAC7D,YAAY,CAAC,EAAE,MAAM,EACrB,WAAW,UAAQ,GAClB,OAAO,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC,CAAC;IASlD;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAGlE"}
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ /**
3
+ * Quarri API Client
4
+ * HTTP client for communicating with the Quarri backend
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.QuarriApiClient = void 0;
8
+ const DEFAULT_API_URL = 'https://app.quarri.ai';
9
+ class QuarriApiClient {
10
+ baseUrl;
11
+ token = null;
12
+ constructor(baseUrl) {
13
+ this.baseUrl = baseUrl || process.env.QUARRI_API_URL || DEFAULT_API_URL;
14
+ }
15
+ /**
16
+ * Set the authentication token
17
+ */
18
+ setToken(token) {
19
+ this.token = token;
20
+ }
21
+ /**
22
+ * Make an HTTP request to the API
23
+ */
24
+ async request(method, path, body, useAuth = true) {
25
+ const url = `${this.baseUrl}${path}`;
26
+ const headers = {
27
+ 'Content-Type': 'application/json',
28
+ };
29
+ if (useAuth && this.token) {
30
+ headers['Authorization'] = `Bearer ${this.token}`;
31
+ }
32
+ try {
33
+ const response = await fetch(url, {
34
+ method,
35
+ headers,
36
+ body: body ? JSON.stringify(body) : undefined,
37
+ });
38
+ const data = await response.json();
39
+ if (!response.ok) {
40
+ return {
41
+ success: false,
42
+ error: data.error || `HTTP ${response.status}: ${response.statusText}`,
43
+ };
44
+ }
45
+ return { success: true, data: data };
46
+ }
47
+ catch (error) {
48
+ const message = error instanceof Error ? error.message : 'Unknown error';
49
+ return { success: false, error: message };
50
+ }
51
+ }
52
+ // ==================== Auth Methods ====================
53
+ /**
54
+ * Request a verification code for CLI authentication
55
+ */
56
+ async requestVerificationCode(email) {
57
+ const result = await this.request('POST', '/api/auth/cli/request-code', { email }, false);
58
+ if (!result.success) {
59
+ return { success: false, error: result.error };
60
+ }
61
+ return { success: true, ...result.data };
62
+ }
63
+ /**
64
+ * Verify a code and get an API token
65
+ */
66
+ async verifyCode(email, code) {
67
+ const result = await this.request('POST', '/api/auth/cli/verify-code', { email, code }, false);
68
+ if (!result.success) {
69
+ return { success: false, error: result.error };
70
+ }
71
+ const data = result.data;
72
+ return {
73
+ success: true,
74
+ token: data.token,
75
+ expiresAt: data.expiresAt,
76
+ user: data.user,
77
+ databases: data.databases,
78
+ };
79
+ }
80
+ /**
81
+ * Verify an invitation token for new users
82
+ */
83
+ async verifyInvite(email, inviteToken) {
84
+ const result = await this.request('POST', '/api/auth/cli/verify-invite', { email, invite_token: inviteToken }, false);
85
+ if (!result.success) {
86
+ return { success: false, error: result.error };
87
+ }
88
+ const data = result.data;
89
+ return {
90
+ success: true,
91
+ token: data.token,
92
+ expiresAt: data.expiresAt,
93
+ user: data.user,
94
+ databases: data.databases,
95
+ };
96
+ }
97
+ /**
98
+ * Validate an existing token
99
+ */
100
+ async validateToken(token) {
101
+ const oldToken = this.token;
102
+ this.token = token;
103
+ const result = await this.request('POST', '/api/auth/cli/validate-token', {}, true);
104
+ this.token = oldToken;
105
+ if (!result.success) {
106
+ return { success: false, error: result.error };
107
+ }
108
+ const data = result.data;
109
+ return {
110
+ success: true,
111
+ user: data.user,
112
+ databases: data.databases,
113
+ };
114
+ }
115
+ // ==================== Tool Methods ====================
116
+ /**
117
+ * List available tools
118
+ */
119
+ async listTools() {
120
+ return this.request('GET', '/api/cli/tools');
121
+ }
122
+ /**
123
+ * Get tool schema
124
+ */
125
+ async getToolSchema(toolName) {
126
+ return this.request('GET', `/api/cli/tools/${toolName}`);
127
+ }
128
+ /**
129
+ * Execute a tool
130
+ */
131
+ async executeTool(toolName, args, databaseName) {
132
+ const body = { args };
133
+ if (databaseName) {
134
+ body.database_name = databaseName;
135
+ }
136
+ const result = await this.request('POST', `/api/cli/tool/${toolName}`, body);
137
+ if (!result.success) {
138
+ return { success: false, error: result.error };
139
+ }
140
+ return result.data;
141
+ }
142
+ /**
143
+ * List user's databases
144
+ */
145
+ async listDatabases() {
146
+ return this.request('GET', '/api/cli/databases');
147
+ }
148
+ /**
149
+ * Execute multiple tools in batch
150
+ */
151
+ async executeBatch(tools, databaseName, stopOnError = false) {
152
+ const body = { tools, stop_on_error: stopOnError };
153
+ if (databaseName) {
154
+ body.database_name = databaseName;
155
+ }
156
+ return this.request('POST', '/api/cli/batch', body);
157
+ }
158
+ /**
159
+ * Health check
160
+ */
161
+ async healthCheck() {
162
+ return this.request('GET', '/api/cli/health', undefined, false);
163
+ }
164
+ }
165
+ exports.QuarriApiClient = QuarriApiClient;
166
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * CLI Authentication flow for Quarri
3
+ * Handles both existing users (email + code) and new users (email + invite token)
4
+ */
5
+ import { QuarriApiClient } from '../api/client.js';
6
+ import { StoredCredentials } from './token-store.js';
7
+ /**
8
+ * Run the interactive authentication flow
9
+ */
10
+ export declare function runAuthFlow(client: QuarriApiClient): Promise<StoredCredentials | null>;
11
+ /**
12
+ * Validate an existing token
13
+ */
14
+ export declare function validateToken(client: QuarriApiClient, token: string): Promise<boolean>;
15
+ //# sourceMappingURL=cli-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-auth.d.ts","sourceRoot":"","sources":["../../src/auth/cli-auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAmB,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAuBtE;;GAEG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAiC5F;AAkGD;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC,CAGlB"}
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ /**
3
+ * CLI Authentication flow for Quarri
4
+ * Handles both existing users (email + code) and new users (email + invite token)
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.runAuthFlow = runAuthFlow;
41
+ exports.validateToken = validateToken;
42
+ const readline = __importStar(require("readline"));
43
+ const token_store_js_1 = require("./token-store.js");
44
+ /**
45
+ * Create a readline interface for user input
46
+ */
47
+ function createReadline() {
48
+ return readline.createInterface({
49
+ input: process.stdin,
50
+ output: process.stderr, // Use stderr so it doesn't interfere with MCP protocol
51
+ });
52
+ }
53
+ /**
54
+ * Prompt user for input
55
+ */
56
+ async function prompt(rl, question) {
57
+ return new Promise((resolve) => {
58
+ rl.question(question, (answer) => {
59
+ resolve(answer.trim());
60
+ });
61
+ });
62
+ }
63
+ /**
64
+ * Run the interactive authentication flow
65
+ */
66
+ async function runAuthFlow(client) {
67
+ const rl = createReadline();
68
+ try {
69
+ console.error('\n=== Quarri CLI Authentication ===\n');
70
+ // Ask if user has an account or invite
71
+ const authType = await prompt(rl, 'Do you have a Quarri account? (yes/no/invite): ');
72
+ const email = await prompt(rl, 'Enter your email address: ');
73
+ if (!email || !email.includes('@')) {
74
+ console.error('Invalid email address');
75
+ return null;
76
+ }
77
+ if (authType.toLowerCase() === 'invite' || authType.toLowerCase() === 'i') {
78
+ // New user with invitation
79
+ return await handleInviteAuth(rl, client, email);
80
+ }
81
+ else if (authType.toLowerCase() === 'yes' || authType.toLowerCase() === 'y') {
82
+ // Existing user
83
+ return await handleExistingUserAuth(rl, client, email);
84
+ }
85
+ else {
86
+ console.error('\nYou need either an existing Quarri account or an invitation.');
87
+ console.error('Contact your administrator for an invitation.');
88
+ return null;
89
+ }
90
+ }
91
+ finally {
92
+ rl.close();
93
+ }
94
+ }
95
+ /**
96
+ * Handle authentication for existing users (email + verification code)
97
+ */
98
+ async function handleExistingUserAuth(rl, client, email) {
99
+ console.error('\nRequesting verification code...');
100
+ // Request verification code
101
+ const requestResult = await client.requestVerificationCode(email);
102
+ if (!requestResult.success) {
103
+ console.error(`Failed to request code: ${requestResult.error}`);
104
+ return null;
105
+ }
106
+ console.error('Verification code sent to your email.');
107
+ const code = await prompt(rl, 'Enter the 6-digit verification code: ');
108
+ if (!code || code.length !== 6) {
109
+ console.error('Invalid verification code');
110
+ return null;
111
+ }
112
+ // Verify code and get token
113
+ console.error('Verifying code...');
114
+ const verifyResult = await client.verifyCode(email, code);
115
+ if (!verifyResult.success) {
116
+ console.error(`Verification failed: ${verifyResult.error}`);
117
+ return null;
118
+ }
119
+ // Save credentials
120
+ const credentials = {
121
+ token: verifyResult.token,
122
+ email: verifyResult.user.email,
123
+ role: verifyResult.user.role,
124
+ databases: verifyResult.databases,
125
+ expiresAt: verifyResult.expiresAt,
126
+ };
127
+ (0, token_store_js_1.saveCredentials)(credentials);
128
+ console.error(`\nAuthenticated successfully as ${email}!`);
129
+ console.error(`Role: ${credentials.role}`);
130
+ console.error(`Databases: ${credentials.databases.map((d) => d.database_name).join(', ')}`);
131
+ return credentials;
132
+ }
133
+ /**
134
+ * Handle authentication for new users with invitation token
135
+ */
136
+ async function handleInviteAuth(rl, client, email) {
137
+ const inviteToken = await prompt(rl, 'Enter your invitation token (from the invite email): ');
138
+ if (!inviteToken) {
139
+ console.error('Invitation token is required');
140
+ return null;
141
+ }
142
+ console.error('\nVerifying invitation...');
143
+ const verifyResult = await client.verifyInvite(email, inviteToken);
144
+ if (!verifyResult.success) {
145
+ console.error(`Invitation verification failed: ${verifyResult.error}`);
146
+ return null;
147
+ }
148
+ // Save credentials
149
+ const credentials = {
150
+ token: verifyResult.token,
151
+ email: verifyResult.user.email,
152
+ role: verifyResult.user.role,
153
+ databases: verifyResult.databases,
154
+ expiresAt: verifyResult.expiresAt,
155
+ };
156
+ (0, token_store_js_1.saveCredentials)(credentials);
157
+ console.error(`\nAccount created and authenticated successfully!`);
158
+ console.error(`Email: ${email}`);
159
+ console.error(`Role: ${credentials.role}`);
160
+ console.error(`Databases: ${credentials.databases.map((d) => d.database_name).join(', ')}`);
161
+ return credentials;
162
+ }
163
+ /**
164
+ * Validate an existing token
165
+ */
166
+ async function validateToken(client, token) {
167
+ const result = await client.validateToken(token);
168
+ return result.success;
169
+ }
170
+ //# sourceMappingURL=cli-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-auth.js","sourceRoot":"","sources":["../../src/auth/cli-auth.ts"],"names":[],"mappings":"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"}