webpeel 0.12.0 → 0.12.2

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 (148) hide show
  1. package/README.md +82 -9
  2. package/dist/cli.js +97 -6
  3. package/dist/cli.js.map +1 -1
  4. package/dist/core/actions.d.ts +28 -0
  5. package/dist/core/actions.d.ts.map +1 -1
  6. package/dist/core/actions.js +60 -0
  7. package/dist/core/actions.js.map +1 -1
  8. package/dist/core/bm25-filter.d.ts +10 -0
  9. package/dist/core/bm25-filter.d.ts.map +1 -1
  10. package/dist/core/bm25-filter.js +40 -0
  11. package/dist/core/bm25-filter.js.map +1 -1
  12. package/dist/core/content-pruner.d.ts +12 -5
  13. package/dist/core/content-pruner.d.ts.map +1 -1
  14. package/dist/core/content-pruner.js +247 -190
  15. package/dist/core/content-pruner.js.map +1 -1
  16. package/dist/core/research.d.ts +67 -0
  17. package/dist/core/research.d.ts.map +1 -0
  18. package/dist/core/research.js +254 -0
  19. package/dist/core/research.js.map +1 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +37 -3
  22. package/dist/index.js.map +1 -1
  23. package/dist/mcp/server.js +107 -2
  24. package/dist/mcp/server.js.map +1 -1
  25. package/dist/server/app.d.ts +14 -0
  26. package/dist/server/app.d.ts.map +1 -0
  27. package/dist/server/app.js +189 -0
  28. package/dist/server/app.js.map +1 -0
  29. package/dist/server/auth-store.d.ts +28 -0
  30. package/dist/server/auth-store.d.ts.map +1 -0
  31. package/dist/server/auth-store.js +89 -0
  32. package/dist/server/auth-store.js.map +1 -0
  33. package/dist/server/job-queue.d.ts +93 -0
  34. package/dist/server/job-queue.d.ts.map +1 -0
  35. package/dist/server/job-queue.js +144 -0
  36. package/dist/server/job-queue.js.map +1 -0
  37. package/dist/server/middleware/auth.d.ts +28 -0
  38. package/dist/server/middleware/auth.d.ts.map +1 -0
  39. package/dist/server/middleware/auth.js +183 -0
  40. package/dist/server/middleware/auth.js.map +1 -0
  41. package/dist/server/middleware/rate-limit.d.ts +23 -0
  42. package/dist/server/middleware/rate-limit.d.ts.map +1 -0
  43. package/dist/server/middleware/rate-limit.js +126 -0
  44. package/dist/server/middleware/rate-limit.js.map +1 -0
  45. package/dist/server/middleware/url-validator.d.ts +16 -0
  46. package/dist/server/middleware/url-validator.d.ts.map +1 -0
  47. package/dist/server/middleware/url-validator.js +187 -0
  48. package/dist/server/middleware/url-validator.js.map +1 -0
  49. package/dist/server/pg-auth-store.d.ts +129 -0
  50. package/dist/server/pg-auth-store.d.ts.map +1 -0
  51. package/dist/server/pg-auth-store.js +457 -0
  52. package/dist/server/pg-auth-store.js.map +1 -0
  53. package/dist/server/pg-job-queue.d.ts +60 -0
  54. package/dist/server/pg-job-queue.d.ts.map +1 -0
  55. package/dist/server/pg-job-queue.js +365 -0
  56. package/dist/server/pg-job-queue.js.map +1 -0
  57. package/dist/server/premium/domain-intel.d.ts +17 -0
  58. package/dist/server/premium/domain-intel.d.ts.map +1 -0
  59. package/dist/server/premium/domain-intel.js +134 -0
  60. package/dist/server/premium/domain-intel.js.map +1 -0
  61. package/dist/server/premium/index.d.ts +18 -0
  62. package/dist/server/premium/index.d.ts.map +1 -0
  63. package/dist/server/premium/index.js +36 -0
  64. package/dist/server/premium/index.js.map +1 -0
  65. package/dist/server/premium/swr-cache.d.ts +15 -0
  66. package/dist/server/premium/swr-cache.d.ts.map +1 -0
  67. package/dist/server/premium/swr-cache.js +35 -0
  68. package/dist/server/premium/swr-cache.js.map +1 -0
  69. package/dist/server/routes/activity.d.ts +7 -0
  70. package/dist/server/routes/activity.d.ts.map +1 -0
  71. package/dist/server/routes/activity.js +66 -0
  72. package/dist/server/routes/activity.js.map +1 -0
  73. package/dist/server/routes/agent.d.ts +12 -0
  74. package/dist/server/routes/agent.d.ts.map +1 -0
  75. package/dist/server/routes/agent.js +356 -0
  76. package/dist/server/routes/agent.js.map +1 -0
  77. package/dist/server/routes/answer.d.ts +6 -0
  78. package/dist/server/routes/answer.d.ts.map +1 -0
  79. package/dist/server/routes/answer.js +124 -0
  80. package/dist/server/routes/answer.js.map +1 -0
  81. package/dist/server/routes/batch.d.ts +7 -0
  82. package/dist/server/routes/batch.d.ts.map +1 -0
  83. package/dist/server/routes/batch.js +287 -0
  84. package/dist/server/routes/batch.js.map +1 -0
  85. package/dist/server/routes/cli-usage.d.ts +7 -0
  86. package/dist/server/routes/cli-usage.d.ts.map +1 -0
  87. package/dist/server/routes/cli-usage.js +121 -0
  88. package/dist/server/routes/cli-usage.js.map +1 -0
  89. package/dist/server/routes/compat.d.ts +24 -0
  90. package/dist/server/routes/compat.d.ts.map +1 -0
  91. package/dist/server/routes/compat.js +651 -0
  92. package/dist/server/routes/compat.js.map +1 -0
  93. package/dist/server/routes/extract.d.ts +9 -0
  94. package/dist/server/routes/extract.d.ts.map +1 -0
  95. package/dist/server/routes/extract.js +121 -0
  96. package/dist/server/routes/extract.js.map +1 -0
  97. package/dist/server/routes/fetch.d.ts +7 -0
  98. package/dist/server/routes/fetch.d.ts.map +1 -0
  99. package/dist/server/routes/fetch.js +537 -0
  100. package/dist/server/routes/fetch.js.map +1 -0
  101. package/dist/server/routes/health.d.ts +8 -0
  102. package/dist/server/routes/health.d.ts.map +1 -0
  103. package/dist/server/routes/health.js +36 -0
  104. package/dist/server/routes/health.js.map +1 -0
  105. package/dist/server/routes/jobs.d.ts +8 -0
  106. package/dist/server/routes/jobs.d.ts.map +1 -0
  107. package/dist/server/routes/jobs.js +374 -0
  108. package/dist/server/routes/jobs.js.map +1 -0
  109. package/dist/server/routes/mcp.d.ts +16 -0
  110. package/dist/server/routes/mcp.d.ts.map +1 -0
  111. package/dist/server/routes/mcp.js +475 -0
  112. package/dist/server/routes/mcp.js.map +1 -0
  113. package/dist/server/routes/oauth.d.ts +10 -0
  114. package/dist/server/routes/oauth.d.ts.map +1 -0
  115. package/dist/server/routes/oauth.js +296 -0
  116. package/dist/server/routes/oauth.js.map +1 -0
  117. package/dist/server/routes/screenshot.d.ts +10 -0
  118. package/dist/server/routes/screenshot.d.ts.map +1 -0
  119. package/dist/server/routes/screenshot.js +217 -0
  120. package/dist/server/routes/screenshot.js.map +1 -0
  121. package/dist/server/routes/search.d.ts +7 -0
  122. package/dist/server/routes/search.d.ts.map +1 -0
  123. package/dist/server/routes/search.js +287 -0
  124. package/dist/server/routes/search.js.map +1 -0
  125. package/dist/server/routes/stats.d.ts +7 -0
  126. package/dist/server/routes/stats.d.ts.map +1 -0
  127. package/dist/server/routes/stats.js +65 -0
  128. package/dist/server/routes/stats.js.map +1 -0
  129. package/dist/server/routes/stripe.d.ts +9 -0
  130. package/dist/server/routes/stripe.d.ts.map +1 -0
  131. package/dist/server/routes/stripe.js +233 -0
  132. package/dist/server/routes/stripe.js.map +1 -0
  133. package/dist/server/routes/users.d.ts +9 -0
  134. package/dist/server/routes/users.d.ts.map +1 -0
  135. package/dist/server/routes/users.js +954 -0
  136. package/dist/server/routes/users.js.map +1 -0
  137. package/dist/server/routes/webhooks.d.ts +15 -0
  138. package/dist/server/routes/webhooks.d.ts.map +1 -0
  139. package/dist/server/routes/webhooks.js +73 -0
  140. package/dist/server/routes/webhooks.js.map +1 -0
  141. package/dist/server/sentry.d.ts +14 -0
  142. package/dist/server/sentry.d.ts.map +1 -0
  143. package/dist/server/sentry.js +39 -0
  144. package/dist/server/sentry.js.map +1 -0
  145. package/dist/types.d.ts +13 -0
  146. package/dist/types.d.ts.map +1 -1
  147. package/dist/types.js.map +1 -1
  148. package/package.json +3 -2
