ocean-brain 0.5.0 → 0.6.1
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/mcp.js +660 -31
- package/package.json +2 -1
- package/server/client/dist/assets/{Calendar-BU9XgX2N.js → Calendar-BJHLksEZ.js} +1 -1
- package/server/client/dist/assets/{Callout-C6tVCxOT.js → Callout-wFx9oCas.js} +1 -1
- package/server/client/dist/assets/Graph-9piERaNR.js +1 -0
- package/server/client/dist/assets/{Image-DxWhlIDG.js → Image-DK0lnaK2.js} +1 -1
- package/server/client/dist/assets/{Image.es-BjGK7y6Y.js → Image.es-Be7par_j.js} +1 -1
- package/server/client/dist/assets/Note-CC9ybxXL.js +21 -0
- package/server/client/dist/assets/{Plus.es-EcmtS_uw.js → Plus.es-BKm7uDYu.js} +1 -1
- package/server/client/dist/assets/Reminders-DRxA8v98.js +1 -0
- package/server/client/dist/assets/Search-BunSQrqv.js +1 -0
- package/server/client/dist/assets/{SurfaceCard-CO0oVxeL.js → SurfaceCard-FhlC8VSR.js} +1 -1
- package/server/client/dist/assets/Tag-z_crJ5JP.js +1 -0
- package/server/client/dist/assets/TagNotes-D7wIJ4jy.js +1 -0
- package/server/client/dist/assets/{Trash.es-DmwfSy3l.js → Trash.es-ByMVwx0d.js} +1 -1
- package/server/client/dist/assets/ViewNotes-Duo9XmcJ.js +1 -0
- package/server/client/dist/assets/Views-D4Z_O9Kd.js +1 -0
- package/server/client/dist/assets/{image.api-DeF9ck7g.js → image.api-B5Qi-Txv.js} +1 -1
- package/server/client/dist/assets/{index-BZUGWdOU.css → index-Cd81UxEh.css} +1 -1
- package/server/client/dist/assets/index-cHJQCo8V.js +1 -0
- package/server/client/dist/assets/index-nYj7BL3a.js +327 -0
- package/server/client/dist/assets/manage-image-detail-DcZggB1M.js +1 -0
- package/server/client/dist/assets/manage-image-glbtBibn.js +1 -0
- package/server/client/dist/assets/{mcp-Bh743HBz.js → mcp-BBUpQdS9.js} +1 -1
- package/server/client/dist/assets/{note-core-Z6kqulGB.js → note-core-DMZcZ4yV.js} +53 -53
- package/server/client/dist/assets/{note-vendor-i1M2FSI2.js → note-vendor-uuJO2MTD.js} +1 -1
- package/server/client/dist/assets/{placeholder-XQqo1Fvr.js → placeholder-B_qb_qkc.js} +5 -5
- package/server/client/dist/assets/properties-CiyQv6Tb.js +1 -0
- package/server/client/dist/assets/trash-CQnj4Rmv.js +1 -0
- package/server/client/dist/assets/{useReminderMutate-D21PurIS.js → useReminderMutate-CSKliBcc.js} +1 -1
- package/server/client/dist/assets/view-dashboard-B5fKgvk_.js +99 -0
- package/server/client/dist/index.html +4 -4
- package/server/dist/features/note/graphql/note.field.resolver.js +2 -0
- package/server/dist/features/note/graphql/note.field.resolver.js.map +1 -1
- package/server/dist/features/note/graphql/note.mutation.resolver.js +119 -0
- package/server/dist/features/note/graphql/note.mutation.resolver.js.map +1 -1
- package/server/dist/features/note/graphql/note.query.resolver.js +14 -0
- package/server/dist/features/note/graphql/note.query.resolver.js.map +1 -1
- package/server/dist/features/note/graphql/note.type-defs.js +100 -0
- package/server/dist/features/note/graphql/note.type-defs.js.map +1 -1
- package/server/dist/features/note/http/mcp.js +394 -1
- package/server/dist/features/note/http/mcp.js.map +1 -1
- package/server/dist/features/note/services/markdown-intent-write.js +495 -0
- package/server/dist/features/note/services/markdown-intent-write.js.map +1 -0
- package/server/dist/features/note/services/markdown-patch.js +601 -0
- package/server/dist/features/note/services/markdown-patch.js.map +1 -0
- package/server/dist/features/note/services/properties.js +874 -0
- package/server/dist/features/note/services/properties.js.map +1 -0
- package/server/dist/features/note/services/snapshot.js +94 -12
- package/server/dist/features/note/services/snapshot.js.map +1 -1
- package/server/dist/features/note/services/trash.js +70 -2
- package/server/dist/features/note/services/trash.js.map +1 -1
- package/server/dist/features/note/services/write.js +21 -7
- package/server/dist/features/note/services/write.js.map +1 -1
- package/server/dist/features/view/graphql/view.query.resolver.js +31 -1
- package/server/dist/features/view/graphql/view.query.resolver.js.map +1 -1
- package/server/dist/features/view/graphql/view.type-defs.js +57 -1
- package/server/dist/features/view/graphql/view.type-defs.js.map +1 -1
- package/server/dist/features/view/services/workspace.js +367 -43
- package/server/dist/features/view/services/workspace.js.map +1 -1
- package/server/dist/modules/blocknote.js +367 -7
- package/server/dist/modules/blocknote.js.map +1 -1
- package/server/dist/routes/mcp.js +21 -1
- package/server/dist/routes/mcp.js.map +1 -1
- package/server/prisma/migrations/20260527073000_0017_note_properties/migration.sql +105 -0
- package/server/prisma/migrations/20260531073000_0018_view_query/migration.sql +3 -0
- package/server/prisma/schema.prisma +226 -130
- package/server/client/dist/assets/Graph-Dond2hGK.js +0 -1
- package/server/client/dist/assets/Note-Cr6GtXUM.js +0 -21
- package/server/client/dist/assets/Reminders-BlLLT_x0.js +0 -1
- package/server/client/dist/assets/Search-CrZ0ap8x.js +0 -1
- package/server/client/dist/assets/Tag-vws5AfNW.js +0 -1
- package/server/client/dist/assets/TagNotes-Fmf1Kgim.js +0 -1
- package/server/client/dist/assets/ViewNotes-BALN7IfH.js +0 -1
- package/server/client/dist/assets/Views-Ccc_Ml5U.js +0 -1
- package/server/client/dist/assets/index-BSVE2cGd.js +0 -1
- package/server/client/dist/assets/index-BvKBTjQq.js +0 -246
- package/server/client/dist/assets/manage-image-IoTXaMBP.js +0 -1
- package/server/client/dist/assets/manage-image-detail-BRTXwOsh.js +0 -1
- package/server/client/dist/assets/trash-hiJIg6-c.js +0 -1
- package/server/client/dist/assets/view-dashboard-BuaZ4MvI.js +0 -90
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
import models from "../../../models.js";
|
|
2
|
+
import {
|
|
3
|
+
blocksToMarkdown,
|
|
4
|
+
countReferenceInlinesFromContentJson,
|
|
5
|
+
extractLiteralAngleBracketTextTokens,
|
|
6
|
+
extractTagIdsFromContentJson,
|
|
7
|
+
hasLiteralAngleBracketTextTokenLoss,
|
|
8
|
+
hasNumericTildeRangeMarkerLoss,
|
|
9
|
+
hasNumericTildeRangeMarkers,
|
|
10
|
+
hasUnsupportedMarkdownBlocks,
|
|
11
|
+
markdownToBlocksJson
|
|
12
|
+
} from "../../../modules/blocknote.js";
|
|
13
|
+
import {
|
|
14
|
+
buildMarkdownAppendPlan,
|
|
15
|
+
buildMarkdownPatchPlan,
|
|
16
|
+
buildMarkdownReplacePlan,
|
|
17
|
+
calculateMarkdownSha256
|
|
18
|
+
} from "./markdown-patch.js";
|
|
19
|
+
import {
|
|
20
|
+
InvalidNotePropertyInputError,
|
|
21
|
+
resolveNotePropertiesPatchValueTypes,
|
|
22
|
+
updateNotePropertiesWithVersionGuardAndSnapshot,
|
|
23
|
+
validateNotePropertiesPatchValues
|
|
24
|
+
} from "./properties.js";
|
|
25
|
+
import { MCP_SNAPSHOT_META } from "./snapshot.js";
|
|
26
|
+
import { updateNoteWithVersionGuardAndSnapshot } from "./write.js";
|
|
27
|
+
import {
|
|
28
|
+
isInvalidNoteVersionError,
|
|
29
|
+
isMissingNoteVersionError,
|
|
30
|
+
isNoteVersionConflictError,
|
|
31
|
+
parseNoteVersion
|
|
32
|
+
} from "./write-conflict.js";
|
|
33
|
+
const serializeNoteSnapshot = async (note, renderMarkdown) => {
|
|
34
|
+
return {
|
|
35
|
+
id: String(note.id),
|
|
36
|
+
title: note.title,
|
|
37
|
+
updatedAt: note.updatedAt.toISOString(),
|
|
38
|
+
markdown: await renderMarkdown(note.content)
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
const isRecord = (value) => {
|
|
42
|
+
return typeof value === "object" && value !== null;
|
|
43
|
+
};
|
|
44
|
+
const serializeSnapshot = (snapshot) => {
|
|
45
|
+
const meta = isRecord(snapshot) && isRecord(snapshot.meta) ? snapshot.meta : {};
|
|
46
|
+
const label = typeof meta.label === "string" ? meta.label : "MCP";
|
|
47
|
+
return {
|
|
48
|
+
id: isRecord(snapshot) && snapshot.id !== void 0 ? String(snapshot.id) : "",
|
|
49
|
+
label,
|
|
50
|
+
createdAt: isRecord(snapshot) && typeof snapshot.createdAt === "string" ? snapshot.createdAt : ""
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
const toDryRun = (plan) => ({
|
|
54
|
+
status: "dry_run",
|
|
55
|
+
note: plan.note,
|
|
56
|
+
...plan.match ? { match: plan.match } : {},
|
|
57
|
+
...plan.placement ? { placement: plan.placement } : {},
|
|
58
|
+
proposed: plan.proposed,
|
|
59
|
+
warnings: plan.warnings
|
|
60
|
+
});
|
|
61
|
+
const toTagIds = (tagIds) => {
|
|
62
|
+
return tagIds.map((tagId) => Number(tagId)).filter((tagId) => Number.isSafeInteger(tagId) && tagId > 0);
|
|
63
|
+
};
|
|
64
|
+
const baselineMismatchFailure = () => ({
|
|
65
|
+
status: "failed",
|
|
66
|
+
reason: "BASELINE_MISMATCH",
|
|
67
|
+
message: "The markdown write baseline does not match the current note."
|
|
68
|
+
});
|
|
69
|
+
const missingBaselineFailure = () => ({
|
|
70
|
+
status: "failed",
|
|
71
|
+
reason: "MISSING_BASELINE",
|
|
72
|
+
message: "expectedUpdatedAt or baseMarkdownSha256 is required for markdown writes."
|
|
73
|
+
});
|
|
74
|
+
const unsupportedMarkdownStructureFailure = () => ({
|
|
75
|
+
status: "failed",
|
|
76
|
+
reason: "UNSUPPORTED_MARKDOWN_STRUCTURE",
|
|
77
|
+
message: "This note contains BlockNote content that cannot be safely represented as Markdown."
|
|
78
|
+
});
|
|
79
|
+
const referenceStructureFailure = () => ({
|
|
80
|
+
status: "failed",
|
|
81
|
+
reason: "REFERENCE_STRUCTURE_DECREASED",
|
|
82
|
+
message: "The markdown write would reduce structured note reference links."
|
|
83
|
+
});
|
|
84
|
+
const markdownImportLossyFailure = () => ({
|
|
85
|
+
status: "failed",
|
|
86
|
+
reason: "MARKDOWN_IMPORT_LOSSY",
|
|
87
|
+
message: "The markdown write would lose literal text during Markdown import."
|
|
88
|
+
});
|
|
89
|
+
const invalidPropertyInputFailure = (error) => ({
|
|
90
|
+
status: "failed",
|
|
91
|
+
reason: "INVALID_PROPERTY_INPUT",
|
|
92
|
+
message: error.message
|
|
93
|
+
});
|
|
94
|
+
const mapGuardedWriteError = (error) => {
|
|
95
|
+
if (isNoteVersionConflictError(error) || isInvalidNoteVersionError(error)) {
|
|
96
|
+
return baselineMismatchFailure();
|
|
97
|
+
}
|
|
98
|
+
if (isMissingNoteVersionError(error)) {
|
|
99
|
+
return missingBaselineFailure();
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
};
|
|
103
|
+
const resolveMetadataPropertyPatch = async (deps, patch) => {
|
|
104
|
+
if (patch === void 0) {
|
|
105
|
+
return void 0;
|
|
106
|
+
}
|
|
107
|
+
if (!deps.resolvePropertyPatch || !deps.validatePropertyPatch) {
|
|
108
|
+
throw new Error("Metadata property patch dependencies are not configured.");
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
const resolvedPatch = await deps.resolvePropertyPatch(patch);
|
|
112
|
+
return deps.validatePropertyPatch(resolvedPatch);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
if (error instanceof InvalidNotePropertyInputError) {
|
|
115
|
+
return invalidPropertyInputFailure(error);
|
|
116
|
+
}
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
const noteVersionMatches = (expectedUpdatedAt, currentUpdatedAt) => {
|
|
121
|
+
try {
|
|
122
|
+
const expectedTimestamp = parseNoteVersion(expectedUpdatedAt);
|
|
123
|
+
return expectedTimestamp !== null && expectedTimestamp === currentUpdatedAt.getTime();
|
|
124
|
+
} catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const getUnsupportedSourceFailure = (deps, note) => {
|
|
129
|
+
if (deps.hasUnsupportedMarkdownBlocks?.(note.content)) {
|
|
130
|
+
return unsupportedMarkdownStructureFailure();
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
};
|
|
134
|
+
const applyMarkdownPlan = async (deps, input) => {
|
|
135
|
+
const content = await deps.parseMarkdownToContentJson(input.plan.afterMarkdown);
|
|
136
|
+
const literalAngleBracketTokens = extractLiteralAngleBracketTextTokens(input.plan.afterMarkdown);
|
|
137
|
+
const shouldCheckMarkdownImportLoss = literalAngleBracketTokens.length > 0 || hasNumericTildeRangeMarkers(input.plan.afterMarkdown);
|
|
138
|
+
if (shouldCheckMarkdownImportLoss) {
|
|
139
|
+
const importedMarkdown = await deps.renderMarkdown(content);
|
|
140
|
+
if (hasLiteralAngleBracketTextTokenLoss(input.plan.afterMarkdown, importedMarkdown) || hasNumericTildeRangeMarkerLoss(input.plan.afterMarkdown, importedMarkdown)) {
|
|
141
|
+
return markdownImportLossyFailure();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const beforeReferenceCount = deps.countReferenceInlines?.(input.beforeContentJson) ?? 0;
|
|
145
|
+
const afterReferenceCount = deps.countReferenceInlines?.(content) ?? 0;
|
|
146
|
+
if (input.policy?.preserveReferences !== false && afterReferenceCount < beforeReferenceCount) {
|
|
147
|
+
return referenceStructureFailure();
|
|
148
|
+
}
|
|
149
|
+
const tagIds = toTagIds(deps.extractTagIds(content));
|
|
150
|
+
let updateResult;
|
|
151
|
+
try {
|
|
152
|
+
updateResult = await deps.updateNote({
|
|
153
|
+
id: input.noteId,
|
|
154
|
+
data: {
|
|
155
|
+
content,
|
|
156
|
+
tagIds
|
|
157
|
+
},
|
|
158
|
+
expectedUpdatedAt: input.expectedUpdatedAt ?? input.noteUpdatedAt,
|
|
159
|
+
snapshotMeta: MCP_SNAPSHOT_META,
|
|
160
|
+
...input.force ? { force: true } : {}
|
|
161
|
+
});
|
|
162
|
+
} catch (error) {
|
|
163
|
+
const mappedError = mapGuardedWriteError(error);
|
|
164
|
+
if (mappedError) {
|
|
165
|
+
return mappedError;
|
|
166
|
+
}
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
if (!updateResult) {
|
|
170
|
+
return {
|
|
171
|
+
status: "failed",
|
|
172
|
+
reason: "TARGET_NOT_FOUND",
|
|
173
|
+
message: "The requested note was not found."
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
status: "applied",
|
|
178
|
+
note: {
|
|
179
|
+
id: String(updateResult.note.id),
|
|
180
|
+
updatedAt: updateResult.note.updatedAt.toISOString()
|
|
181
|
+
},
|
|
182
|
+
change: {
|
|
183
|
+
summary: input.summary,
|
|
184
|
+
changedLineCount: input.plan.proposed.changedLineCount,
|
|
185
|
+
changedCharCount: input.plan.proposed.changedCharCount
|
|
186
|
+
},
|
|
187
|
+
snapshot: serializeSnapshot(updateResult.snapshot)
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
const mapPlanResult = async (deps, input) => {
|
|
191
|
+
if (input.plan.status !== "dry_run") {
|
|
192
|
+
return input.plan;
|
|
193
|
+
}
|
|
194
|
+
if (input.dryRun ?? true) {
|
|
195
|
+
return toDryRun(input.plan);
|
|
196
|
+
}
|
|
197
|
+
return applyMarkdownPlan(deps, {
|
|
198
|
+
noteId: input.noteId,
|
|
199
|
+
noteUpdatedAt: input.noteUpdatedAt,
|
|
200
|
+
beforeContentJson: input.beforeContentJson,
|
|
201
|
+
plan: input.plan,
|
|
202
|
+
expectedUpdatedAt: input.expectedUpdatedAt,
|
|
203
|
+
policy: input.policy,
|
|
204
|
+
summary: input.summary,
|
|
205
|
+
...input.force ? { force: true } : {}
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
const createMarkdownIntentWriteService = (deps) => ({
|
|
209
|
+
patchNoteMarkdown: async (input) => {
|
|
210
|
+
const note = await deps.findNoteById(input.id);
|
|
211
|
+
if (!note) {
|
|
212
|
+
return {
|
|
213
|
+
status: "failed",
|
|
214
|
+
reason: "TARGET_NOT_FOUND",
|
|
215
|
+
message: "The requested note was not found."
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
const unsupportedFailure = getUnsupportedSourceFailure(deps, note);
|
|
219
|
+
if (unsupportedFailure) {
|
|
220
|
+
return unsupportedFailure;
|
|
221
|
+
}
|
|
222
|
+
const noteSnapshot = await serializeNoteSnapshot(note, deps.renderMarkdown);
|
|
223
|
+
const plan = buildMarkdownPatchPlan({
|
|
224
|
+
note: noteSnapshot,
|
|
225
|
+
expectedUpdatedAt: input.expectedUpdatedAt,
|
|
226
|
+
baseMarkdownSha256: input.baseMarkdownSha256,
|
|
227
|
+
intent: input.intent,
|
|
228
|
+
selector: input.selector,
|
|
229
|
+
operation: input.operation,
|
|
230
|
+
policy: input.policy
|
|
231
|
+
});
|
|
232
|
+
return mapPlanResult(deps, {
|
|
233
|
+
noteId: input.id,
|
|
234
|
+
noteUpdatedAt: noteSnapshot.updatedAt,
|
|
235
|
+
beforeContentJson: note.content,
|
|
236
|
+
plan,
|
|
237
|
+
dryRun: input.dryRun,
|
|
238
|
+
expectedUpdatedAt: input.expectedUpdatedAt,
|
|
239
|
+
policy: input.policy,
|
|
240
|
+
summary: input.intent
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
appendNoteMarkdown: async (input) => {
|
|
244
|
+
const note = await deps.findNoteById(input.id);
|
|
245
|
+
if (!note) {
|
|
246
|
+
return {
|
|
247
|
+
status: "failed",
|
|
248
|
+
reason: "TARGET_NOT_FOUND",
|
|
249
|
+
message: "The requested note was not found."
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
const unsupportedFailure = getUnsupportedSourceFailure(deps, note);
|
|
253
|
+
if (unsupportedFailure) {
|
|
254
|
+
return unsupportedFailure;
|
|
255
|
+
}
|
|
256
|
+
const noteSnapshot = await serializeNoteSnapshot(note, deps.renderMarkdown);
|
|
257
|
+
const plan = buildMarkdownAppendPlan({
|
|
258
|
+
note: noteSnapshot,
|
|
259
|
+
expectedUpdatedAt: input.expectedUpdatedAt,
|
|
260
|
+
baseMarkdownSha256: input.baseMarkdownSha256,
|
|
261
|
+
intent: input.intent,
|
|
262
|
+
insertion: input.insertion,
|
|
263
|
+
placement: input.placement,
|
|
264
|
+
separator: input.separator,
|
|
265
|
+
policy: input.policy
|
|
266
|
+
});
|
|
267
|
+
return mapPlanResult(deps, {
|
|
268
|
+
noteId: input.id,
|
|
269
|
+
noteUpdatedAt: noteSnapshot.updatedAt,
|
|
270
|
+
beforeContentJson: note.content,
|
|
271
|
+
plan,
|
|
272
|
+
dryRun: input.dryRun,
|
|
273
|
+
expectedUpdatedAt: input.expectedUpdatedAt,
|
|
274
|
+
policy: input.policy,
|
|
275
|
+
summary: input.intent
|
|
276
|
+
});
|
|
277
|
+
},
|
|
278
|
+
replaceNoteMarkdown: async (input) => {
|
|
279
|
+
const note = await deps.findNoteById(input.id);
|
|
280
|
+
if (!note) {
|
|
281
|
+
return {
|
|
282
|
+
status: "failed",
|
|
283
|
+
reason: "TARGET_NOT_FOUND",
|
|
284
|
+
message: "The requested note was not found."
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
const unsupportedFailure = getUnsupportedSourceFailure(deps, note);
|
|
288
|
+
if (unsupportedFailure) {
|
|
289
|
+
return unsupportedFailure;
|
|
290
|
+
}
|
|
291
|
+
const noteSnapshot = await serializeNoteSnapshot(note, deps.renderMarkdown);
|
|
292
|
+
const plan = buildMarkdownReplacePlan({
|
|
293
|
+
note: noteSnapshot,
|
|
294
|
+
expectedUpdatedAt: input.expectedUpdatedAt,
|
|
295
|
+
baseMarkdownSha256: input.baseMarkdownSha256,
|
|
296
|
+
intent: input.intent,
|
|
297
|
+
replacement: input.replacement,
|
|
298
|
+
policy: input.policy
|
|
299
|
+
});
|
|
300
|
+
return mapPlanResult(deps, {
|
|
301
|
+
noteId: input.id,
|
|
302
|
+
noteUpdatedAt: noteSnapshot.updatedAt,
|
|
303
|
+
beforeContentJson: note.content,
|
|
304
|
+
plan,
|
|
305
|
+
dryRun: input.dryRun,
|
|
306
|
+
expectedUpdatedAt: input.expectedUpdatedAt,
|
|
307
|
+
policy: input.policy,
|
|
308
|
+
summary: input.intent
|
|
309
|
+
});
|
|
310
|
+
},
|
|
311
|
+
updateNoteMetadata: async (input) => {
|
|
312
|
+
const note = await deps.findNoteById(input.id);
|
|
313
|
+
if (!note) {
|
|
314
|
+
return {
|
|
315
|
+
status: "failed",
|
|
316
|
+
reason: "TARGET_NOT_FOUND",
|
|
317
|
+
message: "The requested note was not found."
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
if (!noteVersionMatches(input.expectedUpdatedAt, note.updatedAt)) {
|
|
321
|
+
return {
|
|
322
|
+
status: "failed",
|
|
323
|
+
reason: input.expectedUpdatedAt ? "BASELINE_MISMATCH" : "MISSING_BASELINE",
|
|
324
|
+
message: "The metadata update baseline does not match the current note."
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
const nextTitle = input.title?.trim();
|
|
328
|
+
const resolvedPropertyPatch = await resolveMetadataPropertyPatch(deps, input.properties);
|
|
329
|
+
if (resolvedPropertyPatch && "status" in resolvedPropertyPatch) {
|
|
330
|
+
return resolvedPropertyPatch;
|
|
331
|
+
}
|
|
332
|
+
if (input.title !== void 0 && !nextTitle) {
|
|
333
|
+
return {
|
|
334
|
+
status: "failed",
|
|
335
|
+
reason: "EMPTY_REPLACEMENT",
|
|
336
|
+
message: "Note title must not be empty."
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
if (nextTitle === note.title && (input.layout === void 0 || input.layout === note.layout) && resolvedPropertyPatch === void 0) {
|
|
340
|
+
return {
|
|
341
|
+
status: "failed",
|
|
342
|
+
reason: "NOOP",
|
|
343
|
+
message: "The metadata update would not change the note."
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
status: "dry_run",
|
|
348
|
+
note: {
|
|
349
|
+
id: String(note.id),
|
|
350
|
+
title: note.title,
|
|
351
|
+
updatedAt: note.updatedAt.toISOString()
|
|
352
|
+
},
|
|
353
|
+
proposed: {
|
|
354
|
+
...nextTitle !== void 0 ? { title: nextTitle } : {},
|
|
355
|
+
...input.layout !== void 0 ? { layout: input.layout } : {},
|
|
356
|
+
...resolvedPropertyPatch ? { properties: resolvedPropertyPatch } : {}
|
|
357
|
+
},
|
|
358
|
+
warnings: []
|
|
359
|
+
};
|
|
360
|
+
},
|
|
361
|
+
applyNoteMetadata: async (input) => {
|
|
362
|
+
const preview = await createMarkdownIntentWriteService(deps).updateNoteMetadata(input);
|
|
363
|
+
if (preview.status !== "dry_run") {
|
|
364
|
+
return preview;
|
|
365
|
+
}
|
|
366
|
+
if (input.properties !== void 0) {
|
|
367
|
+
if (!deps.updateProperties) {
|
|
368
|
+
throw new Error("Metadata property write dependency is not configured.");
|
|
369
|
+
}
|
|
370
|
+
let updateResult2;
|
|
371
|
+
try {
|
|
372
|
+
updateResult2 = await deps.updateProperties({
|
|
373
|
+
id: input.id,
|
|
374
|
+
patch: preview.proposed.properties ?? { set: [], deleteKeys: [] },
|
|
375
|
+
expectedUpdatedAt: input.expectedUpdatedAt,
|
|
376
|
+
noteData: {
|
|
377
|
+
...preview.proposed.title !== void 0 ? { title: preview.proposed.title } : {},
|
|
378
|
+
...preview.proposed.layout !== void 0 ? { layout: preview.proposed.layout } : {}
|
|
379
|
+
},
|
|
380
|
+
snapshotMeta: MCP_SNAPSHOT_META
|
|
381
|
+
});
|
|
382
|
+
} catch (error) {
|
|
383
|
+
const mappedError = mapGuardedWriteError(error);
|
|
384
|
+
if (mappedError) {
|
|
385
|
+
return mappedError;
|
|
386
|
+
}
|
|
387
|
+
if (error instanceof InvalidNotePropertyInputError) {
|
|
388
|
+
return invalidPropertyInputFailure(error);
|
|
389
|
+
}
|
|
390
|
+
throw error;
|
|
391
|
+
}
|
|
392
|
+
if (!updateResult2) {
|
|
393
|
+
return {
|
|
394
|
+
status: "failed",
|
|
395
|
+
reason: "TARGET_NOT_FOUND",
|
|
396
|
+
message: "The requested note was not found."
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
return {
|
|
400
|
+
status: "applied",
|
|
401
|
+
note: {
|
|
402
|
+
id: String(updateResult2.note.id),
|
|
403
|
+
title: updateResult2.note.title,
|
|
404
|
+
layout: updateResult2.note.layout,
|
|
405
|
+
updatedAt: updateResult2.note.updatedAt.toISOString()
|
|
406
|
+
},
|
|
407
|
+
snapshot: serializeSnapshot(updateResult2.snapshot)
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
let updateResult;
|
|
411
|
+
try {
|
|
412
|
+
updateResult = await deps.updateNote({
|
|
413
|
+
id: input.id,
|
|
414
|
+
data: {
|
|
415
|
+
...preview.proposed.title !== void 0 ? { title: preview.proposed.title } : {},
|
|
416
|
+
...preview.proposed.layout !== void 0 ? { layout: preview.proposed.layout } : {}
|
|
417
|
+
},
|
|
418
|
+
expectedUpdatedAt: input.expectedUpdatedAt,
|
|
419
|
+
snapshotMeta: MCP_SNAPSHOT_META
|
|
420
|
+
});
|
|
421
|
+
} catch (error) {
|
|
422
|
+
const mappedError = mapGuardedWriteError(error);
|
|
423
|
+
if (mappedError) {
|
|
424
|
+
return mappedError;
|
|
425
|
+
}
|
|
426
|
+
throw error;
|
|
427
|
+
}
|
|
428
|
+
if (!updateResult) {
|
|
429
|
+
return {
|
|
430
|
+
status: "failed",
|
|
431
|
+
reason: "TARGET_NOT_FOUND",
|
|
432
|
+
message: "The requested note was not found."
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
return {
|
|
436
|
+
status: "applied",
|
|
437
|
+
note: {
|
|
438
|
+
id: String(updateResult.note.id),
|
|
439
|
+
title: updateResult.note.title,
|
|
440
|
+
layout: updateResult.note.layout,
|
|
441
|
+
updatedAt: updateResult.note.updatedAt.toISOString()
|
|
442
|
+
},
|
|
443
|
+
snapshot: serializeSnapshot(updateResult.snapshot)
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
const defaultMarkdownIntentWriteService = createMarkdownIntentWriteService({
|
|
448
|
+
findNoteById: (id) => models.note.findUnique({
|
|
449
|
+
where: { id },
|
|
450
|
+
select: {
|
|
451
|
+
id: true,
|
|
452
|
+
title: true,
|
|
453
|
+
content: true,
|
|
454
|
+
layout: true,
|
|
455
|
+
updatedAt: true
|
|
456
|
+
}
|
|
457
|
+
}),
|
|
458
|
+
renderMarkdown: blocksToMarkdown,
|
|
459
|
+
parseMarkdownToContentJson: markdownToBlocksJson,
|
|
460
|
+
extractTagIds: extractTagIdsFromContentJson,
|
|
461
|
+
countReferenceInlines: countReferenceInlinesFromContentJson,
|
|
462
|
+
hasUnsupportedMarkdownBlocks,
|
|
463
|
+
updateNote: updateNoteWithVersionGuardAndSnapshot,
|
|
464
|
+
resolvePropertyPatch: resolveNotePropertiesPatchValueTypes,
|
|
465
|
+
validatePropertyPatch: validateNotePropertiesPatchValues,
|
|
466
|
+
updateProperties: updateNotePropertiesWithVersionGuardAndSnapshot
|
|
467
|
+
});
|
|
468
|
+
const patchNoteMarkdown = async (input) => {
|
|
469
|
+
return defaultMarkdownIntentWriteService.patchNoteMarkdown(input);
|
|
470
|
+
};
|
|
471
|
+
const appendNoteMarkdown = async (input) => {
|
|
472
|
+
return defaultMarkdownIntentWriteService.appendNoteMarkdown(input);
|
|
473
|
+
};
|
|
474
|
+
const replaceNoteMarkdown = async (input) => {
|
|
475
|
+
return defaultMarkdownIntentWriteService.replaceNoteMarkdown(input);
|
|
476
|
+
};
|
|
477
|
+
const updateNoteMetadata = async (input) => {
|
|
478
|
+
if (input.dryRun ?? true) {
|
|
479
|
+
return defaultMarkdownIntentWriteService.updateNoteMetadata(input);
|
|
480
|
+
}
|
|
481
|
+
return defaultMarkdownIntentWriteService.applyNoteMetadata(input);
|
|
482
|
+
};
|
|
483
|
+
const calculateNoteMarkdownSha256 = (markdown) => {
|
|
484
|
+
return calculateMarkdownSha256(markdown);
|
|
485
|
+
};
|
|
486
|
+
export {
|
|
487
|
+
appendNoteMarkdown,
|
|
488
|
+
calculateNoteMarkdownSha256,
|
|
489
|
+
createMarkdownIntentWriteService,
|
|
490
|
+
defaultMarkdownIntentWriteService,
|
|
491
|
+
patchNoteMarkdown,
|
|
492
|
+
replaceNoteMarkdown,
|
|
493
|
+
updateNoteMetadata
|
|
494
|
+
};
|
|
495
|
+
//# sourceMappingURL=markdown-intent-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/features/note/services/markdown-intent-write.ts"],"sourcesContent":["import models, { type NoteLayout } from '~/models.js';\nimport {\n blocksToMarkdown,\n countReferenceInlinesFromContentJson,\n extractLiteralAngleBracketTextTokens,\n extractTagIdsFromContentJson,\n hasLiteralAngleBracketTextTokenLoss,\n hasNumericTildeRangeMarkerLoss,\n hasNumericTildeRangeMarkers,\n hasUnsupportedMarkdownBlocks,\n markdownToBlocksJson,\n} from '~/modules/blocknote.js';\nimport type {\n MarkdownAppendPlanResult,\n MarkdownChangeDryRun,\n MarkdownChangeFailure,\n MarkdownChangePlan,\n MarkdownPatchOperation,\n MarkdownPatchPlanResult,\n MarkdownPatchSelector,\n MarkdownReplacePlanResult,\n} from './markdown-patch.js';\nimport {\n buildMarkdownAppendPlan,\n buildMarkdownPatchPlan,\n buildMarkdownReplacePlan,\n calculateMarkdownSha256,\n} from './markdown-patch.js';\nimport {\n InvalidNotePropertyInputError,\n type NotePropertiesByKeyPatchInput,\n type NotePropertiesPatchInput,\n resolveNotePropertiesPatchValueTypes,\n updateNotePropertiesWithVersionGuardAndSnapshot,\n validateNotePropertiesPatchValues,\n} from './properties.js';\nimport { MCP_SNAPSHOT_META } from './snapshot.js';\nimport { type GuardedNoteWriteResult, updateNoteWithVersionGuardAndSnapshot } from './write.js';\nimport {\n isInvalidNoteVersionError,\n isMissingNoteVersionError,\n isNoteVersionConflictError,\n parseNoteVersion,\n} from './write-conflict.js';\n\ninterface MarkdownIntentNoteRecord {\n id: number;\n title: string;\n content: string;\n layout: NoteLayout;\n updatedAt: Date;\n}\n\ninterface MarkdownIntentWriteDeps {\n findNoteById: (id: number) => Promise<MarkdownIntentNoteRecord | null>;\n renderMarkdown: (contentJson: string) => Promise<string>;\n parseMarkdownToContentJson: (markdown: string) => Promise<string>;\n extractTagIds: (contentJson: string) => string[];\n countReferenceInlines?: (contentJson: string) => number;\n hasUnsupportedMarkdownBlocks?: (contentJson: string) => boolean;\n updateNote: (input: {\n id: number;\n data: {\n title?: string;\n content?: string;\n layout?: NoteLayout;\n tagIds?: number[];\n };\n expectedUpdatedAt: string;\n snapshotMeta?: string;\n force?: boolean;\n }) => Promise<GuardedNoteWriteResult | null>;\n resolvePropertyPatch?: (patch: NotePropertiesByKeyPatchInput) => Promise<NotePropertiesPatchInput>;\n validatePropertyPatch?: (patch: NotePropertiesPatchInput) => Promise<NotePropertiesPatchInput>;\n updateProperties?: (input: {\n id: number;\n patch: NotePropertiesPatchInput;\n expectedUpdatedAt: string;\n noteData?: {\n title?: string;\n layout?: NoteLayout;\n };\n snapshotMeta?: string;\n }) => Promise<{\n note: {\n id: number;\n title: string;\n layout: NoteLayout;\n updatedAt: Date;\n };\n snapshot: unknown;\n } | null>;\n}\n\nexport interface MarkdownWritePolicy {\n allowNoop?: boolean;\n maxChangedChars?: number;\n maxChangedLines?: number;\n preserveReferences?: boolean | 'warn';\n preserveTags?: boolean | 'warn';\n}\n\nexport interface PatchNoteMarkdownInput {\n id: number;\n expectedUpdatedAt?: string;\n baseMarkdownSha256?: string;\n intent: string;\n selector: MarkdownPatchSelector;\n operation: MarkdownPatchOperation;\n policy?: MarkdownWritePolicy;\n dryRun?: boolean;\n}\n\nexport interface AppendNoteMarkdownInput {\n id: number;\n expectedUpdatedAt?: string;\n baseMarkdownSha256?: string;\n intent: string;\n insertion: string;\n placement?:\n | {\n type: 'end';\n }\n | {\n type: 'after_heading';\n heading: string;\n level?: number;\n };\n separator?: '\\n\\n' | '\\n';\n policy?: MarkdownWritePolicy;\n dryRun?: boolean;\n}\n\nexport interface ReplaceNoteMarkdownInput {\n id: number;\n expectedUpdatedAt?: string;\n baseMarkdownSha256?: string;\n intent: string;\n replacement: string;\n policy?: MarkdownWritePolicy;\n dryRun?: boolean;\n}\n\nexport interface UpdateNoteMetadataInput {\n id: number;\n expectedUpdatedAt: string;\n title?: string;\n layout?: NoteLayout;\n properties?: NotePropertiesByKeyPatchInput;\n}\n\nexport interface AppliedMarkdownWriteResult {\n status: 'applied';\n note: {\n id: string;\n updatedAt: string;\n };\n change: {\n summary: string;\n changedLineCount: number;\n changedCharCount: number;\n };\n snapshot: {\n id: string;\n label: string;\n createdAt: string;\n };\n}\n\nexport interface MetadataUpdatePreview {\n status: 'dry_run';\n note: {\n id: string;\n title: string;\n updatedAt: string;\n };\n proposed: {\n title?: string;\n layout?: NoteLayout;\n properties?: NotePropertiesPatchInput;\n };\n warnings: string[];\n}\n\nexport interface AppliedMetadataUpdateResult {\n status: 'applied';\n note: {\n id: string;\n title: string;\n layout: NoteLayout;\n updatedAt: string;\n };\n snapshot: {\n id: string;\n label: string;\n createdAt: string;\n };\n}\n\nexport type MarkdownIntentWriteResult =\n | MarkdownChangeDryRun\n | AppliedMarkdownWriteResult\n | MarkdownChangeFailure\n | Extract<MarkdownPatchPlanResult, { status: 'needs_disambiguation' }>;\n\nexport type MetadataUpdateResult = MetadataUpdatePreview | AppliedMetadataUpdateResult | MarkdownChangeFailure;\n\nconst serializeNoteSnapshot = async (\n note: MarkdownIntentNoteRecord,\n renderMarkdown: (contentJson: string) => Promise<string>,\n) => {\n return {\n id: String(note.id),\n title: note.title,\n updatedAt: note.updatedAt.toISOString(),\n markdown: await renderMarkdown(note.content),\n };\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return typeof value === 'object' && value !== null;\n};\n\nconst serializeSnapshot = (snapshot: unknown) => {\n const meta = isRecord(snapshot) && isRecord(snapshot.meta) ? snapshot.meta : {};\n const label = typeof meta.label === 'string' ? meta.label : 'MCP';\n\n return {\n id: isRecord(snapshot) && snapshot.id !== undefined ? String(snapshot.id) : '',\n label,\n createdAt: isRecord(snapshot) && typeof snapshot.createdAt === 'string' ? snapshot.createdAt : '',\n };\n};\n\nconst toDryRun = (plan: MarkdownChangePlan): MarkdownChangeDryRun => ({\n status: 'dry_run',\n note: plan.note,\n ...(plan.match ? { match: plan.match } : {}),\n ...(plan.placement ? { placement: plan.placement } : {}),\n proposed: plan.proposed,\n warnings: plan.warnings,\n});\n\nconst toTagIds = (tagIds: string[]) => {\n return tagIds.map((tagId) => Number(tagId)).filter((tagId) => Number.isSafeInteger(tagId) && tagId > 0);\n};\n\nconst baselineMismatchFailure = (): MarkdownChangeFailure => ({\n status: 'failed',\n reason: 'BASELINE_MISMATCH',\n message: 'The markdown write baseline does not match the current note.',\n});\n\nconst missingBaselineFailure = (): MarkdownChangeFailure => ({\n status: 'failed',\n reason: 'MISSING_BASELINE',\n message: 'expectedUpdatedAt or baseMarkdownSha256 is required for markdown writes.',\n});\n\nconst unsupportedMarkdownStructureFailure = (): MarkdownChangeFailure => ({\n status: 'failed',\n reason: 'UNSUPPORTED_MARKDOWN_STRUCTURE',\n message: 'This note contains BlockNote content that cannot be safely represented as Markdown.',\n});\n\nconst referenceStructureFailure = (): MarkdownChangeFailure => ({\n status: 'failed',\n reason: 'REFERENCE_STRUCTURE_DECREASED',\n message: 'The markdown write would reduce structured note reference links.',\n});\n\nconst markdownImportLossyFailure = (): MarkdownChangeFailure => ({\n status: 'failed',\n reason: 'MARKDOWN_IMPORT_LOSSY',\n message: 'The markdown write would lose literal text during Markdown import.',\n});\n\nconst invalidPropertyInputFailure = (error: InvalidNotePropertyInputError): MarkdownChangeFailure => ({\n status: 'failed',\n reason: 'INVALID_PROPERTY_INPUT',\n message: error.message,\n});\n\nconst mapGuardedWriteError = (error: unknown): MarkdownChangeFailure | null => {\n if (isNoteVersionConflictError(error) || isInvalidNoteVersionError(error)) {\n return baselineMismatchFailure();\n }\n\n if (isMissingNoteVersionError(error)) {\n return missingBaselineFailure();\n }\n\n return null;\n};\n\nconst resolveMetadataPropertyPatch = async (\n deps: MarkdownIntentWriteDeps,\n patch: NotePropertiesByKeyPatchInput | undefined,\n): Promise<NotePropertiesPatchInput | MarkdownChangeFailure | undefined> => {\n if (patch === undefined) {\n return undefined;\n }\n\n if (!deps.resolvePropertyPatch || !deps.validatePropertyPatch) {\n throw new Error('Metadata property patch dependencies are not configured.');\n }\n\n try {\n const resolvedPatch = await deps.resolvePropertyPatch(patch);\n return deps.validatePropertyPatch(resolvedPatch);\n } catch (error) {\n if (error instanceof InvalidNotePropertyInputError) {\n return invalidPropertyInputFailure(error);\n }\n\n throw error;\n }\n};\n\nconst noteVersionMatches = (expectedUpdatedAt: string | undefined, currentUpdatedAt: Date) => {\n try {\n const expectedTimestamp = parseNoteVersion(expectedUpdatedAt);\n\n return expectedTimestamp !== null && expectedTimestamp === currentUpdatedAt.getTime();\n } catch {\n return false;\n }\n};\n\nconst getUnsupportedSourceFailure = (deps: MarkdownIntentWriteDeps, note: MarkdownIntentNoteRecord) => {\n if (deps.hasUnsupportedMarkdownBlocks?.(note.content)) {\n return unsupportedMarkdownStructureFailure();\n }\n\n return null;\n};\n\nconst applyMarkdownPlan = async (\n deps: MarkdownIntentWriteDeps,\n input: {\n noteId: number;\n noteUpdatedAt: string;\n beforeContentJson: string;\n plan: Extract<MarkdownPatchPlanResult, { status: 'dry_run' }>;\n expectedUpdatedAt?: string;\n policy?: MarkdownWritePolicy;\n summary: string;\n force?: boolean;\n },\n): Promise<AppliedMarkdownWriteResult | MarkdownChangeFailure> => {\n const content = await deps.parseMarkdownToContentJson(input.plan.afterMarkdown);\n const literalAngleBracketTokens = extractLiteralAngleBracketTextTokens(input.plan.afterMarkdown);\n const shouldCheckMarkdownImportLoss =\n literalAngleBracketTokens.length > 0 || hasNumericTildeRangeMarkers(input.plan.afterMarkdown);\n\n if (shouldCheckMarkdownImportLoss) {\n const importedMarkdown = await deps.renderMarkdown(content);\n\n if (\n hasLiteralAngleBracketTextTokenLoss(input.plan.afterMarkdown, importedMarkdown) ||\n hasNumericTildeRangeMarkerLoss(input.plan.afterMarkdown, importedMarkdown)\n ) {\n return markdownImportLossyFailure();\n }\n }\n\n const beforeReferenceCount = deps.countReferenceInlines?.(input.beforeContentJson) ?? 0;\n const afterReferenceCount = deps.countReferenceInlines?.(content) ?? 0;\n\n if (input.policy?.preserveReferences !== false && afterReferenceCount < beforeReferenceCount) {\n return referenceStructureFailure();\n }\n\n const tagIds = toTagIds(deps.extractTagIds(content));\n let updateResult: GuardedNoteWriteResult | null;\n\n try {\n updateResult = await deps.updateNote({\n id: input.noteId,\n data: {\n content,\n tagIds,\n },\n expectedUpdatedAt: input.expectedUpdatedAt ?? input.noteUpdatedAt,\n snapshotMeta: MCP_SNAPSHOT_META,\n ...(input.force ? { force: true } : {}),\n });\n } catch (error) {\n const mappedError = mapGuardedWriteError(error);\n\n if (mappedError) {\n return mappedError;\n }\n\n throw error;\n }\n\n if (!updateResult) {\n return {\n status: 'failed',\n reason: 'TARGET_NOT_FOUND',\n message: 'The requested note was not found.',\n };\n }\n\n return {\n status: 'applied',\n note: {\n id: String(updateResult.note.id),\n updatedAt: updateResult.note.updatedAt.toISOString(),\n },\n change: {\n summary: input.summary,\n changedLineCount: input.plan.proposed.changedLineCount,\n changedCharCount: input.plan.proposed.changedCharCount,\n },\n snapshot: serializeSnapshot(updateResult.snapshot),\n };\n};\n\nconst mapPlanResult = async (\n deps: MarkdownIntentWriteDeps,\n input: {\n noteId: number;\n noteUpdatedAt: string;\n beforeContentJson: string;\n plan: MarkdownPatchPlanResult | MarkdownAppendPlanResult | MarkdownReplacePlanResult;\n dryRun?: boolean;\n expectedUpdatedAt?: string;\n policy?: MarkdownWritePolicy;\n summary: string;\n force?: boolean;\n },\n): Promise<MarkdownIntentWriteResult> => {\n if (input.plan.status !== 'dry_run') {\n return input.plan;\n }\n\n if (input.dryRun ?? true) {\n return toDryRun(input.plan);\n }\n\n return applyMarkdownPlan(deps, {\n noteId: input.noteId,\n noteUpdatedAt: input.noteUpdatedAt,\n beforeContentJson: input.beforeContentJson,\n plan: input.plan,\n expectedUpdatedAt: input.expectedUpdatedAt,\n policy: input.policy,\n summary: input.summary,\n ...(input.force ? { force: true } : {}),\n });\n};\n\nexport const createMarkdownIntentWriteService = (deps: MarkdownIntentWriteDeps) => ({\n patchNoteMarkdown: async (input: PatchNoteMarkdownInput): Promise<MarkdownIntentWriteResult> => {\n const note = await deps.findNoteById(input.id);\n\n if (!note) {\n return {\n status: 'failed',\n reason: 'TARGET_NOT_FOUND',\n message: 'The requested note was not found.',\n };\n }\n\n const unsupportedFailure = getUnsupportedSourceFailure(deps, note);\n\n if (unsupportedFailure) {\n return unsupportedFailure;\n }\n\n const noteSnapshot = await serializeNoteSnapshot(note, deps.renderMarkdown);\n const plan = buildMarkdownPatchPlan({\n note: noteSnapshot,\n expectedUpdatedAt: input.expectedUpdatedAt,\n baseMarkdownSha256: input.baseMarkdownSha256,\n intent: input.intent,\n selector: input.selector,\n operation: input.operation,\n policy: input.policy,\n });\n\n return mapPlanResult(deps, {\n noteId: input.id,\n noteUpdatedAt: noteSnapshot.updatedAt,\n beforeContentJson: note.content,\n plan,\n dryRun: input.dryRun,\n expectedUpdatedAt: input.expectedUpdatedAt,\n policy: input.policy,\n summary: input.intent,\n });\n },\n\n appendNoteMarkdown: async (input: AppendNoteMarkdownInput): Promise<MarkdownIntentWriteResult> => {\n const note = await deps.findNoteById(input.id);\n\n if (!note) {\n return {\n status: 'failed',\n reason: 'TARGET_NOT_FOUND',\n message: 'The requested note was not found.',\n };\n }\n\n const unsupportedFailure = getUnsupportedSourceFailure(deps, note);\n\n if (unsupportedFailure) {\n return unsupportedFailure;\n }\n\n const noteSnapshot = await serializeNoteSnapshot(note, deps.renderMarkdown);\n const plan = buildMarkdownAppendPlan({\n note: noteSnapshot,\n expectedUpdatedAt: input.expectedUpdatedAt,\n baseMarkdownSha256: input.baseMarkdownSha256,\n intent: input.intent,\n insertion: input.insertion,\n placement: input.placement,\n separator: input.separator,\n policy: input.policy,\n });\n\n return mapPlanResult(deps, {\n noteId: input.id,\n noteUpdatedAt: noteSnapshot.updatedAt,\n beforeContentJson: note.content,\n plan,\n dryRun: input.dryRun,\n expectedUpdatedAt: input.expectedUpdatedAt,\n policy: input.policy,\n summary: input.intent,\n });\n },\n\n replaceNoteMarkdown: async (input: ReplaceNoteMarkdownInput): Promise<MarkdownIntentWriteResult> => {\n const note = await deps.findNoteById(input.id);\n\n if (!note) {\n return {\n status: 'failed',\n reason: 'TARGET_NOT_FOUND',\n message: 'The requested note was not found.',\n };\n }\n\n const unsupportedFailure = getUnsupportedSourceFailure(deps, note);\n\n if (unsupportedFailure) {\n return unsupportedFailure;\n }\n\n const noteSnapshot = await serializeNoteSnapshot(note, deps.renderMarkdown);\n const plan = buildMarkdownReplacePlan({\n note: noteSnapshot,\n expectedUpdatedAt: input.expectedUpdatedAt,\n baseMarkdownSha256: input.baseMarkdownSha256,\n intent: input.intent,\n replacement: input.replacement,\n policy: input.policy,\n });\n\n return mapPlanResult(deps, {\n noteId: input.id,\n noteUpdatedAt: noteSnapshot.updatedAt,\n beforeContentJson: note.content,\n plan,\n dryRun: input.dryRun,\n expectedUpdatedAt: input.expectedUpdatedAt,\n policy: input.policy,\n summary: input.intent,\n });\n },\n\n updateNoteMetadata: async (input: UpdateNoteMetadataInput): Promise<MetadataUpdateResult> => {\n const note = await deps.findNoteById(input.id);\n\n if (!note) {\n return {\n status: 'failed',\n reason: 'TARGET_NOT_FOUND',\n message: 'The requested note was not found.',\n };\n }\n\n if (!noteVersionMatches(input.expectedUpdatedAt, note.updatedAt)) {\n return {\n status: 'failed',\n reason: input.expectedUpdatedAt ? 'BASELINE_MISMATCH' : 'MISSING_BASELINE',\n message: 'The metadata update baseline does not match the current note.',\n };\n }\n\n const nextTitle = input.title?.trim();\n const resolvedPropertyPatch = await resolveMetadataPropertyPatch(deps, input.properties);\n\n if (resolvedPropertyPatch && 'status' in resolvedPropertyPatch) {\n return resolvedPropertyPatch;\n }\n\n if (input.title !== undefined && !nextTitle) {\n return {\n status: 'failed',\n reason: 'EMPTY_REPLACEMENT',\n message: 'Note title must not be empty.',\n };\n }\n\n if (\n nextTitle === note.title &&\n (input.layout === undefined || input.layout === note.layout) &&\n resolvedPropertyPatch === undefined\n ) {\n return {\n status: 'failed',\n reason: 'NOOP',\n message: 'The metadata update would not change the note.',\n };\n }\n\n return {\n status: 'dry_run',\n note: {\n id: String(note.id),\n title: note.title,\n updatedAt: note.updatedAt.toISOString(),\n },\n proposed: {\n ...(nextTitle !== undefined ? { title: nextTitle } : {}),\n ...(input.layout !== undefined ? { layout: input.layout } : {}),\n ...(resolvedPropertyPatch ? { properties: resolvedPropertyPatch } : {}),\n },\n warnings: [],\n };\n },\n\n applyNoteMetadata: async (input: UpdateNoteMetadataInput): Promise<MetadataUpdateResult> => {\n const preview = await createMarkdownIntentWriteService(deps).updateNoteMetadata(input);\n\n if (preview.status !== 'dry_run') {\n return preview;\n }\n\n if (input.properties !== undefined) {\n if (!deps.updateProperties) {\n throw new Error('Metadata property write dependency is not configured.');\n }\n\n let updateResult: Awaited<ReturnType<NonNullable<MarkdownIntentWriteDeps['updateProperties']>>>;\n\n try {\n updateResult = await deps.updateProperties({\n id: input.id,\n patch: preview.proposed.properties ?? { set: [], deleteKeys: [] },\n expectedUpdatedAt: input.expectedUpdatedAt,\n noteData: {\n ...(preview.proposed.title !== undefined ? { title: preview.proposed.title } : {}),\n ...(preview.proposed.layout !== undefined ? { layout: preview.proposed.layout } : {}),\n },\n snapshotMeta: MCP_SNAPSHOT_META,\n });\n } catch (error) {\n const mappedError = mapGuardedWriteError(error);\n\n if (mappedError) {\n return mappedError;\n }\n\n if (error instanceof InvalidNotePropertyInputError) {\n return invalidPropertyInputFailure(error);\n }\n\n throw error;\n }\n\n if (!updateResult) {\n return {\n status: 'failed',\n reason: 'TARGET_NOT_FOUND',\n message: 'The requested note was not found.',\n };\n }\n\n return {\n status: 'applied',\n note: {\n id: String(updateResult.note.id),\n title: updateResult.note.title,\n layout: updateResult.note.layout,\n updatedAt: updateResult.note.updatedAt.toISOString(),\n },\n snapshot: serializeSnapshot(updateResult.snapshot),\n };\n }\n\n let updateResult: GuardedNoteWriteResult | null;\n\n try {\n updateResult = await deps.updateNote({\n id: input.id,\n data: {\n ...(preview.proposed.title !== undefined ? { title: preview.proposed.title } : {}),\n ...(preview.proposed.layout !== undefined ? { layout: preview.proposed.layout } : {}),\n },\n expectedUpdatedAt: input.expectedUpdatedAt,\n snapshotMeta: MCP_SNAPSHOT_META,\n });\n } catch (error) {\n const mappedError = mapGuardedWriteError(error);\n\n if (mappedError) {\n return mappedError;\n }\n\n throw error;\n }\n\n if (!updateResult) {\n return {\n status: 'failed',\n reason: 'TARGET_NOT_FOUND',\n message: 'The requested note was not found.',\n };\n }\n\n return {\n status: 'applied',\n note: {\n id: String(updateResult.note.id),\n title: updateResult.note.title,\n layout: updateResult.note.layout,\n updatedAt: updateResult.note.updatedAt.toISOString(),\n },\n snapshot: serializeSnapshot(updateResult.snapshot),\n };\n },\n});\n\nexport const defaultMarkdownIntentWriteService = createMarkdownIntentWriteService({\n findNoteById: (id) =>\n models.note.findUnique({\n where: { id },\n select: {\n id: true,\n title: true,\n content: true,\n layout: true,\n updatedAt: true,\n },\n }),\n renderMarkdown: blocksToMarkdown,\n parseMarkdownToContentJson: markdownToBlocksJson,\n extractTagIds: extractTagIdsFromContentJson,\n countReferenceInlines: countReferenceInlinesFromContentJson,\n hasUnsupportedMarkdownBlocks,\n updateNote: updateNoteWithVersionGuardAndSnapshot,\n resolvePropertyPatch: resolveNotePropertiesPatchValueTypes,\n validatePropertyPatch: validateNotePropertiesPatchValues,\n updateProperties: updateNotePropertiesWithVersionGuardAndSnapshot,\n});\n\nexport const patchNoteMarkdown = async (input: PatchNoteMarkdownInput) => {\n return defaultMarkdownIntentWriteService.patchNoteMarkdown(input);\n};\n\nexport const appendNoteMarkdown = async (input: AppendNoteMarkdownInput) => {\n return defaultMarkdownIntentWriteService.appendNoteMarkdown(input);\n};\n\nexport const replaceNoteMarkdown = async (input: ReplaceNoteMarkdownInput) => {\n return defaultMarkdownIntentWriteService.replaceNoteMarkdown(input);\n};\n\nexport const updateNoteMetadata = async (input: UpdateNoteMetadataInput & { dryRun?: boolean }) => {\n if (input.dryRun ?? true) {\n return defaultMarkdownIntentWriteService.updateNoteMetadata(input);\n }\n\n return defaultMarkdownIntentWriteService.applyNoteMetadata(input);\n};\n\nexport const calculateNoteMarkdownSha256 = (markdown: string) => {\n return calculateMarkdownSha256(markdown);\n};\n"],"mappings":"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","names":["updateResult"]}
|