@endday/search-mcp 1.0.0 → 1.0.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 (84) hide show
  1. package/dist/index.js +4724 -0
  2. package/{mcp → dist}/search-mcp.js +1 -2
  3. package/package.json +14 -14
  4. package/data/blocklist.generated.js +0 -2
  5. package/envs.js +0 -129
  6. package/index.js +0 -6
  7. package/src/content/extract.impl.js +0 -228
  8. package/src/content/extract.js +0 -1
  9. package/src/content/fetch.impl.js +0 -400
  10. package/src/content/fetch.js +0 -1
  11. package/src/core/crypto.js +0 -7
  12. package/src/core/errors.impl.js +0 -52
  13. package/src/core/errors.js +0 -1
  14. package/src/core/html.impl.js +0 -69
  15. package/src/core/html.js +0 -1
  16. package/src/mcp/config.js +0 -75
  17. package/src/mcp/format.js +0 -44
  18. package/src/mcp/index.js +0 -10
  19. package/src/mcp/local/content.js +0 -26
  20. package/src/mcp/local/search.js +0 -233
  21. package/src/mcp/schemas.js +0 -132
  22. package/src/mcp/server.js +0 -97
  23. package/src/mcp/tools/content.js +0 -31
  24. package/src/mcp/tools/jinaContent.js +0 -38
  25. package/src/mcp/tools/newsSearch.js +0 -22
  26. package/src/mcp/tools/webSearch.js +0 -57
  27. package/src/platform/auth.impl.js +0 -166
  28. package/src/platform/auth.js +0 -1
  29. package/src/platform/cache.impl.js +0 -166
  30. package/src/platform/cache.js +0 -1
  31. package/src/platform/health.impl.js +0 -133
  32. package/src/platform/health.js +0 -1
  33. package/src/platform/http.impl.js +0 -108
  34. package/src/platform/http.js +0 -1
  35. package/src/platform/logger.impl.js +0 -51
  36. package/src/platform/logger.js +0 -1
  37. package/src/platform/metrics.impl.js +0 -43
  38. package/src/platform/metrics.js +0 -1
  39. package/src/platform/nodeHttpClient.js +0 -104
  40. package/src/platform/rateLimit.impl.js +0 -141
  41. package/src/platform/rateLimit.js +0 -1
  42. package/src/platform/requestContext.impl.js +0 -10
  43. package/src/platform/requestContext.js +0 -1
  44. package/src/platform/session.impl.js +0 -198
  45. package/src/platform/session.js +0 -1
  46. package/src/platform/stateKv.impl.js +0 -18
  47. package/src/platform/stateKv.js +0 -1
  48. package/src/platform/tasks.impl.js +0 -17
  49. package/src/platform/tasks.js +0 -1
  50. package/src/routes/requestParams.impl.js +0 -12
  51. package/src/routes/requestParams.js +0 -1
  52. package/src/search/engineRegistry.impl.js +0 -117
  53. package/src/search/engineRegistry.js +0 -1
  54. package/src/search/engineRequest.impl.js +0 -377
  55. package/src/search/engineRequest.js +0 -1
  56. package/src/search/engineUtils.impl.js +0 -227
  57. package/src/search/engineUtils.js +0 -1
  58. package/src/search/engines/baidu.impl.js +0 -145
  59. package/src/search/engines/baidu.js +0 -2
  60. package/src/search/engines/bing.impl.js +0 -509
  61. package/src/search/engines/bing.js +0 -2
  62. package/src/search/engines/brave.impl.js +0 -223
  63. package/src/search/engines/brave.js +0 -2
  64. package/src/search/engines/duckduckgo.impl.js +0 -164
  65. package/src/search/engines/duckduckgo.js +0 -2
  66. package/src/search/engines/mojeek.impl.js +0 -115
  67. package/src/search/engines/mojeek.js +0 -2
  68. package/src/search/engines/qwant.impl.js +0 -188
  69. package/src/search/engines/qwant.js +0 -2
  70. package/src/search/engines/startpage.impl.js +0 -237
  71. package/src/search/engines/startpage.js +0 -2
  72. package/src/search/engines/toutiao.impl.js +0 -265
  73. package/src/search/engines/toutiao.js +0 -2
  74. package/src/search/engines/yahoo.impl.js +0 -379
  75. package/src/search/engines/yahoo.js +0 -2
  76. package/src/search/gateway.impl.js +0 -423
  77. package/src/search/gateway.js +0 -1
  78. package/src/search/ranking.impl.js +0 -381
  79. package/src/search/ranking.js +0 -1
  80. package/src/search/requestPolicy.impl.js +0 -137
  81. package/src/search/requestPolicy.js +0 -1
  82. package/src/search/upstreamSession.impl.js +0 -148
  83. package/src/search/upstreamSession.js +0 -1
  84. /package/{index.d.ts → dist/index.d.ts} +0 -0
