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,7 @@
1
+ /**
2
+ * Activity endpoint - provides recent API request history
3
+ */
4
+ import { Router } from 'express';
5
+ import { AuthStore } from '../auth-store.js';
6
+ export declare function createActivityRouter(authStore: AuthStore): Router;
7
+ //# sourceMappingURL=activity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../../../src/server/routes/activity.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAkEjE"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Activity endpoint - provides recent API request history
3
+ */
4
+ import { Router } from 'express';
5
+ import { PostgresAuthStore } from '../pg-auth-store.js';
6
+ export function createActivityRouter(authStore) {
7
+ const router = Router();
8
+ router.get('/v1/activity', 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: 'Activity 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
+ const limit = Math.min(parseInt(req.query.limit) || 50, 100);
30
+ // Get recent requests from usage_logs
31
+ const activityQuery = `
32
+ SELECT
33
+ id,
34
+ url,
35
+ method,
36
+ status_code,
37
+ processing_time_ms,
38
+ created_at
39
+ FROM usage_logs
40
+ WHERE user_id = $1
41
+ ORDER BY created_at DESC
42
+ LIMIT $2
43
+ `;
44
+ const result = await pgStore.pool.query(activityQuery, [userId, limit]);
45
+ // Transform to frontend format
46
+ const requests = result.rows.map((row) => ({
47
+ id: row.id,
48
+ url: row.url || 'N/A',
49
+ status: (row.status_code >= 200 && row.status_code < 300) ? 'success' : 'error',
50
+ responseTime: row.processing_time_ms || 0,
51
+ mode: row.method || 'basic',
52
+ timestamp: row.created_at,
53
+ }));
54
+ res.json({ requests });
55
+ }
56
+ catch (error) {
57
+ console.error('Activity error:', error);
58
+ res.status(500).json({
59
+ error: 'internal_error',
60
+ message: 'Failed to retrieve activity',
61
+ });
62
+ }
63
+ });
64
+ return router;
65
+ }
66
+ //# sourceMappingURL=activity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity.js","sourceRoot":"","sources":["../../../src/server/routes/activity.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,MAAM,UAAU,oBAAoB,CAAC,SAAoB;IACvD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QAC/D,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,+CAA+C;iBACzD,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YAED,0EAA0E;YAC1E,MAAM,OAAO,GAAG,SAAgB,CAAC;YACjC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAe,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;YAEvE,sCAAsC;YACtC,MAAM,aAAa,GAAG;;;;;;;;;;;;OAYrB,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;YAExE,+BAA+B;YAC/B,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,CAAC;gBAC9C,EAAE,EAAE,GAAG,CAAC,EAAE;gBACV,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,KAAK;gBACrB,MAAM,EAAE,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,IAAI,GAAG,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO;gBAC/E,YAAY,EAAE,GAAG,CAAC,kBAAkB,IAAI,CAAC;gBACzC,IAAI,EAAE,GAAG,CAAC,MAAM,IAAI,OAAO;gBAC3B,SAAS,EAAE,GAAG,CAAC,UAAU;aAC1B,CAAC,CAAC,CAAC;YAEJ,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QACzB,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;YACxC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,gBAAgB;gBACvB,OAAO,EAAE,6BAA6B;aACvC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Agent API - autonomous web research endpoint
3
+ *
4
+ * Supports:
5
+ * - POST /v1/agent — synchronous (default) or SSE streaming (stream: true)
6
+ * - POST /v1/agent/async — async with job queue
7
+ * - GET /v1/agent/:id — job status
8
+ * - DELETE /v1/agent/:id — cancel job
9
+ */
10
+ import { Router } from 'express';
11
+ export declare function createAgentRouter(): Router;
12
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/server/routes/agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AASpD,wBAAgB,iBAAiB,IAAI,MAAM,CA+Y1C"}
@@ -0,0 +1,356 @@
1
+ /**
2
+ * Agent API - autonomous web research endpoint
3
+ *
4
+ * Supports:
5
+ * - POST /v1/agent — synchronous (default) or SSE streaming (stream: true)
6
+ * - POST /v1/agent/async — async with job queue
7
+ * - GET /v1/agent/:id — job status
8
+ * - DELETE /v1/agent/:id — cancel job
9
+ */
10
+ import { Router } from 'express';
11
+ import { runAgent } from '../../core/agent.js';
12
+ import { jobQueue } from '../job-queue.js';
13
+ import { sendWebhook } from './webhooks.js';
14
+ const VALID_DEPTHS = ['basic', 'thorough'];
15
+ const VALID_TOPICS = ['general', 'news', 'technical', 'academic'];
16
+ export function createAgentRouter() {
17
+ const router = Router();
18
+ /**
19
+ * POST /v1/agent - Run autonomous web research (synchronous or SSE streaming)
20
+ */
21
+ router.post('/v1/agent', async (req, res) => {
22
+ try {
23
+ const { prompt, urls, schema, outputSchema, llmApiKey, llmApiBase, llmModel, maxPages, maxSources, maxCredits, depth, topic, stream, } = req.body;
24
+ // Validate required parameters
25
+ if (!prompt || typeof prompt !== 'string') {
26
+ res.status(400).json({
27
+ error: 'invalid_request',
28
+ message: 'Missing or invalid "prompt" parameter',
29
+ });
30
+ return;
31
+ }
32
+ if (!llmApiKey || typeof llmApiKey !== 'string') {
33
+ res.status(400).json({
34
+ error: 'invalid_request',
35
+ message: 'Missing or invalid "llmApiKey" parameter (BYOK required)',
36
+ });
37
+ return;
38
+ }
39
+ // Validate optional parameters
40
+ if (urls && !Array.isArray(urls)) {
41
+ res.status(400).json({ error: 'invalid_request', message: '"urls" must be an array' });
42
+ return;
43
+ }
44
+ if (depth && !VALID_DEPTHS.includes(depth)) {
45
+ res.status(400).json({
46
+ error: 'invalid_request',
47
+ message: `"depth" must be one of: ${VALID_DEPTHS.join(', ')}`,
48
+ });
49
+ return;
50
+ }
51
+ if (topic && !VALID_TOPICS.includes(topic)) {
52
+ res.status(400).json({
53
+ error: 'invalid_request',
54
+ message: `"topic" must be one of: ${VALID_TOPICS.join(', ')}`,
55
+ });
56
+ return;
57
+ }
58
+ if (maxSources !== undefined) {
59
+ if (typeof maxSources !== 'number' || maxSources < 1 || maxSources > 20) {
60
+ res.status(400).json({
61
+ error: 'invalid_request',
62
+ message: '"maxSources" must be a number between 1 and 20',
63
+ });
64
+ return;
65
+ }
66
+ }
67
+ if (outputSchema !== undefined && (typeof outputSchema !== 'object' || outputSchema === null)) {
68
+ res.status(400).json({
69
+ error: 'invalid_request',
70
+ message: '"outputSchema" must be a JSON Schema object',
71
+ });
72
+ return;
73
+ }
74
+ // Build agent options
75
+ const agentOptions = {
76
+ prompt,
77
+ urls,
78
+ schema,
79
+ outputSchema,
80
+ llmApiKey,
81
+ llmApiBase,
82
+ llmModel,
83
+ maxPages,
84
+ maxSources,
85
+ maxCredits,
86
+ depth,
87
+ topic,
88
+ };
89
+ // -----------------------------------------------------------------------
90
+ // SSE Streaming mode
91
+ // -----------------------------------------------------------------------
92
+ if (stream) {
93
+ res.setHeader('Content-Type', 'text/event-stream');
94
+ res.setHeader('Cache-Control', 'no-cache');
95
+ res.setHeader('Connection', 'keep-alive');
96
+ res.setHeader('X-Accel-Buffering', 'no'); // Disable nginx buffering
97
+ res.flushHeaders();
98
+ const sendSSE = (data) => {
99
+ if (!res.writableEnded) {
100
+ res.write(`data: ${JSON.stringify(data)}\n\n`);
101
+ }
102
+ };
103
+ let closed = false;
104
+ req.on('close', () => { closed = true; });
105
+ agentOptions.onEvent = (event) => {
106
+ if (closed)
107
+ return;
108
+ sendSSE(event);
109
+ };
110
+ try {
111
+ await runAgent(agentOptions);
112
+ // The 'done' event is already emitted by runAgent via onEvent
113
+ // End the stream
114
+ if (!res.writableEnded) {
115
+ res.end();
116
+ }
117
+ }
118
+ catch (error) {
119
+ sendSSE({ type: 'error', message: error.message || 'Agent failed' });
120
+ if (!res.writableEnded) {
121
+ res.end();
122
+ }
123
+ }
124
+ return;
125
+ }
126
+ // -----------------------------------------------------------------------
127
+ // Normal synchronous mode (backward compatible)
128
+ // -----------------------------------------------------------------------
129
+ const result = await runAgent(agentOptions);
130
+ res.json(result);
131
+ }
132
+ catch (error) {
133
+ console.error('Agent error:', error);
134
+ res.status(500).json({
135
+ error: 'internal_error',
136
+ message: 'An unexpected error occurred. Please try again.',
137
+ });
138
+ }
139
+ });
140
+ /**
141
+ * POST /v1/agent/async - Run autonomous web research (async with job queue)
142
+ */
143
+ router.post('/v1/agent/async', async (req, res) => {
144
+ try {
145
+ const { prompt, urls, schema, outputSchema, llmApiKey, llmApiBase, llmModel, maxPages, maxSources, maxCredits, depth, topic, webhook, } = req.body;
146
+ // Validate required parameters
147
+ if (!prompt || typeof prompt !== 'string') {
148
+ res.status(400).json({
149
+ error: 'invalid_request',
150
+ message: 'Missing or invalid "prompt" parameter',
151
+ });
152
+ return;
153
+ }
154
+ if (!llmApiKey || typeof llmApiKey !== 'string') {
155
+ res.status(400).json({
156
+ error: 'invalid_request',
157
+ message: 'Missing or invalid "llmApiKey" parameter (BYOK required)',
158
+ });
159
+ return;
160
+ }
161
+ // Create job (use 'extract' type since agent extracts data, with owner for authorization)
162
+ const ownerId = req.auth?.keyInfo?.accountId;
163
+ const job = jobQueue.createJob('extract', webhook, ownerId);
164
+ // Start agent in background
165
+ setImmediate(async () => {
166
+ try {
167
+ // Update job to processing
168
+ jobQueue.updateJob(job.id, { status: 'processing' });
169
+ // Send started webhook
170
+ if (webhook) {
171
+ await sendWebhook(webhook, 'started', {
172
+ jobId: job.id,
173
+ prompt,
174
+ });
175
+ }
176
+ // Build agent options with progress callback
177
+ const agentOptions = {
178
+ prompt,
179
+ urls,
180
+ schema,
181
+ outputSchema,
182
+ llmApiKey,
183
+ llmApiBase,
184
+ llmModel,
185
+ maxPages,
186
+ maxSources,
187
+ maxCredits,
188
+ depth,
189
+ topic,
190
+ onProgress: (progress) => {
191
+ // Update job progress
192
+ jobQueue.updateJob(job.id, {
193
+ completed: progress.pagesVisited,
194
+ creditsUsed: progress.pagesVisited,
195
+ });
196
+ // Send progress webhook
197
+ if (webhook && progress.currentUrl) {
198
+ sendWebhook(webhook, 'progress', {
199
+ jobId: job.id,
200
+ status: progress.status,
201
+ currentUrl: progress.currentUrl,
202
+ pagesVisited: progress.pagesVisited,
203
+ message: progress.message,
204
+ }).catch(() => { }); // Fire and forget
205
+ }
206
+ },
207
+ };
208
+ // Run agent
209
+ const result = await runAgent(agentOptions);
210
+ // Update job with results
211
+ if (result.success) {
212
+ jobQueue.updateJob(job.id, {
213
+ status: 'completed',
214
+ data: [result], // Wrap in array to match Job type
215
+ completed: result.pagesVisited,
216
+ creditsUsed: result.creditsUsed,
217
+ });
218
+ // Send completed webhook
219
+ if (webhook) {
220
+ await sendWebhook(webhook, 'completed', {
221
+ jobId: job.id,
222
+ pagesVisited: result.pagesVisited,
223
+ creditsUsed: result.creditsUsed,
224
+ });
225
+ }
226
+ }
227
+ else {
228
+ // Agent returned failure
229
+ jobQueue.updateJob(job.id, {
230
+ status: 'failed',
231
+ error: result.data?.error || 'Agent failed',
232
+ data: [result], // Wrap in array to match Job type
233
+ completed: result.pagesVisited,
234
+ creditsUsed: result.creditsUsed,
235
+ });
236
+ // Send failed webhook
237
+ if (webhook) {
238
+ await sendWebhook(webhook, 'failed', {
239
+ jobId: job.id,
240
+ error: result.data?.error || 'Agent failed',
241
+ });
242
+ }
243
+ }
244
+ }
245
+ catch (error) {
246
+ // Update job with error
247
+ jobQueue.updateJob(job.id, {
248
+ status: 'failed',
249
+ error: error.message || 'Unknown error',
250
+ });
251
+ // Send failed webhook
252
+ if (webhook) {
253
+ await sendWebhook(webhook, 'failed', {
254
+ jobId: job.id,
255
+ error: error.message || 'Unknown error',
256
+ });
257
+ }
258
+ }
259
+ });
260
+ // Return job ID immediately
261
+ res.status(202).json({
262
+ success: true,
263
+ id: job.id,
264
+ url: `/v1/agent/${job.id}`,
265
+ });
266
+ }
267
+ catch (error) {
268
+ console.error('Agent job creation error:', error);
269
+ res.status(500).json({
270
+ error: 'internal_error',
271
+ message: 'Failed to create agent job',
272
+ });
273
+ }
274
+ });
275
+ /**
276
+ * GET /v1/agent/:id - Get agent job status + results
277
+ */
278
+ router.get('/v1/agent/:id', (req, res) => {
279
+ try {
280
+ const id = req.params.id;
281
+ const job = jobQueue.getJob(id);
282
+ if (!job) {
283
+ res.status(404).json({
284
+ error: 'not_found',
285
+ message: 'Job not found',
286
+ });
287
+ return;
288
+ }
289
+ // SECURITY: Verify the requester owns this job
290
+ const requestOwnerId = req.auth?.keyInfo?.accountId;
291
+ if (job.ownerId && requestOwnerId && job.ownerId !== requestOwnerId) {
292
+ res.status(404).json({
293
+ error: 'not_found',
294
+ message: 'Job not found',
295
+ });
296
+ return;
297
+ }
298
+ // Return JSON response
299
+ res.json({
300
+ success: true,
301
+ status: job.status,
302
+ completed: job.completed,
303
+ creditsUsed: job.creditsUsed,
304
+ data: job.data,
305
+ error: job.error,
306
+ expiresAt: job.expiresAt,
307
+ });
308
+ }
309
+ catch (error) {
310
+ console.error('Get agent job error:', error);
311
+ res.status(500).json({
312
+ error: 'internal_error',
313
+ message: 'Failed to retrieve job',
314
+ });
315
+ }
316
+ });
317
+ /**
318
+ * DELETE /v1/agent/:id - Cancel agent job
319
+ */
320
+ router.delete('/v1/agent/:id', (req, res) => {
321
+ try {
322
+ const id = req.params.id;
323
+ // SECURITY: Verify the requester owns this job before cancelling
324
+ const job = jobQueue.getJob(id);
325
+ const requestOwnerId = req.auth?.keyInfo?.accountId;
326
+ if (job?.ownerId && requestOwnerId && job.ownerId !== requestOwnerId) {
327
+ res.status(404).json({
328
+ error: 'not_found',
329
+ message: 'Job not found or cannot be cancelled',
330
+ });
331
+ return;
332
+ }
333
+ const cancelled = jobQueue.cancelJob(id);
334
+ if (!cancelled) {
335
+ res.status(404).json({
336
+ error: 'not_found',
337
+ message: 'Job not found or cannot be cancelled',
338
+ });
339
+ return;
340
+ }
341
+ res.json({
342
+ success: true,
343
+ message: 'Job cancelled',
344
+ });
345
+ }
346
+ catch (error) {
347
+ console.error('Cancel agent job error:', error);
348
+ res.status(500).json({
349
+ error: 'internal_error',
350
+ message: 'Failed to cancel job',
351
+ });
352
+ }
353
+ });
354
+ return router;
355
+ }
356
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../src/server/routes/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * /v1/answer — search + fetch + LLM-generated answer with citations (BYOK)
3
+ */
4
+ import { Router } from 'express';
5
+ export declare function createAnswerRouter(): Router;
6
+ //# sourceMappingURL=answer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../../src/server/routes/answer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAWpD,wBAAgB,kBAAkB,IAAI,MAAM,CAsJ3C"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * /v1/answer — search + fetch + LLM-generated answer with citations (BYOK)
3
+ */
4
+ import { Router } from 'express';
5
+ import { answerQuestion, } from '../../core/answer.js';
6
+ const VALID_LLM_PROVIDERS = ['openai', 'anthropic', 'google'];
7
+ const VALID_SEARCH_PROVIDERS = ['duckduckgo', 'brave'];
8
+ export function createAnswerRouter() {
9
+ const router = Router();
10
+ router.post('/v1/answer', async (req, res) => {
11
+ try {
12
+ const { question, searchProvider, searchApiKey, llmProvider, llmApiKey, llmModel, maxSources, stream, } = req.body;
13
+ // --- Validation -----------------------------------------------------------
14
+ if (!question || typeof question !== 'string' || question.trim().length === 0) {
15
+ res.status(400).json({
16
+ error: 'invalid_request',
17
+ message: 'Missing or invalid "question" parameter',
18
+ });
19
+ return;
20
+ }
21
+ if (question.length > 2000) {
22
+ res.status(400).json({
23
+ error: 'invalid_request',
24
+ message: '"question" too long (max 2000 characters)',
25
+ });
26
+ return;
27
+ }
28
+ if (!llmProvider || !VALID_LLM_PROVIDERS.includes(llmProvider)) {
29
+ res.status(400).json({
30
+ error: 'invalid_request',
31
+ message: `"llmProvider" is required and must be one of: ${VALID_LLM_PROVIDERS.join(', ')}`,
32
+ });
33
+ return;
34
+ }
35
+ if (!llmApiKey || typeof llmApiKey !== 'string' || llmApiKey.trim().length === 0) {
36
+ res.status(400).json({
37
+ error: 'invalid_request',
38
+ message: 'Missing or invalid "llmApiKey" (BYOK required)',
39
+ });
40
+ return;
41
+ }
42
+ const resolvedSearchProvider = searchProvider && VALID_SEARCH_PROVIDERS.includes(searchProvider)
43
+ ? searchProvider
44
+ : 'duckduckgo';
45
+ // Accept search API key from body or header
46
+ const resolvedSearchApiKey = searchApiKey || req.headers['x-search-api-key'] || undefined;
47
+ const resolvedMaxSources = typeof maxSources === 'number'
48
+ ? Math.min(Math.max(maxSources, 1), 10)
49
+ : 5;
50
+ const shouldStream = stream === true;
51
+ // --- Streaming response (SSE) -------------------------------------------
52
+ if (shouldStream) {
53
+ res.setHeader('Content-Type', 'text/event-stream');
54
+ res.setHeader('Cache-Control', 'no-cache');
55
+ res.setHeader('Connection', 'keep-alive');
56
+ res.setHeader('X-Accel-Buffering', 'no'); // nginx
57
+ res.flushHeaders();
58
+ const answerReq = {
59
+ question: question.trim(),
60
+ searchProvider: resolvedSearchProvider,
61
+ searchApiKey: resolvedSearchApiKey,
62
+ llmProvider: llmProvider,
63
+ llmApiKey: llmApiKey.trim(),
64
+ llmModel,
65
+ maxSources: resolvedMaxSources,
66
+ stream: true,
67
+ onChunk: (text) => {
68
+ const payload = JSON.stringify({ type: 'chunk', text });
69
+ res.write(`data: ${payload}\n\n`);
70
+ },
71
+ };
72
+ try {
73
+ const result = await answerQuestion(answerReq);
74
+ const donePayload = JSON.stringify({
75
+ type: 'done',
76
+ citations: result.citations,
77
+ searchProvider: result.searchProvider,
78
+ llmProvider: result.llmProvider,
79
+ llmModel: result.llmModel,
80
+ tokensUsed: result.tokensUsed,
81
+ });
82
+ res.write(`data: ${donePayload}\n\n`);
83
+ }
84
+ catch (err) {
85
+ const errMsg = err instanceof Error ? err.message : 'Unknown error';
86
+ const errPayload = JSON.stringify({ type: 'error', message: errMsg });
87
+ res.write(`data: ${errPayload}\n\n`);
88
+ }
89
+ res.end();
90
+ return;
91
+ }
92
+ // --- Non-streaming response ---------------------------------------------
93
+ const answerReq = {
94
+ question: question.trim(),
95
+ searchProvider: resolvedSearchProvider,
96
+ searchApiKey: resolvedSearchApiKey,
97
+ llmProvider: llmProvider,
98
+ llmApiKey: llmApiKey.trim(),
99
+ llmModel,
100
+ maxSources: resolvedMaxSources,
101
+ stream: false,
102
+ };
103
+ const result = await answerQuestion(answerReq);
104
+ res.json({
105
+ answer: result.answer,
106
+ citations: result.citations,
107
+ searchProvider: result.searchProvider,
108
+ llmProvider: result.llmProvider,
109
+ llmModel: result.llmModel,
110
+ tokensUsed: result.tokensUsed,
111
+ });
112
+ }
113
+ catch (error) {
114
+ const err = error;
115
+ console.error('Answer error:', err);
116
+ res.status(500).json({
117
+ error: 'answer_failed',
118
+ message: 'Failed to generate answer. Please try again.',
119
+ });
120
+ }
121
+ });
122
+ return router;
123
+ }
124
+ //# sourceMappingURL=answer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"answer.js","sourceRoot":"","sources":["../../../src/server/routes/answer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Batch scrape API - process multiple URLs concurrently
3
+ */
4
+ import { Router } from 'express';
5
+ import type { IJobQueue } from '../job-queue.js';
6
+ export declare function createBatchRouter(jobQueue: IJobQueue): Router;
7
+ //# sourceMappingURL=batch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../../src/server/routes/batch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAGpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,SAAS,GAAG,MAAM,CAoT7D"}