@lwelliott/cortex-cli 1.0.5 → 1.0.6
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/index.js +4 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/db/generated/schema-types.d.ts +2 -2
- package/dist/db/generated/schema-types.js +2 -2
- package/dist/db/generated/schema-types.js.map +1 -1
- package/dist/models/relation.d.ts.map +1 -1
- package/dist/models/relation.js +81 -73
- package/dist/models/relation.js.map +1 -1
- package/dist/services/document-service.d.ts +3 -0
- package/dist/services/document-service.d.ts.map +1 -1
- package/dist/services/document-service.js +77 -76
- package/dist/services/document-service.js.map +1 -1
- package/dist/services/review-service.d.ts +47 -2
- package/dist/services/review-service.d.ts.map +1 -1
- package/dist/services/review-service.js +189 -27
- package/dist/services/review-service.js.map +1 -1
- package/dist/services/schema-migration-service.js +2 -2
- package/dist/services/schema-migration-service.js.map +1 -1
- package/dist/utils/errors.d.ts +8 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +17 -1
- package/dist/utils/errors.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -111,9 +111,11 @@ try {
|
|
|
111
111
|
program.parse(process.argv);
|
|
112
112
|
}
|
|
113
113
|
catch (err) {
|
|
114
|
-
// CommanderError is already output via writeErr interceptor — don't double-output
|
|
114
|
+
// CommanderError is already output via writeErr interceptor — don't double-output.
|
|
115
|
+
// commander.version: --version was requested — output already printed, exit cleanly.
|
|
115
116
|
if (err instanceof Error && 'code' in err && typeof err.code === 'string' && err.code.startsWith('commander.')) {
|
|
116
|
-
|
|
117
|
+
const exitCode = err.exitCode;
|
|
118
|
+
process.exit(exitCode && exitCode !== 0 ? exitCode : err.code === 'commander.version' ? 0 : 1);
|
|
117
119
|
}
|
|
118
120
|
if (err instanceof errors_1.CortexError) {
|
|
119
121
|
const msg = err.message.replace(/^ERR-[A-Z]+-[0-9]+:\s*/, '');
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -89,7 +89,7 @@ export declare const RELATION_TYPES: readonly [{
|
|
|
89
89
|
readonly description: "A requirement fulfills a user story (inverse of fulfilled_by)";
|
|
90
90
|
}, {
|
|
91
91
|
readonly name: "implemented_by";
|
|
92
|
-
readonly from_types: readonly ["SAD", "AD", "QA"];
|
|
92
|
+
readonly from_types: readonly ["SAD", "AD", "QA", "TC"];
|
|
93
93
|
readonly to_types: readonly ["SRC"];
|
|
94
94
|
readonly cardinality: "many_to_many";
|
|
95
95
|
readonly inverse_of: "implements";
|
|
@@ -97,7 +97,7 @@ export declare const RELATION_TYPES: readonly [{
|
|
|
97
97
|
}, {
|
|
98
98
|
readonly name: "implements";
|
|
99
99
|
readonly from_types: readonly ["SRC"];
|
|
100
|
-
readonly to_types: readonly ["SAD", "AD", "QA"];
|
|
100
|
+
readonly to_types: readonly ["SAD", "AD", "QA", "TC"];
|
|
101
101
|
readonly cardinality: "many_to_many";
|
|
102
102
|
readonly inverse_of: "implemented_by";
|
|
103
103
|
readonly description: "Source code implements a design or QA artifact (inverse of implemented_by)";
|
|
@@ -21,8 +21,8 @@ exports.RELATION_TYPES = [
|
|
|
21
21
|
{ name: 'divided_into', from_types: ["TS"], to_types: ["TC"], cardinality: "one_to_many", inverse_of: "divided_from", description: "A test suite is divided into test cases (inverse of divided_from)" },
|
|
22
22
|
{ name: 'fulfilled_by', from_types: ["US"], to_types: ["FR", "NFR"], cardinality: "many_to_many", inverse_of: "fulfills", description: "A user story is fulfilled by functional or non-functional requirements (e.g., US-001 fulfilled by FR-001)" },
|
|
23
23
|
{ name: 'fulfills', from_types: ["FR", "NFR"], to_types: ["US"], cardinality: "many_to_many", inverse_of: "fulfilled_by", description: "A requirement fulfills a user story (inverse of fulfilled_by)" },
|
|
24
|
-
{ name: 'implemented_by', from_types: ["SAD", "AD", "QA"], to_types: ["SRC"], cardinality: "many_to_many", inverse_of: "implements", description: "A design or QA artifact is implemented by source code (e.g., SAD-0035 implemented by SRC-auth)" },
|
|
25
|
-
{ name: 'implements', from_types: ["SRC"], to_types: ["SAD", "AD", "QA"], cardinality: "many_to_many", inverse_of: "implemented_by", description: "Source code implements a design or QA artifact (inverse of implemented_by)" },
|
|
24
|
+
{ name: 'implemented_by', from_types: ["SAD", "AD", "QA", "TC"], to_types: ["SRC"], cardinality: "many_to_many", inverse_of: "implements", description: "A design or QA artifact is implemented by source code (e.g., SAD-0035 implemented by SRC-auth)" },
|
|
25
|
+
{ name: 'implements', from_types: ["SRC"], to_types: ["SAD", "AD", "QA", "TC"], cardinality: "many_to_many", inverse_of: "implemented_by", description: "Source code implements a design or QA artifact (inverse of implemented_by)" },
|
|
26
26
|
{ name: 'realized_by', from_types: ["FR", "NFR"], to_types: ["FS", "NFS"], cardinality: "many_to_many", inverse_of: "realizes", description: "A functional or non-functional requirement is realized by a functional or non-functional specification (e.g., FR-001 realized by FS-001, NFR-001 realized by NFS-001)" },
|
|
27
27
|
{ name: 'realizes', from_types: ["FS", "NFS"], to_types: ["FR", "NFR"], cardinality: "many_to_many", inverse_of: "realized_by", description: "A functional or non-functional specification realizes a functional or non-functional requirement (inverse of realized_by; e.g., FS-001 realizes FR-001, NFS-001 realizes NFR-001)" },
|
|
28
28
|
{ name: 'verified_by', from_types: ["FS", "NFS"], to_types: ["TS"], cardinality: "many_to_many", inverse_of: "verifies", description: "A specification is verified by a test suite (e.g., FS-001 verified by TS-033)" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-types.js","sourceRoot":"","sources":["../../../src/db/generated/schema-types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"schema-types.js","sourceRoot":"","sources":["../../../src/db/generated/schema-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relation.d.ts","sourceRoot":"","sources":["../../src/models/relation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"relation.d.ts","sourceRoot":"","sources":["../../src/models/relation.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAe,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAoB1F;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAM7F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC5B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,QAAQ,CAgFV;AAsDD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAkB9E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,oBAAoB,GAAG,QAAQ,EAAE,CA+B/F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,YAAY,EAAE,CAEvE"}
|
package/dist/models/relation.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Relation model: CRUD operations for graph relations
|
|
3
3
|
// MOD-010: Relations with constraint enforcement (AD-0017)
|
|
4
4
|
// + MOD-008: Schema dependency
|
|
5
|
+
// AD-0006: Advisory lock wrapping for write operations
|
|
5
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
7
|
exports.getRelationType = getRelationType;
|
|
7
8
|
exports.createRelation = createRelation;
|
|
@@ -9,6 +10,7 @@ exports.removeRelation = removeRelation;
|
|
|
9
10
|
exports.queryRelations = queryRelations;
|
|
10
11
|
exports.listRelationTypes = listRelationTypes;
|
|
11
12
|
const retry_1 = require("../db/retry");
|
|
13
|
+
const locks_1 = require("../db/locks");
|
|
12
14
|
const errors_1 = require("../utils/errors");
|
|
13
15
|
/** Parse JSON field safely */
|
|
14
16
|
function parseJson(raw, fallback) {
|
|
@@ -46,69 +48,72 @@ function getRelationType(db, name) {
|
|
|
46
48
|
* 8. Insert inverse
|
|
47
49
|
*/
|
|
48
50
|
function createRelation(db, fromId, relType, toId, properties) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
db.prepare(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
51
|
+
const owner = (0, locks_1.generateLockOwner)();
|
|
52
|
+
return (0, locks_1.withLock)(db, { name: 'graph:mutations', owner }, () => {
|
|
53
|
+
return (0, retry_1.withTransaction)(db, () => {
|
|
54
|
+
// 1. Self-relation check
|
|
55
|
+
if (fromId === toId) {
|
|
56
|
+
throw new errors_1.GraphSelfRelationError(fromId, relType);
|
|
57
|
+
}
|
|
58
|
+
// 2. Document existence (SAD-0035: entities table dropped, use documents)
|
|
59
|
+
const fromDoc = db.prepare('SELECT id, type AS type_name FROM documents WHERE id = ?').get(fromId);
|
|
60
|
+
if (!fromDoc)
|
|
61
|
+
throw new errors_1.GraphEntityNotFoundError(fromId);
|
|
62
|
+
const toDoc = db.prepare('SELECT id, type AS type_name FROM documents WHERE id = ?').get(toId);
|
|
63
|
+
if (!toDoc)
|
|
64
|
+
throw new errors_1.GraphEntityNotFoundError(toId);
|
|
65
|
+
// 3. Relation type existence
|
|
66
|
+
const rt = getRelationType(db, relType);
|
|
67
|
+
if (!rt)
|
|
68
|
+
throw new errors_1.GraphRelationTypeNotFoundError(relType);
|
|
69
|
+
// 4. Type constraint check
|
|
70
|
+
const fromTypes = parseJson(rt.from_types, []);
|
|
71
|
+
const toTypes = parseJson(rt.to_types, []);
|
|
72
|
+
if (fromTypes.length > 0 && !fromTypes.includes(fromDoc.type_name)) {
|
|
73
|
+
throw new errors_1.GraphTypeConstraintError(relType, 'from', fromDoc.type_name, fromTypes);
|
|
74
|
+
}
|
|
75
|
+
if (toTypes.length > 0 && !toTypes.includes(toDoc.type_name)) {
|
|
76
|
+
throw new errors_1.GraphTypeConstraintError(relType, 'to', toDoc.type_name, toTypes);
|
|
77
|
+
}
|
|
78
|
+
// 5. Cardinality constraint check
|
|
79
|
+
enforceCardinality(db, rt, fromId, toId, relType);
|
|
80
|
+
// 6. Duplicate check
|
|
81
|
+
const existing = db.prepare('SELECT id FROM relations WHERE from_id = ? AND rel_type = ? AND to_id = ?').get(fromId, relType, toId);
|
|
82
|
+
if (existing)
|
|
83
|
+
throw new errors_1.GraphDuplicateRelationError(fromId, relType, toId);
|
|
84
|
+
const now = new Date().toISOString();
|
|
85
|
+
const propsJson = JSON.stringify(properties ?? {});
|
|
86
|
+
// 7. Insert primary relation
|
|
87
|
+
const result = db.prepare(`
|
|
88
|
+
INSERT INTO relations (from_id, rel_type, to_id, properties, created_at, updated_at)
|
|
89
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
90
|
+
`).run(fromId, relType, toId, propsJson, now, now);
|
|
91
|
+
const relation = {
|
|
92
|
+
id: Number(result.lastInsertRowid),
|
|
93
|
+
from_id: fromId,
|
|
94
|
+
rel_type: relType,
|
|
95
|
+
to_id: toId,
|
|
96
|
+
properties: propsJson,
|
|
97
|
+
created_at: now,
|
|
98
|
+
updated_at: now,
|
|
99
|
+
};
|
|
100
|
+
// 8. Insert inverse relation if defined
|
|
101
|
+
if (rt.inverse_of) {
|
|
102
|
+
const inverseRt = getRelationType(db, rt.inverse_of);
|
|
103
|
+
if (inverseRt) {
|
|
104
|
+
// Check cardinality for inverse too
|
|
105
|
+
enforceCardinality(db, inverseRt, toId, fromId, rt.inverse_of);
|
|
106
|
+
const existingInverse = db.prepare('SELECT id FROM relations WHERE from_id = ? AND rel_type = ? AND to_id = ?').get(toId, rt.inverse_of, fromId);
|
|
107
|
+
if (!existingInverse) {
|
|
108
|
+
db.prepare(`
|
|
109
|
+
INSERT INTO relations (from_id, rel_type, to_id, properties, created_at, updated_at)
|
|
110
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
111
|
+
`).run(toId, rt.inverse_of, fromId, propsJson, now, now);
|
|
112
|
+
}
|
|
108
113
|
}
|
|
109
114
|
}
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
return relation;
|
|
116
|
+
});
|
|
112
117
|
});
|
|
113
118
|
}
|
|
114
119
|
/**
|
|
@@ -152,18 +157,21 @@ function enforceCardinality(db, rt, fromId, toId, relType) {
|
|
|
152
157
|
* Also removes any inverse relation.
|
|
153
158
|
*/
|
|
154
159
|
function removeRelation(db, relationId) {
|
|
155
|
-
(0,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
160
|
+
const owner = (0, locks_1.generateLockOwner)();
|
|
161
|
+
(0, locks_1.withLock)(db, { name: 'graph:mutations', owner }, () => {
|
|
162
|
+
(0, retry_1.withTransaction)(db, () => {
|
|
163
|
+
const rel = db.prepare('SELECT from_id, rel_type, to_id FROM relations WHERE id = ?')
|
|
164
|
+
.get(relationId);
|
|
165
|
+
if (!rel)
|
|
166
|
+
throw new errors_1.GraphRelationNotFoundError(relationId);
|
|
167
|
+
db.prepare('DELETE FROM relations WHERE id = ?').run(relationId);
|
|
168
|
+
// Remove inverse if defined
|
|
169
|
+
const rt = getRelationType(db, rel.rel_type);
|
|
170
|
+
if (rt?.inverse_of) {
|
|
171
|
+
db.prepare('DELETE FROM relations WHERE from_id = ? AND rel_type = ? AND to_id = ?')
|
|
172
|
+
.run(rel.to_id, rt.inverse_of, rel.from_id);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
167
175
|
});
|
|
168
176
|
}
|
|
169
177
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relation.js","sourceRoot":"","sources":["../../src/models/relation.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,2DAA2D;AAC3D,+BAA+B
|
|
1
|
+
{"version":3,"file":"relation.js","sourceRoot":"","sources":["../../src/models/relation.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import type Database from 'better-sqlite3';
|
|
|
2
2
|
import type { Document, DocumentDetail, DocumentRegisterOptions, DocumentUpdateFields, SearchResult, ListOptions, SearchOptions } from '../models/document';
|
|
3
3
|
/**
|
|
4
4
|
* Register a new document.
|
|
5
|
+
* Wrapped with doc:global advisory lock (AD-0006) for multi-process coordination.
|
|
5
6
|
*/
|
|
6
7
|
export declare function registerDocument(db: Database.Database, id: string, type: string, title: string, opts?: DocumentRegisterOptions): Document;
|
|
7
8
|
/**
|
|
@@ -25,6 +26,7 @@ export declare function getDocument(db: Database.Database, id: string): Document
|
|
|
25
26
|
export declare function showDocument(db: Database.Database, id: string): DocumentDetail;
|
|
26
27
|
/**
|
|
27
28
|
* Update document metadata.
|
|
29
|
+
* Wrapped with doc:global advisory lock (AD-0006) for multi-process coordination.
|
|
28
30
|
* --meta replaces entirely (not merge), per spec.
|
|
29
31
|
*
|
|
30
32
|
* MOD-021: When fields.type changes the document type, the old entity is deleted
|
|
@@ -35,6 +37,7 @@ export declare function showDocument(db: Database.Database, id: string): Documen
|
|
|
35
37
|
export declare function updateDocument(db: Database.Database, id: string, fields: DocumentUpdateFields): Document;
|
|
36
38
|
/**
|
|
37
39
|
* Remove a document registration.
|
|
40
|
+
* Wrapped with doc:global advisory lock (AD-0006) for multi-process coordination.
|
|
38
41
|
*
|
|
39
42
|
* Deletion ordering per SAD-0035 (3-step sequence after entities table drop):
|
|
40
43
|
* Step 1: Delete relations (outgoing and incoming) referencing the document
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-service.d.ts","sourceRoot":"","sources":["../../src/services/document-service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"document-service.d.ts","sourceRoot":"","sources":["../../src/services/document-service.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAoC5J;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,uBAAuB,GAC7B,QAAQ,CA8DV;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,IAAI,CAAC,EAAE,WAAW,GACjB,QAAQ,EAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAkDhC;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,CAIvE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,cAAc,CAkB9E;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,oBAAoB,GAC3B,QAAQ,CAiEV;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAgBtE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,aAAa,GACnB,YAAY,EAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAgIpC"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// SAD-0003: MOD-012 Document Registry & Content
|
|
4
4
|
// AD-0018: FTS5 with trigger-based index
|
|
5
5
|
// AD-0019: Dual-mode document storage
|
|
6
|
+
// AD-0006: Advisory lock wrapping for multi-step write operations
|
|
6
7
|
// SAD-0035: Entity auto-sync removed — entities table dropped
|
|
7
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
9
|
exports.registerDocument = registerDocument;
|
|
@@ -16,6 +17,7 @@ const crypto_1 = require("crypto");
|
|
|
16
17
|
const fs_1 = require("fs");
|
|
17
18
|
const errors_1 = require("../utils/errors");
|
|
18
19
|
const retry_1 = require("../db/retry");
|
|
20
|
+
const locks_1 = require("../db/locks");
|
|
19
21
|
// ─── Order-by validation ───
|
|
20
22
|
const VALID_ORDER_FIELDS = ['id', 'type', 'title', 'created', 'updated'];
|
|
21
23
|
function parseOrderBy(raw) {
|
|
@@ -41,6 +43,7 @@ function sha256(content) {
|
|
|
41
43
|
// ─── Public API ───
|
|
42
44
|
/**
|
|
43
45
|
* Register a new document.
|
|
46
|
+
* Wrapped with doc:global advisory lock (AD-0006) for multi-process coordination.
|
|
44
47
|
*/
|
|
45
48
|
function registerDocument(db, id, type, title, opts) {
|
|
46
49
|
if (!id || !id.trim())
|
|
@@ -49,25 +52,13 @@ function registerDocument(db, id, type, title, opts) {
|
|
|
49
52
|
throw new errors_1.DocumentMissingFieldError('type');
|
|
50
53
|
if (!title || !title.trim())
|
|
51
54
|
throw new errors_1.DocumentMissingFieldError('title');
|
|
52
|
-
// Check duplicate
|
|
53
|
-
const existing = db.prepare('SELECT id FROM documents WHERE id = ?').get(id);
|
|
54
|
-
if (existing)
|
|
55
|
-
throw new errors_1.DocumentDuplicateError(id);
|
|
56
|
-
// Pre-transaction doc type validation gate (FS-SS-012-0011, SAD-0027 §5)
|
|
57
|
-
// builtin:3.0: doc type IS entity type name (no mapping needed)
|
|
58
55
|
// Pre-transaction SRC storage enforcement (FS-SS-029-0001 v2 VR-001/VR-002)
|
|
59
56
|
// SRC documents must use filesystem storage; DB storage via --content-file is rejected
|
|
60
57
|
if (type === 'SRC' && (opts?.content || opts?.contentFile)) {
|
|
61
58
|
throw new errors_1.DocSrcStorageError();
|
|
62
59
|
}
|
|
63
|
-
//
|
|
64
|
-
// content_storage defaults to 'db'. Otherwise defaults to 'filesystem'.
|
|
65
|
-
const storage = opts?.contentStorage ?? ((opts?.content || opts?.contentFile) ? 'db' : 'filesystem');
|
|
66
|
-
const metadata = opts?.metadata ? JSON.stringify(opts.metadata) : '{}';
|
|
67
|
-
const now = new Date().toISOString();
|
|
60
|
+
// Pre-transaction file read (fail fast before lock acquisition)
|
|
68
61
|
// Handle content: compute hash and load content from file or direct input
|
|
69
|
-
// Content is ALWAYS stored in document_contents to enable FTS5 indexing,
|
|
70
|
-
// regardless of whether content_storage is 'db' or 'filesystem'.
|
|
71
62
|
let contentHash = null;
|
|
72
63
|
let contentValue = null;
|
|
73
64
|
let contentFilePath = null;
|
|
@@ -87,19 +78,27 @@ function registerDocument(db, id, type, title, opts) {
|
|
|
87
78
|
throw new errors_1.DocumentFileError(opts.contentFile, msg);
|
|
88
79
|
}
|
|
89
80
|
}
|
|
90
|
-
|
|
91
|
-
|
|
81
|
+
const storage = opts?.contentStorage ?? ((opts?.content || opts?.contentFile) ? 'db' : 'filesystem');
|
|
82
|
+
const metadata = opts?.metadata ? JSON.stringify(opts.metadata) : '{}';
|
|
92
83
|
const storedPath = opts?.path ?? contentFilePath ?? null;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
db.prepare(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
84
|
+
const owner = (0, locks_1.generateLockOwner)();
|
|
85
|
+
return (0, locks_1.withLock)(db, { name: 'doc:global', owner }, () => {
|
|
86
|
+
// Check duplicate inside lock to prevent TOCTOU races
|
|
87
|
+
const existing = db.prepare('SELECT id FROM documents WHERE id = ?').get(id);
|
|
88
|
+
if (existing)
|
|
89
|
+
throw new errors_1.DocumentDuplicateError(id);
|
|
90
|
+
const now = new Date().toISOString();
|
|
91
|
+
// Insert document and content (FK: document_contents → documents)
|
|
92
|
+
// SAD-0035: Entity auto-creation removed — entities table dropped
|
|
93
|
+
(0, retry_1.withTransaction)(db, () => {
|
|
94
|
+
db.prepare(`INSERT INTO documents (id, type, title, path, content_hash, content_storage, metadata, created_at, updated_at)
|
|
95
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, type, title, storedPath, contentHash, storage, metadata, now, now);
|
|
96
|
+
if (contentValue !== null) {
|
|
97
|
+
db.prepare(`INSERT INTO document_contents (document_id, content, content_hash, updated_at) VALUES (?, ?, ?, ?)`).run(id, contentValue, contentHash, now);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return getDocument(db, id);
|
|
101
101
|
});
|
|
102
|
-
return getDocument(db, id);
|
|
103
102
|
}
|
|
104
103
|
/**
|
|
105
104
|
* List documents with optional filters, pagination, sorting, and count-only support.
|
|
@@ -190,6 +189,7 @@ function showDocument(db, id) {
|
|
|
190
189
|
}
|
|
191
190
|
/**
|
|
192
191
|
* Update document metadata.
|
|
192
|
+
* Wrapped with doc:global advisory lock (AD-0006) for multi-process coordination.
|
|
193
193
|
* --meta replaces entirely (not merge), per spec.
|
|
194
194
|
*
|
|
195
195
|
* MOD-021: When fields.type changes the document type, the old entity is deleted
|
|
@@ -198,29 +198,10 @@ function showDocument(db, id) {
|
|
|
198
198
|
* atomic transaction per FS-SS-021-0004.
|
|
199
199
|
*/
|
|
200
200
|
function updateDocument(db, id, fields) {
|
|
201
|
+
// Pre-lock validation
|
|
201
202
|
const doc = getDocument(db, id);
|
|
202
|
-
|
|
203
|
-
const sets = ['updated_at = ?'];
|
|
204
|
-
const params = [now];
|
|
205
|
-
if (fields.title !== undefined) {
|
|
206
|
-
sets.push('title = ?');
|
|
207
|
-
params.push(fields.title);
|
|
208
|
-
}
|
|
209
|
-
if (fields.type !== undefined) {
|
|
210
|
-
sets.push('type = ?');
|
|
211
|
-
params.push(fields.type);
|
|
212
|
-
}
|
|
213
|
-
if (fields.metadata !== undefined) {
|
|
214
|
-
sets.push('metadata = ?');
|
|
215
|
-
params.push(JSON.stringify(fields.metadata));
|
|
216
|
-
}
|
|
217
|
-
if (fields.content_storage !== undefined) {
|
|
218
|
-
sets.push('content_storage = ?');
|
|
219
|
-
params.push(fields.content_storage);
|
|
220
|
-
}
|
|
221
|
-
// Handle content update
|
|
203
|
+
// Handle content file read before lock acquisition (fail fast)
|
|
222
204
|
let newContent;
|
|
223
|
-
let contentHash;
|
|
224
205
|
if (fields.contentFile) {
|
|
225
206
|
try {
|
|
226
207
|
newContent = (0, fs_1.readFileSync)(fields.contentFile, 'utf-8');
|
|
@@ -233,39 +214,58 @@ function updateDocument(db, id, fields) {
|
|
|
233
214
|
else if (fields.content !== undefined) {
|
|
234
215
|
newContent = fields.content;
|
|
235
216
|
}
|
|
236
|
-
if (newContent !== undefined) {
|
|
237
|
-
contentHash = sha256(newContent);
|
|
238
|
-
sets.push('content_hash = ?');
|
|
239
|
-
params.push(contentHash);
|
|
240
|
-
}
|
|
241
|
-
// SAD-0035: Entity sync on type change removed — entities table dropped
|
|
242
217
|
// content_storage switch validation (FR-URD-G001-0001 M6)
|
|
243
|
-
// Switching from filesystem to db without providing content creates an
|
|
244
|
-
// inconsistency: the document_contents table has no authoritative copy.
|
|
245
218
|
if (fields.content_storage !== undefined && fields.content_storage !== doc.content_storage) {
|
|
246
219
|
if (fields.content_storage === 'db' && doc.content_storage === 'filesystem' && newContent === undefined && !fields.contentFile) {
|
|
247
220
|
throw new errors_1.DocumentMissingFieldError('content');
|
|
248
221
|
}
|
|
249
222
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
223
|
+
const owner = (0, locks_1.generateLockOwner)();
|
|
224
|
+
return (0, locks_1.withLock)(db, { name: 'doc:global', owner }, () => {
|
|
225
|
+
const now = new Date().toISOString();
|
|
226
|
+
const sets = ['updated_at = ?'];
|
|
227
|
+
const params = [now];
|
|
228
|
+
if (fields.title !== undefined) {
|
|
229
|
+
sets.push('title = ?');
|
|
230
|
+
params.push(fields.title);
|
|
231
|
+
}
|
|
232
|
+
if (fields.type !== undefined) {
|
|
233
|
+
sets.push('type = ?');
|
|
234
|
+
params.push(fields.type);
|
|
235
|
+
}
|
|
236
|
+
if (fields.metadata !== undefined) {
|
|
237
|
+
sets.push('metadata = ?');
|
|
238
|
+
params.push(JSON.stringify(fields.metadata));
|
|
239
|
+
}
|
|
240
|
+
if (fields.content_storage !== undefined) {
|
|
241
|
+
sets.push('content_storage = ?');
|
|
242
|
+
params.push(fields.content_storage);
|
|
243
|
+
}
|
|
244
|
+
let contentHash;
|
|
257
245
|
if (newContent !== undefined) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
246
|
+
contentHash = sha256(newContent);
|
|
247
|
+
sets.push('content_hash = ?');
|
|
248
|
+
params.push(contentHash);
|
|
261
249
|
}
|
|
262
|
-
|
|
263
|
-
|
|
250
|
+
params.push(id);
|
|
251
|
+
// Single atomic transaction: content upsert + document update
|
|
252
|
+
// SAD-0035: Entity sync removed — entities table dropped
|
|
253
|
+
(0, retry_1.withTransaction)(db, () => {
|
|
254
|
+
// Step 1: Content upsert
|
|
255
|
+
if (newContent !== undefined) {
|
|
256
|
+
db.prepare(`INSERT INTO document_contents (document_id, content, content_hash, updated_at)
|
|
257
|
+
VALUES (?, ?, ?, ?)
|
|
258
|
+
ON CONFLICT(document_id) DO UPDATE SET content = excluded.content, content_hash = excluded.content_hash, updated_at = excluded.updated_at`).run(id, newContent, contentHash, now);
|
|
259
|
+
}
|
|
260
|
+
// Step 2: Document row UPDATE
|
|
261
|
+
db.prepare(`UPDATE documents SET ${sets.join(', ')} WHERE id = ?`).run(...params);
|
|
262
|
+
});
|
|
263
|
+
return getDocument(db, id);
|
|
264
264
|
});
|
|
265
|
-
return getDocument(db, id);
|
|
266
265
|
}
|
|
267
266
|
/**
|
|
268
267
|
* Remove a document registration.
|
|
268
|
+
* Wrapped with doc:global advisory lock (AD-0006) for multi-process coordination.
|
|
269
269
|
*
|
|
270
270
|
* Deletion ordering per SAD-0035 (3-step sequence after entities table drop):
|
|
271
271
|
* Step 1: Delete relations (outgoing and incoming) referencing the document
|
|
@@ -276,16 +276,17 @@ function updateDocument(db, id, fields) {
|
|
|
276
276
|
* Content is always deleted unconditionally per AD-0028 — there is no soft-delete option.
|
|
277
277
|
*/
|
|
278
278
|
function removeDocument(db, id) {
|
|
279
|
-
getDocument(db, id); // verify exists
|
|
280
|
-
(0,
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
279
|
+
getDocument(db, id); // verify exists before lock
|
|
280
|
+
const owner = (0, locks_1.generateLockOwner)();
|
|
281
|
+
(0, locks_1.withLock)(db, { name: 'doc:global', owner }, () => {
|
|
282
|
+
(0, retry_1.withTransaction)(db, () => {
|
|
283
|
+
// Step 1: Delete all relations referencing this document (from_id OR to_id)
|
|
284
|
+
db.prepare('DELETE FROM relations WHERE from_id = ? OR to_id = ?').run(id, id);
|
|
285
|
+
// Step 2: Delete document_contents unconditionally per AD-0028
|
|
286
|
+
db.prepare('DELETE FROM document_contents WHERE document_id = ?').run(id);
|
|
287
|
+
// Step 3: Delete document row
|
|
288
|
+
db.prepare('DELETE FROM documents WHERE id = ?').run(id);
|
|
289
|
+
});
|
|
289
290
|
});
|
|
290
291
|
}
|
|
291
292
|
/**
|