@@ -1,166 +0,0 @@
1
- import { env } from "../../envs.js";
2
- import { ApiError } from "../core/errors.js";
3
- import { validateSession, getSessionIdFromRequest } from "./session.js";
4
- import { enforceRateLimit } from "./rateLimit.js";
5
-
6
- function matchesConfigSet(value, allowedValues) {
7
- return allowedValues.includes(
8
- String(value || "").trim().toLowerCase()
9
- );
10
- }
11
-
12
- const TRUTHY_CONFIG_VALUES = ["1", "true", "yes", "on", "required"];
13
-
14
- function getBearerToken(request) {
15
- return request.headers.get("Authorization")?.replace(/^Bearer\s+/i, "");
16
- }
17
-
18
- function getRequestToken(request, paramToken) {
19
- return getBearerToken(request) || request.headers.get("x-api-key") || paramToken;
20
- }
21
-
22
- function isAuthRequired() {
23
- return !!env.TOKEN || isTruthyConfig(env.AUTH_REQUIRED);
24
- }
25
-
26
- function isTruthyConfig(value) {
27
- return matchesConfigSet(value, TRUTHY_CONFIG_VALUES);
28
- }
29
-
30
- function isAuthorizedToken(requestToken) {
31
- if (!isAuthRequired()) {
32
- return true;
33
- }
34
- return !!env.TOKEN && requestToken === env.TOKEN;
35
- }
36
-
37
- /**
38
- * Unified authentication: checks token OR session cookie.
39
- * Returns { authenticated, method } where method is 'token', 'session', or 'none'.
40
- */
41
- export async function authenticateRequest(request, params = {}) {
42
- // If auth is not required at all, allow immediately
43
- if (!isAuthRequired()) {
44
- return { authenticated: true, method: "none" };
45
- }
46
-
47
- // 1. Check token auth (Authorization header, x-api-key header, or query param)
48
- const requestToken = getRequestToken(request, params.token);
49
- if (requestToken && isAuthorizedToken(requestToken)) {
50
- return { authenticated: true, method: "token", token: requestToken };
51
- }
52
-
53
- // 2. Check session cookie
54
- const sessionResult = await validateSession(request);
55
- if (sessionResult.valid) {
56
- return {
57
- authenticated: true,
58
- method: "session",
59
- sessionId: sessionResult.sessionId,
60
- setCookie: sessionResult.setCookie,
61
- };
62
- }
63
-
64
- // 3. Not authenticated - fail closed if AUTH_REQUIRED but no TOKEN configured
65
- if (isTruthyConfig(env.AUTH_REQUIRED) && !env.TOKEN) {
66
- throw new ApiError({
67
- status: 503,
68
- code: "AUTH_TOKEN_NOT_CONFIGURED",
69
- category: "configuration",
70
- message:
71
- "AUTH_REQUIRED is enabled but TOKEN is not configured. Set TOKEN before using protected local MCP flows.",
72
- });
73
- }
74
-
75
- return { authenticated: false, method: "none" };
76
- }
77
-
78
- /**
79
- * Get the rate limit key based on auth method.
80
- */
81
- export function getRateLimitKey(authResult) {
82
- if (authResult.method === "token") {
83
- return authResult.token;
84
- }
85
- if (authResult.method === "session" && authResult.sessionId) {
86
- return `session:${authResult.sessionId}`;
87
- }
88
- // For unauthenticated, use null (IP-based rate limiting)
89
- return null;
90
- }
91
-
92
- export function getRequestClientId(request, authResult, paramToken) {
93
- if (authResult?.method === "session" && authResult.sessionId) {
94
- return `session:${authResult.sessionId}`;
95
- }
96
-
97
- if (authResult?.method === "token" && authResult.token) {
98
- return `token:${authResult.token}`;
99
- }
100
-
101
- const requestToken = getRequestToken(request, paramToken);
102
- if (requestToken && isAuthorizedToken(requestToken)) {
103
- return `token:${requestToken}`;
104
- }
105
-
106
- const sessionId = getSessionIdFromRequest(request);
107
- if (sessionId) {
108
- return `session:${sessionId}`;
109
- }
110
-
111
- const clientIp =
112
- request.headers.get("cf-connecting-ip") ||
113
- request.headers.get("x-forwarded-for") ||
114
- "anonymous";
115
-
116
- return `ip:${clientIp}`;
117
- }
118
-
119
- /**
120
- * Get rate limit token for pre-auth rate limiting.
121
- * Returns the token if valid, session ID if cookie present, otherwise null (IP-based).
122
- * Fix #7: Session users get their own bucket, not shared with unauthenticated IP users.
123
- */
124
- export function getRateLimitToken(request, paramToken) {
125
- if (!isAuthRequired()) {
126
- return null;
127
- }
128
-
129
- const requestToken = getRequestToken(request, paramToken);
130
- if (requestToken && isAuthorizedToken(requestToken)) {
131
- return requestToken;
132
- }
133
-
134
- // Peek at session cookie without KV validation - gives session users
135
- // their own rate limit bucket so they don't share with unauthenticated IPs
136
- const sessionId = getSessionIdFromRequest(request);
137
- if (sessionId) {
138
- return `session:${sessionId}`;
139
- }
140
-
141
- return null;
142
- }
143
-
144
- /**
145
- * Fix #8: Unified auth+rate-limit helper to eliminate boilerplate duplication.
146
- * Rate limits first (prevents brute force), then authenticates.
147
- * Returns authResult or throws 401/429.
148
- */
149
- export async function requireAuth(request, params = {}) {
150
- await enforceRateLimit(request, getRateLimitToken(request, params.token));
151
-
152
- const authResult = await authenticateRequest(request, params);
153
-
154
- if (!authResult.authenticated) {
155
- throw new ApiError({
156
- status: 401,
157
- code: "UNAUTHORIZED",
158
- category: "auth",
159
- message: "Authentication required. Provide a valid token or session cookie.",
160
- });
161
- }
162
-
163
- return authResult;
164
- }
165
-
166
- export { isAuthRequired, isTruthyConfig, matchesConfigSet, getRequestToken, isAuthorizedToken };
@@ -1 +0,0 @@
1
- export * from "./auth.impl.js";
@@ -1,166 +0,0 @@
1
- import { env } from "../../envs.js";
2
- import { sha256Hex } from "../core/crypto.js";
3
- import { logWarn } from "./logger.js";
4
-
5
- const CACHE_PREFIX = "search:v3";
6
- const EDGE_CACHE_NAMESPACE = "search-edge:v1";
7
-
8
- function isKvAvailable() {
9
- return !!env.SEARCH_KV && typeof env.SEARCH_KV.get === "function";
10
- }
11
-
12
- function isEdgeCacheAvailable() {
13
- return typeof caches !== "undefined" && !!caches.default;
14
- }
15
-
16
- async function getCacheKey({
17
- query,
18
- requested_engines,
19
- engines,
20
- language,
21
- time_range,
22
- pageno,
23
- }) {
24
- const payload = JSON.stringify({
25
- query,
26
- requested_engines,
27
- engines,
28
- language,
29
- time_range,
30
- pageno,
31
- });
32
- const hash = await sha256Hex(payload);
33
- return `${CACHE_PREFIX}:${hash}`;
34
- }
35
-
36
- async function getEdgeCacheKey(searchParams) {
37
- const key = await getCacheKey(searchParams);
38
- return `${EDGE_CACHE_NAMESPACE}:${key}`;
39
- }
40
-
41
- async function getCachedSearchResponseFromEdge(searchParams) {
42
- const ttl = Number.parseInt(env.EDGE_CACHE_TTL_SECONDS || "0", 10);
43
- if (!isEdgeCacheAvailable() || ttl <= 0) {
44
- return null;
45
- }
46
-
47
- try {
48
- const cacheKey = await getEdgeCacheKey(searchParams);
49
- const response = await caches.default.match(`https://cache.internal/${cacheKey}`);
50
- if (!response) {
51
- return null;
52
- }
53
-
54
- const payload = await response.json();
55
- if (!payload?.response) {
56
- return null;
57
- }
58
-
59
- return {
60
- response: payload.response,
61
- state: "hit",
62
- layer: "edge",
63
- };
64
- } catch (error) {
65
- logWarn("cache.edge_read_failed", {}, error);
66
- return null;
67
- }
68
- }
69
-
70
- async function setCachedSearchResponseToEdge(searchParams, response) {
71
- const ttl = Number.parseInt(env.EDGE_CACHE_TTL_SECONDS || "0", 10);
72
- if (!isEdgeCacheAvailable() || ttl <= 0) {
73
- return;
74
- }
75
-
76
- try {
77
- const cacheKey = await getEdgeCacheKey(searchParams);
78
- const request = new Request(`https://cache.internal/${cacheKey}`);
79
- const payload = new Response(
80
- JSON.stringify({
81
- response,
82
- }),
83
- {
84
- headers: {
85
- "Content-Type": "application/json",
86
- "Cache-Control": `max-age=${ttl}`,
87
- },
88
- }
89
- );
90
- await caches.default.put(request, payload);
91
- } catch (error) {
92
- logWarn("cache.edge_write_failed", {}, error);
93
- }
94
- }
95
-
96
- export async function getCachedSearchResponse(searchParams) {
97
- const edgeEntry = await getCachedSearchResponseFromEdge(searchParams);
98
- if (edgeEntry) {
99
- return edgeEntry;
100
- }
101
-
102
- const ttl = Number.parseInt(env.CACHE_TTL_SECONDS || "0", 10);
103
- if (!isKvAvailable() || ttl <= 0) {
104
- return null;
105
- }
106
-
107
- const key = await getCacheKey(searchParams);
108
- const entry = await env.SEARCH_KV.get(key, "json");
109
- if (!entry?.response) {
110
- return null;
111
- }
112
-
113
- const now = Date.now();
114
- if (entry.freshUntil > now) {
115
- return {
116
- response: entry.response,
117
- state: "hit",
118
- layer: "kv",
119
- };
120
- }
121
-
122
- if (entry.staleUntil > now) {
123
- return {
124
- response: entry.response,
125
- state: "stale",
126
- layer: "kv",
127
- };
128
- }
129
-
130
- return null;
131
- }
132
-
133
- export async function setCachedSearchResponse(searchParams, response) {
134
- await setCachedSearchResponseToEdge(searchParams, response);
135
-
136
- const ttl = Number.parseInt(env.CACHE_TTL_SECONDS || "0", 10);
137
- if (!isKvAvailable() || ttl <= 0) {
138
- return;
139
- }
140
-
141
- const staleTtl = Math.max(
142
- 0,
143
- Number.parseInt(env.STALE_CACHE_TTL_SECONDS || "0", 10)
144
- );
145
- const now = Date.now();
146
- const freshUntil = now + ttl * 1000;
147
- const staleUntil = freshUntil + staleTtl * 1000;
148
- const key = await getCacheKey(searchParams);
149
- await env.SEARCH_KV.put(
150
- key,
151
- JSON.stringify({
152
- response,
153
- freshUntil,
154
- staleUntil,
155
- }),
156
- {
157
- expirationTtl: ttl + staleTtl,
158
- }
159
- );
160
- }
161
-
162
- export function createDeferredCachedSearchResponseWriter(searchParams, response) {
163
- return async function writeCachedSearchResponse() {
164
- await setCachedSearchResponse(searchParams, response);
165
- };
166
- }
@@ -1 +0,0 @@
1
- export * from "./cache.impl.js";
@@ -1,133 +0,0 @@
1
- import { env } from "../../envs.js";
2
- import { getStateKv, normalizeExpirationTtl } from "./stateKv.js";
3
- import { logWarn } from "./logger.js";
4
-
5
- const HEALTH_PREFIX = "health:v2";
6
- const memoryHealthState = new Map();
7
-
8
- export function resetHealthState() {
9
- memoryHealthState.clear();
10
- }
11
-
12
- function createDefaultEngineState() {
13
- return {
14
- consecutiveFailures: 0,
15
- disabledUntil: 0,
16
- lastFailureAt: 0,
17
- lastSuccessAt: 0,
18
- };
19
- }
20
-
21
- function getHealthKey(engineName) {
22
- return `${HEALTH_PREFIX}:${engineName}`;
23
- }
24
-
25
- function getMemoryEngineState(engineName) {
26
- if (!memoryHealthState.has(engineName)) {
27
- memoryHealthState.set(engineName, createDefaultEngineState());
28
- }
29
-
30
- return memoryHealthState.get(engineName);
31
- }
32
-
33
- async function getKvEngineState(kv, engineName) {
34
- try {
35
- return (await kv.get(getHealthKey(engineName), "json")) || null;
36
- } catch (error) {
37
- logWarn("health.kv_read_failed", { engine: engineName }, error);
38
- return null;
39
- }
40
- }
41
-
42
- async function persistEngineState(engineName, state) {
43
- const memoryState = getMemoryEngineState(engineName);
44
- Object.assign(memoryState, state);
45
-
46
- const kv = getStateKv();
47
- if (!kv) {
48
- return;
49
- }
50
-
51
- try {
52
- await kv.put(getHealthKey(engineName), JSON.stringify(state), {
53
- expirationTtl: normalizeExpirationTtl(env.HEALTH_STATE_TTL_SECONDS, 3600),
54
- });
55
- } catch (error) {
56
- logWarn("health.kv_write_failed", { engine: engineName }, error);
57
- }
58
- }
59
-
60
- async function getEngineState(engineName) {
61
- const kv = getStateKv();
62
- const kvState = kv ? await getKvEngineState(kv, engineName) : null;
63
-
64
- if (kvState) {
65
- return {
66
- ...createDefaultEngineState(),
67
- ...kvState,
68
- };
69
- }
70
-
71
- return getMemoryEngineState(engineName);
72
- }
73
-
74
- export async function prioritizeHealthyEngines(engineNames) {
75
- const now = Date.now();
76
- const healthy = [];
77
- const degraded = [];
78
- const engineStates = await Promise.all(
79
- engineNames.map(async (engineName) => ({
80
- engineName,
81
- state: await getEngineState(engineName),
82
- }))
83
- );
84
-
85
- for (const { engineName, state } of engineStates) {
86
- if (state.disabledUntil > now) {
87
- degraded.push(engineName);
88
- } else {
89
- healthy.push(engineName);
90
- }
91
- }
92
-
93
- return healthy.length > 0 ? [...healthy, ...degraded] : [...engineNames];
94
- }
95
-
96
- export async function recordEngineSuccess(engineName) {
97
- const state = await getEngineState(engineName);
98
- state.consecutiveFailures = 0;
99
- state.disabledUntil = 0;
100
- state.lastSuccessAt = Date.now();
101
- await persistEngineState(engineName, state);
102
- }
103
-
104
- export async function recordEngineFailure(engineName) {
105
- const state = await getEngineState(engineName);
106
- const failureThreshold = Number.parseInt(
107
- env.HEALTH_FAILURE_THRESHOLD || "2",
108
- 10
109
- );
110
- const cooldownMs =
111
- Number.parseInt(env.HEALTH_COOLDOWN_SECONDS || "180", 10) * 1000;
112
-
113
- state.consecutiveFailures += 1;
114
- state.lastFailureAt = Date.now();
115
-
116
- if (state.consecutiveFailures >= failureThreshold) {
117
- state.disabledUntil = Date.now() + cooldownMs;
118
- }
119
-
120
- await persistEngineState(engineName, state);
121
- }
122
-
123
- export function createDeferredEngineSuccessRecorder(engineName) {
124
- return async function recordSuccess() {
125
- await recordEngineSuccess(engineName);
126
- };
127
- }
128
-
129
- export function createDeferredEngineFailureRecorder(engineName) {
130
- return async function recordFailure() {
131
- await recordEngineFailure(engineName);
132
- };
133
- }
@@ -1 +0,0 @@
1
- export * from "./health.impl.js";
@@ -1,108 +0,0 @@
1
- import { env } from "../../envs.js";
2
- import { normalizeError, toErrorPayload } from "../core/errors.js";
3
-
4
- const ALLOWED_METHODS = "GET, POST, OPTIONS";
5
-
6
- function buildServerTimingHeader(engineTimings) {
7
- return engineTimings
8
- .map((timing) => `${timing.engine};dur=${timing.duration_ms}`)
9
- .join(", ");
10
- }
11
-
12
- function buildTierSummary(engineTimings) {
13
- const tiers = new Set();
14
- for (const timing of engineTimings) {
15
- if (timing?.tier) {
16
- tiers.add(String(timing.tier));
17
- }
18
- }
19
-
20
- return [...tiers].join(",");
21
- }
22
-
23
- export function buildCorsHeaders(request) {
24
- const headers = {
25
- "Access-Control-Allow-Methods": ALLOWED_METHODS,
26
- "Access-Control-Allow-Headers":
27
- request.headers.get("Access-Control-Request-Headers") ||
28
- env.CORS_ALLOWED_HEADERS.join(", "),
29
- "Access-Control-Max-Age": "86400",
30
- };
31
- const origin = request.headers.get("Origin");
32
-
33
- if (env.CORS_ALLOWED_ORIGINS.includes("*")) {
34
- headers["Access-Control-Allow-Origin"] = "*";
35
- return headers;
36
- }
37
-
38
- if (origin && env.CORS_ALLOWED_ORIGINS.includes(origin)) {
39
- headers["Access-Control-Allow-Origin"] = origin;
40
- headers.Vary = "Origin";
41
- }
42
-
43
- return headers;
44
- }
45
-
46
- export function jsonResponse(request, payload, status = 200, headers = {}) {
47
- return new Response(JSON.stringify(payload), {
48
- status,
49
- headers: {
50
- "Content-Type": "application/json",
51
- ...buildCorsHeaders(request),
52
- ...headers,
53
- },
54
- });
55
- }
56
-
57
- export function getRequestId(request) {
58
- return request.headers.get("cf-ray") || crypto.randomUUID();
59
- }
60
-
61
- export function buildSearchResponseHeaders({ requestId, durationMs, meta }) {
62
- const headers = {
63
- "X-Search-Request-Id": requestId,
64
- "X-Search-Duration-Ms": String(durationMs),
65
- "X-Search-Cache": meta.cache_status,
66
- "X-Search-Cache-Layer": meta.cache_layer || "none",
67
- "X-Search-Fallback-Path": meta.fallback_path.join(","),
68
- "X-Search-Strategy": meta.strategy || "tiered",
69
- };
70
-
71
- if (meta.fallback_order.length > 0) {
72
- headers["X-Search-Fallback-Order"] = meta.fallback_order.join(",");
73
- }
74
-
75
- if (meta.engine_timings.length > 0) {
76
- headers["Server-Timing"] = buildServerTimingHeader(meta.engine_timings);
77
- const tierSummary = buildTierSummary(meta.engine_timings);
78
- if (tierSummary) {
79
- headers["X-Search-Upstream-Tiers"] = tierSummary;
80
- }
81
- }
82
-
83
- return headers;
84
- }
85
-
86
- export function createOptionsResponse(request, requestId) {
87
- return new Response(null, {
88
- status: 204,
89
- headers: {
90
- ...buildCorsHeaders(request),
91
- "X-Search-Request-Id": requestId,
92
- },
93
- });
94
- }
95
-
96
- export function createErrorResponse(request, requestId, error) {
97
- const normalized = normalizeError(error);
98
- const status = normalized.status || 500;
99
- const headers = {
100
- "X-Search-Request-Id": requestId,
101
- };
102
-
103
- if (normalized.details?.retry_after) {
104
- headers["Retry-After"] = String(normalized.details.retry_after);
105
- }
106
-
107
- return jsonResponse(request, toErrorPayload(normalized), status, headers);
108
- }
@@ -1 +0,0 @@
1
- export * from "./http.impl.js";
@@ -1,51 +0,0 @@
1
- function pruneUndefined(value) {
2
- if (!value || typeof value !== "object") {
3
- return value;
4
- }
5
-
6
- const result = {};
7
- for (const [key, entry] of Object.entries(value)) {
8
- if (entry !== undefined) {
9
- result[key] = entry;
10
- }
11
- }
12
-
13
- return result;
14
- }
15
-
16
- function write(level, event, fields = {}, error, runtimeContext) {
17
- const request = runtimeContext?.request;
18
- const url = request ? new URL(request.url) : null;
19
- const payload = pruneUndefined({
20
- level,
21
- event,
22
- request_id: request?.headers?.get("cf-ray") || fields.request_id,
23
- method: request?.method,
24
- path: url?.pathname,
25
- ...fields,
26
- });
27
-
28
- if (level === "error") {
29
- console.error(JSON.stringify(payload), error || "");
30
- return;
31
- }
32
-
33
- if (level === "warn") {
34
- console.warn(JSON.stringify(payload), error || "");
35
- return;
36
- }
37
-
38
- console.log(JSON.stringify(payload), error || "");
39
- }
40
-
41
- export function logInfo(event, fields = {}, runtimeContext) {
42
- write("info", event, fields, undefined, runtimeContext);
43
- }
44
-
45
- export function logWarn(event, fields = {}, error, runtimeContext) {
46
- write("warn", event, fields, error, runtimeContext);
47
- }
48
-
49
- export function logError(event, fields = {}, error, runtimeContext) {
50
- write("error", event, fields, error, runtimeContext);
51
- }
@@ -1 +0,0 @@
1
- export * from "./logger.impl.js";
@@ -1,43 +0,0 @@
1
- function getStore(runtimeContext) {
2
- if (!runtimeContext) {
3
- return null;
4
- }
5
-
6
- if (!runtimeContext.metrics) {
7
- runtimeContext.metrics = {
8
- counters: [],
9
- timings: [],
10
- };
11
- }
12
-
13
- return runtimeContext.metrics;
14
- }
15
-
16
- export function recordMetric(runtimeContext, name, fields = {}) {
17
- const store = getStore(runtimeContext);
18
- if (!store) {
19
- return;
20
- }
21
-
22
- store.counters.push({
23
- name,
24
- ...fields,
25
- });
26
- }
27
-
28
- export function recordTiming(runtimeContext, name, durationMs, fields = {}) {
29
- const store = getStore(runtimeContext);
30
- if (!store) {
31
- return;
32
- }
33
-
34
- store.timings.push({
35
- name,
36
- duration_ms: durationMs,
37
- ...fields,
38
- });
39
- }
40
-
41
- export function readRecordedMetrics(runtimeContext) {
42
- return runtimeContext?.metrics || { counters: [], timings: [] };
43
- }
@@ -1 +0,0 @@
1
- export * from "./metrics.impl.js";