@kreativa/tools-client
v1.1.0
Published
TypeScript SDK for Kreativa Tools services (email, media, logger)
Maintainers
Readme
@kreativa/tools-client
TypeScript SDK for Kreativa Tools services - Email, Media, and Logger.
Installation
npm install @kreativa/tools-client
# or
pnpm add @kreativa/tools-client
# or
yarn add @kreativa/tools-clientQuick Start
import { createEmailApi, createMediaApi, createCompatApi, createLogger } from '@kreativa/tools-client'
// Email client
const email = createEmailApi({ apiKey: 'your-api-key' })
// Media client
const media = createMediaApi({ apiKey: 'your-api-key' })
// Compat client (XChaCha20-Poly1305 encrypted files)
const compat = createCompatApi({ apiKey: 'your-api-key' })
// Logger client
const logger = createLogger({ apiKey: 'your-api-key' })Logger Client
Track events, errors, and user behavior in your applications.
Basic Usage
import { createLogger } from '@kreativa/tools-client'
const logger = createLogger({
apiKey: 'your-project-api-key',
environment: 'production',
product: 'portal',
})
// Log events
logger.log('button_clicked', { button_id: 'submit' })
logger.info('User logged in')
logger.error('Payment failed', { code: 'CARD_DECLINED' })
logger.success('Order completed', { order_id: '12345' })
logger.warn('Low inventory', { remaining: 5 })
logger.debug('API response', { data: response })Configuration
interface LoggerConfig {
apiKey: string // Required: Your project API key
basePath?: string // API endpoint (default: '/api/logger')
environment?: EnvironmentType // 'production' | 'stage' | 'preview' | 'development' | 'test'
product?: ProductType // 'portal' | 'phone-app' | 'server' | 'image-server' | 'api' | 'other'
batchSize?: number // Events before auto-flush (default: 10)
flushInterval?: number // Ms between auto-flushes (default: 5000)
autoCapture?: {
pageViews?: boolean // Auto-log page navigations (default: false)
errors?: boolean // Capture unhandled errors (default: false)
}
}Auto-Capture
Automatically track page views and unhandled errors:
const logger = createLogger({
apiKey: 'your-api-key',
autoCapture: {
pageViews: true, // Logs 'page_view' on navigation
errors: true, // Logs 'unhandled_error' and 'unhandled_promise_rejection'
},
})User Identification
// Identify a user (call after login)
logger.identify('user_123', {
email: '[email protected]',
plan: 'premium',
})
// Update user properties
logger.setUserProperties({ plan: 'enterprise' })
// Clear user data (call on logout)
logger.reset()Manual Flush
Events are batched and sent automatically. Force an immediate flush:
await logger.flush()Cleanup
// Stop the logger and flush remaining events
logger.destroy()Log Types
| Method | Type | Use Case |
|--------|------|----------|
| log(event, props) | info | General events |
| info(message, props) | info | Informational messages |
| error(event, props) | error | Errors and failures |
| success(message, props) | success | Successful operations |
| warn(message, props) | warning | Warnings |
| debug(message, props) | debug | Debug information |
Email Client
Send emails using templates.
Basic Usage
import { createEmailApi } from '@kreativa/tools-client'
const email = createEmailApi({ apiKey: 'your-api-key' })
// Send email using template
await email.sendEmail({
templateSlug: 'welcome-email',
to: '[email protected]',
params: {
name: 'John',
activationLink: 'https://example.com/activate/xyz',
},
})
// Or use template ID
await email.sendEmail({
templateId: '507f1f77bcf86cd799439011',
to: ['[email protected]', '[email protected]'],
params: { ... },
})Configuration
interface EmailApiOptions {
basePath?: string // API endpoint (default: '/api/email')
apiKey?: string // Your project API key
}Methods
// Send email
email.sendEmail(params: SendEmailParams): Promise<SendEmailResponse>
// Generic HTTP methods
email.get<T>(endpoint, params?)
email.post<T>(endpoint, body?)
email.put<T>(endpoint, body?)
email.delete<T>(endpoint)Media Client
Upload, manage, and serve files.
Basic Usage
import { createMediaApi } from '@kreativa/tools-client'
const media = createMediaApi({ apiKey: 'your-api-key' })
// Upload a file
const result = await media.uploadFile({
projectId: 'your-project-id',
file: fileBlob,
filename: 'photo.jpg',
folder: 'avatars',
accessType: 'public',
})
// List files
const files = await media.listFiles({
projectId: 'your-project-id',
folder: 'avatars',
})
// Get file details
const file = await media.getFile('file-id')
// Move file to different folder
await media.moveFile('file-id', 'new-folder/path')
// Delete file
await media.deleteFile('file-id')Configuration
interface MediaApiOptions {
basePath?: string // API endpoint (default: '/api/media')
apiKey?: string // Your project API key
}Upload Options
interface UploadFileParams {
projectId: string
file: File | Blob
filename?: string
folder?: string // e.g., 'images/avatars'
accessType?: FileAccessType // 'public' | 'token' | 'server-only' | 'e2e-encrypted' | 'server-encrypted'
}Access Types
| Type | Description |
|------|-------------|
| public | Accessible via public URL |
| token | Requires signed token |
| server-only | Only accessible server-side |
| server-encrypted | Encrypted at rest (AES-256-GCM), decrypted on access |
| e2e-encrypted | End-to-end encrypted (client-side) |
| xchacha-encrypted | XChaCha20-Poly1305 with per-file client keys (PHP-compatible) |
Methods
media.uploadFile(params): Promise<UploadFileResponse>
media.deleteFile(fileId): Promise<DeleteFileResponse>
media.listFiles(params): Promise<ListFilesResponse>
media.getFile(fileId): Promise<{ success: boolean; data?: MediaFile }>
media.moveFile(fileId, folder): Promise<{ success: boolean; data?: MediaFile }>
// Generic HTTP methods
media.get<T>(endpoint, params?)
media.post<T>(endpoint, body?)
media.put<T>(endpoint, body?)
media.patch<T>(endpoint, body?)
media.delete<T>(endpoint)
media.upload<T>(endpoint, formData, params?)Compat API (XChaCha20-Poly1305 Encryption)
Upload and download files with XChaCha20-Poly1305 encryption, compatible with PHP sodium encryption.
Basic Usage
import { createCompatApi } from '@kreativa/tools-client'
const compat = createCompatApi({
apiKey: 'your-project-api-key',
basePath: 'https://media.example.com/api', // Optional
})
// Generate a random encryption key
const encryptionKey = compat.generateKey()
// Upload a file with encryption
const result = await compat.upload({
file: fileBlob,
encryptionKey,
app: 'myapp', // Optional: defaults to project slug
tag: 'avatars', // Optional: defaults to 'general'
})
console.log(result.data.id) // File ID for later retrieval
// Download and decrypt a file
const blob = await compat.download({
id: result.data.id,
encryptionKey,
})
// Or download using PHP-compatible path pattern
const blob2 = await compat.downloadByPath({
app: 'myapp',
tag: 'avatars',
id: 'file-id',
encryptionKey,
})
// Delete a file
await compat.delete('file-id')
await compat.deleteByPath('myapp', 'avatars', 'file-id')Configuration
interface CompatApiOptions {
apiKey: string // Required: Your project API key
basePath?: string // API endpoint (default: '/api')
}Upload Options
interface CompatUploadParams {
file: File | Blob
encryptionKey: string // Base64-encoded 32-byte key
app?: string // Application identifier (default: project slug)
tag?: string // File category/tag (default: 'general')
date?: string // ISO 8601 date for folder structure (default: now)
id?: string // Custom file ID (default: auto-generated)
}Key Management
The encryption key is a 32-byte random value that you must store securely:
// Generate a new key
const key = compat.generateKey()
// Store this key securely - you need it to decrypt the file!
// The server cannot decrypt without this key.
// Example: Store with the file reference in your database
await db.files.insert({
fileId: result.data.id,
encryptionKey: key, // Store encrypted or in secure storage
})PHP Interoperability
Files encrypted with this API can be decrypted by the PHP file server and vice versa, as long as both use the same master key (XCHACHA_MASTER_KEY).
The encryption uses:
- Algorithm: XChaCha20-Poly1305 (libsodium)
- Key derivation: HMAC-SHA256(clientKey, masterKey)
- Format: 24-byte nonce + ciphertext (metadata + file content)
Methods
// Generate random encryption key
compat.generateKey(): string
// Upload with encryption
compat.upload(params: CompatUploadParams): Promise<CompatUploadResponse>
// Download and decrypt by ID
compat.download(params: CompatDownloadParams): Promise<Blob>
// Download by PHP path pattern (app/tag/id)
compat.downloadByPath(params: CompatDownloadByPathParams): Promise<Blob>
// Delete by ID
compat.delete(id: string): Promise<CompatDeleteResponse>
// Delete by PHP path pattern
compat.deleteByPath(app: string, tag: string, id: string): Promise<CompatDeleteResponse>Generic API Client
Create a client for any service:
import { createApiClient } from '@kreativa/tools-client'
const client = createApiClient('/api/custom', { apiKey: 'your-key' })
await client.get('/endpoint')
await client.post('/endpoint', { data: 'value' })
await client.put('/endpoint', { data: 'value' })
await client.patch('/endpoint', { data: 'value' })
await client.delete('/endpoint')
await client.upload('/endpoint', formData)Session Handling
The SDK automatically handles 401 responses by dispatching a custom event:
import { SESSION_EXPIRED_EVENT } from '@kreativa/tools-client'
window.addEventListener(SESSION_EXPIRED_EVENT, () => {
// Redirect to login or refresh token
window.location.href = '/login'
})TypeScript Types
All types are exported:
import type {
// Email
SendEmailParams,
SendEmailResponse,
EmailApiClient,
// Media
MediaFile,
FileAccessType,
StorageBackend,
UploadFileParams,
UploadFileResponse,
ListFilesParams,
ListFilesResponse,
DeleteFileResponse,
MediaApiClient,
// Compat (XChaCha20 encryption)
CompatUploadParams,
CompatUploadResponse,
CompatDownloadParams,
CompatDownloadByPathParams,
CompatDeleteResponse,
CompatApiClient,
XChachaMeta,
// Logger
LoggerConfig,
LogEvent,
LogType,
DeviceType,
ProductType,
EnvironmentType,
Logger,
// Generic
ApiClient,
ServiceId,
} from '@kreativa/tools-client'Environment Variables
When using in a browser with Vite:
VITE_MEDIA_API_URL=/api/media
VITE_EMAIL_API_URL=/api/email
VITE_LOGGER_API_URL=/api/loggerThe SDK will automatically use these if no basePath is provided.
License
MIT
