@cerefox/memory 1.9.2 → 1.10.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 +259 -84
- package/dist/frontend/assets/index-i67RH1VY.js +121 -0
- package/dist/frontend/assets/index-i67RH1VY.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/_document-meta.ts +377 -0
- package/dist/server-assets/_shared/mcp-tools/_projects.ts +13 -32
- package/dist/server-assets/_shared/mcp-tools/_utils.ts +9 -2
- package/dist/server-assets/_shared/mcp-tools/types.ts +6 -2
- package/dist/server-assets/db/migrations/0030_rename_document_rpc.sql +80 -0
- package/dist/server-assets/db/rpcs.sql +63 -1
- package/dist/server-assets/db/schema.sql +1 -1
- package/package.json +1 -1
- package/dist/frontend/assets/index-DWT7wZMR.js +0 -121
- package/dist/frontend/assets/index-DWT7wZMR.js.map +0 -1
package/dist/bin/cerefox.js
CHANGED
|
@@ -7438,7 +7438,7 @@ var exports_meta = {};
|
|
|
7438
7438
|
__export(exports_meta, {
|
|
7439
7439
|
PKG_VERSION: () => PKG_VERSION
|
|
7440
7440
|
});
|
|
7441
|
-
var PKG_VERSION = "1.
|
|
7441
|
+
var PKG_VERSION = "1.10.0";
|
|
7442
7442
|
var init_meta = () => {};
|
|
7443
7443
|
|
|
7444
7444
|
// ../../_shared/config/paths.ts
|
|
@@ -23530,9 +23530,9 @@ function isAuditCheckError(message) {
|
|
|
23530
23530
|
function isDuplicateKeyError(message) {
|
|
23531
23531
|
return /duplicate key|unique constraint|23505/i.test(message);
|
|
23532
23532
|
}
|
|
23533
|
-
function storeWriteRemediation(message, fnName) {
|
|
23533
|
+
function storeWriteRemediation(message, fnName, requiredSchema = "0.14.0") {
|
|
23534
23534
|
if (isMissingFunctionError(message, fnName)) {
|
|
23535
|
-
return
|
|
23535
|
+
return `The deployed server predates schema ${requiredSchema} — or PostgREST's schema cache ` + "is stale right after a deploy. If you just deployed, retry in a few " + "seconds; otherwise run `cerefox server deploy`.";
|
|
23536
23536
|
}
|
|
23537
23537
|
if (isAuditCheckError(message)) {
|
|
23538
23538
|
return "The server's audit-log constraint predates migration 0028 (partial " + "deploy). Run `cerefox server deploy` to apply pending migrations, then retry.";
|
|
@@ -25598,6 +25598,221 @@ var init_src = __esm(() => {
|
|
|
25598
25598
|
src_default = Postgres;
|
|
25599
25599
|
});
|
|
25600
25600
|
|
|
25601
|
+
// ../../_shared/mcp-tools/_document-meta.ts
|
|
25602
|
+
function stableStringify(value) {
|
|
25603
|
+
if (Array.isArray(value))
|
|
25604
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
25605
|
+
if (value !== null && typeof value === "object") {
|
|
25606
|
+
const keys = Object.keys(value).sort();
|
|
25607
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`).join(",")}}`;
|
|
25608
|
+
}
|
|
25609
|
+
return JSON.stringify(value);
|
|
25610
|
+
}
|
|
25611
|
+
function normalizeMetadata(value) {
|
|
25612
|
+
const out = {};
|
|
25613
|
+
for (const [k, v] of Object.entries(value)) {
|
|
25614
|
+
if (v !== null)
|
|
25615
|
+
out[k] = v;
|
|
25616
|
+
}
|
|
25617
|
+
return out;
|
|
25618
|
+
}
|
|
25619
|
+
async function changeDocumentTitle(supabase, documentId, newTitle, who) {
|
|
25620
|
+
const trimmed = (newTitle ?? "").trim();
|
|
25621
|
+
if (!trimmed)
|
|
25622
|
+
throw new FacetValidationError("Title cannot be empty.");
|
|
25623
|
+
const { data, error } = await supabase.rpc("cerefox_rename_document", {
|
|
25624
|
+
p_document_id: documentId,
|
|
25625
|
+
p_new_title: trimmed,
|
|
25626
|
+
p_author: who.author,
|
|
25627
|
+
p_author_type: who.authorType
|
|
25628
|
+
});
|
|
25629
|
+
if (error) {
|
|
25630
|
+
const msg = error.message ?? String(error);
|
|
25631
|
+
if (/not found/i.test(msg))
|
|
25632
|
+
throw new FacetNotFoundError(msg);
|
|
25633
|
+
if (/cannot be empty/i.test(msg))
|
|
25634
|
+
throw new FacetValidationError(msg);
|
|
25635
|
+
const remediation = storeWriteRemediation(msg, "cerefox_rename_document", "0.15.0");
|
|
25636
|
+
if (remediation)
|
|
25637
|
+
throw new Error(`Title update failed: ${remediation}`);
|
|
25638
|
+
throw new Error(`Title update failed: ${msg}`);
|
|
25639
|
+
}
|
|
25640
|
+
const row = data?.[0];
|
|
25641
|
+
return { changed: row?.renamed ?? false, title: row?.new_title ?? trimmed };
|
|
25642
|
+
}
|
|
25643
|
+
async function applyMembershipReplace(supabase, opts) {
|
|
25644
|
+
const { data: current, error: curErr } = await supabase.from("cerefox_document_projects").select("project_id").eq("document_id", opts.documentId);
|
|
25645
|
+
if (curErr)
|
|
25646
|
+
throw new Error(`Membership read failed: ${curErr.message}`);
|
|
25647
|
+
const currentSet = new Set((current ?? []).map((r) => r.project_id));
|
|
25648
|
+
if (opts.projectIds.length === currentSet.size && opts.projectIds.every((id) => currentSet.has(id))) {
|
|
25649
|
+
return { changed: false };
|
|
25650
|
+
}
|
|
25651
|
+
const { error: delErr } = await supabase.from("cerefox_document_projects").delete().eq("document_id", opts.documentId);
|
|
25652
|
+
if (delErr)
|
|
25653
|
+
throw new Error(`Membership replace failed: ${delErr.message}`);
|
|
25654
|
+
if (opts.projectIds.length > 0) {
|
|
25655
|
+
const rows = opts.projectIds.map((pid) => ({
|
|
25656
|
+
document_id: opts.documentId,
|
|
25657
|
+
project_id: pid
|
|
25658
|
+
}));
|
|
25659
|
+
const { error: insErr } = await supabase.from("cerefox_document_projects").insert(rows);
|
|
25660
|
+
if (insErr)
|
|
25661
|
+
throw new Error(`Membership replace failed: ${insErr.message}`);
|
|
25662
|
+
}
|
|
25663
|
+
const { error: auditErr } = await supabase.rpc("cerefox_create_audit_entry", {
|
|
25664
|
+
p_document_id: opts.documentId,
|
|
25665
|
+
p_version_id: null,
|
|
25666
|
+
p_operation: "update-metadata",
|
|
25667
|
+
p_author: opts.author,
|
|
25668
|
+
p_author_type: opts.authorType,
|
|
25669
|
+
p_size_before: null,
|
|
25670
|
+
p_size_after: null,
|
|
25671
|
+
p_description: opts.projectNames.length > 0 ? `Set document projects to [${opts.projectNames.join(", ")}]` : "Cleared all project memberships"
|
|
25672
|
+
});
|
|
25673
|
+
if (auditErr)
|
|
25674
|
+
console.warn("applyMembershipReplace: audit entry failed", auditErr.message);
|
|
25675
|
+
logUsage(supabase, {
|
|
25676
|
+
operation: "set-document-projects",
|
|
25677
|
+
accessPath: opts.accessPath,
|
|
25678
|
+
requestor: opts.author,
|
|
25679
|
+
document_id: opts.documentId,
|
|
25680
|
+
result_count: opts.projectIds.length
|
|
25681
|
+
});
|
|
25682
|
+
return { changed: true };
|
|
25683
|
+
}
|
|
25684
|
+
async function assertDocumentLive(supabase, documentId) {
|
|
25685
|
+
const { data, error } = await supabase.from("cerefox_documents").select("id").eq("id", documentId).is("deleted_at", null).limit(1);
|
|
25686
|
+
if (error)
|
|
25687
|
+
throw new Error(`Document read failed: ${error.message}`);
|
|
25688
|
+
if (!data?.length) {
|
|
25689
|
+
throw new FacetNotFoundError(`Document not found (or in the trash): ${documentId}`);
|
|
25690
|
+
}
|
|
25691
|
+
}
|
|
25692
|
+
async function setDocumentProjectsByIds(supabase, opts) {
|
|
25693
|
+
const wanted = [...new Set(opts.projectIds)];
|
|
25694
|
+
const { data: current, error: curErr } = await supabase.from("cerefox_document_projects").select("project_id").eq("document_id", opts.documentId);
|
|
25695
|
+
if (curErr)
|
|
25696
|
+
throw new Error(`Membership read failed: ${curErr.message}`);
|
|
25697
|
+
const currentSet = new Set((current ?? []).map((r2) => r2.project_id));
|
|
25698
|
+
if (wanted.length === currentSet.size && wanted.every((id) => currentSet.has(id))) {
|
|
25699
|
+
return { changed: false, names: [] };
|
|
25700
|
+
}
|
|
25701
|
+
await assertDocumentLive(supabase, opts.documentId);
|
|
25702
|
+
let names = [];
|
|
25703
|
+
if (wanted.length > 0) {
|
|
25704
|
+
const { data: found, error: valErr } = await supabase.from("cerefox_projects").select("id, name").in("id", wanted);
|
|
25705
|
+
if (valErr)
|
|
25706
|
+
throw new Error(`Project validation failed: ${valErr.message}`);
|
|
25707
|
+
const byId = new Map((found ?? []).map((r2) => [r2.id, r2.name]));
|
|
25708
|
+
const missing = wanted.filter((id) => !byId.has(id));
|
|
25709
|
+
if (missing.length > 0) {
|
|
25710
|
+
throw new FacetValidationError(`Unknown project id(s): ${missing.join(", ")} — memberships left unchanged.`);
|
|
25711
|
+
}
|
|
25712
|
+
names = wanted.map((id) => byId.get(id));
|
|
25713
|
+
}
|
|
25714
|
+
const r = await applyMembershipReplace(supabase, {
|
|
25715
|
+
documentId: opts.documentId,
|
|
25716
|
+
projectIds: wanted,
|
|
25717
|
+
projectNames: names,
|
|
25718
|
+
accessPath: opts.accessPath,
|
|
25719
|
+
author: opts.author,
|
|
25720
|
+
authorType: opts.authorType
|
|
25721
|
+
});
|
|
25722
|
+
return { changed: r.changed, names };
|
|
25723
|
+
}
|
|
25724
|
+
async function updateDocumentFacets(supabase, opts) {
|
|
25725
|
+
const result = {
|
|
25726
|
+
titleChanged: false,
|
|
25727
|
+
metadataChanged: false,
|
|
25728
|
+
projectsChanged: false
|
|
25729
|
+
};
|
|
25730
|
+
const who = { author: opts.author, authorType: opts.authorType };
|
|
25731
|
+
const step = async (fn) => {
|
|
25732
|
+
try {
|
|
25733
|
+
return await fn();
|
|
25734
|
+
} catch (err) {
|
|
25735
|
+
throw err instanceof FacetUpdateError ? err : new FacetUpdateError(result, err instanceof Error ? err : new Error(String(err)));
|
|
25736
|
+
}
|
|
25737
|
+
};
|
|
25738
|
+
if (opts.metadata !== undefined) {
|
|
25739
|
+
await step(async () => {
|
|
25740
|
+
const { data: doc, error } = await supabase.from("cerefox_documents").select("metadata").eq("id", opts.documentId).is("deleted_at", null).limit(1);
|
|
25741
|
+
if (error)
|
|
25742
|
+
throw new Error(`Metadata read failed: ${error.message}`);
|
|
25743
|
+
if (!doc?.length) {
|
|
25744
|
+
throw new FacetNotFoundError(`Document not found (or in the trash): ${opts.documentId}`);
|
|
25745
|
+
}
|
|
25746
|
+
const stored = doc[0].metadata ?? {};
|
|
25747
|
+
const wanted = normalizeMetadata(opts.metadata);
|
|
25748
|
+
if (stableStringify(stored) !== stableStringify(wanted)) {
|
|
25749
|
+
const { error: rpcErr } = await supabase.rpc("cerefox_set_document_metadata", {
|
|
25750
|
+
p_document_id: opts.documentId,
|
|
25751
|
+
p_metadata: wanted,
|
|
25752
|
+
p_replace: true,
|
|
25753
|
+
p_author: opts.author,
|
|
25754
|
+
p_author_type: opts.authorType
|
|
25755
|
+
});
|
|
25756
|
+
if (rpcErr) {
|
|
25757
|
+
const msg = rpcErr.message ?? String(rpcErr);
|
|
25758
|
+
if (/not found/i.test(msg))
|
|
25759
|
+
throw new FacetNotFoundError(msg);
|
|
25760
|
+
throw new Error(`Metadata update failed: ${msg}`);
|
|
25761
|
+
}
|
|
25762
|
+
result.metadataChanged = true;
|
|
25763
|
+
}
|
|
25764
|
+
});
|
|
25765
|
+
}
|
|
25766
|
+
if (opts.projectIds !== undefined) {
|
|
25767
|
+
await step(async () => {
|
|
25768
|
+
const r = await setDocumentProjectsByIds(supabase, {
|
|
25769
|
+
documentId: opts.documentId,
|
|
25770
|
+
projectIds: opts.projectIds,
|
|
25771
|
+
accessPath: opts.accessPath,
|
|
25772
|
+
...who
|
|
25773
|
+
});
|
|
25774
|
+
result.projectsChanged = r.changed;
|
|
25775
|
+
});
|
|
25776
|
+
}
|
|
25777
|
+
if (opts.title !== undefined) {
|
|
25778
|
+
await step(async () => {
|
|
25779
|
+
const r = await changeDocumentTitle(supabase, opts.documentId, opts.title, who);
|
|
25780
|
+
result.titleChanged = r.changed;
|
|
25781
|
+
});
|
|
25782
|
+
}
|
|
25783
|
+
return result;
|
|
25784
|
+
}
|
|
25785
|
+
var FacetNotFoundError, FacetValidationError, FacetUpdateError;
|
|
25786
|
+
var init__document_meta = __esm(() => {
|
|
25787
|
+
init__utils();
|
|
25788
|
+
FacetNotFoundError = class FacetNotFoundError extends Error {
|
|
25789
|
+
constructor(message) {
|
|
25790
|
+
super(message);
|
|
25791
|
+
this.name = "FacetNotFoundError";
|
|
25792
|
+
}
|
|
25793
|
+
};
|
|
25794
|
+
FacetValidationError = class FacetValidationError extends Error {
|
|
25795
|
+
constructor(message) {
|
|
25796
|
+
super(message);
|
|
25797
|
+
this.name = "FacetValidationError";
|
|
25798
|
+
}
|
|
25799
|
+
};
|
|
25800
|
+
FacetUpdateError = class FacetUpdateError extends Error {
|
|
25801
|
+
applied;
|
|
25802
|
+
constructor(applied, cause) {
|
|
25803
|
+
const done = [
|
|
25804
|
+
applied.metadataChanged ? "metadata" : null,
|
|
25805
|
+
applied.projectsChanged ? "projects" : null,
|
|
25806
|
+
applied.titleChanged ? "title" : null
|
|
25807
|
+
].filter(Boolean);
|
|
25808
|
+
super(done.length > 0 ? `${cause.message} (already applied before the failure: ${done.join(", ")})` : cause.message);
|
|
25809
|
+
this.name = "FacetUpdateError";
|
|
25810
|
+
this.applied = applied;
|
|
25811
|
+
this.cause = cause;
|
|
25812
|
+
}
|
|
25813
|
+
};
|
|
25814
|
+
});
|
|
25815
|
+
|
|
25601
25816
|
// ../../_shared/mcp-tools/_projects.ts
|
|
25602
25817
|
async function resolveOrCreateProject(supabase, projectName, audit) {
|
|
25603
25818
|
const { data, error } = await supabase.rpc("cerefox_create_project", {
|
|
@@ -25670,31 +25885,13 @@ async function replaceDocumentProjects(supabase, opts) {
|
|
|
25670
25885
|
throw new Error(`Could not resolve project(s): ${failed.join(", ")} — memberships left unchanged.`);
|
|
25671
25886
|
}
|
|
25672
25887
|
const projectIds = resolved.map((r) => r.projectId);
|
|
25673
|
-
await supabase
|
|
25674
|
-
|
|
25675
|
-
|
|
25676
|
-
|
|
25677
|
-
}
|
|
25678
|
-
try {
|
|
25679
|
-
await supabase.rpc("cerefox_create_audit_entry", {
|
|
25680
|
-
p_document_id: documentId,
|
|
25681
|
-
p_version_id: null,
|
|
25682
|
-
p_operation: "update-metadata",
|
|
25683
|
-
p_author: author,
|
|
25684
|
-
p_author_type: authorType,
|
|
25685
|
-
p_size_before: null,
|
|
25686
|
-
p_size_after: null,
|
|
25687
|
-
p_description: cleanNames.length > 0 ? `Set document projects to [${cleanNames.join(", ")}]` : "Cleared all project memberships"
|
|
25688
|
-
});
|
|
25689
|
-
} catch (err) {
|
|
25690
|
-
console.warn("replaceDocumentProjects: audit entry failed", err);
|
|
25691
|
-
}
|
|
25692
|
-
logUsage(supabase, {
|
|
25693
|
-
operation: "set-document-projects",
|
|
25888
|
+
await applyMembershipReplace(supabase, {
|
|
25889
|
+
documentId,
|
|
25890
|
+
projectIds,
|
|
25891
|
+
projectNames: cleanNames,
|
|
25694
25892
|
accessPath,
|
|
25695
|
-
|
|
25696
|
-
|
|
25697
|
-
result_count: projectIds.length
|
|
25893
|
+
author,
|
|
25894
|
+
authorType
|
|
25698
25895
|
});
|
|
25699
25896
|
return { documentTitle: doc[0].title, cleanNames, projectIds };
|
|
25700
25897
|
}
|
|
@@ -25705,6 +25902,7 @@ async function lookupProjectId(supabase, projectName) {
|
|
|
25705
25902
|
return data[0].id;
|
|
25706
25903
|
}
|
|
25707
25904
|
var init__projects = __esm(() => {
|
|
25905
|
+
init__document_meta();
|
|
25708
25906
|
init__utils();
|
|
25709
25907
|
});
|
|
25710
25908
|
|
|
@@ -25802,7 +26000,7 @@ var init_bundled_docs = __esm(() => {
|
|
|
25802
26000
|
});
|
|
25803
26001
|
|
|
25804
26002
|
// ../../_shared/ef-meta/index.ts
|
|
25805
|
-
var EF_VERSION = "1.
|
|
26003
|
+
var EF_VERSION = "1.10.0", CEREFOX_VERSION = "1.10.0", EF_LAST_CHANGED = "1.10.0";
|
|
25806
26004
|
var init_ef_meta = () => {};
|
|
25807
26005
|
|
|
25808
26006
|
// ../../_shared/compatibility/index.ts
|
|
@@ -73421,6 +73619,7 @@ function registerDeployServer(program2) {
|
|
|
73421
73619
|
|
|
73422
73620
|
// src/cli/commands/document-edit.ts
|
|
73423
73621
|
init_cli_core();
|
|
73622
|
+
init__document_meta();
|
|
73424
73623
|
init_client();
|
|
73425
73624
|
function parseMetaPair(pair) {
|
|
73426
73625
|
const eq = pair.indexOf("=");
|
|
@@ -73484,27 +73683,17 @@ async function action11(documentId, options) {
|
|
|
73484
73683
|
throw systemError(`Metadata update failed: ${metaErr.message}`);
|
|
73485
73684
|
}
|
|
73486
73685
|
}
|
|
73487
|
-
if (hasTitle) {
|
|
73488
|
-
|
|
73489
|
-
|
|
73490
|
-
|
|
73491
|
-
|
|
73492
|
-
|
|
73493
|
-
|
|
73494
|
-
|
|
73495
|
-
|
|
73496
|
-
|
|
73497
|
-
|
|
73498
|
-
throw systemError(`Title updated but FTS refresh failed: ${ftsErr.message}`);
|
|
73499
|
-
}
|
|
73500
|
-
if (titleChanged) {
|
|
73501
|
-
await client.raw.rpc("cerefox_create_audit_entry", {
|
|
73502
|
-
p_document_id: documentId,
|
|
73503
|
-
p_operation: "update-metadata",
|
|
73504
|
-
p_author: author,
|
|
73505
|
-
p_author_type: authorType,
|
|
73506
|
-
p_description: "Edited title"
|
|
73507
|
-
});
|
|
73686
|
+
if (hasTitle && titleChanged) {
|
|
73687
|
+
try {
|
|
73688
|
+
await changeDocumentTitle(client.raw, documentId, newTitle, { author, authorType });
|
|
73689
|
+
} catch (err) {
|
|
73690
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
73691
|
+
if (err instanceof FacetNotFoundError)
|
|
73692
|
+
throw notFound(msg);
|
|
73693
|
+
if (err instanceof FacetValidationError)
|
|
73694
|
+
throw userError(msg);
|
|
73695
|
+
throw systemError(msg);
|
|
73696
|
+
}
|
|
73508
73697
|
}
|
|
73509
73698
|
println(c.green(`✓ Edited "${newTitle}" (id: ${documentId}).`));
|
|
73510
73699
|
if (titleChanged) {
|
|
@@ -85298,6 +85487,7 @@ function registerDocumentReadRoutes(app, ctx) {
|
|
|
85298
85487
|
});
|
|
85299
85488
|
}
|
|
85300
85489
|
// src/web/routes/documents-write.ts
|
|
85490
|
+
init__document_meta();
|
|
85301
85491
|
init__utils();
|
|
85302
85492
|
async function createAuditEntry(ctx, args) {
|
|
85303
85493
|
try {
|
|
@@ -85313,16 +85503,6 @@ async function createAuditEntry(ctx, args) {
|
|
|
85313
85503
|
});
|
|
85314
85504
|
} catch {}
|
|
85315
85505
|
}
|
|
85316
|
-
async function assignDocumentProjects(ctx, documentId, projectIds) {
|
|
85317
|
-
await ctx.supabase.from("cerefox_document_projects").delete().eq("document_id", documentId);
|
|
85318
|
-
if (projectIds.length > 0) {
|
|
85319
|
-
const rows = projectIds.map((pid) => ({
|
|
85320
|
-
document_id: documentId,
|
|
85321
|
-
project_id: pid
|
|
85322
|
-
}));
|
|
85323
|
-
await ctx.supabase.from("cerefox_document_projects").insert(rows);
|
|
85324
|
-
}
|
|
85325
|
-
}
|
|
85326
85506
|
async function getCurrentDoc(ctx, documentId) {
|
|
85327
85507
|
const { data } = await ctx.supabase.from("cerefox_documents").select("*").eq("id", documentId).maybeSingle();
|
|
85328
85508
|
return data ?? null;
|
|
@@ -85375,7 +85555,7 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
85375
85555
|
title: title || doc2.title,
|
|
85376
85556
|
source: "manual",
|
|
85377
85557
|
projectIds: Array.isArray(body.project_ids) ? body.project_ids : undefined,
|
|
85378
|
-
metadata:
|
|
85558
|
+
metadata: body.metadata != null ? metadata : undefined,
|
|
85379
85559
|
author: "web-ui",
|
|
85380
85560
|
authorType: "user",
|
|
85381
85561
|
expectedContentHash: typeof body.expected_content_hash === "string" ? body.expected_content_hash : null
|
|
@@ -85416,33 +85596,28 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
85416
85596
|
return c2.json({ success: false, error: msg }, 500);
|
|
85417
85597
|
}
|
|
85418
85598
|
}
|
|
85419
|
-
|
|
85420
|
-
|
|
85421
|
-
updates.title = title;
|
|
85422
|
-
}
|
|
85423
|
-
if (Object.keys(metadata).length > 0) {
|
|
85424
|
-
updates.metadata = metadata;
|
|
85425
|
-
}
|
|
85426
|
-
if (Object.keys(updates).length > 0) {
|
|
85427
|
-
updates.updated_at = new Date().toISOString();
|
|
85428
|
-
const { error: error3 } = await ctx.supabase.from("cerefox_documents").update(updates).eq("id", documentId);
|
|
85429
|
-
if (error3)
|
|
85430
|
-
return c2.json({ success: false, error: error3.message }, 500);
|
|
85431
|
-
}
|
|
85432
|
-
const projectsTouched = Array.isArray(body.project_ids);
|
|
85433
|
-
if (projectsTouched) {
|
|
85434
|
-
await assignDocumentProjects(ctx, documentId, projectIds);
|
|
85435
|
-
}
|
|
85436
|
-
const anythingChanged = "title" in updates || "metadata" in updates || projectsTouched;
|
|
85437
|
-
if (anythingChanged) {
|
|
85438
|
-
await createAuditEntry(ctx, {
|
|
85439
|
-
operation: "update-metadata",
|
|
85440
|
-
author: "web-ui",
|
|
85599
|
+
try {
|
|
85600
|
+
const facets = await updateDocumentFacets(ctx.supabase, {
|
|
85441
85601
|
documentId,
|
|
85442
|
-
|
|
85602
|
+
title: body.title !== undefined && title !== doc2.title ? title : undefined,
|
|
85603
|
+
metadata: body.metadata != null ? metadata : undefined,
|
|
85604
|
+
projectIds: Array.isArray(body.project_ids) ? projectIds : undefined,
|
|
85605
|
+
author: "web-ui",
|
|
85606
|
+
authorType: "user",
|
|
85607
|
+
accessPath: "webapp"
|
|
85443
85608
|
});
|
|
85609
|
+
return c2.json({ success: true, reindexed: false, ...facets });
|
|
85610
|
+
} catch (err) {
|
|
85611
|
+
const cause = err instanceof FacetUpdateError ? err.cause : err;
|
|
85612
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
85613
|
+
if (cause instanceof FacetNotFoundError) {
|
|
85614
|
+
return c2.json({ success: false, error: msg, detail: msg }, 404);
|
|
85615
|
+
}
|
|
85616
|
+
if (cause instanceof FacetValidationError) {
|
|
85617
|
+
return c2.json({ success: false, error: msg, detail: msg }, 400);
|
|
85618
|
+
}
|
|
85619
|
+
return c2.json({ success: false, error: msg, detail: msg }, 500);
|
|
85444
85620
|
}
|
|
85445
|
-
return c2.json({ success: true, reindexed: false });
|
|
85446
85621
|
});
|
|
85447
85622
|
app.delete("/api/v1/documents/:document_id", async (c2) => {
|
|
85448
85623
|
const documentId = c2.req.param("document_id");
|