collectlie
Version:
TypeScript SDK for Collectlie - flexible data collection platform with custom types, schema validation, and Supabase backend integration
697 lines (576 loc) • 17.5 kB
Markdown
# Getting Started with Collectlie
Ultra-minimal TypeScript SDK for flexible user submission platform. Only one method to learn: `submit()`.
## Installation
```bash
npm install collectlie
```
## Environment Setup
### 1. Create .env file
```bash
# Copy from .env.example
cp .env.example .env
```
### 2. Add your credentials
```env
# Your project credentials from the dashboard
COLLECTLIE_PROJECT_ID=your_project_id_here
COLLECTLIE_API_KEY=proj_your_api_key_here
# Optional settings
NODE_ENV=development
```
### 3. Environment Detection
The SDK automatically detects environment variables based on your platform:
- **Node.js**: `COLLECTLIE_PROJECT_ID`, `COLLECTLIE_API_KEY`
- **Vite**: `VITE_COLLECTLIE_PROJECT_ID`, `VITE_COLLECTLIE_API_KEY`
- **React**: `REACT_APP_COLLECTLIE_PROJECT_ID`, `REACT_APP_COLLECTLIE_API_KEY`
- **Next.js**: `NEXT_PUBLIC_COLLECTLIE_PROJECT_ID`, `NEXT_PUBLIC_COLLECTLIE_API_KEY`
### 4. Manual Configuration (Alternative)
If environment variables aren't available, you can pass credentials manually:
```javascript
const collectlie = new Collectlie({
projectId: 'your_project_id',
apiKey: 'proj_your_api_key'
});
```
## Quick Start Examples
### Option 1: Full SDK Import
```javascript
import { Collectlie } from 'collectlie';
// SDK automatically picks up environment variables
const collectlie = new Collectlie();
// Basic submission
await collectlie.submit({
type: 'issue',
title: 'Bug Report',
content: 'Found a bug in the checkout process',
author: {
email: 'user@example.com',
name: 'John Doe'
}
});
// With automatic data gathering (recommended)
await collectlie.submit({
type: 'issue',
title: 'Performance Issue',
content: 'Page loads slowly on mobile',
author: {
email: 'user@example.com'
}
}, true); // Automatically gather browser, device, source, performance, error data
// With selective data gathering
await collectlie.submit({
type: 'issue',
title: 'UI Layout Problem',
content: 'Button overlaps text on small screens'
}, {
browser: { viewport: true, screen: true }, // Just dimensions
device: { deviceType: true }, // Just mobile/desktop
source: { url: true, title: true } // Just URL and page title
});
// Submit with tags
await collectlie.submit({
type: 'feature',
title: 'Add dark mode',
content: 'Users are requesting a dark theme option',
tags: ['feature', 'ui', 'theme'] // Multiple tags
});
// Submit with single tag
await collectlie.submit({
type: 'issue',
title: 'Login problem',
content: 'Cannot authenticate with Google',
tags: 'authentication' // Single tag
});
```
### Option 2: Standalone Submit Function
```javascript
import { submit } from 'collectlie';
// Basic submission (uses environment variables)
await submit({
type: 'issue',
title: 'Bug Report',
content: 'Found a bug in the checkout process',
author: {
email: 'user@example.com',
name: 'John Doe'
}
});
// With automatic data gathering
await submit({
type: 'feature',
title: 'Add dark mode',
content: 'Users are requesting a dark theme option',
tags: ['feature', 'ui', 'theme']
}, {
browser: true, // All browser info
device: true, // All device info
performance: true // All performance data
});
// With explicit configuration (legacy)
await submit({
type: 'feedback',
title: 'Great app!',
content: 'Love the new features'
}, {
projectId: 'your-project-id',
apiKey: 'proj-your-api-key'
});
```
### File Upload Examples
```javascript
// Submit with file attachments
const fileInput = document.querySelector('#screenshot');
const file = fileInput.files[0];
if (file) {
await collectlie.submit({
type: 'bug',
title: 'UI Issue with Screenshot',
content: 'Button is not aligned properly on mobile',
author: {
email: 'user@example.com'
},
attachments: [{
filename: file.name,
data: file
}]
});
}
```
### React Integration
```jsx
import React, { useState } from 'react';
import { Collectlie } from 'collectlie';
// Initialize SDK (uses environment variables)
const collectlie = new Collectlie();
function SubmissionForm() {
const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState(null);
const handleSubmit = async (e) => {
e.preventDefault();
setIsSubmitting(true);
setError(null);
try {
const result = await collectlie.submit({
type: 'feedback',
title: 'User Feedback',
content: 'This is great!',
// Custom fields
source: 'react_form',
component: 'SubmissionForm'
}, {
// Automatically gather technical context (recommended)
browser: true, // Browser info and capabilities
device: true, // Device type and screen info
source: true, // Current page URL and title
performance: true // Page load time and performance data
});
console.log('Submitted:', result);
} catch (err) {
setError(err.message);
} finally {
setIsSubmitting(false);
}
};
return (
<form onSubmit={handleSubmit}>
{error && <div className="error">{error}</div>}
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? 'Submitting...' : 'Submit'}
</button>
</form>
);
}
```
### Node.js
```javascript
const { Collectlie } = require('collectlie');
const collectlie = new Collectlie();
// Submit server-side data
await collectlie.submit({
type: 'server_log',
title: 'Error Report',
content: 'Server error occurred during processing',
metadata: {
error_code: 500,
timestamp: new Date().toISOString(),
server_id: 'web-01'
}
});
```
## Basic Usage Patterns
### Simple Submission
```typescript
await collectlie.submit({
type: 'issue',
title: 'Bug Report',
content: 'Description of the issue',
author: {
email: 'user@example.com'
}
});
```
### Submission with Custom Fields
```typescript
await collectlie.submit({
type: 'feedback',
title: 'User Feedback',
content: 'This is great!',
author: {
email: 'user@example.com',
name: 'Jane Smith'
},
metadata: {
priority: 'high',
category: 'ui',
browser: 'Chrome',
version: '1.2.3'
}
});
```
### File Upload Examples
#### Simple File Upload
```typescript
// Single file upload
const fileInput = document.querySelector('#file-input') as HTMLInputElement;
const selectedFile = fileInput.files?.[0];
if (selectedFile) {
await collectlie.submit({
type: 'bug',
title: 'Error Screenshot',
content: 'Application crashes when clicking save button',
author: {
email: 'tester@company.com'
},
attachments: [{
filename: selectedFile.name,
data: selectedFile
}]
});
}
```
#### Multiple File Upload
```typescript
// Multiple files from input
const fileInput = document.querySelector('#files') as HTMLInputElement;
const files = Array.from(fileInput.files || []);
await collectlie.submit({
type: 'feature',
title: 'Feature Request with Mockups',
content: 'Please implement dark mode as shown in attached designs',
author: {
email: 'designer@company.com',
name: 'Sarah Designer'
},
attachments: files.map(file => ({
filename: file.name,
mimeType: file.type,
data: file
}))
});
```
#### File Upload with Configuration
```typescript
// Note: Backend enforces all file limits (1MB, images only)
// No client-side validation - maximum freedom for users
const sdk = new Collectlie({
// All file validation handled by backend
// Users can attach any files they want
});
// Upload any files - backend validates
try {
await collectlie.submit({
type: 'feedback',
title: 'Feedback with Documents',
content: 'Please review the attached specifications',
attachments: [{
filename: 'requirements.pdf',
data: pdfFile
}]
});
console.log('Upload successful!');
} catch (error) {
if (error.message.includes('file size')) {
console.error('File too large');
} else if (error.message.includes('file type')) {
console.error('File type not supported');
}
}
```
```
### Submission with Metadata
```typescript
await collectlie.submit({
type: 'rating',
title: 'App Rating',
metadata: {
rating: 5,
category: 'overall'
}
}, {
metadata: {
source: 'mobile_app',
user_id: 'user_123',
session_id: 'session_abc'
}
});
```
## Data Types Overview
### SubmissionData
```typescript
interface SubmissionData {
type: string; // Required: submission type
title?: string; // Optional: submission title
content?: string; // Optional: main content
author?: AuthorInfo; // Optional: author information
metadata?: Record<string, any>; // Optional: any metadata
attachments?: AttachmentInfo[]; // Optional: file attachments
}
interface AttachmentInfo {
filename: string; // Original filename
mimeType?: string; // MIME type (auto-detected)
size?: number; // File size in bytes
data?: File | Blob; // File data for upload
url?: string; // URL of existing file
}
interface AuthorInfo {
email?: string; // Author's email address
name?: string; // Author's display name
avatar?: string; // URL to author's avatar
userId?: string; // Internal user ID
username?: string; // Author's username
}
```
### SubmissionConfig
```typescript
interface SubmissionConfig {
projectId?: string; // Project ID (auto-detected from env)
apiKey?: string; // API key (auto-detected from env)
// File Upload Configuration (backend enforced)
maxFileSize?: number; // Informational: backend enforces 1MB
allowedFileTypes?: string[]; // Informational: backend enforces images only
}
```
## Error Handling
```typescript
try {
await collectlie.submit(data);
} catch (error) {
if (error.message.includes('Validation failed')) {
// Handle validation errors
console.error('Data validation failed:', error.message);
} else if (error.message.includes('401') || error.message.includes('403')) {
// Handle authentication errors
console.error('Authentication failed - check your API key');
} else if (error.message.includes('timeout')) {
// Handle timeouts
console.error('Request timed out - please try again');
} else {
// Handle other errors
console.error('Submission failed:', error.message);
}
}
```
## Development Workflow
### 1. Environment Setup
```bash
# Copy environment template
cp .env.example .env
# Edit with your credentials
# COLLECTLIE_PROJECT_ID=your_project_id
# COLLECTLIE_API_KEY=proj_your_api_key
```
### 2. Development
```bash
# Build the SDK
npm run build
# Run in development mode
npm run dev
```
### 3. Verify Your Integration
```javascript
// verify-integration.js
import { Collectlie } from 'collectlie';
const collectlie = new Collectlie();
// Verify your integration is working
await collectlie.submit({
type: 'feedback',
title: 'Integration Verification',
content: 'Testing that the SDK is properly integrated'
});
```
## File Upload Technical Details
### Upload Process
- **Automatic Upload**: Files are uploaded automatically when `data` field is present
- **Multipart Form Data**: Uses `multipart/form-data` for efficient binary transfer
- **Atomic Operations**: All files must upload successfully or submission fails
- **MIME Detection**: Automatically detects file types if not provided
- **Size Validation**: Files validated against limits before upload
### File Upload Technical Details
#### Default Settings
- **Max File Size**: 1MB per file (backend enforced)
- **Allowed Types**: Images only (JPEG, PNG, GIF, WebP) - backend enforced
- **Supported Formats**: `File`, `Blob` objects, or URLs to existing files
- **Validation**: All validation handled by backend for maximum user freedom
- **No Client Limits**: Users can attach any files, backend validates
#### Backend Security Features
- **MIME Type Validation**: Backend validates image types only
- **Size Limits**: Backend enforces 1MB per file limit
- **Content Validation**: Server-side binary content verification
- **No Client Restrictions**: Maximum user freedom, backend handles security
#### File Upload Patterns
**Simple File Upload:**
```typescript
// Basic file attachment
const fileInput = document.querySelector('#file') as HTMLInputElement;
const file = fileInput.files?.[0];
if (file) {
await collectlie.submit({
type: 'bug',
title: 'Issue with screenshot',
content: 'Attaching screenshot of the problem',
attachments: [{
filename: file.name,
data: file // SDK handles upload automatically
}]
});
}
```
**Multiple File Upload (No Client Validation):**
```typescript
// Upload any files - backend handles all validation
const files = Array.from(fileInput.files || []);
const attachments = files.map(file => ({
filename: file.name,
mimeType: file.type,
data: file
}));
try {
await collectlie.submit({
type: 'feedback',
title: 'Feedback with attachments',
content: 'Please see attached files',
attachments
});
console.log('Files uploaded successfully!');
} catch (error) {
// Backend will provide specific error messages
console.error('Upload failed:', error.message);
}
```
**File Upload with Progress Handling:**
```typescript
// Handle upload progress and errors gracefully
async function uploadWithProgress(files: File[]) {
const attachments = files.map(file => ({
filename: file.name,
mimeType: file.type,
data: file
}));
try {
console.log('Starting upload...', attachments.length, 'files');
const result = await collectlie.submit({
type: 'bug',
title: 'Bug report with files',
content: 'Detailed bug report with supporting files',
attachments
});
console.log('✅ Upload completed successfully!');
return result;
} catch (error) {
if (error.message.includes('file size')) {
console.error('❌ File too large');
} else if (error.message.includes('file type')) {
console.error('❌ Unsupported file type');
} else if (error.message.includes('network')) {
console.error('❌ Network error during upload');
} else {
console.error('❌ Upload failed:', error.message);
}
throw error;
}
}
```
### Example File Types
```typescript
// Default allowed file types
const defaultAllowedTypes = [
'image/jpeg',
'image/png',
'image/gif',
'image/webp'
];
```
## File Upload Error Handling
```typescript
// Comprehensive error handling for file uploads
try {
await collectlie.submit({
type: 'feedback',
title: 'Feedback with files',
content: 'Attaching relevant files',
attachments: [{
filename: 'screenshot.png',
data: selectedFile
}]
});
console.log('✅ Files uploaded successfully!');
} catch (error) {
// Handle specific file upload errors
if (error.message.includes('File size exceeds')) {
alert('One or more files are too large. Maximum size: 1MB per file.');
} else if (error.message.includes('File type not allowed')) {
alert('Unsupported file type. Backend only accepts images.');
} else if (error.message.includes('Too many attachments')) {
alert('File upload failed. Please try again.');
} else if (error.message.includes('Upload timeout')) {
alert('Upload timed out. Please check your connection and try again.');
} else if (error.message.includes('Virus detected')) {
alert('File failed security scan. Please check your files.');
} else {
alert('Upload failed: ' + error.message);
}
}
```
## Verify Your Setup
After setting up your environment variables, you can verify everything is working by making a test submission:
```javascript
// verify-setup.js
import { Collectlie } from 'collectlie';
const collectlie = new Collectlie();
try {
const result = await collectlie.submit({
type: 'test',
title: 'Setup Verification',
content: 'Testing that my API credentials are working'
});
console.log('✅ Setup verified successfully!', result);
} catch (error) {
console.error('❌ Setup verification failed:', error.message);
}
```
You should see the submission appear in your Collectlie dashboard.
## Next Steps
- **[Complete API Reference](./api-reference.md)** - Detailed API documentation
- **[Framework Examples](./examples/)** - Specific integration guides
- **[Best Practices](./advanced/best-practices.md)** - Production recommendations
## Common Issues
### Missing Environment Variables
```
Error: project_id is required. Set COLLECTLIE_PROJECT_ID environment variable
```
**Solution**: Add `COLLECTLIE_PROJECT_ID=your_project_id` to your `.env` file
### Invalid API Key
```
Error: API key is required
```
**Solution**: Add your API key to your `.env` file
### Network Timeout
```
Error: Request timeout after 10000ms
```
**Solution**: Check your internet connection or increase timeout in SDK config
## Support
- Check your `.env` file setup
- Verify API key starts with `proj_`
- Ensure project ID is correct
- [GitHub Issues](https://github.com/collectlie/collectlie/issues) for bugs and questions