@cerefox/memory 1.10.1 → 1.11.0
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/bin/cerefox.js +208 -48
- package/dist/frontend/assets/{index-i67RH1VY.js → index-sef54G6W.js} +26 -26
- package/dist/frontend/assets/index-sef54G6W.js.map +1 -0
- package/dist/frontend/index.html +1 -1
- package/dist/server-assets/_shared/ef-meta/index.ts +3 -3
- package/dist/server-assets/_shared/mcp-tools/access-paths.ts +51 -0
- package/dist/server-assets/_shared/mcp-tools/types.ts +13 -14
- package/docs/guides/access-paths.md +1 -0
- package/docs/guides/configuration.md +27 -3
- package/package.json +1 -1
- package/dist/frontend/assets/index-i67RH1VY.js.map +0 -1
package/dist/bin/cerefox.js
CHANGED
|
@@ -7440,7 +7440,7 @@ var exports_meta = {};
|
|
|
7440
7440
|
__export(exports_meta, {
|
|
7441
7441
|
PKG_VERSION: () => PKG_VERSION
|
|
7442
7442
|
});
|
|
7443
|
-
var PKG_VERSION = "1.
|
|
7443
|
+
var PKG_VERSION = "1.11.0";
|
|
7444
7444
|
var init_meta = () => {};
|
|
7445
7445
|
|
|
7446
7446
|
// ../../_shared/config/paths.ts
|
|
@@ -7468,12 +7468,12 @@ function resolveConfigDir(opts = {}) {
|
|
|
7468
7468
|
}
|
|
7469
7469
|
const here = opts.cwd ?? processCwd();
|
|
7470
7470
|
const cwdEnv = join(here, ".env");
|
|
7471
|
-
if (existsSync(cwdEnv) &&
|
|
7471
|
+
if (existsSync(cwdEnv) && envFileHasCerefoxKey(cwdEnv)) {
|
|
7472
7472
|
return resolvePath(here);
|
|
7473
7473
|
}
|
|
7474
7474
|
return userState;
|
|
7475
7475
|
}
|
|
7476
|
-
function
|
|
7476
|
+
function envFileHasCerefoxKey(envPath) {
|
|
7477
7477
|
try {
|
|
7478
7478
|
const contents = readFileSync(envPath, "utf8");
|
|
7479
7479
|
return /^\s*CEREFOX_[A-Z0-9_]+\s*=/m.test(contents);
|
|
@@ -7494,7 +7494,7 @@ function isDevMode(opts = {}) {
|
|
|
7494
7494
|
return false;
|
|
7495
7495
|
const here = opts.cwd ?? processCwd();
|
|
7496
7496
|
const cwdEnv = join(here, ".env");
|
|
7497
|
-
return existsSync(cwdEnv) &&
|
|
7497
|
+
return existsSync(cwdEnv) && envFileHasCerefoxKey(cwdEnv);
|
|
7498
7498
|
}
|
|
7499
7499
|
var USER_STATE_DIR_NAME = ".cerefox";
|
|
7500
7500
|
var init_paths = () => {};
|
|
@@ -7565,6 +7565,7 @@ var init_env = __esm(() => {
|
|
|
7565
7565
|
var exports_config = {};
|
|
7566
7566
|
__export(exports_config, {
|
|
7567
7567
|
USER_STATE_DIR_NAME: () => USER_STATE_DIR_NAME,
|
|
7568
|
+
envFileHasCerefoxKey: () => envFileHasCerefoxKey,
|
|
7568
7569
|
isDevMode: () => isDevMode,
|
|
7569
7570
|
loadEnv: () => loadEnv,
|
|
7570
7571
|
loadSettings: () => loadSettings,
|
|
@@ -26002,7 +26003,7 @@ var init_bundled_docs = __esm(() => {
|
|
|
26002
26003
|
});
|
|
26003
26004
|
|
|
26004
26005
|
// ../../_shared/ef-meta/index.ts
|
|
26005
|
-
var EF_VERSION = "1.
|
|
26006
|
+
var EF_VERSION = "1.11.0", CEREFOX_VERSION = "1.11.0", EF_LAST_CHANGED = "1.11.0";
|
|
26006
26007
|
var init_ef_meta = () => {};
|
|
26007
26008
|
|
|
26008
26009
|
// ../../_shared/compatibility/index.ts
|
|
@@ -55096,9 +55097,13 @@ var init_audit_log = __esm(() => {
|
|
|
55096
55097
|
};
|
|
55097
55098
|
});
|
|
55098
55099
|
|
|
55100
|
+
// ../../_shared/mcp-tools/access-paths.ts
|
|
55101
|
+
var init_access_paths = () => {};
|
|
55102
|
+
|
|
55099
55103
|
// ../../_shared/mcp-tools/types.ts
|
|
55100
55104
|
var McpInvalidParams;
|
|
55101
55105
|
var init_types3 = __esm(() => {
|
|
55106
|
+
init_access_paths();
|
|
55102
55107
|
McpInvalidParams = class McpInvalidParams extends Error {
|
|
55103
55108
|
constructor(message) {
|
|
55104
55109
|
super(message);
|
|
@@ -77982,21 +77987,22 @@ function checkMcpConfigs() {
|
|
|
77982
77987
|
detail: found.join(", ")
|
|
77983
77988
|
};
|
|
77984
77989
|
}
|
|
77985
|
-
function checkLegacyShadowEnv() {
|
|
77986
|
-
const
|
|
77987
|
-
const
|
|
77988
|
-
|
|
77989
|
-
if (!existsSync10(homeEnv) || !existsSync10(cwdEnv))
|
|
77990
|
+
function checkLegacyShadowEnv(opts = {}) {
|
|
77991
|
+
const activeEnv = resolveEnvFile(opts);
|
|
77992
|
+
const cwdEnv = join9(opts.cwd ?? process.cwd(), ".env");
|
|
77993
|
+
if (!existsSync10(activeEnv) || !existsSync10(cwdEnv))
|
|
77990
77994
|
return null;
|
|
77991
77995
|
try {
|
|
77992
|
-
if (realpathSync(
|
|
77996
|
+
if (realpathSync(activeEnv) === realpathSync(cwdEnv))
|
|
77993
77997
|
return null;
|
|
77994
77998
|
} catch {}
|
|
77999
|
+
if (!envFileHasCerefoxKey(cwdEnv))
|
|
78000
|
+
return null;
|
|
77995
78001
|
return {
|
|
77996
78002
|
name: "legacy env",
|
|
77997
78003
|
status: "skipped",
|
|
77998
|
-
detail: `${cwdEnv} (shadowed by
|
|
77999
|
-
hint:
|
|
78004
|
+
detail: `${cwdEnv} (shadowed by ${activeEnv})`,
|
|
78005
|
+
hint: `Shadowed by ${activeEnv} and no longer read by anything (Python was removed at v1.0.0). Safe to delete.`
|
|
78000
78006
|
};
|
|
78001
78007
|
}
|
|
78002
78008
|
async function checkPostgres() {
|
|
@@ -84457,7 +84463,7 @@ var CONFIG_CATALOG = [
|
|
|
84457
84463
|
},
|
|
84458
84464
|
{
|
|
84459
84465
|
key: "require_requestor_identity",
|
|
84460
|
-
description: "Require a requestor/author on MCP
|
|
84466
|
+
description: "Require a requestor/author. Enforced on the Edge Functions (incl. remote MCP) ONLY — not local MCP, /api/v1 or the CLI.",
|
|
84461
84467
|
kind: "boolean",
|
|
84462
84468
|
defaultValue: "false",
|
|
84463
84469
|
group: "Governance",
|
|
@@ -84569,6 +84575,78 @@ function validateConfigValue(key, value) {
|
|
|
84569
84575
|
|
|
84570
84576
|
// src/web/routes/config.ts
|
|
84571
84577
|
init_config();
|
|
84578
|
+
|
|
84579
|
+
// src/web/identity.ts
|
|
84580
|
+
var DEFAULT_WEB_AUTHOR = "web-ui";
|
|
84581
|
+
var DEFAULT_WEB_AUTHOR_TYPE = "user";
|
|
84582
|
+
var WEB_UI_IDENTITY = {
|
|
84583
|
+
author: DEFAULT_WEB_AUTHOR,
|
|
84584
|
+
authorType: DEFAULT_WEB_AUTHOR_TYPE,
|
|
84585
|
+
requestor: DEFAULT_WEB_AUTHOR,
|
|
84586
|
+
accessPath: "webapp",
|
|
84587
|
+
named: false
|
|
84588
|
+
};
|
|
84589
|
+
var HEADER = {
|
|
84590
|
+
author: "x-cerefox-author",
|
|
84591
|
+
authorType: "x-cerefox-author-type",
|
|
84592
|
+
requestor: "x-cerefox-requestor"
|
|
84593
|
+
};
|
|
84594
|
+
function readField(c2, headerName, body, bodyKey) {
|
|
84595
|
+
const header = c2.req.header(headerName);
|
|
84596
|
+
if (header !== undefined) {
|
|
84597
|
+
if (header.trim() === "") {
|
|
84598
|
+
return { ok: false, detail: `${headerName} must not be blank.` };
|
|
84599
|
+
}
|
|
84600
|
+
return { ok: true, value: header.trim() };
|
|
84601
|
+
}
|
|
84602
|
+
if (body && bodyKey in body) {
|
|
84603
|
+
const raw2 = body[bodyKey];
|
|
84604
|
+
if (raw2 === null || raw2 === undefined)
|
|
84605
|
+
return { ok: true, value: undefined };
|
|
84606
|
+
if (typeof raw2 !== "string") {
|
|
84607
|
+
return { ok: false, detail: `${bodyKey} must be a string.` };
|
|
84608
|
+
}
|
|
84609
|
+
if (raw2.trim() === "") {
|
|
84610
|
+
return { ok: false, detail: `${bodyKey} must not be blank.` };
|
|
84611
|
+
}
|
|
84612
|
+
return { ok: true, value: raw2.trim() };
|
|
84613
|
+
}
|
|
84614
|
+
return { ok: true, value: undefined };
|
|
84615
|
+
}
|
|
84616
|
+
function resolveCallerIdentity(c2, body) {
|
|
84617
|
+
const author = readField(c2, HEADER.author, body, "author");
|
|
84618
|
+
if (!author.ok)
|
|
84619
|
+
return author;
|
|
84620
|
+
const requestor = readField(c2, HEADER.requestor, body, "requestor");
|
|
84621
|
+
if (!requestor.ok)
|
|
84622
|
+
return requestor;
|
|
84623
|
+
const authorType = readField(c2, HEADER.authorType, body, "author_type");
|
|
84624
|
+
if (!authorType.ok)
|
|
84625
|
+
return authorType;
|
|
84626
|
+
if (authorType.value !== undefined && authorType.value !== "user" && authorType.value !== "agent") {
|
|
84627
|
+
return {
|
|
84628
|
+
ok: false,
|
|
84629
|
+
detail: `author_type must be "user" or "agent" (got ${JSON.stringify(authorType.value)}).`
|
|
84630
|
+
};
|
|
84631
|
+
}
|
|
84632
|
+
const named = author.value !== undefined || requestor.value !== undefined || authorType.value !== undefined;
|
|
84633
|
+
if (!named)
|
|
84634
|
+
return { ok: true, identity: WEB_UI_IDENTITY };
|
|
84635
|
+
const resolvedAuthor = author.value ?? requestor.value ?? DEFAULT_WEB_AUTHOR;
|
|
84636
|
+
const resolvedRequestor = requestor.value ?? author.value ?? DEFAULT_WEB_AUTHOR;
|
|
84637
|
+
return {
|
|
84638
|
+
ok: true,
|
|
84639
|
+
identity: {
|
|
84640
|
+
author: resolvedAuthor,
|
|
84641
|
+
authorType: authorType.value ?? DEFAULT_WEB_AUTHOR_TYPE,
|
|
84642
|
+
requestor: resolvedRequestor,
|
|
84643
|
+
accessPath: "api",
|
|
84644
|
+
named: true
|
|
84645
|
+
}
|
|
84646
|
+
};
|
|
84647
|
+
}
|
|
84648
|
+
|
|
84649
|
+
// src/web/routes/config.ts
|
|
84572
84650
|
init__utils();
|
|
84573
84651
|
function unwrapScalarRpc(data) {
|
|
84574
84652
|
if (typeof data === "string")
|
|
@@ -84640,11 +84718,14 @@ function registerConfigRoutes(app, ctx) {
|
|
|
84640
84718
|
const invalid = validateConfigValue(key, value);
|
|
84641
84719
|
if (invalid)
|
|
84642
84720
|
return c2.json({ detail: invalid }, 400);
|
|
84721
|
+
const who = resolveCallerIdentity(c2, body);
|
|
84722
|
+
if (!who.ok)
|
|
84723
|
+
return c2.json({ detail: who.detail }, 400);
|
|
84643
84724
|
const { error: error3 } = await ctx.supabase.rpc("cerefox_set_config", {
|
|
84644
84725
|
p_key: key,
|
|
84645
84726
|
p_value: value,
|
|
84646
|
-
p_author:
|
|
84647
|
-
p_author_type:
|
|
84727
|
+
p_author: who.identity.author,
|
|
84728
|
+
p_author_type: who.identity.authorType
|
|
84648
84729
|
});
|
|
84649
84730
|
if (error3) {
|
|
84650
84731
|
const remediation = storeWriteRemediation(error3.message ?? "", "cerefox_set_config");
|
|
@@ -84662,8 +84743,8 @@ init__utils();
|
|
|
84662
84743
|
function logWebUsage(ctx, params) {
|
|
84663
84744
|
Promise.resolve(ctx.supabase.rpc("cerefox_log_usage", {
|
|
84664
84745
|
p_operation: params.operation,
|
|
84665
|
-
p_access_path: "webapp",
|
|
84666
|
-
p_requestor: params.requestor ??
|
|
84746
|
+
p_access_path: params.access_path ?? "webapp",
|
|
84747
|
+
p_requestor: params.requestor ?? DEFAULT_WEB_AUTHOR,
|
|
84667
84748
|
p_document_id: params.document_id ?? null,
|
|
84668
84749
|
p_project_id: params.project_id ?? null,
|
|
84669
84750
|
p_query_text: params.query_text ?? null,
|
|
@@ -84989,7 +85070,16 @@ function registerDiscoveryRoutes(app, ctx) {
|
|
|
84989
85070
|
results = results.filter((r) => statusMap.get(r.document_id) === reviewStatus);
|
|
84990
85071
|
}
|
|
84991
85072
|
}
|
|
84992
|
-
|
|
85073
|
+
const who = resolveCallerIdentity(c2);
|
|
85074
|
+
if (!who.ok)
|
|
85075
|
+
return c2.json({ detail: who.detail }, 400);
|
|
85076
|
+
logWebUsage(ctx, {
|
|
85077
|
+
operation: "search",
|
|
85078
|
+
query_text: q,
|
|
85079
|
+
result_count: results.length,
|
|
85080
|
+
requestor: who.identity.requestor,
|
|
85081
|
+
access_path: who.identity.accessPath
|
|
85082
|
+
});
|
|
84993
85083
|
return c2.json({
|
|
84994
85084
|
results,
|
|
84995
85085
|
query: q,
|
|
@@ -85314,7 +85404,15 @@ function registerDocumentReadRoutes(app, ctx) {
|
|
|
85314
85404
|
const meta = await getDocumentRow(ctx, documentId);
|
|
85315
85405
|
const projectIds = await listDocumentProjectIds(ctx, documentId);
|
|
85316
85406
|
const versions3 = await listDocumentVersions(ctx, documentId);
|
|
85317
|
-
|
|
85407
|
+
const who = resolveCallerIdentity(c2);
|
|
85408
|
+
if (!who.ok)
|
|
85409
|
+
return c2.json({ detail: who.detail }, 400);
|
|
85410
|
+
logWebUsage(ctx, {
|
|
85411
|
+
operation: "get-document",
|
|
85412
|
+
document_id: documentId,
|
|
85413
|
+
requestor: who.identity.requestor,
|
|
85414
|
+
access_path: who.identity.accessPath
|
|
85415
|
+
});
|
|
85318
85416
|
return c2.json({
|
|
85319
85417
|
document_id: documentId,
|
|
85320
85418
|
full_content: doc2.full_content ?? "",
|
|
@@ -85451,6 +85549,9 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
85451
85549
|
} catch {
|
|
85452
85550
|
return c2.json({ success: false, error: "Invalid JSON body" }, 400);
|
|
85453
85551
|
}
|
|
85552
|
+
const who = resolveCallerIdentity(c2, body);
|
|
85553
|
+
if (!who.ok)
|
|
85554
|
+
return c2.json({ detail: who.detail }, 400);
|
|
85454
85555
|
const title = String(body.title ?? "").trim();
|
|
85455
85556
|
const content = String(body.content ?? "");
|
|
85456
85557
|
const projectIds = Array.isArray(body.project_ids) ? body.project_ids : [];
|
|
@@ -85491,8 +85592,8 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
85491
85592
|
source: "manual",
|
|
85492
85593
|
projectIds: Array.isArray(body.project_ids) ? body.project_ids : undefined,
|
|
85493
85594
|
metadata: body.metadata != null ? metadata : undefined,
|
|
85494
|
-
author:
|
|
85495
|
-
authorType:
|
|
85595
|
+
author: who.identity.author,
|
|
85596
|
+
authorType: who.identity.authorType,
|
|
85496
85597
|
expectedContentHash: typeof body.expected_content_hash === "string" ? body.expected_content_hash : null
|
|
85497
85598
|
});
|
|
85498
85599
|
return c2.json({ success: true, reindexed: result.reindexed });
|
|
@@ -85537,9 +85638,9 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
85537
85638
|
title: body.title !== undefined && title !== doc2.title ? title : undefined,
|
|
85538
85639
|
metadata: body.metadata != null ? metadata : undefined,
|
|
85539
85640
|
projectIds: Array.isArray(body.project_ids) ? projectIds : undefined,
|
|
85540
|
-
author:
|
|
85541
|
-
authorType:
|
|
85542
|
-
accessPath:
|
|
85641
|
+
author: who.identity.author,
|
|
85642
|
+
authorType: who.identity.authorType,
|
|
85643
|
+
accessPath: who.identity.accessPath
|
|
85543
85644
|
});
|
|
85544
85645
|
return c2.json({ success: true, reindexed: false, ...facets });
|
|
85545
85646
|
} catch (err) {
|
|
@@ -85556,10 +85657,20 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
85556
85657
|
});
|
|
85557
85658
|
app.delete("/api/v1/documents/:document_id", async (c2) => {
|
|
85558
85659
|
const documentId = c2.req.param("document_id");
|
|
85660
|
+
const who = resolveCallerIdentity(c2);
|
|
85661
|
+
if (!who.ok)
|
|
85662
|
+
return c2.json({ detail: who.detail }, 400);
|
|
85663
|
+
const expectedHash = (c2.req.header("x-cerefox-expected-content-hash") ?? c2.req.query("expected_content_hash") ?? "").trim();
|
|
85664
|
+
if (who.identity.named && expectedHash === "") {
|
|
85665
|
+
return c2.json({
|
|
85666
|
+
detail: "CEREFOX_TOKEN_REQUIRED: an identified caller must send the content_hash it read, " + "as the X-Cerefox-Expected-Content-Hash header or an expected_content_hash query " + "parameter. A delete must follow a read."
|
|
85667
|
+
}, 400);
|
|
85668
|
+
}
|
|
85559
85669
|
const { data, error: error3 } = await ctx.supabase.rpc("cerefox_delete_document", {
|
|
85560
85670
|
p_document_id: documentId,
|
|
85561
|
-
p_author:
|
|
85562
|
-
p_author_type:
|
|
85671
|
+
p_author: who.identity.author,
|
|
85672
|
+
p_author_type: who.identity.authorType,
|
|
85673
|
+
p_expected_content_hash: expectedHash === "" ? null : expectedHash
|
|
85563
85674
|
});
|
|
85564
85675
|
if (error3) {
|
|
85565
85676
|
if (isDocumentNotFoundError(error3)) {
|
|
@@ -85572,10 +85683,13 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
85572
85683
|
});
|
|
85573
85684
|
app.post("/api/v1/documents/:document_id/restore", async (c2) => {
|
|
85574
85685
|
const documentId = c2.req.param("document_id");
|
|
85686
|
+
const who = resolveCallerIdentity(c2);
|
|
85687
|
+
if (!who.ok)
|
|
85688
|
+
return c2.json({ detail: who.detail }, 400);
|
|
85575
85689
|
const { data, error: error3 } = await ctx.supabase.rpc("cerefox_restore_document", {
|
|
85576
85690
|
p_document_id: documentId,
|
|
85577
|
-
p_author:
|
|
85578
|
-
p_author_type:
|
|
85691
|
+
p_author: who.identity.author,
|
|
85692
|
+
p_author_type: who.identity.authorType
|
|
85579
85693
|
});
|
|
85580
85694
|
if (error3) {
|
|
85581
85695
|
if (isDocumentNotFoundError(error3)) {
|
|
@@ -85588,10 +85702,13 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
85588
85702
|
});
|
|
85589
85703
|
app.delete("/api/v1/documents/:document_id/purge", async (c2) => {
|
|
85590
85704
|
const documentId = c2.req.param("document_id");
|
|
85705
|
+
const who = resolveCallerIdentity(c2);
|
|
85706
|
+
if (!who.ok)
|
|
85707
|
+
return c2.json({ detail: who.detail }, 400);
|
|
85591
85708
|
const { error: error3 } = await ctx.supabase.rpc("cerefox_purge_document", {
|
|
85592
85709
|
p_document_id: documentId,
|
|
85593
|
-
p_author:
|
|
85594
|
-
p_author_type:
|
|
85710
|
+
p_author: who.identity.author,
|
|
85711
|
+
p_author_type: who.identity.authorType
|
|
85595
85712
|
});
|
|
85596
85713
|
if (error3)
|
|
85597
85714
|
return c2.json({ detail: error3.message }, 500);
|
|
@@ -85605,6 +85722,9 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
85605
85722
|
} catch {
|
|
85606
85723
|
return c2.json({ detail: "Invalid JSON body" }, 400);
|
|
85607
85724
|
}
|
|
85725
|
+
const who = resolveCallerIdentity(c2, body);
|
|
85726
|
+
if (!who.ok)
|
|
85727
|
+
return c2.json({ detail: who.detail }, 400);
|
|
85608
85728
|
const status = body.status;
|
|
85609
85729
|
if (status !== "approved" && status !== "pending_review") {
|
|
85610
85730
|
return c2.json({ detail: `Invalid status: ${JSON.stringify(status)}` }, 400);
|
|
@@ -85619,7 +85739,8 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
85619
85739
|
return c2.json({ detail: error3.message }, 500);
|
|
85620
85740
|
await createAuditEntry(ctx, {
|
|
85621
85741
|
operation: "status-change",
|
|
85622
|
-
author:
|
|
85742
|
+
author: who.identity.author,
|
|
85743
|
+
authorType: who.identity.authorType,
|
|
85623
85744
|
documentId,
|
|
85624
85745
|
description: `Review status changed from '${oldStatus}' to '${status}'`
|
|
85625
85746
|
});
|
|
@@ -85634,6 +85755,9 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
85634
85755
|
} catch {
|
|
85635
85756
|
return c2.json({ detail: "Invalid JSON body" }, 400);
|
|
85636
85757
|
}
|
|
85758
|
+
const who = resolveCallerIdentity(c2, body);
|
|
85759
|
+
if (!who.ok)
|
|
85760
|
+
return c2.json({ detail: who.detail }, 400);
|
|
85637
85761
|
const archived = Boolean(body.archived);
|
|
85638
85762
|
const { data, error: error3 } = await ctx.supabase.from("cerefox_document_versions").update({ archived }).eq("id", versionId).select("document_id, version_number").maybeSingle();
|
|
85639
85763
|
if (error3)
|
|
@@ -85642,7 +85766,8 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
85642
85766
|
const op = archived ? "archive" : "unarchive";
|
|
85643
85767
|
await createAuditEntry(ctx, {
|
|
85644
85768
|
operation: op,
|
|
85645
|
-
author:
|
|
85769
|
+
author: who.identity.author,
|
|
85770
|
+
authorType: who.identity.authorType,
|
|
85646
85771
|
documentId: ver?.document_id ?? documentId,
|
|
85647
85772
|
versionId,
|
|
85648
85773
|
description: `Version ${ver?.version_number ?? "?"} ${op}d`
|
|
@@ -85671,6 +85796,9 @@ function registerIngestRoutes(app, ctx) {
|
|
|
85671
85796
|
return c2.json(notReady("Title is required."), 200);
|
|
85672
85797
|
if (!content.trim())
|
|
85673
85798
|
return c2.json(notReady("Content cannot be empty."), 200);
|
|
85799
|
+
const who = resolveCallerIdentity(c2, body);
|
|
85800
|
+
if (!who.ok)
|
|
85801
|
+
return c2.json({ detail: who.detail }, 400);
|
|
85674
85802
|
try {
|
|
85675
85803
|
const pipeline2 = new IngestionPipeline({
|
|
85676
85804
|
supabase: ctx.supabase,
|
|
@@ -85684,8 +85812,8 @@ function registerIngestRoutes(app, ctx) {
|
|
|
85684
85812
|
metadata: body.metadata ?? null,
|
|
85685
85813
|
updateExisting: Boolean(body.update_existing),
|
|
85686
85814
|
documentId: body.document_id ?? null,
|
|
85687
|
-
author:
|
|
85688
|
-
authorType:
|
|
85815
|
+
author: who.identity.author,
|
|
85816
|
+
authorType: who.identity.authorType
|
|
85689
85817
|
});
|
|
85690
85818
|
const skipped = result.action === "skipped";
|
|
85691
85819
|
const resp = {
|
|
@@ -85697,7 +85825,12 @@ function registerIngestRoutes(app, ctx) {
|
|
|
85697
85825
|
};
|
|
85698
85826
|
if (result.note)
|
|
85699
85827
|
resp.note = result.note;
|
|
85700
|
-
logWebUsage(ctx, {
|
|
85828
|
+
logWebUsage(ctx, {
|
|
85829
|
+
operation: "ingest",
|
|
85830
|
+
document_id: result.documentId,
|
|
85831
|
+
requestor: who.identity.requestor,
|
|
85832
|
+
access_path: who.identity.accessPath
|
|
85833
|
+
});
|
|
85701
85834
|
return c2.json(resp, 200);
|
|
85702
85835
|
} catch (err) {
|
|
85703
85836
|
return c2.json(notReady(err instanceof Error ? err.message : String(err)), 200);
|
|
@@ -85736,6 +85869,9 @@ function registerIngestRoutes(app, ctx) {
|
|
|
85736
85869
|
metadata = null;
|
|
85737
85870
|
}
|
|
85738
85871
|
}
|
|
85872
|
+
const who = resolveCallerIdentity(c2, form);
|
|
85873
|
+
if (!who.ok)
|
|
85874
|
+
return c2.json({ detail: who.detail }, 400);
|
|
85739
85875
|
try {
|
|
85740
85876
|
const pipeline2 = new IngestionPipeline({
|
|
85741
85877
|
supabase: ctx.supabase,
|
|
@@ -85749,11 +85885,16 @@ function registerIngestRoutes(app, ctx) {
|
|
|
85749
85885
|
projectIds,
|
|
85750
85886
|
metadata,
|
|
85751
85887
|
updateExisting,
|
|
85752
|
-
author:
|
|
85753
|
-
authorType:
|
|
85888
|
+
author: who.identity.author,
|
|
85889
|
+
authorType: who.identity.authorType
|
|
85754
85890
|
});
|
|
85755
85891
|
const skipped = result.action === "skipped";
|
|
85756
|
-
logWebUsage(ctx, {
|
|
85892
|
+
logWebUsage(ctx, {
|
|
85893
|
+
operation: "ingest",
|
|
85894
|
+
document_id: result.documentId,
|
|
85895
|
+
requestor: who.identity.requestor,
|
|
85896
|
+
access_path: who.identity.accessPath
|
|
85897
|
+
});
|
|
85757
85898
|
return c2.json({
|
|
85758
85899
|
success: !skipped,
|
|
85759
85900
|
document_id: result.documentId,
|
|
@@ -85790,6 +85931,9 @@ function registerIngestRoutes(app, ctx) {
|
|
|
85790
85931
|
if (!existing)
|
|
85791
85932
|
return c2.json(notReady("Document not found"), 404);
|
|
85792
85933
|
const title = existing.title || file.name || "Untitled";
|
|
85934
|
+
const who = resolveCallerIdentity(c2, form);
|
|
85935
|
+
if (!who.ok)
|
|
85936
|
+
return c2.json({ detail: who.detail }, 400);
|
|
85793
85937
|
try {
|
|
85794
85938
|
const pipeline2 = new IngestionPipeline({
|
|
85795
85939
|
supabase: ctx.supabase,
|
|
@@ -85800,10 +85944,17 @@ function registerIngestRoutes(app, ctx) {
|
|
|
85800
85944
|
text,
|
|
85801
85945
|
title,
|
|
85802
85946
|
source: "file",
|
|
85803
|
-
author:
|
|
85804
|
-
authorType:
|
|
85947
|
+
author: who.identity.author,
|
|
85948
|
+
authorType: who.identity.authorType,
|
|
85949
|
+
expectedContentHash: typeof form.expected_content_hash === "string" && form.expected_content_hash.trim() !== "" ? form.expected_content_hash.trim() : null,
|
|
85950
|
+
lastWriteWins: String(form.last_write_wins ?? "") === "true"
|
|
85951
|
+
});
|
|
85952
|
+
logWebUsage(ctx, {
|
|
85953
|
+
operation: "ingest",
|
|
85954
|
+
document_id: result.documentId,
|
|
85955
|
+
requestor: who.identity.requestor,
|
|
85956
|
+
access_path: who.identity.accessPath
|
|
85805
85957
|
});
|
|
85806
|
-
logWebUsage(ctx, { operation: "ingest", document_id: result.documentId });
|
|
85807
85958
|
return c2.json({
|
|
85808
85959
|
success: true,
|
|
85809
85960
|
document_id: result.documentId,
|
|
@@ -86154,11 +86305,14 @@ function registerProjectsRoutes(app, ctx) {
|
|
|
86154
86305
|
if (!name)
|
|
86155
86306
|
return c2.json({ detail: "Project name is required" }, 400);
|
|
86156
86307
|
const description = String(body.description ?? "").trim();
|
|
86308
|
+
const who = resolveCallerIdentity(c2, body);
|
|
86309
|
+
if (!who.ok)
|
|
86310
|
+
return c2.json({ detail: who.detail }, 400);
|
|
86157
86311
|
const { data, error: error3 } = await ctx.supabase.rpc("cerefox_create_project", {
|
|
86158
86312
|
p_name: name,
|
|
86159
86313
|
p_description: description,
|
|
86160
|
-
p_author:
|
|
86161
|
-
p_author_type:
|
|
86314
|
+
p_author: who.identity.author,
|
|
86315
|
+
p_author_type: who.identity.authorType
|
|
86162
86316
|
});
|
|
86163
86317
|
if (error3) {
|
|
86164
86318
|
const msg = error3.message ?? "";
|
|
@@ -86194,12 +86348,15 @@ function registerProjectsRoutes(app, ctx) {
|
|
|
86194
86348
|
if (Object.keys(update).length === 0) {
|
|
86195
86349
|
return c2.json({ detail: "Nothing to update — pass name and/or description" }, 400);
|
|
86196
86350
|
}
|
|
86351
|
+
const who = resolveCallerIdentity(c2, body);
|
|
86352
|
+
if (!who.ok)
|
|
86353
|
+
return c2.json({ detail: who.detail }, 400);
|
|
86197
86354
|
const { data, error: error3 } = await ctx.supabase.rpc("cerefox_update_project", {
|
|
86198
86355
|
p_project_id: projectId,
|
|
86199
86356
|
p_name: update.name ?? null,
|
|
86200
86357
|
p_description: update.description ?? null,
|
|
86201
|
-
p_author:
|
|
86202
|
-
p_author_type:
|
|
86358
|
+
p_author: who.identity.author,
|
|
86359
|
+
p_author_type: who.identity.authorType
|
|
86203
86360
|
});
|
|
86204
86361
|
if (error3) {
|
|
86205
86362
|
const msg = error3.message ?? "";
|
|
@@ -86217,10 +86374,13 @@ function registerProjectsRoutes(app, ctx) {
|
|
|
86217
86374
|
});
|
|
86218
86375
|
app.delete("/api/v1/projects/:project_id", async (c2) => {
|
|
86219
86376
|
const projectId = c2.req.param("project_id");
|
|
86377
|
+
const who = resolveCallerIdentity(c2);
|
|
86378
|
+
if (!who.ok)
|
|
86379
|
+
return c2.json({ detail: who.detail }, 400);
|
|
86220
86380
|
const { data, error: error3 } = await ctx.supabase.rpc("cerefox_delete_project", {
|
|
86221
86381
|
p_project_id: projectId,
|
|
86222
|
-
p_author:
|
|
86223
|
-
p_author_type:
|
|
86382
|
+
p_author: who.identity.author,
|
|
86383
|
+
p_author_type: who.identity.authorType
|
|
86224
86384
|
});
|
|
86225
86385
|
if (error3)
|
|
86226
86386
|
return c2.json({ detail: error3.message }, 500);
|