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
+ * Batch scrape API - process multiple URLs concurrently
3
+ */
4
+ import { Router } from 'express';
5
+ import { peel } from '../../index.js';
6
+ import { sendWebhook } from './webhooks.js';
7
+ export function createBatchRouter(jobQueue) {
8
+ const router = Router();
9
+ /**
10
+ * POST /v1/batch/scrape - Submit batch of URLs
11
+ */
12
+ router.post('/v1/batch/scrape', async (req, res) => {
13
+ try {
14
+ const { urls, formats, extract, maxTokens, webhook } = req.body;
15
+ // Validate required parameters
16
+ if (!urls || !Array.isArray(urls) || urls.length === 0) {
17
+ res.status(400).json({
18
+ error: 'invalid_request',
19
+ message: 'Missing or invalid "urls" parameter (must be non-empty array)',
20
+ });
21
+ return;
22
+ }
23
+ // Limit batch size
24
+ if (urls.length > 100) {
25
+ res.status(400).json({
26
+ error: 'invalid_request',
27
+ message: 'Batch size too large (max 100 URLs)',
28
+ });
29
+ return;
30
+ }
31
+ // Validate URLs
32
+ for (const url of urls) {
33
+ if (typeof url !== 'string') {
34
+ res.status(400).json({
35
+ error: 'invalid_request',
36
+ message: 'All URLs must be strings',
37
+ });
38
+ return;
39
+ }
40
+ try {
41
+ new URL(url);
42
+ }
43
+ catch {
44
+ res.status(400).json({
45
+ error: 'invalid_url',
46
+ message: `Invalid URL format: ${url}`,
47
+ });
48
+ return;
49
+ }
50
+ }
51
+ // Create job (with owner for authorization)
52
+ const ownerId = req.auth?.keyInfo?.accountId;
53
+ const job = await jobQueue.createJob('batch', webhook, ownerId);
54
+ await jobQueue.updateJob(job.id, {
55
+ total: urls.length,
56
+ });
57
+ // Start batch processing in background
58
+ setImmediate(async () => {
59
+ try {
60
+ // Update job to processing
61
+ jobQueue.updateJob(job.id, { status: 'processing' });
62
+ // Send started webhook
63
+ if (webhook) {
64
+ await sendWebhook(webhook, 'started', {
65
+ jobId: job.id,
66
+ total: urls.length,
67
+ });
68
+ }
69
+ // Build peel options
70
+ const peelOptions = {
71
+ format: formats?.[0] || 'markdown',
72
+ extract,
73
+ maxTokens,
74
+ };
75
+ // Process URLs with semaphore (max 5 concurrent)
76
+ const results = [];
77
+ const maxConcurrent = 5;
78
+ let activeCount = 0;
79
+ let urlIndex = 0;
80
+ const processBatch = async () => {
81
+ while (urlIndex < urls.length) {
82
+ // Check if job was cancelled
83
+ const currentJob = await jobQueue.getJob(job.id);
84
+ if (currentJob?.status === 'cancelled') {
85
+ return;
86
+ }
87
+ // Wait for available slot
88
+ while (activeCount >= maxConcurrent) {
89
+ await new Promise(resolve => setTimeout(resolve, 100));
90
+ }
91
+ const url = urls[urlIndex];
92
+ const index = urlIndex;
93
+ urlIndex++;
94
+ activeCount++;
95
+ // Process URL
96
+ (async () => {
97
+ try {
98
+ const result = await peel(url, peelOptions);
99
+ results[index] = result;
100
+ // Update progress
101
+ const completed = results.filter(r => r !== undefined).length;
102
+ jobQueue.updateJob(job.id, {
103
+ completed,
104
+ creditsUsed: completed,
105
+ });
106
+ // Send page webhook
107
+ if (webhook) {
108
+ sendWebhook(webhook, 'page', {
109
+ jobId: job.id,
110
+ url,
111
+ completed,
112
+ total: urls.length,
113
+ }).catch(() => { }); // Fire and forget
114
+ }
115
+ }
116
+ catch (error) {
117
+ // Store error as result
118
+ results[index] = {
119
+ url,
120
+ error: error.message || 'Unknown error',
121
+ };
122
+ // Update progress
123
+ const completed = results.filter(r => r !== undefined).length;
124
+ jobQueue.updateJob(job.id, {
125
+ completed,
126
+ creditsUsed: completed,
127
+ });
128
+ }
129
+ finally {
130
+ activeCount--;
131
+ }
132
+ })();
133
+ }
134
+ // Wait for all tasks to complete
135
+ while (activeCount > 0) {
136
+ await new Promise(resolve => setTimeout(resolve, 100));
137
+ }
138
+ };
139
+ await processBatch();
140
+ // Update job with results
141
+ jobQueue.updateJob(job.id, {
142
+ status: 'completed',
143
+ data: results,
144
+ });
145
+ // Send completed webhook
146
+ if (webhook) {
147
+ await sendWebhook(webhook, 'completed', {
148
+ jobId: job.id,
149
+ total: urls.length,
150
+ completed: results.length,
151
+ });
152
+ }
153
+ }
154
+ catch (error) {
155
+ // Update job with error
156
+ jobQueue.updateJob(job.id, {
157
+ status: 'failed',
158
+ error: error.message || 'Unknown error',
159
+ });
160
+ // Send failed webhook
161
+ if (webhook) {
162
+ await sendWebhook(webhook, 'failed', {
163
+ jobId: job.id,
164
+ error: error.message || 'Unknown error',
165
+ });
166
+ }
167
+ }
168
+ });
169
+ // Return job ID immediately
170
+ res.status(202).json({
171
+ success: true,
172
+ id: job.id,
173
+ url: `/v1/batch/scrape/${job.id}`,
174
+ });
175
+ }
176
+ catch (error) {
177
+ console.error('Batch scrape creation error:', error);
178
+ res.status(500).json({
179
+ error: 'internal_error',
180
+ message: 'Failed to create batch scrape job',
181
+ });
182
+ }
183
+ });
184
+ /**
185
+ * GET /v1/batch/scrape/:id - Get batch scrape status + results
186
+ */
187
+ router.get('/v1/batch/scrape/:id', async (req, res) => {
188
+ try {
189
+ const id = req.params.id;
190
+ const job = await jobQueue.getJob(id);
191
+ if (!job) {
192
+ res.status(404).json({
193
+ error: 'not_found',
194
+ message: 'Job not found',
195
+ });
196
+ return;
197
+ }
198
+ // SECURITY: Verify the requester owns this job
199
+ const requestOwnerId = req.auth?.keyInfo?.accountId;
200
+ if (job.ownerId && requestOwnerId && job.ownerId !== requestOwnerId) {
201
+ res.status(404).json({
202
+ error: 'not_found',
203
+ message: 'Job not found',
204
+ });
205
+ return;
206
+ }
207
+ if (job.type !== 'batch') {
208
+ res.status(400).json({
209
+ error: 'invalid_request',
210
+ message: 'Job is not a batch scrape job',
211
+ });
212
+ return;
213
+ }
214
+ res.json({
215
+ success: true,
216
+ status: job.status,
217
+ progress: job.progress,
218
+ total: job.total,
219
+ completed: job.completed,
220
+ creditsUsed: job.creditsUsed,
221
+ data: job.data,
222
+ error: job.error,
223
+ expiresAt: job.expiresAt,
224
+ });
225
+ }
226
+ catch (error) {
227
+ console.error('Get batch scrape error:', error);
228
+ res.status(500).json({
229
+ error: 'internal_error',
230
+ message: 'Failed to retrieve job',
231
+ });
232
+ }
233
+ });
234
+ /**
235
+ * DELETE /v1/batch/scrape/:id - Cancel batch scrape job
236
+ */
237
+ router.delete('/v1/batch/scrape/:id', async (req, res) => {
238
+ try {
239
+ const id = req.params.id;
240
+ const job = await jobQueue.getJob(id);
241
+ if (!job) {
242
+ res.status(404).json({
243
+ error: 'not_found',
244
+ message: 'Job not found',
245
+ });
246
+ return;
247
+ }
248
+ // SECURITY: Verify the requester owns this job
249
+ const requestOwnerId = req.auth?.keyInfo?.accountId;
250
+ if (job.ownerId && requestOwnerId && job.ownerId !== requestOwnerId) {
251
+ res.status(404).json({
252
+ error: 'not_found',
253
+ message: 'Job not found',
254
+ });
255
+ return;
256
+ }
257
+ if (job.type !== 'batch') {
258
+ res.status(400).json({
259
+ error: 'invalid_request',
260
+ message: 'Job is not a batch scrape job',
261
+ });
262
+ return;
263
+ }
264
+ const cancelled = await jobQueue.cancelJob(id);
265
+ if (!cancelled) {
266
+ res.status(400).json({
267
+ error: 'invalid_request',
268
+ message: 'Job cannot be cancelled (already completed or failed)',
269
+ });
270
+ return;
271
+ }
272
+ res.json({
273
+ success: true,
274
+ message: 'Job cancelled',
275
+ });
276
+ }
277
+ catch (error) {
278
+ console.error('Cancel batch scrape error:', error);
279
+ res.status(500).json({
280
+ error: 'internal_error',
281
+ message: 'Failed to cancel job',
282
+ });
283
+ }
284
+ });
285
+ return router;
286
+ }
287
+ //# sourceMappingURL=batch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../../src/server/routes/batch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * CLI Usage endpoint — works with API key auth (not JWT)
3
+ * Used by the `webpeel usage` command and pre-fetch usage checks
4
+ */
5
+ import { Router } from 'express';
6
+ export declare function createCLIUsageRouter(): Router;
7
+ //# sourceMappingURL=cli-usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-usage.d.ts","sourceRoot":"","sources":["../../../src/server/routes/cli-usage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAKpD,wBAAgB,oBAAoB,IAAI,MAAM,CAwI7C"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * CLI Usage endpoint — works with API key auth (not JWT)
3
+ * Used by the `webpeel usage` command and pre-fetch usage checks
4
+ */
5
+ import { Router } from 'express';
6
+ import pg from 'pg';
7
+ const { Pool } = pg;
8
+ export function createCLIUsageRouter() {
9
+ const router = Router();
10
+ const dbUrl = process.env.DATABASE_URL;
11
+ if (!dbUrl) {
12
+ // If no DB, return a stub router
13
+ router.get('/v1/cli/usage', (_req, res) => {
14
+ res.status(501).json({
15
+ error: 'not_configured',
16
+ message: 'Usage tracking requires PostgreSQL backend',
17
+ });
18
+ });
19
+ return router;
20
+ }
21
+ const pool = new Pool({
22
+ connectionString: dbUrl,
23
+ // TLS: enabled when DATABASE_URL contains sslmode=require.
24
+ // Secure by default (rejectUnauthorized: true); set PG_REJECT_UNAUTHORIZED=false
25
+ // only for managed DBs (Render/Neon/Supabase) that use self-signed certs.
26
+ ssl: process.env.DATABASE_URL?.includes('sslmode=require')
27
+ ? { rejectUnauthorized: process.env.PG_REJECT_UNAUTHORIZED !== 'false' }
28
+ : undefined,
29
+ });
30
+ /**
31
+ * GET /v1/cli/usage
32
+ * Returns usage info for the authenticated API key's owner
33
+ * Auth: API key via Authorization: Bearer <key> or X-API-Key header
34
+ */
35
+ router.get('/v1/cli/usage', async (req, res) => {
36
+ try {
37
+ // Require API key auth (set by global auth middleware)
38
+ if (!req.auth?.keyInfo?.accountId) {
39
+ res.status(401).json({
40
+ error: 'unauthorized',
41
+ message: 'Valid API key required. Run `webpeel login` to authenticate.',
42
+ });
43
+ return;
44
+ }
45
+ const userId = req.auth.keyInfo.accountId;
46
+ // Get user plan info
47
+ const planResult = await pool.query('SELECT tier, weekly_limit, burst_limit FROM users WHERE id = $1', [userId]);
48
+ if (planResult.rows.length === 0) {
49
+ res.status(404).json({ error: 'user_not_found', message: 'User not found' });
50
+ return;
51
+ }
52
+ const plan = planResult.rows[0];
53
+ // Current week (ISO format)
54
+ const now = new Date();
55
+ const year = now.getUTCFullYear();
56
+ const jan4 = new Date(Date.UTC(year, 0, 4));
57
+ const weekNum = Math.ceil(((now.getTime() - jan4.getTime()) / 86400000 + jan4.getUTCDay() + 1) / 7);
58
+ const currentWeek = `${year}-W${String(weekNum).padStart(2, '0')}`;
59
+ // Current hour bucket
60
+ const currentHour = now.toISOString().substring(0, 13);
61
+ // Get weekly usage
62
+ const weeklyResult = await pool.query(`SELECT
63
+ COALESCE(SUM(wu.total_count), 0) as total_used,
64
+ COALESCE(SUM(wu.basic_count), 0) as basic_used,
65
+ COALESCE(SUM(wu.stealth_count), 0) as stealth_used,
66
+ COALESCE(SUM(wu.search_count), 0) as search_used
67
+ FROM api_keys ak
68
+ LEFT JOIN weekly_usage wu ON wu.api_key_id = ak.id AND wu.week = $2
69
+ WHERE ak.user_id = $1 AND ak.is_active = true`, [userId, currentWeek]);
70
+ const weekly = weeklyResult.rows[0];
71
+ const totalUsed = parseInt(weekly.total_used) || 0;
72
+ const weeklyLimit = plan.weekly_limit || 125;
73
+ const remaining = Math.max(0, weeklyLimit - totalUsed);
74
+ // Get burst usage
75
+ const burstResult = await pool.query(`SELECT COALESCE(SUM(bu.count), 0) as burst_used
76
+ FROM api_keys ak
77
+ LEFT JOIN burst_usage bu ON bu.api_key_id = ak.id AND bu.hour_bucket = $2
78
+ WHERE ak.user_id = $1 AND ak.is_active = true`, [userId, currentHour]);
79
+ const burstUsed = parseInt(burstResult.rows[0]?.burst_used) || 0;
80
+ const burstLimit = plan.burst_limit || 25;
81
+ const minutesRemaining = 59 - now.getUTCMinutes();
82
+ // Get next Monday reset time
83
+ const dayOfWeek = now.getUTCDay();
84
+ const daysUntilMonday = dayOfWeek === 0 ? 1 : 8 - dayOfWeek;
85
+ const nextMonday = new Date(now);
86
+ nextMonday.setUTCDate(now.getUTCDate() + daysUntilMonday);
87
+ nextMonday.setUTCHours(0, 0, 0, 0);
88
+ res.json({
89
+ plan: {
90
+ tier: plan.tier,
91
+ weeklyLimit,
92
+ burstLimit,
93
+ },
94
+ weekly: {
95
+ used: totalUsed,
96
+ limit: weeklyLimit,
97
+ remaining,
98
+ resetsAt: nextMonday.toISOString(),
99
+ percentUsed: Math.round((totalUsed / weeklyLimit) * 100),
100
+ },
101
+ burst: {
102
+ used: burstUsed,
103
+ limit: burstLimit,
104
+ resetsIn: minutesRemaining <= 0 ? '< 1 min' : `${minutesRemaining}m`,
105
+ },
106
+ // Simple boolean flags for CLI to check quickly
107
+ canFetch: remaining > 0 && burstUsed < burstLimit,
108
+ upgradeUrl: 'https://webpeel.dev/#pricing',
109
+ });
110
+ }
111
+ catch (error) {
112
+ console.error('CLI usage error:', error);
113
+ res.status(500).json({
114
+ error: 'internal_error',
115
+ message: 'Failed to retrieve usage',
116
+ });
117
+ }
118
+ });
119
+ return router;
120
+ }
121
+ //# sourceMappingURL=cli-usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-usage.js","sourceRoot":"","sources":["../../../src/server/routes/cli-usage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Firecrawl API Compatibility Layer
3
+ *
4
+ * Drop-in replacement for Firecrawl's API - users can switch by ONLY changing the base URL.
5
+ * This is our killer acquisition feature.
6
+ *
7
+ * NOTE: Error responses in this file intentionally use Firecrawl's format:
8
+ * { success: false, error: "Human-readable message" }
9
+ * This is required for Firecrawl drop-in compatibility and differs from the
10
+ * standard WebPeel API error format: { error: "error_code", message: "description" }.
11
+ * Do NOT change this format — it would break Firecrawl-compatible integrations.
12
+ *
13
+ * Implements Firecrawl endpoints:
14
+ * - POST /v1/scrape
15
+ * - POST /v2/scrape (v2 with formats: ["screenshot"] support)
16
+ * - POST /v1/crawl
17
+ * - GET /v1/crawl/:id
18
+ * - POST /v1/search
19
+ * - POST /v1/map
20
+ */
21
+ import { Router } from 'express';
22
+ import type { IJobQueue } from '../job-queue.js';
23
+ export declare function createCompatRouter(jobQueue: IJobQueue): Router;
24
+ //# sourceMappingURL=compat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compat.d.ts","sourceRoot":"","sources":["../../../src/server/routes/compat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAKpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAkBjD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,SAAS,GAAG,MAAM,CA+sB9D"}