@agentmemory/agentmemory 0.9.17 → 0.9.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +6 -0
- package/README.md +15 -1
- package/dist/.env.example +6 -0
- package/dist/cli.mjs +12 -6
- package/dist/cli.mjs.map +1 -1
- package/dist/index.mjs +186 -28
- package/dist/index.mjs.map +1 -1
- package/dist/{src-TiNuQ3Ub.mjs → src-C7vygXCj.mjs} +186 -28
- package/dist/src-C7vygXCj.mjs.map +1 -0
- package/dist/{standalone-BIXq6S80.mjs → standalone-kg2TedgD.mjs} +16 -7
- package/dist/standalone-kg2TedgD.mjs.map +1 -0
- package/dist/standalone.mjs +16 -7
- package/dist/standalone.mjs.map +1 -1
- package/dist/viewer/favicon.svg +1 -0
- package/dist/viewer/index.html +190 -60
- package/package.json +2 -2
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/dist/src-TiNuQ3Ub.mjs.map +0 -1
- package/dist/standalone-BIXq6S80.mjs.map +0 -1
|
@@ -104,6 +104,20 @@ var AnthropicProvider = class {
|
|
|
104
104
|
}
|
|
105
105
|
};
|
|
106
106
|
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/providers/_fetch.ts
|
|
109
|
+
function fetchWithTimeout(url, init, timeoutMs) {
|
|
110
|
+
const parsed = timeoutMs ?? Number.parseInt(getEnvVar("AGENTMEMORY_LLM_TIMEOUT_MS") ?? "60000", 10);
|
|
111
|
+
const ms = Number.isFinite(parsed) && parsed > 0 ? parsed : 6e4;
|
|
112
|
+
const ctl = new AbortController();
|
|
113
|
+
const signal = init.signal ? AbortSignal.any([init.signal, ctl.signal]) : ctl.signal;
|
|
114
|
+
const t = setTimeout(() => ctl.abort(), ms);
|
|
115
|
+
return fetch(url, {
|
|
116
|
+
...init,
|
|
117
|
+
signal
|
|
118
|
+
}).finally(() => clearTimeout(t));
|
|
119
|
+
}
|
|
120
|
+
|
|
107
121
|
//#endregion
|
|
108
122
|
//#region src/providers/minimax.ts
|
|
109
123
|
/**
|
|
@@ -139,8 +153,7 @@ var MinimaxProvider = class {
|
|
|
139
153
|
return this.call(systemPrompt, userPrompt);
|
|
140
154
|
}
|
|
141
155
|
async call(systemPrompt, userPrompt) {
|
|
142
|
-
const
|
|
143
|
-
const response = await fetch(url, {
|
|
156
|
+
const response = await fetchWithTimeout(`${this.baseUrl}/v1/messages`, {
|
|
144
157
|
method: "POST",
|
|
145
158
|
headers: {
|
|
146
159
|
"Content-Type": "application/json",
|
|
@@ -208,7 +221,12 @@ const DEFAULT_AZURE_API_VERSION = "2024-08-01-preview";
|
|
|
208
221
|
* Azure: https://<resource>.openai.azure.com/openai/deployments/<deployment>
|
|
209
222
|
* OPENAI_MODEL — model name (default: gpt-4o-mini)
|
|
210
223
|
* OPENAI_API_VERSION — Azure api-version query param (default: 2024-08-01-preview)
|
|
211
|
-
* OPENAI_TIMEOUT_MS — outbound fetch timeout in ms (
|
|
224
|
+
* OPENAI_TIMEOUT_MS — outbound fetch timeout in ms (OpenAI-scoped alias,
|
|
225
|
+
* takes precedence over AGENTMEMORY_LLM_TIMEOUT_MS
|
|
226
|
+
* for back-compat with the v0.9.17 shipping name).
|
|
227
|
+
* AGENTMEMORY_LLM_TIMEOUT_MS — outbound fetch timeout in ms shared across all
|
|
228
|
+
* raw-fetch LLM + embedding providers. Used when
|
|
229
|
+
* OPENAI_TIMEOUT_MS is not set. Default: 60000.
|
|
212
230
|
* MAX_TOKENS — max output tokens (default: from config or 4096)
|
|
213
231
|
* OPENAI_REASONING_EFFORT — "low" | "medium" | "high" | "none"
|
|
214
232
|
* Passthrough for reasoning models (e.g. Ollama Cloud
|
|
@@ -232,7 +250,7 @@ var OpenAIProvider = class {
|
|
|
232
250
|
this.maxTokens = maxTokens;
|
|
233
251
|
this.baseUrl = (baseURL || getEnvVar("OPENAI_BASE_URL") || DEFAULT_BASE_URL$1).replace(/\/+$/, "");
|
|
234
252
|
this.reasoningEffort = getEnvVar("OPENAI_REASONING_EFFORT") || void 0;
|
|
235
|
-
this.timeoutMs =
|
|
253
|
+
this.timeoutMs = resolveTimeout();
|
|
236
254
|
this.azureApiVersion = getEnvVar("OPENAI_API_VERSION") || DEFAULT_AZURE_API_VERSION;
|
|
237
255
|
this.isAzure = detectAzure(this.baseUrl);
|
|
238
256
|
}
|
|
@@ -273,21 +291,16 @@ var OpenAIProvider = class {
|
|
|
273
291
|
}]
|
|
274
292
|
};
|
|
275
293
|
if (this.reasoningEffort) body.reasoning_effort = this.reasoningEffort;
|
|
276
|
-
const ac = new AbortController();
|
|
277
|
-
const t = setTimeout(() => ac.abort(), this.timeoutMs);
|
|
278
294
|
let response;
|
|
279
295
|
try {
|
|
280
|
-
response = await
|
|
296
|
+
response = await fetchWithTimeout(url, {
|
|
281
297
|
method: "POST",
|
|
282
298
|
headers: this.buildHeaders(),
|
|
283
|
-
body: JSON.stringify(body)
|
|
284
|
-
|
|
285
|
-
});
|
|
299
|
+
body: JSON.stringify(body)
|
|
300
|
+
}, this.timeoutMs);
|
|
286
301
|
} catch (err) {
|
|
287
|
-
if (
|
|
302
|
+
if (err instanceof Error && err.name === "AbortError") throw new Error(`OpenAI API request timed out after ${this.timeoutMs}ms — set OPENAI_TIMEOUT_MS (or AGENTMEMORY_LLM_TIMEOUT_MS) to raise the bound or check the provider status.`);
|
|
288
303
|
throw err;
|
|
289
|
-
} finally {
|
|
290
|
-
clearTimeout(t);
|
|
291
304
|
}
|
|
292
305
|
if (!response.ok) {
|
|
293
306
|
const text = await response.text();
|
|
@@ -302,10 +315,19 @@ var OpenAIProvider = class {
|
|
|
302
315
|
throw new Error(`OpenAI returned unexpected response: ${JSON.stringify(data).slice(0, 200)}`);
|
|
303
316
|
}
|
|
304
317
|
};
|
|
305
|
-
function
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
318
|
+
function resolveTimeout() {
|
|
319
|
+
const openai = parsePositiveInt(getEnvVar("OPENAI_TIMEOUT_MS"));
|
|
320
|
+
if (openai !== void 0) return openai;
|
|
321
|
+
const globalMs = parsePositiveInt(getEnvVar("AGENTMEMORY_LLM_TIMEOUT_MS"));
|
|
322
|
+
if (globalMs !== void 0) return globalMs;
|
|
323
|
+
return DEFAULT_TIMEOUT_MS;
|
|
324
|
+
}
|
|
325
|
+
function parsePositiveInt(raw) {
|
|
326
|
+
if (!raw) return void 0;
|
|
327
|
+
const trimmed = raw.trim();
|
|
328
|
+
if (!/^\d+$/.test(trimmed)) return void 0;
|
|
329
|
+
const n = Number(trimmed);
|
|
330
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
309
331
|
}
|
|
310
332
|
function detectAzure(baseUrl) {
|
|
311
333
|
try {
|
|
@@ -337,7 +359,7 @@ var OpenRouterProvider = class {
|
|
|
337
359
|
return this.call(systemPrompt, userPrompt);
|
|
338
360
|
}
|
|
339
361
|
async call(systemPrompt, userPrompt) {
|
|
340
|
-
const response = await
|
|
362
|
+
const response = await fetchWithTimeout(this.baseUrl, {
|
|
341
363
|
method: "POST",
|
|
342
364
|
headers: {
|
|
343
365
|
"Content-Type": "application/json",
|
|
@@ -506,7 +528,7 @@ var GeminiEmbeddingProvider = class {
|
|
|
506
528
|
const results = [];
|
|
507
529
|
for (let i = 0; i < texts.length; i += BATCH_LIMIT) {
|
|
508
530
|
const chunk = texts.slice(i, i + BATCH_LIMIT);
|
|
509
|
-
const response = await
|
|
531
|
+
const response = await fetchWithTimeout(`${API_BASE}?key=${this.apiKey}`, {
|
|
510
532
|
method: "POST",
|
|
511
533
|
headers: { "Content-Type": "application/json" },
|
|
512
534
|
body: JSON.stringify({ requests: chunk.map((t) => ({
|
|
@@ -595,8 +617,7 @@ var OpenAIEmbeddingProvider = class {
|
|
|
595
617
|
return result;
|
|
596
618
|
}
|
|
597
619
|
async embedBatch(texts) {
|
|
598
|
-
const
|
|
599
|
-
const response = await fetch(url, {
|
|
620
|
+
const response = await fetchWithTimeout(`${this.baseUrl}/v1/embeddings`, {
|
|
600
621
|
method: "POST",
|
|
601
622
|
headers: {
|
|
602
623
|
Authorization: `Bearer ${this.apiKey}`,
|
|
@@ -631,7 +652,7 @@ var VoyageEmbeddingProvider = class {
|
|
|
631
652
|
return result;
|
|
632
653
|
}
|
|
633
654
|
async embedBatch(texts) {
|
|
634
|
-
const response = await
|
|
655
|
+
const response = await fetchWithTimeout(API_URL$2, {
|
|
635
656
|
method: "POST",
|
|
636
657
|
headers: {
|
|
637
658
|
Authorization: `Bearer ${this.apiKey}`,
|
|
@@ -667,7 +688,7 @@ var CohereEmbeddingProvider = class {
|
|
|
667
688
|
return result;
|
|
668
689
|
}
|
|
669
690
|
async embedBatch(texts) {
|
|
670
|
-
const response = await
|
|
691
|
+
const response = await fetchWithTimeout(API_URL$1, {
|
|
671
692
|
method: "POST",
|
|
672
693
|
headers: {
|
|
673
694
|
Authorization: `Bearer ${this.apiKey}`,
|
|
@@ -705,7 +726,7 @@ var OpenRouterEmbeddingProvider = class {
|
|
|
705
726
|
return result;
|
|
706
727
|
}
|
|
707
728
|
async embedBatch(texts) {
|
|
708
|
-
const response = await
|
|
729
|
+
const response = await fetchWithTimeout(API_URL, {
|
|
709
730
|
method: "POST",
|
|
710
731
|
headers: {
|
|
711
732
|
Authorization: `Bearer ${this.apiKey}`,
|
|
@@ -4095,7 +4116,11 @@ function registerContextFunction(sdk, kv, tokenBudget) {
|
|
|
4095
4116
|
sdk.registerFunction("mem::context", async (data) => {
|
|
4096
4117
|
const budget = data.budget || tokenBudget;
|
|
4097
4118
|
const blocks = [];
|
|
4098
|
-
const [pinnedSlots, profile] = await Promise.all([
|
|
4119
|
+
const [pinnedSlots, profile, lessons] = await Promise.all([
|
|
4120
|
+
isSlotsEnabled() ? listPinnedSlots(kv).catch(() => []) : Promise.resolve([]),
|
|
4121
|
+
kv.get(KV.profiles, data.project).catch(() => null),
|
|
4122
|
+
kv.list(KV.lessons).catch(() => [])
|
|
4123
|
+
]);
|
|
4099
4124
|
const slotContent = renderPinnedContext(pinnedSlots);
|
|
4100
4125
|
if (slotContent) blocks.push({
|
|
4101
4126
|
type: "memory",
|
|
@@ -4119,6 +4144,24 @@ function registerContextFunction(sdk, kv, tokenBudget) {
|
|
|
4119
4144
|
});
|
|
4120
4145
|
}
|
|
4121
4146
|
}
|
|
4147
|
+
const relevantLessons = lessons.filter((l) => !l.deleted && (!l.project || l.project === data.project)).sort((a, b) => {
|
|
4148
|
+
const scoreA = (a.project === data.project ? 1.5 : 1) * a.confidence;
|
|
4149
|
+
return (b.project === data.project ? 1.5 : 1) * b.confidence - scoreA;
|
|
4150
|
+
}).slice(0, 10);
|
|
4151
|
+
if (relevantLessons.length > 0) {
|
|
4152
|
+
const lessonsContent = `## Lessons Learned\n${relevantLessons.map((l) => `- (${l.confidence.toFixed(2)}) ${l.content}${l.context ? ` — ${l.context}` : ""}`).join("\n")}`;
|
|
4153
|
+
const mostRecent = relevantLessons.reduce((acc, l) => {
|
|
4154
|
+
const t = new Date(l.lastReinforcedAt || l.updatedAt).getTime();
|
|
4155
|
+
return t > acc ? t : acc;
|
|
4156
|
+
}, 0);
|
|
4157
|
+
blocks.push({
|
|
4158
|
+
type: "memory",
|
|
4159
|
+
content: lessonsContent,
|
|
4160
|
+
tokens: estimateTokens$1(lessonsContent),
|
|
4161
|
+
recency: mostRecent,
|
|
4162
|
+
sourceIds: relevantLessons.map((l) => l.id)
|
|
4163
|
+
});
|
|
4164
|
+
}
|
|
4122
4165
|
const sessions = (await kv.list(KV.sessions)).filter((s) => s.project === data.project && s.id !== data.sessionId).sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime()).slice(0, 10);
|
|
4123
4166
|
const summariesPerSession = await Promise.all(sessions.map((s) => kv.get(KV.summaries, s.id).catch(() => null)));
|
|
4124
4167
|
const sessionsNeedingObs = [];
|
|
@@ -4941,6 +4984,46 @@ const DEFAULTS$1 = {
|
|
|
4941
4984
|
lowImportanceThreshold: 3,
|
|
4942
4985
|
maxObservationsPerProject: 1e4
|
|
4943
4986
|
};
|
|
4987
|
+
function isValidRecoveryResult(result) {
|
|
4988
|
+
if (!result || typeof result !== "object") return false;
|
|
4989
|
+
if (!("success" in result)) return true;
|
|
4990
|
+
return result.success !== false;
|
|
4991
|
+
}
|
|
4992
|
+
function isCompressedObservation(observation) {
|
|
4993
|
+
return "title" in observation && typeof observation.title === "string" && observation.title.length > 0;
|
|
4994
|
+
}
|
|
4995
|
+
async function recoverStaleSession(sdk, sessionId) {
|
|
4996
|
+
try {
|
|
4997
|
+
const result = await sdk.trigger({
|
|
4998
|
+
function_id: "event::session::stopped",
|
|
4999
|
+
payload: { sessionId }
|
|
5000
|
+
});
|
|
5001
|
+
if (!isValidRecoveryResult(result)) {
|
|
5002
|
+
logger.warn("Stale session recovery failed", {
|
|
5003
|
+
sessionId,
|
|
5004
|
+
result
|
|
5005
|
+
});
|
|
5006
|
+
return false;
|
|
5007
|
+
}
|
|
5008
|
+
return true;
|
|
5009
|
+
} catch (err) {
|
|
5010
|
+
logger.warn("Stale session recovery failed", {
|
|
5011
|
+
sessionId,
|
|
5012
|
+
error: err instanceof Error ? err.message : String(err)
|
|
5013
|
+
});
|
|
5014
|
+
return false;
|
|
5015
|
+
}
|
|
5016
|
+
}
|
|
5017
|
+
async function runRecoveredSessionConsolidation(sdk) {
|
|
5018
|
+
try {
|
|
5019
|
+
await sdk.trigger({
|
|
5020
|
+
function_id: "mem::consolidate-pipeline",
|
|
5021
|
+
payload: { tier: "all" }
|
|
5022
|
+
});
|
|
5023
|
+
} catch (err) {
|
|
5024
|
+
logger.warn("Recovered session consolidation failed", { error: err instanceof Error ? err.message : String(err) });
|
|
5025
|
+
}
|
|
5026
|
+
}
|
|
4944
5027
|
function registerEvictFunction(sdk, kv) {
|
|
4945
5028
|
sdk.registerFunction("mem::evict", async (data) => {
|
|
4946
5029
|
const dryRun = data?.dryRun ?? false;
|
|
@@ -4959,6 +5042,7 @@ function registerEvictFunction(sdk, kv) {
|
|
|
4959
5042
|
nonLatestMemories: 0,
|
|
4960
5043
|
dryRun
|
|
4961
5044
|
};
|
|
5045
|
+
let recoveredStaleSessions = 0;
|
|
4962
5046
|
const sessions = await kv.list(KV.sessions).catch(() => []);
|
|
4963
5047
|
const summaries = await kv.list(KV.summaries).catch(() => []);
|
|
4964
5048
|
const summaryIds = new Set(summaries.map((s) => s.sessionId));
|
|
@@ -4966,6 +5050,23 @@ function registerEvictFunction(sdk, kv) {
|
|
|
4966
5050
|
if (!session.startedAt) continue;
|
|
4967
5051
|
if (now - new Date(session.startedAt).getTime() > cfg.staleSessionDays * MS_PER_DAY$1 && !summaryIds.has(session.id)) if (dryRun) stats.staleSessions++;
|
|
4968
5052
|
else {
|
|
5053
|
+
const observations = await kv.list(KV.observations(session.id)).catch((err) => {
|
|
5054
|
+
logger.warn("Stale session observation scan failed", {
|
|
5055
|
+
sessionId: session.id,
|
|
5056
|
+
error: err instanceof Error ? err.message : String(err)
|
|
5057
|
+
});
|
|
5058
|
+
return null;
|
|
5059
|
+
});
|
|
5060
|
+
if (!observations) continue;
|
|
5061
|
+
let recovered = false;
|
|
5062
|
+
if (observations.some(isCompressedObservation)) {
|
|
5063
|
+
recovered = await recoverStaleSession(sdk, session.id);
|
|
5064
|
+
if (!recovered) continue;
|
|
5065
|
+
recoveredStaleSessions++;
|
|
5066
|
+
} else if (observations.length > 0) {
|
|
5067
|
+
logger.warn("Stale session has no compressed observations", { sessionId: session.id });
|
|
5068
|
+
continue;
|
|
5069
|
+
}
|
|
4969
5070
|
try {
|
|
4970
5071
|
await kv.delete(KV.sessions, session.id);
|
|
4971
5072
|
stats.staleSessions++;
|
|
@@ -4979,11 +5080,12 @@ function registerEvictFunction(sdk, kv) {
|
|
|
4979
5080
|
}
|
|
4980
5081
|
await recordAudit(kv, "delete", "mem::evict", [session.id], {
|
|
4981
5082
|
resource: "session",
|
|
4982
|
-
reason: "stale_session_without_summary",
|
|
5083
|
+
reason: recovered ? "stale_session_recovered_then_evicted" : "stale_session_without_summary",
|
|
4983
5084
|
dryRun
|
|
4984
5085
|
});
|
|
4985
5086
|
}
|
|
4986
5087
|
}
|
|
5088
|
+
if (!dryRun && recoveredStaleSessions > 0) await runRecoveredSessionConsolidation(sdk);
|
|
4987
5089
|
const projectObs = /* @__PURE__ */ new Map();
|
|
4988
5090
|
for (const session of sessions) {
|
|
4989
5091
|
const compressed = (await kv.list(KV.observations(session.id)).catch(() => [])).filter((o) => o.title);
|
|
@@ -5793,7 +5895,8 @@ function registerExportImportFunction(sdk, kv) {
|
|
|
5793
5895
|
"0.9.14",
|
|
5794
5896
|
"0.9.15",
|
|
5795
5897
|
"0.9.16",
|
|
5796
|
-
"0.9.17"
|
|
5898
|
+
"0.9.17",
|
|
5899
|
+
"0.9.18"
|
|
5797
5900
|
]).has(importData.version)) return {
|
|
5798
5901
|
success: false,
|
|
5799
5902
|
error: `Unsupported export version: ${importData.version}`
|
|
@@ -17987,7 +18090,38 @@ function registerMcpEndpoints(sdk, kv, secret) {
|
|
|
17987
18090
|
|
|
17988
18091
|
//#endregion
|
|
17989
18092
|
//#region src/viewer/server.ts
|
|
18093
|
+
function loadViewerFavicon() {
|
|
18094
|
+
const base = dirname(fileURLToPath(import.meta.url));
|
|
18095
|
+
const candidates = [
|
|
18096
|
+
join(base, "..", "src", "viewer", "favicon.svg"),
|
|
18097
|
+
join(base, "..", "viewer", "favicon.svg"),
|
|
18098
|
+
join(base, "viewer", "favicon.svg")
|
|
18099
|
+
];
|
|
18100
|
+
for (const path of candidates) try {
|
|
18101
|
+
return readFileSync(path);
|
|
18102
|
+
} catch {}
|
|
18103
|
+
return null;
|
|
18104
|
+
}
|
|
17990
18105
|
const ALLOWED_ORIGINS = (process.env.VIEWER_ALLOWED_ORIGINS || "http://localhost:3111,http://localhost:3113,http://127.0.0.1:3111,http://127.0.0.1:3113").split(",").map((o) => o.trim());
|
|
18106
|
+
const ALLOWED_HOSTS_OVERRIDE = (process.env.VIEWER_ALLOWED_HOSTS || "").split(",").map((h) => h.trim().toLowerCase()).filter(Boolean);
|
|
18107
|
+
function buildAllowedHosts(origins, listenPort) {
|
|
18108
|
+
const hosts = /* @__PURE__ */ new Set();
|
|
18109
|
+
for (const o of origins) try {
|
|
18110
|
+
const parsed = new URL(o);
|
|
18111
|
+
if (parsed.host) hosts.add(parsed.host.toLowerCase());
|
|
18112
|
+
} catch {}
|
|
18113
|
+
hosts.add(`localhost:${listenPort}`);
|
|
18114
|
+
hosts.add(`127.0.0.1:${listenPort}`);
|
|
18115
|
+
hosts.add(`[::1]:${listenPort}`);
|
|
18116
|
+
for (const h of ALLOWED_HOSTS_OVERRIDE) hosts.add(h);
|
|
18117
|
+
return hosts;
|
|
18118
|
+
}
|
|
18119
|
+
function isHostAllowed(headerHost, allowed) {
|
|
18120
|
+
if (typeof headerHost !== "string") return false;
|
|
18121
|
+
const lower = headerHost.toLowerCase().trim();
|
|
18122
|
+
if (!lower) return false;
|
|
18123
|
+
return allowed.has(lower);
|
|
18124
|
+
}
|
|
17991
18125
|
function corsHeaders(req) {
|
|
17992
18126
|
const origin = req.headers.origin || "";
|
|
17993
18127
|
const allowed = ALLOWED_ORIGINS.includes(origin) ? origin : ALLOWED_ORIGINS[0];
|
|
@@ -18031,7 +18165,17 @@ const MAX_VIEWER_PORT_RETRIES = 10;
|
|
|
18031
18165
|
function startViewerServer(port, _kv, _sdk, secret, restPort) {
|
|
18032
18166
|
const resolvedRestPort = restPort ?? port - 2;
|
|
18033
18167
|
const requestedPort = port;
|
|
18168
|
+
let allowedHosts = null;
|
|
18034
18169
|
const server = createServer(async (req, res) => {
|
|
18170
|
+
if (!allowedHosts) {
|
|
18171
|
+
const addr = server.address();
|
|
18172
|
+
allowedHosts = buildAllowedHosts(ALLOWED_ORIGINS, addr && typeof addr === "object" && "port" in addr ? addr.port : port);
|
|
18173
|
+
}
|
|
18174
|
+
if (!isHostAllowed(req.headers.host, allowedHosts)) {
|
|
18175
|
+
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
18176
|
+
res.end("forbidden host");
|
|
18177
|
+
return;
|
|
18178
|
+
}
|
|
18035
18179
|
const raw = req.url || "/";
|
|
18036
18180
|
const qIdx = raw.indexOf("?");
|
|
18037
18181
|
const pathname = qIdx >= 0 ? raw.slice(0, qIdx) : raw;
|
|
@@ -18060,6 +18204,20 @@ function startViewerServer(port, _kv, _sdk, secret, restPort) {
|
|
|
18060
18204
|
res.end("viewer not found");
|
|
18061
18205
|
return;
|
|
18062
18206
|
}
|
|
18207
|
+
if (method === "GET" && pathname === "/favicon.svg") {
|
|
18208
|
+
const favicon = loadViewerFavicon();
|
|
18209
|
+
if (favicon) {
|
|
18210
|
+
res.writeHead(200, {
|
|
18211
|
+
"Content-Type": "image/svg+xml",
|
|
18212
|
+
"Cache-Control": "public, max-age=3600"
|
|
18213
|
+
});
|
|
18214
|
+
res.end(favicon);
|
|
18215
|
+
return;
|
|
18216
|
+
}
|
|
18217
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
18218
|
+
res.end("favicon not found");
|
|
18219
|
+
return;
|
|
18220
|
+
}
|
|
18063
18221
|
try {
|
|
18064
18222
|
await proxyToRestApi(resolvedRestPort, pathname, qs, method, req, res, secret);
|
|
18065
18223
|
} catch (err) {
|
|
@@ -18527,4 +18685,4 @@ main().catch((err) => {
|
|
|
18527
18685
|
|
|
18528
18686
|
//#endregion
|
|
18529
18687
|
export { };
|
|
18530
|
-
//# sourceMappingURL=src-
|
|
18688
|
+
//# sourceMappingURL=src-C7vygXCj.mjs.map
|