@smallwebco/tinypivot-server 1.0.57

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.
package/LICENSE.md ADDED
@@ -0,0 +1,78 @@
1
+ # TinyPivot License
2
+
3
+ ## Free Tier (MIT License)
4
+
5
+ Copyright (c) 2024 TinyPivot
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of the Free Tier features of this software and associated documentation files
9
+ (the "Software"), to deal in the Software without restriction, including without
10
+ limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
+ and/or sell copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ ### Free Tier Features Include:
15
+ - Basic data grid display with sorting
16
+ - Column filtering with unique values
17
+ - Keyboard navigation and cell selection
18
+ - Copy/paste support
19
+ - Row striping and hover states
20
+ - Responsive column widths
21
+ - Cell number formatting
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
26
+
27
+ ---
28
+
29
+ ## Pro License (Commercial)
30
+
31
+ The following features require a Pro license:
32
+
33
+ ### Pro Features:
34
+ - **Pivot Table**: Full pivot table functionality with drag-and-drop configuration
35
+ - **Advanced Aggregations**: Sum, Count, Average, Min, Max, Count Distinct
36
+ - **Row/Column Totals**: Automatic total calculations
37
+ - **Percentage Mode**: View data as % of row, column, or grand total
38
+ - **Column/Row Grouping**: Multi-level grouping for pivot tables
39
+ - **Session Persistence**: Auto-save and restore pivot configuration
40
+ - **Priority Support**: Direct email support and issue prioritization
41
+
42
+ ### Pricing:
43
+ - **Single Project**: $49 one-time payment
44
+ - **Unlimited Projects**: $149 one-time payment
45
+ - **Team License (up to 10 devs)**: $399 one-time payment
46
+
47
+ ### How to Purchase:
48
+ Visit https://tiny-pivot.com/#pricing to purchase a license.
49
+
50
+ After purchase, you'll receive a license key to unlock Pro features:
51
+
52
+ ```typescript
53
+ import { DataGrid, setLicenseKey } from 'tinypivot'
54
+
55
+ setLicenseKey('YOUR_LICENSE_KEY')
56
+ ```
57
+
58
+ ### License Validation:
59
+ - License keys are validated locally (no network calls)
60
+ - Keys are tied to your npm username or organization
61
+ - Licenses are perpetual with 1 year of updates included
62
+
63
+ ---
64
+
65
+ ## Terms
66
+
67
+ 1. **No Removal of Attribution**: Free tier users must keep the "Powered by TinyPivot"
68
+ watermark visible. Pro license removes this requirement.
69
+
70
+ 2. **No Redistribution**: You may not redistribute this library as part of another
71
+ component library or framework.
72
+
73
+ 3. **No Sub-licensing**: Licenses cannot be transferred or sub-licensed.
74
+
75
+ ---
76
+
77
+ For questions about licensing, contact: license@tiny-pivot.com
78
+
package/README.md ADDED
@@ -0,0 +1,362 @@
1
+ # @smallwebco/tinypivot-server
2
+
3
+ Server-side handlers for TinyPivot AI Data Analyst.
4
+
5
+ ## Two Deployment Options
6
+
7
+ ### Option 1: Full Server (PostgreSQL + AI)
8
+
9
+ Use this when you have a PostgreSQL database. The unified handler provides:
10
+ - Auto-discovery of tables from your database
11
+ - Schema introspection
12
+ - SQL query execution with safety validation
13
+ - AI chat proxy
14
+
15
+ ### Option 2: Client-Side Queries + AI Proxy Only
16
+
17
+ Use this when your data is already in the browser (e.g., DuckDB WASM, static data). You only need a server endpoint for AI chat to keep API keys secure.
18
+
19
+ ---
20
+
21
+ ## Option 1: Full Server Setup
22
+
23
+ ### Requirements
24
+
25
+ - PostgreSQL database
26
+ - AI API key (OpenAI, Anthropic, or OpenRouter)
27
+ - Node.js 18+
28
+
29
+ ### 1. Install
30
+
31
+ ```bash
32
+ pnpm add @smallwebco/tinypivot-server pg
33
+ ```
34
+
35
+ ### 2. Set Environment Variables
36
+
37
+ ```bash
38
+ # .env
39
+ DATABASE_URL=postgresql://user:password@localhost:5432/mydb
40
+ AI_API_KEY=sk-... # Your API key
41
+
42
+ # Optional: Override the default model
43
+ AI_MODEL=claude-sonnet-4-20250514
44
+ ```
45
+
46
+ The AI provider is **auto-detected** from your API key format:
47
+ - `sk-ant-...` → Anthropic (defaults to `claude-3-haiku-20240307`)
48
+ - `sk-or-...` → OpenRouter (defaults to `anthropic/claude-3-haiku`)
49
+ - `sk-...` → OpenAI (defaults to `gpt-4o-mini`)
50
+
51
+ Default models are cheap/fast. Override with `AI_MODEL` for better quality.
52
+
53
+ ### 3. Create API Endpoint
54
+
55
+ **Next.js App Router**
56
+
57
+ ```typescript
58
+ // app/api/tinypivot/route.ts
59
+ import { createTinyPivotHandler } from '@smallwebco/tinypivot-server'
60
+
61
+ export const POST = createTinyPivotHandler()
62
+ ```
63
+
64
+ **Next.js Pages Router**
65
+
66
+ ```typescript
67
+ // pages/api/tinypivot.ts
68
+ import type { NextApiRequest, NextApiResponse } from 'next'
69
+ import { createTinyPivotHandler } from '@smallwebco/tinypivot-server'
70
+
71
+ const handler = createTinyPivotHandler()
72
+
73
+ export default async function (req: NextApiRequest, res: NextApiResponse) {
74
+ const response = await handler(
75
+ new Request('http://localhost', {
76
+ method: 'POST',
77
+ body: JSON.stringify(req.body),
78
+ headers: { 'Content-Type': 'application/json' },
79
+ })
80
+ )
81
+ const data = await response.json()
82
+ res.status(response.status).json(data)
83
+ }
84
+ ```
85
+
86
+ **Express**
87
+
88
+ ```typescript
89
+ import express from 'express'
90
+ import { createTinyPivotHandler } from '@smallwebco/tinypivot-server'
91
+
92
+ const app = express()
93
+ app.use(express.json())
94
+
95
+ const handler = createTinyPivotHandler()
96
+
97
+ app.post('/api/tinypivot', async (req, res) => {
98
+ const response = await handler(
99
+ new Request('http://localhost', {
100
+ method: 'POST',
101
+ body: JSON.stringify(req.body),
102
+ headers: { 'Content-Type': 'application/json' },
103
+ })
104
+ )
105
+ const data = await response.json()
106
+ res.status(response.status).json(data)
107
+ })
108
+ ```
109
+
110
+ ### 4. Use in Frontend
111
+
112
+ **Vue 3**
113
+
114
+ ```vue
115
+ <script setup>
116
+ import { DataGrid } from '@smallwebco/tinypivot-vue'
117
+ import '@smallwebco/tinypivot-vue/style.css'
118
+ </script>
119
+
120
+ <template>
121
+ <DataGrid
122
+ :data="[]"
123
+ :ai-analyst="{ endpoint: '/api/tinypivot' }"
124
+ />
125
+ </template>
126
+ ```
127
+
128
+ **React**
129
+
130
+ ```tsx
131
+ import { DataGrid } from '@smallwebco/tinypivot-react'
132
+ import '@smallwebco/tinypivot-react/style.css'
133
+
134
+ function App() {
135
+ return (
136
+ <DataGrid
137
+ data={[]}
138
+ aiAnalyst={{ endpoint: '/api/tinypivot' }}
139
+ />
140
+ )
141
+ }
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Option 2: Client-Side Queries + AI Proxy
147
+
148
+ Use this when you're executing queries in the browser (e.g., DuckDB WASM) and only need the server for AI chat.
149
+
150
+ ### 1. Create AI-Only Endpoint
151
+
152
+ ```typescript
153
+ // api/ai-proxy.ts (Vercel) or your framework equivalent
154
+ export default async function handler(req, res) {
155
+ const apiKey = process.env.AI_API_KEY
156
+ if (!apiKey) {
157
+ return res.status(500).json({ error: 'AI_API_KEY not configured' })
158
+ }
159
+
160
+ const { messages } = req.body
161
+
162
+ // Auto-detect provider from key format
163
+ const isAnthropic = apiKey.startsWith('sk-ant-')
164
+ const isOpenRouter = apiKey.startsWith('sk-or-')
165
+
166
+ // Call the appropriate API...
167
+ // (See full implementation in the TinyPivot demo)
168
+
169
+ return res.json({ content: aiResponse })
170
+ }
171
+ ```
172
+
173
+ ### 2. Configure Frontend with queryExecutor
174
+
175
+ **Vue 3**
176
+
177
+ ```vue
178
+ <script setup>
179
+ import { DataGrid } from '@smallwebco/tinypivot-vue'
180
+ import '@smallwebco/tinypivot-vue/style.css'
181
+
182
+ // Your client-side query function (e.g., DuckDB WASM)
183
+ async function executeQuery(sql: string, table: string) {
184
+ const result = await duckdb.query(sql)
185
+ return {
186
+ data: result.toArray(),
187
+ rowCount: result.numRows,
188
+ }
189
+ }
190
+
191
+ const aiConfig = {
192
+ endpoint: '/api/ai-proxy', // Server endpoint for AI chat only
193
+ queryExecutor: executeQuery, // Client-side SQL execution
194
+ dataSources: [
195
+ { id: 'sales', table: 'sales', name: 'Sales Data', description: 'Sales transactions' }
196
+ ],
197
+ dataSourceLoader: async (id) => {
198
+ // Load data into your client-side DB and return schema
199
+ const data = await loadDataset(id)
200
+ return { data, schema: inferSchema(data) }
201
+ }
202
+ }
203
+ </script>
204
+
205
+ <template>
206
+ <DataGrid :data="myData" :ai-analyst="aiConfig" />
207
+ </template>
208
+ ```
209
+
210
+ **React**
211
+
212
+ ```tsx
213
+ import { DataGrid } from '@smallwebco/tinypivot-react'
214
+ import '@smallwebco/tinypivot-react/style.css'
215
+
216
+ function App() {
217
+ const executeQuery = async (sql: string, table: string) => {
218
+ const result = await duckdb.query(sql)
219
+ return { data: result.toArray(), rowCount: result.numRows }
220
+ }
221
+
222
+ const aiConfig = {
223
+ endpoint: '/api/ai-proxy',
224
+ queryExecutor: executeQuery,
225
+ dataSources: [
226
+ { id: 'sales', table: 'sales', name: 'Sales Data', description: 'Sales transactions' }
227
+ ],
228
+ dataSourceLoader: async (id) => {
229
+ const data = await loadDataset(id)
230
+ return { data, schema: inferSchema(data) }
231
+ }
232
+ }
233
+
234
+ return <DataGrid data={myData} aiAnalyst={aiConfig} />
235
+ }
236
+ ```
237
+
238
+ ---
239
+
240
+ ## Configuration Options
241
+
242
+ ### Handler Options (Full Server)
243
+
244
+ ```typescript
245
+ createTinyPivotHandler({
246
+ // PostgreSQL connection (default: process.env.DATABASE_URL)
247
+ connectionString: 'postgresql://...',
248
+
249
+ // AI API key (default: process.env.AI_API_KEY)
250
+ apiKey: 'sk-...',
251
+
252
+ // Table filtering
253
+ tables: {
254
+ include: ['sales', 'customers'], // Only these tables
255
+ exclude: [/^_/, 'migrations'], // Exclude patterns
256
+ schemas: ['public'], // PostgreSQL schemas
257
+ descriptions: { // Context for AI
258
+ sales: 'Sales transactions with revenue data',
259
+ }
260
+ },
261
+
262
+ // Query limits (optional)
263
+ maxRows: 10000,
264
+ timeout: 30000,
265
+
266
+ // AI settings
267
+ model: 'claude-sonnet-4-20250514', // Override default model
268
+ maxTokens: 2048,
269
+
270
+ // Error handling
271
+ onError: (error) => console.error(error),
272
+ })
273
+ ```
274
+
275
+ ### AI Analyst Config (Frontend)
276
+
277
+ ```typescript
278
+ interface AIAnalystConfig {
279
+ // Required: API endpoint
280
+ endpoint: string
281
+
282
+ // For client-side queries (Option 2)
283
+ queryExecutor?: (sql: string, table: string) => Promise<QueryResult>
284
+ dataSources?: AIDataSource[]
285
+ dataSourceLoader?: (id: string) => Promise<{ data: any[], schema?: Schema }>
286
+
287
+ // Optional
288
+ enabled?: boolean
289
+ persistToLocalStorage?: boolean
290
+ sessionId?: string
291
+ maxRows?: number
292
+ aiModelName?: string // Display name in UI
293
+ }
294
+ ```
295
+
296
+ ---
297
+
298
+ ## API Contract
299
+
300
+ The endpoint accepts POST requests with an `action` field:
301
+
302
+ ### `list-tables`
303
+ ```typescript
304
+ // Request
305
+ { action: 'list-tables' }
306
+
307
+ // Response
308
+ { tables: [{ name: 'sales', description: '...' }] }
309
+ ```
310
+
311
+ ### `get-schema`
312
+ ```typescript
313
+ // Request
314
+ { action: 'get-schema', tables: ['sales'] }
315
+
316
+ // Response
317
+ { schemas: [{ table: 'sales', columns: [...] }] }
318
+ ```
319
+
320
+ ### `query`
321
+ ```typescript
322
+ // Request
323
+ { action: 'query', sql: 'SELECT ...', table: 'sales' }
324
+
325
+ // Response
326
+ { success: true, data: [...], rowCount: 100, truncated: false }
327
+ ```
328
+
329
+ ### `chat`
330
+ ```typescript
331
+ // Request
332
+ { action: 'chat', messages: [{ role: 'user', content: '...' }] }
333
+
334
+ // Response
335
+ { content: 'AI response with SQL...' }
336
+ ```
337
+
338
+ ---
339
+
340
+ ## Security
341
+
342
+ Built-in protections:
343
+
344
+ 1. **SQL Validation**: Only SELECT queries allowed
345
+ 2. **Table Whitelisting**: Only configured tables are queryable
346
+ 3. **LIMIT Enforcement**: Auto-added if missing
347
+ 4. **Error Sanitization**: Connection strings stripped from errors
348
+
349
+ ---
350
+
351
+ ## Troubleshooting
352
+
353
+ | Error | Solution |
354
+ |-------|----------|
355
+ | "PostgreSQL driver not installed" | `pnpm add pg` |
356
+ | "Database connection not configured" | Set `DATABASE_URL` |
357
+ | "AI API key not configured" | Set `AI_API_KEY` |
358
+ | "Table X is not allowed" | Add to `tables.include` or remove from `tables.exclude` |
359
+
360
+ ## License
361
+
362
+ MIT