@@ -0,0 +1,287 @@
1
+ /**
2
+ * Search endpoint with caching — supports DuckDuckGo (default) and Brave (BYOK)
3
+ */
4
+ import { Router } from 'express';
5
+ import { fetch as undiciFetch } from 'undici';
6
+ import { load } from 'cheerio';
7
+ import { LRUCache } from 'lru-cache';
8
+ import { peel } from '../../index.js';
9
+ import { getSearchProvider, } from '../../core/search-provider.js';
10
+ export function createSearchRouter(authStore) {
11
+ const router = Router();
12
+ // LRU cache: 15 minute TTL, max 500 entries, 50MB total size
13
+ const cache = new LRUCache({
14
+ max: 500,
15
+ ttl: 15 * 60 * 1000, // 15 minutes
16
+ maxSize: 50 * 1024 * 1024, // 50MB
17
+ sizeCalculation: (entry) => {
18
+ return JSON.stringify(entry).length;
19
+ },
20
+ });
21
+ router.get('/v1/search', async (req, res) => {
22
+ try {
23
+ const { q, count, scrapeResults, sources, categories, tbs, country, location } = req.query;
24
+ // --- Search provider (new: BYOK Brave support) ---
25
+ const providerParam = (req.query.provider || '').toLowerCase() || 'duckduckgo';
26
+ const validProviders = ['duckduckgo', 'brave'];
27
+ const providerId = validProviders.includes(providerParam)
28
+ ? providerParam
29
+ : 'duckduckgo';
30
+ // API key: query param, header, or empty
31
+ const searchApiKey = req.query.searchApiKey ||
32
+ req.headers['x-search-api-key'] ||
33
+ '';
34
+ // Validate query parameter
35
+ if (!q || typeof q !== 'string') {
36
+ res.status(400).json({
37
+ error: 'invalid_request',
38
+ message: 'Missing or invalid "q" parameter. Pass a search query: GET /v1/search?q=your+search+terms',
39
+ example: 'curl "https://api.webpeel.dev/v1/search?q=latest+AI+news&count=5"',
40
+ docs: 'https://webpeel.dev/docs/api-reference#search',
41
+ });
42
+ return;
43
+ }
44
+ // Parse and validate count
45
+ const resultCount = count ? parseInt(count, 10) : 5;
46
+ if (isNaN(resultCount) || resultCount < 1 || resultCount > 10) {
47
+ res.status(400).json({
48
+ error: 'invalid_request',
49
+ message: 'Invalid "count" parameter: must be between 1 and 10',
50
+ });
51
+ return;
52
+ }
53
+ // Parse sources parameter (comma-separated: web,news,images)
54
+ const sourcesStr = sources || 'web';
55
+ const sourcesArray = sourcesStr.split(',').map(s => s.trim());
56
+ const shouldScrape = scrapeResults === 'true';
57
+ // Parse new search parameters
58
+ const categoriesStr = categories || '';
59
+ const tbsStr = tbs || '';
60
+ const countryStr = country || '';
61
+ const locationStr = location || '';
62
+ // Build cache key (include all parameters)
63
+ const cacheKey = `search:${providerId}:${q}:${resultCount}:${sourcesStr}:${shouldScrape}:${categoriesStr}:${tbsStr}:${countryStr}:${locationStr}`;
64
+ // Check cache
65
+ const cached = cache.get(cacheKey);
66
+ if (cached) {
67
+ res.setHeader('X-Cache', 'HIT');
68
+ res.setHeader('X-Cache-Age', Math.floor((Date.now() - cached.timestamp) / 1000).toString());
69
+ res.json({
70
+ success: true,
71
+ data: cached.data,
72
+ });
73
+ return;
74
+ }
75
+ const startTime = Date.now();
76
+ const data = {};
77
+ // Fetch web results via the search-provider abstraction
78
+ if (sourcesArray.includes('web')) {
79
+ const provider = getSearchProvider(providerId);
80
+ const providerResults = await provider.searchWeb(q, {
81
+ count: resultCount,
82
+ apiKey: searchApiKey || undefined,
83
+ tbs: tbsStr || undefined,
84
+ country: countryStr || undefined,
85
+ location: locationStr || undefined,
86
+ });
87
+ // Map to SearchResult (with optional content field)
88
+ let results = providerResults.map(r => ({
89
+ title: r.title,
90
+ url: r.url,
91
+ snippet: r.snippet,
92
+ }));
93
+ // Apply category filtering if specified
94
+ if (categoriesStr) {
95
+ const categoryList = categoriesStr.split(',').map(c => c.trim().toLowerCase());
96
+ results = results.filter(result => {
97
+ const urlLower = result.url.toLowerCase();
98
+ return categoryList.some(category => {
99
+ switch (category) {
100
+ case 'github':
101
+ return urlLower.includes('github.com');
102
+ case 'pdf':
103
+ return urlLower.endsWith('.pdf');
104
+ case 'docs':
105
+ case 'documentation':
106
+ return urlLower.includes('/docs') || urlLower.includes('/documentation');
107
+ case 'blog':
108
+ return urlLower.includes('blog') || urlLower.includes('/post/');
109
+ case 'news':
110
+ return urlLower.includes('news') || urlLower.includes('/article/');
111
+ case 'video':
112
+ return urlLower.includes('youtube.com') || urlLower.includes('vimeo.com');
113
+ case 'social':
114
+ return urlLower.includes('twitter.com') || urlLower.includes('x.com') ||
115
+ urlLower.includes('facebook.com') || urlLower.includes('linkedin.com');
116
+ default:
117
+ return urlLower.includes(category);
118
+ }
119
+ });
120
+ });
121
+ }
122
+ // Scrape each result URL if requested
123
+ if (shouldScrape) {
124
+ for (const result of results) {
125
+ try {
126
+ const peelResult = await peel(result.url, {
127
+ format: 'markdown',
128
+ maxTokens: 2000,
129
+ });
130
+ result.content = peelResult.content;
131
+ }
132
+ catch (error) {
133
+ result.content = `[Failed to scrape: ${error.message}]`;
134
+ }
135
+ }
136
+ }
137
+ data.web = results;
138
+ }
139
+ // Fetch news results (DDG only — Brave news is not supported via HTML scraping)
140
+ if (sourcesArray.includes('news')) {
141
+ const newsUrl = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(q)}&t=news`;
142
+ const response = await undiciFetch(newsUrl, {
143
+ headers: {
144
+ 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
145
+ },
146
+ });
147
+ if (response.ok) {
148
+ const html = await response.text();
149
+ const $ = load(html);
150
+ const results = [];
151
+ $('.result').each((_i, elem) => {
152
+ if (results.length >= resultCount)
153
+ return;
154
+ const $result = $(elem);
155
+ let title = $result.find('.result__title').text().trim();
156
+ const rawUrl = $result.find('.result__a').attr('href') || '';
157
+ let snippet = $result.find('.result__snippet').text().trim();
158
+ const sourceText = $result.find('.result__extras__url').text().trim();
159
+ if (!title || !rawUrl)
160
+ return;
161
+ let url = rawUrl;
162
+ try {
163
+ const ddgUrl = new URL(rawUrl, 'https://duckduckgo.com');
164
+ const uddg = ddgUrl.searchParams.get('uddg');
165
+ if (uddg) {
166
+ url = decodeURIComponent(uddg);
167
+ }
168
+ }
169
+ catch {
170
+ // Use raw URL if parsing fails
171
+ }
172
+ try {
173
+ const parsed = new URL(url);
174
+ if (!['http:', 'https:'].includes(parsed.protocol)) {
175
+ return;
176
+ }
177
+ url = parsed.href;
178
+ }
179
+ catch {
180
+ return;
181
+ }
182
+ title = title.slice(0, 200);
183
+ snippet = snippet.slice(0, 500);
184
+ results.push({
185
+ title,
186
+ url,
187
+ snippet,
188
+ source: sourceText.slice(0, 100),
189
+ });
190
+ });
191
+ data.news = results;
192
+ }
193
+ }
194
+ // Fetch image results (DDG only)
195
+ if (sourcesArray.includes('images')) {
196
+ const imagesUrl = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(q)}&t=images`;
197
+ const response = await undiciFetch(imagesUrl, {
198
+ headers: {
199
+ 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
200
+ },
201
+ });
202
+ if (response.ok) {
203
+ const html = await response.text();
204
+ const $ = load(html);
205
+ const results = [];
206
+ $('.result').each((_i, elem) => {
207
+ if (results.length >= resultCount)
208
+ return;
209
+ const $result = $(elem);
210
+ const title = $result.find('.result__title').text().trim();
211
+ const thumbnail = $result.find('.result__image img').attr('src') || '';
212
+ const rawUrl = $result.find('.result__a').attr('href') || '';
213
+ const sourceText = $result.find('.result__extras__url').text().trim();
214
+ if (!title || !rawUrl || !thumbnail)
215
+ return;
216
+ let url = rawUrl;
217
+ try {
218
+ const ddgUrl = new URL(rawUrl, 'https://duckduckgo.com');
219
+ const uddg = ddgUrl.searchParams.get('uddg');
220
+ if (uddg) {
221
+ url = decodeURIComponent(uddg);
222
+ }
223
+ }
224
+ catch {
225
+ // Use raw URL if parsing fails
226
+ }
227
+ results.push({
228
+ title: title.slice(0, 200),
229
+ url,
230
+ thumbnail,
231
+ source: sourceText.slice(0, 100),
232
+ });
233
+ });
234
+ data.images = results;
235
+ }
236
+ }
237
+ const elapsed = Date.now() - startTime;
238
+ // Track usage
239
+ const isSoftLimited = req.auth?.softLimited === true;
240
+ const hasExtraUsage = req.auth?.extraUsageAvailable === true;
241
+ const pgStore = authStore;
242
+ if (req.auth?.keyInfo?.key && typeof pgStore.trackBurstUsage === 'function') {
243
+ // Track burst usage (always)
244
+ await pgStore.trackBurstUsage(req.auth.keyInfo.key);
245
+ // If soft-limited with extra usage available, charge to extra usage
246
+ if (isSoftLimited && hasExtraUsage) {
247
+ const extraResult = await pgStore.trackExtraUsage(req.auth.keyInfo.key, 'search', `search:${q}`, elapsed, 200);
248
+ if (extraResult.success) {
249
+ res.setHeader('X-Extra-Usage-Charged', `$${extraResult.cost.toFixed(4)}`);
250
+ res.setHeader('X-Extra-Usage-New-Balance', extraResult.newBalance.toFixed(2));
251
+ }
252
+ }
253
+ else if (!isSoftLimited) {
254
+ // Normal weekly usage tracking
255
+ await pgStore.trackUsage(req.auth.keyInfo.key, 'search');
256
+ }
257
+ }
258
+ // Cache results
259
+ cache.set(cacheKey, {
260
+ data,
261
+ timestamp: Date.now(),
262
+ });
263
+ // Add headers
264
+ res.setHeader('X-Cache', 'MISS');
265
+ res.setHeader('X-Credits-Used', '1');
266
+ res.setHeader('X-Processing-Time', elapsed.toString());
267
+ res.setHeader('X-Fetch-Type', 'search');
268
+ res.json({
269
+ success: true,
270
+ data,
271
+ });
272
+ }
273
+ catch (error) {
274
+ const err = error;
275
+ // SECURITY: Generic error message to prevent information disclosure
276
+ console.error('Search error:', err); // Log full error server-side
277
+ res.status(500).json({
278
+ error: 'search_failed',
279
+ message: 'Search request failed. If using Brave provider, verify your API key. Otherwise try again.',
280
+ hint: 'Free search uses DuckDuckGo (no key required). For higher quality, add provider=brave&searchApiKey=YOUR_KEY',
281
+ docs: 'https://webpeel.dev/docs/api-reference#search',
282
+ });
283
+ }
284
+ });
285
+ return router;
286
+ }
287
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/server/routes/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Stats endpoint - provides dashboard statistics
3
+ */
4
+ import { Router } from 'express';
5
+ import { AuthStore } from '../auth-store.js';
6
+ export declare function createStatsRouter(authStore: AuthStore): Router;
7
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../../src/server/routes/stats.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAkE9D"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Stats endpoint - provides dashboard statistics
3
+ */
4
+ import { Router } from 'express';
5
+ import { PostgresAuthStore } from '../pg-auth-store.js';
6
+ export function createStatsRouter(authStore) {
7
+ const router = Router();
8
+ router.get('/v1/stats', async (req, res) => {
9
+ try {
10
+ // Require authentication (API key or JWT session token)
11
+ const userId = req.auth?.keyInfo?.accountId || req.user?.userId;
12
+ if (!userId) {
13
+ res.status(401).json({
14
+ error: 'unauthorized',
15
+ message: 'Authentication required',
16
+ });
17
+ return;
18
+ }
19
+ // Only works with PostgreSQL backend
20
+ if (!(authStore instanceof PostgresAuthStore)) {
21
+ res.status(501).json({
22
+ error: 'not_implemented',
23
+ message: 'Stats endpoint requires PostgreSQL backend',
24
+ });
25
+ return;
26
+ }
27
+ // Access pool via any cast (pool is private but we need direct DB access)
28
+ const pgStore = authStore;
29
+ // Get stats from usage_logs table
30
+ const statsQuery = `
31
+ SELECT
32
+ COUNT(*) as total_requests,
33
+ AVG(CASE WHEN status_code >= 200 AND status_code < 300 THEN 1.0 ELSE 0.0 END) * 100 as success_rate,
34
+ AVG(processing_time_ms) as avg_response_time
35
+ FROM usage_logs
36
+ WHERE user_id = $1
37
+ `;
38
+ const result = await pgStore.pool.query(statsQuery, [userId]);
39
+ if (result.rows.length === 0) {
40
+ // No data yet - return defaults
41
+ res.json({
42
+ totalRequests: 0,
43
+ successRate: 100,
44
+ avgResponseTime: 0,
45
+ });
46
+ return;
47
+ }
48
+ const row = result.rows[0];
49
+ res.json({
50
+ totalRequests: parseInt(row.total_requests) || 0,
51
+ successRate: parseFloat(row.success_rate) || 100,
52
+ avgResponseTime: Math.round(parseFloat(row.avg_response_time)) || 0,
53
+ });
54
+ }
55
+ catch (error) {
56
+ console.error('Stats error:', error);
57
+ res.status(500).json({
58
+ error: 'internal_error',
59
+ message: 'Failed to retrieve stats',
60
+ });
61
+ }
62
+ });
63
+ return router;
64
+ }
65
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../../src/server/routes/stats.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,MAAM,UAAU,iBAAiB,CAAC,SAAoB;IACpD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QAC5D,IAAI,CAAC;YACH,wDAAwD;YACxD,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,IAAK,GAAW,CAAC,IAAI,EAAE,MAAM,CAAC;YACzE,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBACnB,KAAK,EAAE,cAAc;oBACrB,OAAO,EAAE,yBAAyB;iBACnC,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YAED,qCAAqC;YACrC,IAAI,CAAC,CAAC,SAAS,YAAY,iBAAiB,CAAC,EAAE,CAAC;gBAC9C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBACnB,KAAK,EAAE,iBAAiB;oBACxB,OAAO,EAAE,4CAA4C;iBACtD,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YAED,0EAA0E;YAC1E,MAAM,OAAO,GAAG,SAAgB,CAAC;YAEjC,kCAAkC;YAClC,MAAM,UAAU,GAAG;;;;;;;OAOlB,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;YAE9D,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7B,gCAAgC;gBAChC,GAAG,CAAC,IAAI,CAAC;oBACP,aAAa,EAAE,CAAC;oBAChB,WAAW,EAAE,GAAG;oBAChB,eAAe,EAAE,CAAC;iBACnB,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YAED,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAE3B,GAAG,CAAC,IAAI,CAAC;gBACP,aAAa,EAAE,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC;gBAChD,WAAW,EAAE,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,GAAG;gBAChD,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC;aACpE,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;YACrC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,gBAAgB;gBACvB,OAAO,EAAE,0BAA0B;aACpC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Stripe webhook handler for subscription management
3
+ */
4
+ import { Router } from 'express';
5
+ /**
6
+ * Create Stripe webhook router
7
+ */
8
+ export declare function createStripeRouter(): Router;
9
+ //# sourceMappingURL=stripe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stripe.d.ts","sourceRoot":"","sources":["../../../src/server/routes/stripe.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAepD;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CA4G3C"}
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Stripe webhook handler for subscription management
3
+ */
4
+ import { Router } from 'express';
5
+ import Stripe from 'stripe';
6
+ import pg from 'pg';
7
+ const { Pool } = pg;
8
+ /**
9
+ * Tier configuration (weekly usage model)
10
+ */
11
+ const TIER_LIMITS = {
12
+ free: { weekly_limit: 125, burst_limit: 25, rate_limit: 10 },
13
+ pro: { weekly_limit: 1250, burst_limit: 100, rate_limit: 60 },
14
+ max: { weekly_limit: 6250, burst_limit: 500, rate_limit: 200 },
15
+ };
16
+ /**
17
+ * Create Stripe webhook router
18
+ */
19
+ export function createStripeRouter() {
20
+ const router = Router();
21
+ const stripeSecretKey = process.env.STRIPE_SECRET_KEY;
22
+ const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
23
+ const dbUrl = process.env.DATABASE_URL;
24
+ if (!stripeSecretKey) {
25
+ console.warn('STRIPE_SECRET_KEY not configured - Stripe webhooks disabled');
26
+ return router;
27
+ }
28
+ if (!webhookSecret) {
29
+ console.warn('STRIPE_WEBHOOK_SECRET not configured - Stripe webhooks disabled');
30
+ return router;
31
+ }
32
+ if (!dbUrl) {
33
+ throw new Error('DATABASE_URL environment variable is required');
34
+ }
35
+ const stripe = new Stripe(stripeSecretKey);
36
+ const pool = new Pool({
37
+ connectionString: dbUrl,
38
+ // TLS: enabled when DATABASE_URL contains sslmode=require.
39
+ // Secure by default (rejectUnauthorized: true); set PG_REJECT_UNAUTHORIZED=false
40
+ // only for managed DBs (Render/Neon/Supabase) that use self-signed certs.
41
+ ssl: process.env.DATABASE_URL?.includes('sslmode=require')
42
+ ? { rejectUnauthorized: process.env.PG_REJECT_UNAUTHORIZED !== 'false' }
43
+ : undefined,
44
+ });
45
+ /**
46
+ * POST /v1/webhooks/stripe
47
+ * Handle Stripe webhook events
48
+ * SECURITY: Verifies webhook signature
49
+ */
50
+ router.post('/', async (req, res) => {
51
+ try {
52
+ const sig = req.headers['stripe-signature'];
53
+ if (!sig || typeof sig !== 'string') {
54
+ res.status(400).json({
55
+ error: 'missing_signature',
56
+ message: 'Stripe signature header missing',
57
+ });
58
+ return;
59
+ }
60
+ // SECURITY: Verify webhook signature
61
+ let event;
62
+ try {
63
+ event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);
64
+ }
65
+ catch (err) {
66
+ console.error('Webhook signature verification failed:', err.message);
67
+ res.status(400).json({
68
+ error: 'invalid_signature',
69
+ message: 'Webhook signature verification failed',
70
+ });
71
+ return;
72
+ }
73
+ // Handle different event types
74
+ switch (event.type) {
75
+ case 'checkout.session.completed': {
76
+ const session = event.data.object;
77
+ await handleCheckoutCompleted(pool, session);
78
+ break;
79
+ }
80
+ case 'customer.subscription.updated': {
81
+ const subscription = event.data.object;
82
+ await handleSubscriptionUpdated(pool, subscription);
83
+ break;
84
+ }
85
+ case 'customer.subscription.deleted': {
86
+ const subscription = event.data.object;
87
+ await handleSubscriptionDeleted(pool, subscription);
88
+ break;
89
+ }
90
+ case 'invoice.payment_failed': {
91
+ const invoice = event.data.object;
92
+ await handlePaymentFailed(pool, invoice);
93
+ break;
94
+ }
95
+ default:
96
+ console.log(`Unhandled event type: ${event.type}`);
97
+ }
98
+ res.json({ received: true });
99
+ }
100
+ catch (error) {
101
+ console.error('Webhook error:', error);
102
+ res.status(500).json({
103
+ error: 'webhook_failed',
104
+ message: 'Failed to process webhook',
105
+ });
106
+ }
107
+ });
108
+ return router;
109
+ }
110
+ /**
111
+ * Handle checkout.session.completed
112
+ * Upgrade user tier and set limits
113
+ */
114
+ async function handleCheckoutCompleted(pool, session) {
115
+ try {
116
+ const customerId = session.customer;
117
+ const subscriptionId = session.subscription;
118
+ // Get subscription to determine tier
119
+ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
120
+ const subscription = await stripe.subscriptions.retrieve(subscriptionId);
121
+ // Determine tier from price ID (you'll need to configure these)
122
+ const priceId = subscription.items.data[0]?.price.id;
123
+ const tier = getTierFromPriceId(priceId);
124
+ const limits = TIER_LIMITS[tier];
125
+ // Update user
126
+ await pool.query(`UPDATE users
127
+ SET
128
+ stripe_customer_id = $1,
129
+ stripe_subscription_id = $2,
130
+ tier = $3,
131
+ weekly_limit = $4,
132
+ burst_limit = $5,
133
+ rate_limit = $6,
134
+ updated_at = now()
135
+ WHERE stripe_customer_id = $1 OR email = $7`, [
136
+ customerId,
137
+ subscriptionId,
138
+ tier,
139
+ limits.weekly_limit,
140
+ limits.burst_limit,
141
+ limits.rate_limit,
142
+ session.customer_email,
143
+ ]);
144
+ console.log(`Checkout completed for customer ${customerId}: upgraded to ${tier}`);
145
+ }
146
+ catch (error) {
147
+ console.error('Failed to handle checkout completion:', error);
148
+ throw error;
149
+ }
150
+ }
151
+ /**
152
+ * Handle customer.subscription.updated
153
+ * Update user tier based on subscription changes
154
+ */
155
+ async function handleSubscriptionUpdated(pool, subscription) {
156
+ try {
157
+ const customerId = subscription.customer;
158
+ const priceId = subscription.items.data[0]?.price.id;
159
+ const tier = getTierFromPriceId(priceId);
160
+ const limits = TIER_LIMITS[tier];
161
+ await pool.query(`UPDATE users
162
+ SET
163
+ tier = $1,
164
+ weekly_limit = $2,
165
+ burst_limit = $3,
166
+ rate_limit = $4,
167
+ stripe_subscription_id = $5,
168
+ updated_at = now()
169
+ WHERE stripe_customer_id = $6`, [tier, limits.weekly_limit, limits.burst_limit, limits.rate_limit, subscription.id, customerId]);
170
+ console.log(`Subscription updated for customer ${customerId}: tier=${tier}`);
171
+ }
172
+ catch (error) {
173
+ console.error('Failed to handle subscription update:', error);
174
+ throw error;
175
+ }
176
+ }
177
+ /**
178
+ * Handle customer.subscription.deleted
179
+ * Downgrade user to free tier
180
+ */
181
+ async function handleSubscriptionDeleted(pool, subscription) {
182
+ try {
183
+ const customerId = subscription.customer;
184
+ const limits = TIER_LIMITS.free;
185
+ await pool.query(`UPDATE users
186
+ SET
187
+ tier = 'free',
188
+ weekly_limit = $1,
189
+ burst_limit = $2,
190
+ rate_limit = $3,
191
+ stripe_subscription_id = NULL,
192
+ updated_at = now()
193
+ WHERE stripe_customer_id = $4`, [limits.weekly_limit, limits.burst_limit, limits.rate_limit, customerId]);
194
+ console.log(`Subscription deleted for customer ${customerId}: downgraded to free`);
195
+ }
196
+ catch (error) {
197
+ console.error('Failed to handle subscription deletion:', error);
198
+ throw error;
199
+ }
200
+ }
201
+ /**
202
+ * Handle invoice.payment_failed
203
+ * Log payment failure (could add email notification here)
204
+ */
205
+ async function handlePaymentFailed(pool, invoice) {
206
+ try {
207
+ const customerId = invoice.customer;
208
+ // Get user email for logging
209
+ const result = await pool.query('SELECT email FROM users WHERE stripe_customer_id = $1', [customerId]);
210
+ if (result.rows.length > 0) {
211
+ console.warn(`Payment failed for customer ${customerId} (${result.rows[0].email})`);
212
+ // Note: Email notification not implemented. Log only for now.
213
+ }
214
+ }
215
+ catch (error) {
216
+ console.error('Failed to handle payment failure:', error);
217
+ throw error;
218
+ }
219
+ }
220
+ /**
221
+ * Map Stripe price ID to tier
222
+ * Maps Stripe price IDs to tiers (configured via STRIPE_PRICE_PRO and STRIPE_PRICE_MAX env vars)
223
+ */
224
+ function getTierFromPriceId(priceId) {
225
+ // Map price IDs to tiers
226
+ const priceMap = {
227
+ // Add your Stripe price IDs here
228
+ [process.env.STRIPE_PRICE_PRO || '']: 'pro',
229
+ [process.env.STRIPE_PRICE_MAX || '']: 'max',
230
+ };
231
+ return priceMap[priceId] || 'free';
232
+ }
233
+ //# sourceMappingURL=stripe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stripe.js","sourceRoot":"","sources":["../../../src/server/routes/stripe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * User authentication and API key management routes
3
+ */
4
+ import { Router } from 'express';
5
+ /**
6
+ * Create user routes
7
+ */
8
+ export declare function createUserRouter(): Router;
9
+ //# sourceMappingURL=users.d.ts.map