@hasna/mementos 0.14.68 → 0.14.69
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/dist/cli/__fixtures__/clean-fallback-stub-server.d.ts +2 -0
- package/dist/cli/__fixtures__/clean-fallback-stub-server.d.ts.map +1 -0
- package/dist/cli/commands/io-clean.d.ts.map +1 -1
- package/dist/cli/commands/memory-cmd-crud.d.ts.map +1 -1
- package/dist/cli/commands/storage.d.ts.map +1 -1
- package/dist/cli/global-options.d.ts +27 -0
- package/dist/cli/global-options.d.ts.map +1 -0
- package/dist/cli/index.js +502 -241
- package/dist/cli/register-all.d.ts +17 -0
- package/dist/cli/register-all.d.ts.map +1 -0
- package/dist/cli/startup-side-effects.d.ts +9 -0
- package/dist/cli/startup-side-effects.d.ts.map +1 -0
- package/dist/db/__fixtures__/fail-closed-stub-server.d.ts +2 -0
- package/dist/db/__fixtures__/fail-closed-stub-server.d.ts.map +1 -0
- package/dist/db/api-mode.d.ts +70 -2
- package/dist/db/api-mode.d.ts.map +1 -1
- package/dist/db/locks.d.ts.map +1 -1
- package/dist/db/memories.d.ts +24 -6
- package/dist/db/memories.d.ts.map +1 -1
- package/dist/db/session-jobs.d.ts.map +1 -1
- package/dist/db/store-backend.d.ts +33 -0
- package/dist/db/store-backend.d.ts.map +1 -0
- package/dist/index.js +80 -20
- package/dist/lib/enum-validation.d.ts +20 -0
- package/dist/lib/enum-validation.d.ts.map +1 -0
- package/dist/mcp/index.js +147 -30
- package/dist/server/helpers.d.ts +11 -0
- package/dist/server/helpers.d.ts.map +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +185 -30
- package/dist/test-support/preload-local-store.d.ts +2 -0
- package/dist/test-support/preload-local-store.d.ts.map +1 -0
- package/dist/test-support/store-isolation.d.ts +83 -0
- package/dist/test-support/store-isolation.d.ts.map +1 -0
- package/dist/types/index.d.ts +8 -4
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/mcp/index.js
CHANGED
|
@@ -66,8 +66,19 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
66
66
|
var __require = import.meta.require;
|
|
67
67
|
|
|
68
68
|
// src/types/index.ts
|
|
69
|
-
var AgentConflictError, EntityNotFoundError, MemoryNotFoundError, DuplicateMemoryError, InvalidScopeError, VersionConflictError, MemoryConflictError;
|
|
69
|
+
var MEMORY_SCOPES, MEMORY_CATEGORIES, MEMORY_SOURCES, MEMORY_STATUSES, AgentConflictError, EntityNotFoundError, MemoryNotFoundError, DuplicateMemoryError, InvalidScopeError, VersionConflictError, MemoryConflictError;
|
|
70
70
|
var init_types = __esm(() => {
|
|
71
|
+
MEMORY_SCOPES = ["global", "shared", "private", "working"];
|
|
72
|
+
MEMORY_CATEGORIES = [
|
|
73
|
+
"preference",
|
|
74
|
+
"fact",
|
|
75
|
+
"knowledge",
|
|
76
|
+
"history",
|
|
77
|
+
"procedural",
|
|
78
|
+
"resource"
|
|
79
|
+
];
|
|
80
|
+
MEMORY_SOURCES = ["user", "agent", "system", "auto", "imported"];
|
|
81
|
+
MEMORY_STATUSES = ["active", "archived", "expired"];
|
|
71
82
|
AgentConflictError = class AgentConflictError extends Error {
|
|
72
83
|
conflict = true;
|
|
73
84
|
existing_id;
|
|
@@ -996,7 +1007,7 @@ import { tmpdir } from "os";
|
|
|
996
1007
|
import { join as join2 } from "path";
|
|
997
1008
|
import { writeFileSync as writeFileSync2, unlinkSync } from "fs";
|
|
998
1009
|
import { randomUUID } from "crypto";
|
|
999
|
-
function firstEnv(
|
|
1010
|
+
function firstEnv(keys) {
|
|
1000
1011
|
for (const k of keys) {
|
|
1001
1012
|
const v = process.env[k]?.trim();
|
|
1002
1013
|
if (v)
|
|
@@ -1004,8 +1015,38 @@ function firstEnv(...keys) {
|
|
|
1004
1015
|
}
|
|
1005
1016
|
return;
|
|
1006
1017
|
}
|
|
1018
|
+
function firstEnvKey(keys) {
|
|
1019
|
+
for (const k of keys) {
|
|
1020
|
+
if (process.env[k]?.trim())
|
|
1021
|
+
return k;
|
|
1022
|
+
}
|
|
1023
|
+
return null;
|
|
1024
|
+
}
|
|
1007
1025
|
function hasDatabaseUrl() {
|
|
1008
|
-
return Boolean(firstEnv(
|
|
1026
|
+
return Boolean(firstEnv(DATABASE_URL_ENV_KEYS));
|
|
1027
|
+
}
|
|
1028
|
+
function isLoopbackHost(rawHost) {
|
|
1029
|
+
const host = rawHost.replace(/^\[/, "").replace(/\]$/, "").toLowerCase();
|
|
1030
|
+
return host === "localhost" || host === "::1" || /^127\./.test(host);
|
|
1031
|
+
}
|
|
1032
|
+
function assertRequestAllowedUnderTest(baseUrl) {
|
|
1033
|
+
if (process.env["NODE_ENV"] !== "test")
|
|
1034
|
+
return;
|
|
1035
|
+
if (process.env[ALLOW_REMOTE_API_IN_TESTS_ENV]?.trim())
|
|
1036
|
+
return;
|
|
1037
|
+
let host;
|
|
1038
|
+
try {
|
|
1039
|
+
host = new URL(baseUrl).hostname;
|
|
1040
|
+
} catch {
|
|
1041
|
+
host = "";
|
|
1042
|
+
}
|
|
1043
|
+
if (host && isLoopbackHost(host))
|
|
1044
|
+
return;
|
|
1045
|
+
throw new Error("api-mode: REFUSING to make a cloud request from a test process \u2014 this would write to or read " + "from the SHARED PRODUCTION memory store, where test fixtures are indistinguishable from real " + `memories.
|
|
1046
|
+
` + ` host : ${host || "(unparseable base URL)"}
|
|
1047
|
+
` + ` how this happens: a selector set at module scope (after the bun test preload ran), or \`bun test\` ` + `invoked from a directory with no bunfig.toml so the preload never loaded.
|
|
1048
|
+
` + " fix : build the child/process env via src/test-support/store-isolation.ts, or point the " + `suite at a loopback stub.
|
|
1049
|
+
` + ` override : set ${ALLOW_REMOTE_API_IN_TESTS_ENV}=1 only for a test that must reach a remote endpoint.`);
|
|
1009
1050
|
}
|
|
1010
1051
|
function normalizeBase(raw) {
|
|
1011
1052
|
let base = raw.trim().replace(/\/+$/, "");
|
|
@@ -1013,9 +1054,24 @@ function normalizeBase(raw) {
|
|
|
1013
1054
|
return base;
|
|
1014
1055
|
return `${base}/v1`;
|
|
1015
1056
|
}
|
|
1057
|
+
function assertUnambiguousStoreEnv() {
|
|
1058
|
+
if (firstEnvKey(DB_PATH_ENV_KEYS))
|
|
1059
|
+
return;
|
|
1060
|
+
if (hasDatabaseUrl())
|
|
1061
|
+
return;
|
|
1062
|
+
const urlKey = firstEnvKey(API_URL_ENV_KEYS);
|
|
1063
|
+
const keyKey = firstEnvKey(API_KEY_ENV_KEYS);
|
|
1064
|
+
if (urlKey && !keyKey) {
|
|
1065
|
+
throw new MementosStoreConfigError(`${urlKey} points at the cloud memory store but ${API_KEY_ENV_KEYS[0]} is not set. ` + `Refusing to serve the on-box SQLite store in its place, because it holds a different ` + `dataset. Set ${API_KEY_ENV_KEYS[0]} to reach the cloud store. If you meant to use the ` + `on-box SQLite store, unset ${urlKey} or set ${DB_PATH_ENV_KEYS[0]} explicitly.`);
|
|
1066
|
+
}
|
|
1067
|
+
if (keyKey && !urlKey) {
|
|
1068
|
+
throw new MementosStoreConfigError(`${keyKey} is set but ${API_URL_ENV_KEYS[0]} is not, so the cloud memory store cannot be ` + `reached. Refusing to serve the on-box SQLite store in its place, because it holds a ` + `different dataset. Set ${API_URL_ENV_KEYS[0]} to reach the cloud store. If you meant to ` + `use the on-box SQLite store, unset ${keyKey} or set ${DB_PATH_ENV_KEYS[0]} explicitly.`);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1016
1071
|
function getApiConfig() {
|
|
1017
|
-
|
|
1018
|
-
const
|
|
1072
|
+
assertUnambiguousStoreEnv();
|
|
1073
|
+
const rawBase = firstEnv(API_URL_ENV_KEYS);
|
|
1074
|
+
const apiKey = firstEnv(API_KEY_ENV_KEYS);
|
|
1019
1075
|
if (!rawBase || !apiKey)
|
|
1020
1076
|
return null;
|
|
1021
1077
|
return { baseUrl: normalizeBase(rawBase), apiKey };
|
|
@@ -1029,6 +1085,7 @@ function apiRequestRaw(method, path, body) {
|
|
|
1029
1085
|
const cfg = getApiConfig();
|
|
1030
1086
|
if (!cfg)
|
|
1031
1087
|
throw new Error("api-mode: not configured (HASNA_MEMENTOS_API_URL / HASNA_MEMENTOS_API_KEY)");
|
|
1088
|
+
assertRequestAllowedUnderTest(cfg.baseUrl);
|
|
1032
1089
|
const url = `${cfg.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
|
|
1033
1090
|
const hasBody = body !== undefined && body !== null;
|
|
1034
1091
|
const timeout = process.env["HASNA_MEMENTOS_API_TIMEOUT"] || DEFAULT_TIMEOUT_S;
|
|
@@ -1095,13 +1152,13 @@ x-api-key: ${cfg.apiKey}
|
|
|
1095
1152
|
}
|
|
1096
1153
|
return { status, body: respBody };
|
|
1097
1154
|
}
|
|
1098
|
-
function apiJson(method, path, body) {
|
|
1155
|
+
function apiJson(method, path, body, options) {
|
|
1099
1156
|
const raw = apiRequestRaw(method, path, body);
|
|
1100
1157
|
if (raw.status >= 200 && raw.status < 300) {
|
|
1101
1158
|
const data = raw.body.trim() ? JSON.parse(raw.body) : undefined;
|
|
1102
1159
|
return { status: raw.status, data };
|
|
1103
1160
|
}
|
|
1104
|
-
if (raw.status === 404) {
|
|
1161
|
+
if (raw.status === 404 && options?.allow404) {
|
|
1105
1162
|
return { status: 404, data: undefined };
|
|
1106
1163
|
}
|
|
1107
1164
|
let msg = `mementos cloud ${method} ${path} \u2192 ${raw.status}`;
|
|
@@ -1133,8 +1190,19 @@ function toQuery(params) {
|
|
|
1133
1190
|
const s = sp.toString();
|
|
1134
1191
|
return s ? `?${s}` : "";
|
|
1135
1192
|
}
|
|
1136
|
-
var ApiRequestError, DEFAULT_TIMEOUT_S = "45";
|
|
1193
|
+
var API_URL_ENV_KEYS, API_KEY_ENV_KEYS, DATABASE_URL_ENV_KEYS, ALLOW_REMOTE_API_IN_TESTS_ENV = "MEMENTOS_ALLOW_REMOTE_API_IN_TESTS", DB_PATH_ENV_KEYS, MementosStoreConfigError, ApiRequestError, DEFAULT_TIMEOUT_S = "45";
|
|
1137
1194
|
var init_api_mode = __esm(() => {
|
|
1195
|
+
API_URL_ENV_KEYS = ["HASNA_MEMENTOS_API_URL", "MEMENTOS_API_URL"];
|
|
1196
|
+
API_KEY_ENV_KEYS = ["HASNA_MEMENTOS_API_KEY", "MEMENTOS_API_KEY"];
|
|
1197
|
+
DATABASE_URL_ENV_KEYS = ["HASNA_MEMENTOS_DATABASE_URL", "MEMENTOS_DATABASE_URL"];
|
|
1198
|
+
DB_PATH_ENV_KEYS = ["HASNA_MEMENTOS_DB_PATH", "MEMENTOS_DB_PATH"];
|
|
1199
|
+
MementosStoreConfigError = class MementosStoreConfigError extends Error {
|
|
1200
|
+
code = "MEMENTOS_STORE_CONFIG";
|
|
1201
|
+
constructor(message) {
|
|
1202
|
+
super(message);
|
|
1203
|
+
this.name = "MementosStoreConfigError";
|
|
1204
|
+
}
|
|
1205
|
+
};
|
|
1138
1206
|
ApiRequestError = class ApiRequestError extends Error {
|
|
1139
1207
|
status;
|
|
1140
1208
|
body;
|
|
@@ -2379,6 +2447,41 @@ var init_redact = __esm(() => {
|
|
|
2379
2447
|
];
|
|
2380
2448
|
});
|
|
2381
2449
|
|
|
2450
|
+
// src/lib/enum-validation.ts
|
|
2451
|
+
function formatEnumViolation(v) {
|
|
2452
|
+
return `Invalid ${v.field}: "${v.value}". Allowed values: ${v.allowed.join(", ")}.`;
|
|
2453
|
+
}
|
|
2454
|
+
function validateEnumField(field, value) {
|
|
2455
|
+
const allowed = ENUM_FIELDS[field];
|
|
2456
|
+
if (!allowed)
|
|
2457
|
+
return null;
|
|
2458
|
+
if (value === undefined || value === null || value === "")
|
|
2459
|
+
return null;
|
|
2460
|
+
if (typeof value === "string" && allowed.includes(value))
|
|
2461
|
+
return null;
|
|
2462
|
+
return { field, value: String(value), allowed };
|
|
2463
|
+
}
|
|
2464
|
+
function validateMemoryEnums(input) {
|
|
2465
|
+
for (const field of Object.keys(ENUM_FIELDS)) {
|
|
2466
|
+
if (!(field in input))
|
|
2467
|
+
continue;
|
|
2468
|
+
const violation = validateEnumField(field, input[field]);
|
|
2469
|
+
if (violation)
|
|
2470
|
+
return violation;
|
|
2471
|
+
}
|
|
2472
|
+
return null;
|
|
2473
|
+
}
|
|
2474
|
+
var ENUM_FIELDS;
|
|
2475
|
+
var init_enum_validation = __esm(() => {
|
|
2476
|
+
init_types();
|
|
2477
|
+
ENUM_FIELDS = {
|
|
2478
|
+
category: MEMORY_CATEGORIES,
|
|
2479
|
+
scope: MEMORY_SCOPES,
|
|
2480
|
+
source: MEMORY_SOURCES,
|
|
2481
|
+
status: MEMORY_STATUSES
|
|
2482
|
+
};
|
|
2483
|
+
});
|
|
2484
|
+
|
|
2382
2485
|
// src/lib/hooks.ts
|
|
2383
2486
|
function generateHookId() {
|
|
2384
2487
|
return `hook_${++_idCounter}_${Date.now().toString(36)}`;
|
|
@@ -2692,7 +2795,10 @@ function parseMemoryRow(row) {
|
|
|
2692
2795
|
}
|
|
2693
2796
|
function createMemory(input, dedupeMode = "merge", db) {
|
|
2694
2797
|
if (!db && isApiMode()) {
|
|
2695
|
-
const { data } = apiJson("POST", "/memories", { ...input, dedupe: dedupeMode });
|
|
2798
|
+
const { status, data } = apiJson("POST", "/memories", { ...input, dedupe: dedupeMode });
|
|
2799
|
+
if (!data || !data.id) {
|
|
2800
|
+
throw new ApiRequestError(`mementos cloud POST /memories \u2192 ${status} but no memory was returned; the write did not persist (key: ${input.key})`, status, "");
|
|
2801
|
+
}
|
|
2696
2802
|
return data;
|
|
2697
2803
|
}
|
|
2698
2804
|
const d = db || getDatabase();
|
|
@@ -2831,16 +2937,25 @@ function bulkUpsertMemories(memories, db) {
|
|
|
2831
2937
|
const d = db || getDatabase();
|
|
2832
2938
|
let inserted = 0;
|
|
2833
2939
|
let skipped = 0;
|
|
2940
|
+
let rejected = 0;
|
|
2834
2941
|
const errors = [];
|
|
2835
|
-
const insert = d.prepare(`INSERT
|
|
2836
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2942
|
+
const insert = d.prepare(`INSERT INTO memories (id, key, value, category, scope, summary, tags, importance, source, status, pinned, agent_id, project_id, session_id, machine_id, namespace, created_by_agent, when_to_use, sequence_group, sequence_order, metadata, access_count, version, expires_at, valid_from, valid_until, ingested_at, created_at, updated_at)
|
|
2943
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2944
|
+
ON CONFLICT DO NOTHING`);
|
|
2837
2945
|
const insertTag = d.prepare("INSERT OR IGNORE INTO memory_tags (memory_id, tag) VALUES (?, ?)");
|
|
2838
2946
|
for (const mem of memories) {
|
|
2839
2947
|
const key = mem["key"];
|
|
2840
2948
|
const id = mem["id"] || uuid();
|
|
2841
2949
|
try {
|
|
2842
2950
|
if (!key) {
|
|
2843
|
-
|
|
2951
|
+
rejected++;
|
|
2952
|
+
errors.push(`rejected row without key (id=${id})`);
|
|
2953
|
+
continue;
|
|
2954
|
+
}
|
|
2955
|
+
const violation = validateMemoryEnums(mem);
|
|
2956
|
+
if (violation) {
|
|
2957
|
+
rejected++;
|
|
2958
|
+
errors.push(`Rejected "${key}": ${formatEnumViolation(violation)}`);
|
|
2844
2959
|
continue;
|
|
2845
2960
|
}
|
|
2846
2961
|
const timestamp = now();
|
|
@@ -2889,10 +3004,11 @@ function bulkUpsertMemories(memories, db) {
|
|
|
2889
3004
|
skipped++;
|
|
2890
3005
|
}
|
|
2891
3006
|
} catch (e) {
|
|
3007
|
+
rejected++;
|
|
2892
3008
|
errors.push(`Failed "${String(key)}": ${e instanceof Error ? e.message : String(e)}`);
|
|
2893
3009
|
}
|
|
2894
3010
|
}
|
|
2895
|
-
return { inserted, skipped, errors, total: memories.length };
|
|
3011
|
+
return { inserted, skipped, rejected, errors, total: memories.length };
|
|
2896
3012
|
}
|
|
2897
3013
|
function ensureMemoryReferences(d, input) {
|
|
2898
3014
|
const t = now();
|
|
@@ -2920,7 +3036,7 @@ function listMemoriesByKey(key, db) {
|
|
|
2920
3036
|
}
|
|
2921
3037
|
function getMemory(id, db) {
|
|
2922
3038
|
if (!db && isApiMode()) {
|
|
2923
|
-
const { status, data } = apiJson("GET", `/memories/${encodeURIComponent(id)}
|
|
3039
|
+
const { status, data } = apiJson("GET", `/memories/${encodeURIComponent(id)}`, undefined, { allow404: true });
|
|
2924
3040
|
return status === 404 ? null : data ?? null;
|
|
2925
3041
|
}
|
|
2926
3042
|
const d = db || getDatabase();
|
|
@@ -3253,7 +3369,7 @@ function getMemoryEmbeddings(ids, db) {
|
|
|
3253
3369
|
}
|
|
3254
3370
|
function updateMemory(id, input, db) {
|
|
3255
3371
|
if (!db && isApiMode()) {
|
|
3256
|
-
const { status, data } = apiJson("PATCH", `/memories/${encodeURIComponent(id)}`, input);
|
|
3372
|
+
const { status, data } = apiJson("PATCH", `/memories/${encodeURIComponent(id)}`, input, { allow404: true });
|
|
3257
3373
|
if (status === 404)
|
|
3258
3374
|
throw new MemoryNotFoundError(id);
|
|
3259
3375
|
return data;
|
|
@@ -3361,7 +3477,7 @@ function updateMemory(id, input, db) {
|
|
|
3361
3477
|
}
|
|
3362
3478
|
function deleteMemory(id, db) {
|
|
3363
3479
|
if (!db && isApiMode()) {
|
|
3364
|
-
const { status } = apiJson("DELETE", `/memories/${encodeURIComponent(id)}
|
|
3480
|
+
const { status } = apiJson("DELETE", `/memories/${encodeURIComponent(id)}`, undefined, { allow404: true });
|
|
3365
3481
|
return status !== 404;
|
|
3366
3482
|
}
|
|
3367
3483
|
const d = db || getDatabase();
|
|
@@ -3513,6 +3629,7 @@ var init_memories = __esm(() => {
|
|
|
3513
3629
|
init_types();
|
|
3514
3630
|
init_database();
|
|
3515
3631
|
init_redact();
|
|
3632
|
+
init_enum_validation();
|
|
3516
3633
|
init_hooks();
|
|
3517
3634
|
init_poisoning();
|
|
3518
3635
|
init_entity_memories();
|
|
@@ -3660,7 +3777,7 @@ function createWebhookHook(input, db) {
|
|
|
3660
3777
|
}
|
|
3661
3778
|
function getWebhookHook(id, db) {
|
|
3662
3779
|
if (!db && isApiMode()) {
|
|
3663
|
-
const { status, data } = apiJson("GET", `/webhooks/${encodeURIComponent(id)}
|
|
3780
|
+
const { status, data } = apiJson("GET", `/webhooks/${encodeURIComponent(id)}`, undefined, { allow404: true });
|
|
3664
3781
|
if (status === 404 || !data)
|
|
3665
3782
|
return null;
|
|
3666
3783
|
return data;
|
|
@@ -3696,7 +3813,7 @@ function updateWebhookHook(id, updates, db) {
|
|
|
3696
3813
|
enabled: updates.enabled,
|
|
3697
3814
|
priority: updates.priority,
|
|
3698
3815
|
description: updates.description
|
|
3699
|
-
});
|
|
3816
|
+
}, { allow404: true });
|
|
3700
3817
|
if (status === 404 || !data)
|
|
3701
3818
|
return null;
|
|
3702
3819
|
return data;
|
|
@@ -3727,7 +3844,7 @@ function updateWebhookHook(id, updates, db) {
|
|
|
3727
3844
|
}
|
|
3728
3845
|
function deleteWebhookHook(id, db) {
|
|
3729
3846
|
if (!db && isApiMode()) {
|
|
3730
|
-
const { status } = apiJson("DELETE", `/webhooks/${encodeURIComponent(id)}
|
|
3847
|
+
const { status } = apiJson("DELETE", `/webhooks/${encodeURIComponent(id)}`, undefined, { allow404: true });
|
|
3731
3848
|
return status === 204 || status === 200;
|
|
3732
3849
|
}
|
|
3733
3850
|
const d = db || getDatabase();
|
|
@@ -3825,7 +3942,7 @@ function createEntity(input, db) {
|
|
|
3825
3942
|
}
|
|
3826
3943
|
function getEntity(id, db) {
|
|
3827
3944
|
if (!db && isApiMode()) {
|
|
3828
|
-
const { status, data } = apiJson("GET", `/entities/${encodeURIComponent(id)}
|
|
3945
|
+
const { status, data } = apiJson("GET", `/entities/${encodeURIComponent(id)}`, undefined, { allow404: true });
|
|
3829
3946
|
if (status === 404 || !data)
|
|
3830
3947
|
throw new EntityNotFoundError(id);
|
|
3831
3948
|
return data;
|
|
@@ -3908,7 +4025,7 @@ function listEntities(filter = {}, db) {
|
|
|
3908
4025
|
}
|
|
3909
4026
|
function updateEntity(id, input, db) {
|
|
3910
4027
|
if (!db && isApiMode()) {
|
|
3911
|
-
const { status, data } = apiJson("PATCH", `/entities/${encodeURIComponent(id)}`, input);
|
|
4028
|
+
const { status, data } = apiJson("PATCH", `/entities/${encodeURIComponent(id)}`, input, { allow404: true });
|
|
3912
4029
|
if (status === 404 || !data)
|
|
3913
4030
|
throw new EntityNotFoundError(id);
|
|
3914
4031
|
return data;
|
|
@@ -3941,7 +4058,7 @@ function updateEntity(id, input, db) {
|
|
|
3941
4058
|
}
|
|
3942
4059
|
function deleteEntity(id, db) {
|
|
3943
4060
|
if (!db && isApiMode()) {
|
|
3944
|
-
const { status } = apiJson("DELETE", `/entities/${encodeURIComponent(id)}
|
|
4061
|
+
const { status } = apiJson("DELETE", `/entities/${encodeURIComponent(id)}`, undefined, { allow404: true });
|
|
3945
4062
|
if (status === 404)
|
|
3946
4063
|
throw new EntityNotFoundError(id);
|
|
3947
4064
|
return;
|
|
@@ -4920,7 +5037,7 @@ function createRelation(input, db) {
|
|
|
4920
5037
|
}
|
|
4921
5038
|
function getRelation(id, db) {
|
|
4922
5039
|
if (!db && isApiMode()) {
|
|
4923
|
-
const { status, data } = apiJson("GET", `/relations/${encodeURIComponent(id)}
|
|
5040
|
+
const { status, data } = apiJson("GET", `/relations/${encodeURIComponent(id)}`, undefined, { allow404: true });
|
|
4924
5041
|
if (status === 404 || !data)
|
|
4925
5042
|
throw new Error(`Relation not found: ${id}`);
|
|
4926
5043
|
return data;
|
|
@@ -4965,7 +5082,7 @@ function listRelations(filter, db) {
|
|
|
4965
5082
|
}
|
|
4966
5083
|
function deleteRelation(id, db) {
|
|
4967
5084
|
if (!db && isApiMode()) {
|
|
4968
|
-
const { status } = apiJson("DELETE", `/relations/${encodeURIComponent(id)}
|
|
5085
|
+
const { status } = apiJson("DELETE", `/relations/${encodeURIComponent(id)}`, undefined, { allow404: true });
|
|
4969
5086
|
if (status === 404)
|
|
4970
5087
|
throw new Error(`Relation not found: ${id}`);
|
|
4971
5088
|
return;
|
|
@@ -55581,7 +55698,7 @@ function registerAgent(name, sessionId, description, role, projectId, db) {
|
|
|
55581
55698
|
}
|
|
55582
55699
|
function getAgent(idOrName, db) {
|
|
55583
55700
|
if (!db && isApiMode()) {
|
|
55584
|
-
const { status, data } = apiJson("GET", `/agents/${encodeURIComponent(idOrName)}
|
|
55701
|
+
const { status, data } = apiJson("GET", `/agents/${encodeURIComponent(idOrName)}`, undefined, { allow404: true });
|
|
55585
55702
|
if (status === 404 || !data)
|
|
55586
55703
|
return null;
|
|
55587
55704
|
return data;
|
|
@@ -55634,7 +55751,7 @@ function listAgentsByProject(projectId, db) {
|
|
|
55634
55751
|
}
|
|
55635
55752
|
function updateAgent(id, updates, db) {
|
|
55636
55753
|
if (!db && isApiMode()) {
|
|
55637
|
-
const { status, data } = apiJson("PATCH", `/agents/${encodeURIComponent(id)}`, updates);
|
|
55754
|
+
const { status, data } = apiJson("PATCH", `/agents/${encodeURIComponent(id)}`, updates, { allow404: true });
|
|
55638
55755
|
if (status === 404 || !data)
|
|
55639
55756
|
return null;
|
|
55640
55757
|
return data;
|
|
@@ -55719,7 +55836,7 @@ function registerProject(name, path, description, memoryPrefix, db) {
|
|
|
55719
55836
|
}
|
|
55720
55837
|
function getProject(idOrPath, db) {
|
|
55721
55838
|
if (!db && isApiMode()) {
|
|
55722
|
-
const { status, data } = apiJson("GET", `/projects/${encodeURIComponent(idOrPath)}
|
|
55839
|
+
const { status, data } = apiJson("GET", `/projects/${encodeURIComponent(idOrPath)}`, undefined, { allow404: true });
|
|
55723
55840
|
if (status === 404 || !data)
|
|
55724
55841
|
return null;
|
|
55725
55842
|
return data;
|
|
@@ -58856,7 +58973,7 @@ function createSubscription(input, db) {
|
|
|
58856
58973
|
}
|
|
58857
58974
|
function deleteSubscription(id, db) {
|
|
58858
58975
|
if (!db && isApiMode()) {
|
|
58859
|
-
const { status } = apiJson("DELETE", `/subscriptions/${encodeURIComponent(id)}
|
|
58976
|
+
const { status } = apiJson("DELETE", `/subscriptions/${encodeURIComponent(id)}`, undefined, { allow404: true });
|
|
58860
58977
|
return status !== 404;
|
|
58861
58978
|
}
|
|
58862
58979
|
const d = db || getDatabase();
|
|
@@ -60772,7 +60889,7 @@ function acquireLock(agentId, resourceType, resourceId, lockType = "exclusive",
|
|
|
60772
60889
|
}
|
|
60773
60890
|
function releaseLock(lockId, agentId, db) {
|
|
60774
60891
|
if (!db && isApiMode()) {
|
|
60775
|
-
const { status } = apiJson("DELETE", `/locks/${encodeURIComponent(lockId)}`, { agent_id: agentId });
|
|
60892
|
+
const { status } = apiJson("DELETE", `/locks/${encodeURIComponent(lockId)}`, { agent_id: agentId }, { allow404: true });
|
|
60776
60893
|
return status !== 404;
|
|
60777
60894
|
}
|
|
60778
60895
|
const d = db || getDatabase();
|
|
@@ -62517,7 +62634,7 @@ function createSessionJob(input, db) {
|
|
|
62517
62634
|
}
|
|
62518
62635
|
function getSessionJob(id, db) {
|
|
62519
62636
|
if (!db && isApiMode()) {
|
|
62520
|
-
const { status, data } = apiJson("GET", `/sessions/jobs/${encodeURIComponent(id)}
|
|
62637
|
+
const { status, data } = apiJson("GET", `/sessions/jobs/${encodeURIComponent(id)}`, undefined, { allow404: true });
|
|
62521
62638
|
if (status === 404 || !data)
|
|
62522
62639
|
return null;
|
|
62523
62640
|
return data;
|
package/dist/server/helpers.d.ts
CHANGED
|
@@ -2,6 +2,17 @@ export declare const CORS_HEADERS: Record<string, string>;
|
|
|
2
2
|
export declare const MIME_TYPES: Record<string, string>;
|
|
3
3
|
export declare function json(data: unknown, status?: number): Response;
|
|
4
4
|
export declare function errorResponse(message: string, status: number, details?: unknown): Response;
|
|
5
|
+
/**
|
|
6
|
+
* Classify a thrown error as a database constraint violation — i.e. the caller
|
|
7
|
+
* sent a value the schema refuses (bad enum, missing FK, duplicate unique key).
|
|
8
|
+
* Returns an actionable message for a 400, or `null` when the error is a
|
|
9
|
+
* genuine server fault that must stay a 500.
|
|
10
|
+
*
|
|
11
|
+
* Defence in depth behind the per-route validators: a column whose CHECK is not
|
|
12
|
+
* yet mirrored by a validator still gets reported as a client error rather than
|
|
13
|
+
* as an opaque outage.
|
|
14
|
+
*/
|
|
15
|
+
export declare function describeConstraintViolation(e: unknown): string | null;
|
|
5
16
|
export declare function readJson(req: Request): Promise<unknown>;
|
|
6
17
|
export declare function getCorsHeaders(req?: Request): Record<string, string>;
|
|
7
18
|
export declare function authenticateRequest(req: Request): Response | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/server/helpers.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK/C,CAAC;AAMF,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAU7C,CAAC;AAMF,wBAAgB,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,SAAM,GAAG,QAAQ,CAK1D;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,OAAO,GAChB,QAAQ,CAIV;AAKD,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAU7D;AAMD,wBAAgB,cAAc,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWpE;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAqBjE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMhE;AAMD,wBAAgB,mBAAmB,IAAI,MAAM,CAiB5C;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAMjE"}
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/server/helpers.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK/C,CAAC;AAMF,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAU7C,CAAC;AAMF,wBAAgB,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,SAAM,GAAG,QAAQ,CAK1D;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,OAAO,GAChB,QAAQ,CAIV;AAED;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAWrE;AAKD,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAU7D;AAMD,wBAAgB,cAAc,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWpE;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAqBjE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMhE;AAMD,wBAAgB,mBAAmB,IAAI,MAAM,CAiB5C;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAMjE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AA8CH,OAAO,sBAAsB,CAAC;AAC9B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,sBAAsB,CAAC;AAC9B,OAAO,sBAAsB,CAAC;AAC9B,OAAO,mBAAmB,CAAC;AAC3B,OAAO,oBAAoB,CAAC;AA0F5B,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AA8CH,OAAO,sBAAsB,CAAC;AAC9B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,sBAAsB,CAAC;AAC9B,OAAO,sBAAsB,CAAC;AAC9B,OAAO,mBAAmB,CAAC;AAC3B,OAAO,oBAAoB,CAAC;AA0F5B,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAsL9C"}
|