ocean-brain 0.7.4 → 0.8.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.
Files changed (111) hide show
  1. package/dist/index.js +3 -3
  2. package/dist/mcp.js +180 -736
  3. package/package.json +4 -1
  4. package/server/client/dist/assets/ArrowRight.es-C4zlc54Z.js +1 -0
  5. package/server/client/dist/assets/{Calendar-Bz7jheg6.js → Calendar-COrN6Hjv.js} +2 -2
  6. package/server/client/dist/assets/Callout-BK0K9E74.js +1 -0
  7. package/server/client/dist/assets/Copy.es-zm8f_XXX.js +1 -0
  8. package/server/client/dist/assets/Graph-BH1fzhue.js +1 -0
  9. package/server/client/dist/assets/{Image-DxWhlIDG.js → Image-KXuHOG4b.js} +1 -1
  10. package/server/client/dist/assets/Image.es-BKahRbIm.js +1 -0
  11. package/server/client/dist/assets/Note-C143cKKw.js +12 -0
  12. package/server/client/dist/assets/Plus.es-BqeC8T8h.js +1 -0
  13. package/server/client/dist/assets/Reminders-BYG5rz1M.js +1 -0
  14. package/server/client/dist/assets/Search-DBWsIMDP.js +1 -0
  15. package/server/client/dist/assets/{SurfaceCard-CfL1jD-O.js → SurfaceCard-CNSQfYfM.js} +1 -1
  16. package/server/client/dist/assets/Tag-5aCfSO8Y.js +1 -0
  17. package/server/client/dist/assets/TagNotes-BPZjN-6l.js +1 -0
  18. package/server/client/dist/assets/Trash.es-CRQkTnXZ.js +1 -0
  19. package/server/client/dist/assets/ViewNotes-DGLNF96x.js +1 -0
  20. package/server/client/dist/assets/ViewSectionDialog-CzskgmMF.js +102 -0
  21. package/server/client/dist/assets/Views-DR5jT23G.js +1 -0
  22. package/server/client/dist/assets/{graph-vendor-CUxe67Lr.js → graph-vendor-UTvF2NS_.js} +2 -2
  23. package/server/client/dist/assets/image.api-8dlMwzMd.js +17 -0
  24. package/server/client/dist/assets/{index-C5BGzDgt.css → index-BEUqDuAZ.css} +1 -1
  25. package/server/client/dist/assets/{index-DiMt3Dz4.js → index-DGIAh3ZY.js} +1 -1
  26. package/server/client/dist/assets/index-VHp17GQX.js +342 -0
  27. package/server/client/dist/assets/manage-image-RqtWKas2.js +1 -0
  28. package/server/client/dist/assets/{manage-image-detail-Bqw8NURO.js → manage-image-detail-BTSIbLlQ.js} +1 -1
  29. package/server/client/dist/assets/mcp-EDurbggR.js +4 -0
  30. package/server/client/dist/assets/mcp-admin-adapter-DmGUo5G8.js +1 -0
  31. package/server/client/dist/assets/{note-core-Z6kqulGB.js → note-core-BklwyZHk.js} +1 -1
  32. package/server/client/dist/assets/{note-vendor-i1M2FSI2.js → note-vendor-DkYKUmLo.js} +1 -1
  33. package/server/client/dist/assets/{placeholder-Ro00byT7.js → placeholder-DeKgSBnC.js} +4 -4
  34. package/server/client/dist/assets/{properties-Tid6-ghT.js → properties-BjrZvOYn.js} +1 -1
  35. package/server/client/dist/assets/tag.api-Dl8DQd0m.js +21 -0
  36. package/server/client/dist/assets/trash-C5ntddLu.js +1 -0
  37. package/server/client/dist/assets/{useReminderMutate-BWymIujb.js → useReminderMutate-CoXXqJY2.js} +1 -1
  38. package/server/client/dist/index.html +5 -5
  39. package/server/dist/app.js +2 -2
  40. package/server/dist/app.js.map +1 -1
  41. package/server/dist/features/auth/http/api.js +5 -1
  42. package/server/dist/features/auth/http/api.js.map +1 -1
  43. package/server/dist/features/auth/http/login-page.js +1 -1
  44. package/server/dist/features/auth/http/pages.js +8 -1
  45. package/server/dist/features/auth/http/pages.js.map +1 -1
  46. package/server/dist/features/auth/service.js +16 -7
  47. package/server/dist/features/auth/service.js.map +1 -1
  48. package/server/dist/features/image/http/upload.js +34 -23
  49. package/server/dist/features/image/http/upload.js.map +1 -1
  50. package/server/dist/features/image/services/validation.js +111 -0
  51. package/server/dist/features/image/services/validation.js.map +1 -0
  52. package/server/dist/features/mcp-admin/http/handlers.js +11 -3
  53. package/server/dist/features/mcp-admin/http/handlers.js.map +1 -1
  54. package/server/dist/features/note/http/mcp.js +8 -43
  55. package/server/dist/features/note/http/mcp.js.map +1 -1
  56. package/server/dist/features/note/services/cleanup.js +2 -2
  57. package/server/dist/features/note/services/cleanup.js.map +1 -1
  58. package/server/dist/features/note/services/markdown-intent-write.js +11 -43
  59. package/server/dist/features/note/services/markdown-intent-write.js.map +1 -1
  60. package/server/dist/features/note/services/markdown-patch.js +4 -123
  61. package/server/dist/features/note/services/markdown-patch.js.map +1 -1
  62. package/server/dist/features/note/services/write.js +13 -13
  63. package/server/dist/features/note/services/write.js.map +1 -1
  64. package/server/dist/features/tag/graphql/tag.query.resolver.js +16 -1
  65. package/server/dist/features/tag/graphql/tag.query.resolver.js.map +1 -1
  66. package/server/dist/features/tag/graphql/tag.type-defs.js +2 -0
  67. package/server/dist/features/tag/graphql/tag.type-defs.js.map +1 -1
  68. package/server/dist/modules/app-version.js +105 -0
  69. package/server/dist/modules/app-version.js.map +1 -0
  70. package/server/dist/modules/auth-guard.js +21 -2
  71. package/server/dist/modules/auth-guard.js.map +1 -1
  72. package/server/dist/modules/auth-redirect.js +10 -0
  73. package/server/dist/modules/auth-redirect.js.map +1 -0
  74. package/server/dist/modules/mcp-auth.js +62 -1
  75. package/server/dist/modules/mcp-auth.js.map +1 -1
  76. package/server/dist/modules/rate-limit.js +15 -1
  77. package/server/dist/modules/rate-limit.js.map +1 -1
  78. package/server/dist/modules/server-events-handler.js +17 -0
  79. package/server/dist/modules/server-events-handler.js.map +1 -1
  80. package/server/dist/modules/session-store.js +149 -0
  81. package/server/dist/modules/session-store.js.map +1 -0
  82. package/server/dist/paths.js +1 -0
  83. package/server/dist/paths.js.map +1 -1
  84. package/server/dist/routes/api.js +39 -20
  85. package/server/dist/routes/api.js.map +1 -1
  86. package/server/dist/routes/auth-pages.js +13 -2
  87. package/server/dist/routes/auth-pages.js.map +1 -1
  88. package/server/dist/routes/client.js +63 -3
  89. package/server/dist/routes/client.js.map +1 -1
  90. package/server/dist/routes/graphql.js +23 -19
  91. package/server/dist/routes/graphql.js.map +1 -1
  92. package/server/client/dist/assets/Callout-DlFLkTCG.js +0 -1
  93. package/server/client/dist/assets/Graph-BdxtJvog.js +0 -1
  94. package/server/client/dist/assets/Image.es-BFodqKS5.js +0 -1
  95. package/server/client/dist/assets/Note-BgMxsWZT.js +0 -22
  96. package/server/client/dist/assets/Plus.es-Yq7J1Ur4.js +0 -1
  97. package/server/client/dist/assets/Reminders-CUsR56ff.js +0 -1
  98. package/server/client/dist/assets/Search-DncrGgOZ.js +0 -1
  99. package/server/client/dist/assets/Tag-CKDLs2Y6.js +0 -1
  100. package/server/client/dist/assets/TagNotes-ByX_Qias.js +0 -1
  101. package/server/client/dist/assets/Trash.es-BPrF6TPV.js +0 -1
  102. package/server/client/dist/assets/ViewNotes-r1kxKZ8O.js +0 -1
  103. package/server/client/dist/assets/ViewSectionTableRenderer-DQ4UeCnm.js +0 -102
  104. package/server/client/dist/assets/Views-FzFBtNT2.js +0 -1
  105. package/server/client/dist/assets/image.api-Bcg3TFCG.js +0 -17
  106. package/server/client/dist/assets/index-BFfQKAUY.js +0 -361
  107. package/server/client/dist/assets/manage-image-DzDlncCM.js +0 -1
  108. package/server/client/dist/assets/mcp-BqasqTWC.js +0 -1
  109. package/server/client/dist/assets/trash-bHK02-Up.js +0 -1
  110. package/server/dist/features/image/services/remote-fetch.js +0 -176
  111. package/server/dist/features/image/services/remote-fetch.js.map +0 -1
@@ -38,15 +38,6 @@ const resolveOptionalString = (value, code, message) => {
38
38
  }
39
39
  throw createAppError(400, code, message);
40
40
  };
41
- const resolveOptionalBoolean = (value, code, message) => {
42
- if (value === void 0) {
43
- return void 0;
44
- }
45
- if (typeof value === "boolean") {
46
- return value;
47
- }
48
- throw createAppError(400, code, message);
49
- };
50
41
  const resolveMetadataPropertyPatch = (value) => {
51
42
  if (value === void 0) {
52
43
  return void 0;
@@ -117,24 +108,6 @@ const resolveMarkdownWritePolicy = (value) => {
117
108
  }
118
109
  policy.allowNoop = value.allowNoop;
119
110
  }
120
- if (value.maxChangedChars !== void 0) {
121
- if (!isNonNegativeInteger(value.maxChangedChars)) {
122
- throw createAppError(400, "INVALID_MARKDOWN_POLICY", "maxChangedChars must be a non-negative integer.");
123
- }
124
- policy.maxChangedChars = value.maxChangedChars;
125
- }
126
- if (value.maxChangedLines !== void 0) {
127
- if (!isNonNegativeInteger(value.maxChangedLines)) {
128
- throw createAppError(400, "INVALID_MARKDOWN_POLICY", "maxChangedLines must be a non-negative integer.");
129
- }
130
- policy.maxChangedLines = value.maxChangedLines;
131
- }
132
- if (value.diffPreviewMaxChars !== void 0) {
133
- if (!isNonNegativeInteger(value.diffPreviewMaxChars)) {
134
- throw createAppError(400, "INVALID_MARKDOWN_POLICY", "diffPreviewMaxChars must be a non-negative integer.");
135
- }
136
- policy.diffPreviewMaxChars = value.diffPreviewMaxChars;
137
- }
138
111
  if (value.preserveTags !== void 0) {
139
112
  if (!PRESERVATION_POLICIES.has(value.preserveTags)) {
140
113
  throw createAppError(400, "INVALID_MARKDOWN_POLICY", "preserveTags must be boolean or warn.");
@@ -368,7 +341,7 @@ const createMcpNoteWriteBaselineHandler = (findNoteBaseline = async (id) => mode
368
341
  };
369
342
  const createMcpPatchNoteMarkdownHandler = (patchMarkdown = patchNoteMarkdown, emitEvent = emitServerEvent) => {
370
343
  return async (req, res) => {
371
- const { id, expectedUpdatedAt, baseMarkdownSha256, intent, selector, operation, policy, dryRun } = req.body ?? {};
344
+ const { id, expectedUpdatedAt, baseMarkdownSha256, intent, selector, operation, policy } = req.body ?? {};
372
345
  const noteId = resolvePositiveNoteId(id);
373
346
  const resolvedExpectedUpdatedAt = resolveOptionalString(
374
347
  expectedUpdatedAt,
@@ -380,7 +353,6 @@ const createMcpPatchNoteMarkdownHandler = (patchMarkdown = patchNoteMarkdown, em
380
353
  "INVALID_MARKDOWN_HASH",
381
354
  "baseMarkdownSha256 must be a string."
382
355
  );
383
- const resolvedDryRun = resolveOptionalBoolean(dryRun, "INVALID_DRY_RUN", "dryRun must be a boolean.");
384
356
  if (typeof intent !== "string") {
385
357
  throw createAppError(400, "INVALID_PATCH_INTENT", "Patch intent must be a string.");
386
358
  }
@@ -391,8 +363,7 @@ const createMcpPatchNoteMarkdownHandler = (patchMarkdown = patchNoteMarkdown, em
391
363
  intent,
392
364
  selector: resolvePatchSelector(selector),
393
365
  operation: resolvePatchOperation(operation),
394
- policy: resolveMarkdownWritePolicy(policy),
395
- dryRun: resolvedDryRun
366
+ policy: resolveMarkdownWritePolicy(policy)
396
367
  });
397
368
  if (result.status === "applied") {
398
369
  emitEvent({
@@ -407,7 +378,7 @@ const createMcpPatchNoteMarkdownHandler = (patchMarkdown = patchNoteMarkdown, em
407
378
  };
408
379
  const createMcpAppendNoteMarkdownHandler = (appendMarkdown = appendNoteMarkdown, emitEvent = emitServerEvent) => {
409
380
  return async (req, res) => {
410
- const { id, expectedUpdatedAt, baseMarkdownSha256, intent, insertion, placement, separator, policy, dryRun } = req.body ?? {};
381
+ const { id, expectedUpdatedAt, baseMarkdownSha256, intent, insertion, placement, separator, policy } = req.body ?? {};
411
382
  const noteId = resolvePositiveNoteId(id);
412
383
  const resolvedExpectedUpdatedAt = resolveOptionalString(
413
384
  expectedUpdatedAt,
@@ -419,7 +390,6 @@ const createMcpAppendNoteMarkdownHandler = (appendMarkdown = appendNoteMarkdown,
419
390
  "INVALID_MARKDOWN_HASH",
420
391
  "baseMarkdownSha256 must be a string."
421
392
  );
422
- const resolvedDryRun = resolveOptionalBoolean(dryRun, "INVALID_DRY_RUN", "dryRun must be a boolean.");
423
393
  if (typeof intent !== "string") {
424
394
  throw createAppError(400, "INVALID_APPEND_INTENT", "Append intent must be a string.");
425
395
  }
@@ -434,8 +404,7 @@ const createMcpAppendNoteMarkdownHandler = (appendMarkdown = appendNoteMarkdown,
434
404
  insertion,
435
405
  placement: resolveAppendPlacement(placement),
436
406
  separator: resolveSeparator(separator),
437
- policy: resolveMarkdownWritePolicy(policy),
438
- dryRun: resolvedDryRun
407
+ policy: resolveMarkdownWritePolicy(policy)
439
408
  });
440
409
  if (result.status === "applied") {
441
410
  emitEvent({
@@ -450,7 +419,7 @@ const createMcpAppendNoteMarkdownHandler = (appendMarkdown = appendNoteMarkdown,
450
419
  };
451
420
  const createMcpReplaceNoteMarkdownHandler = (replaceMarkdown = replaceNoteMarkdown, emitEvent = emitServerEvent) => {
452
421
  return async (req, res) => {
453
- const { id, expectedUpdatedAt, baseMarkdownSha256, intent, replacement, policy, dryRun } = req.body ?? {};
422
+ const { id, expectedUpdatedAt, baseMarkdownSha256, intent, replacement, policy } = req.body ?? {};
454
423
  const noteId = resolvePositiveNoteId(id);
455
424
  const resolvedExpectedUpdatedAt = resolveOptionalString(
456
425
  expectedUpdatedAt,
@@ -462,7 +431,6 @@ const createMcpReplaceNoteMarkdownHandler = (replaceMarkdown = replaceNoteMarkdo
462
431
  "INVALID_MARKDOWN_HASH",
463
432
  "baseMarkdownSha256 must be a string."
464
433
  );
465
- const resolvedDryRun = resolveOptionalBoolean(dryRun, "INVALID_DRY_RUN", "dryRun must be a boolean.");
466
434
  if (typeof intent !== "string") {
467
435
  throw createAppError(400, "INVALID_REPLACE_INTENT", "Replace intent must be a string.");
468
436
  }
@@ -475,8 +443,7 @@ const createMcpReplaceNoteMarkdownHandler = (replaceMarkdown = replaceNoteMarkdo
475
443
  baseMarkdownSha256: resolvedBaseMarkdownSha256,
476
444
  intent,
477
445
  replacement,
478
- policy: resolveMarkdownWritePolicy(policy),
479
- dryRun: resolvedDryRun
446
+ policy: resolveMarkdownWritePolicy(policy)
480
447
  });
481
448
  if (result.status === "applied") {
482
449
  emitEvent({
@@ -491,11 +458,10 @@ const createMcpReplaceNoteMarkdownHandler = (replaceMarkdown = replaceNoteMarkdo
491
458
  };
492
459
  const createMcpUpdateNoteMetadataHandler = (updateMetadata = updateNoteMetadata, emitEvent = emitServerEvent) => {
493
460
  return async (req, res) => {
494
- const { id, expectedUpdatedAt, title, layout, properties, dryRun } = req.body ?? {};
461
+ const { id, expectedUpdatedAt, title, layout, properties } = req.body ?? {};
495
462
  const noteId = resolvePositiveNoteId(id);
496
463
  const resolvedLayout = resolveNoteLayout(layout);
497
464
  const resolvedProperties = resolveMetadataPropertyPatch(properties);
498
- const resolvedDryRun = resolveOptionalBoolean(dryRun, "INVALID_DRY_RUN", "dryRun must be a boolean.");
499
465
  if (typeof expectedUpdatedAt !== "string") {
500
466
  throw createAppError(400, "INVALID_NOTE_VERSION", "expectedUpdatedAt must be a string.");
501
467
  }
@@ -513,8 +479,7 @@ const createMcpUpdateNoteMetadataHandler = (updateMetadata = updateNoteMetadata,
513
479
  expectedUpdatedAt,
514
480
  ...title !== void 0 ? { title } : {},
515
481
  ...resolvedLayout ? { layout: resolvedLayout } : {},
516
- ...resolvedProperties !== void 0 ? { properties: resolvedProperties } : {},
517
- dryRun: resolvedDryRun
482
+ ...resolvedProperties !== void 0 ? { properties: resolvedProperties } : {}
518
483
  });
519
484
  if (result.status === "applied") {
520
485
  emitEvent({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/features/note/http/mcp.ts"],"sourcesContent":["import {\n createNoteFromMarkdown,\n InvalidNoteAuthoringInputError,\n updateNoteFromMarkdown,\n} from '~/features/note/services/authoring.js';\nimport { deleteNoteById } from '~/features/note/services/cleanup.js';\nimport {\n appendNoteMarkdown,\n patchNoteMarkdown,\n replaceNoteMarkdown,\n updateNoteMetadata,\n} from '~/features/note/services/markdown-intent-write.js';\nimport type {\n MarkdownAppendPlacement,\n MarkdownChangePolicy,\n MarkdownPatchOperation,\n MarkdownPatchSelector,\n} from '~/features/note/services/markdown-patch.js';\nimport type { NotePropertiesByKeyPatchInput } from '~/features/note/services/properties.js';\nimport { MCP_SNAPSHOT_META } from '~/features/note/services/snapshot.js';\nimport models, { type NoteLayout } from '~/models.js';\nimport { createAppError } from '~/modules/error-handler.js';\nimport { emitServerEvent, type ServerEventInput } from '~/modules/server-events.js';\nimport type { Controller } from '~/types/index.js';\n\nconst NOTE_LAYOUTS = new Set<NoteLayout>(['narrow', 'wide', 'full']);\n\nconst POSITION_HINTS = new Set(['first', 'last']);\nconst PRESERVATION_POLICIES = new Set<unknown>([true, false, 'warn']);\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return typeof value === 'object' && value !== null;\n};\n\nconst resolveNoteLayout = (value: unknown): NoteLayout | null | undefined => {\n if (value === undefined) {\n return undefined;\n }\n\n if (typeof value === 'string' && NOTE_LAYOUTS.has(value as NoteLayout)) {\n return value as NoteLayout;\n }\n\n return null;\n};\n\nconst resolveOptionalString = (value: unknown, code: string, message: string) => {\n if (value === undefined) {\n return undefined;\n }\n\n if (typeof value === 'string') {\n return value;\n }\n\n throw createAppError(400, code, message);\n};\n\nconst resolveOptionalBoolean = (value: unknown, code: string, message: string) => {\n if (value === undefined) {\n return undefined;\n }\n\n if (typeof value === 'boolean') {\n return value;\n }\n\n throw createAppError(400, code, message);\n};\n\nconst resolveMetadataPropertyPatch = (value: unknown): NotePropertiesByKeyPatchInput | undefined => {\n if (value === undefined) {\n return undefined;\n }\n\n if (!isRecord(value)) {\n throw createAppError(400, 'INVALID_NOTE_PROPERTIES', 'Properties patch must be an object.');\n }\n\n const set =\n value.set === undefined\n ? undefined\n : Array.isArray(value.set)\n ? value.set.map((item) => {\n if (!isRecord(item) || typeof item.key !== 'string' || typeof item.value !== 'string') {\n throw createAppError(\n 400,\n 'INVALID_NOTE_PROPERTIES',\n 'Property set items must include string key and value fields.',\n );\n }\n\n return {\n key: item.key,\n value: item.value,\n };\n })\n : null;\n\n if (set === null) {\n throw createAppError(400, 'INVALID_NOTE_PROPERTIES', 'Property set must be an array.');\n }\n\n const deleteKeys =\n value.deleteKeys === undefined\n ? undefined\n : Array.isArray(value.deleteKeys)\n ? value.deleteKeys.map((key) => {\n if (typeof key !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_PROPERTIES', 'Property deleteKeys must be strings.');\n }\n\n return key;\n })\n : null;\n\n if (deleteKeys === null) {\n throw createAppError(400, 'INVALID_NOTE_PROPERTIES', 'Property deleteKeys must be an array.');\n }\n\n return {\n ...(set !== undefined ? { set } : {}),\n ...(deleteKeys !== undefined ? { deleteKeys } : {}),\n };\n};\n\nconst resolvePositiveNoteId = (value: unknown) => {\n const noteId = Number(value);\n\n if (!Number.isInteger(noteId) || noteId <= 0) {\n throw createAppError(400, 'INVALID_NOTE_ID', 'A valid note id is required.');\n }\n\n return noteId;\n};\n\nconst serializeNoteWriteBaseline = (note: { id: number | string; updatedAt: Date | string }) => {\n return {\n id: String(note.id),\n updatedAt: note.updatedAt instanceof Date ? note.updatedAt.toISOString() : note.updatedAt,\n };\n};\n\nconst isNonNegativeInteger = (value: unknown): value is number => {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n};\n\nconst isPositiveInteger = (value: unknown): value is number => {\n return typeof value === 'number' && Number.isInteger(value) && value > 0;\n};\n\nconst resolveMarkdownWritePolicy = (value: unknown): MarkdownChangePolicy | undefined => {\n if (value === undefined) {\n return undefined;\n }\n\n if (!isRecord(value)) {\n throw createAppError(400, 'INVALID_MARKDOWN_POLICY', 'Markdown write policy must be an object.');\n }\n\n const policy: MarkdownChangePolicy = {};\n\n if (value.allowNoop !== undefined) {\n if (typeof value.allowNoop !== 'boolean') {\n throw createAppError(400, 'INVALID_MARKDOWN_POLICY', 'allowNoop must be a boolean.');\n }\n policy.allowNoop = value.allowNoop;\n }\n\n if (value.maxChangedChars !== undefined) {\n if (!isNonNegativeInteger(value.maxChangedChars)) {\n throw createAppError(400, 'INVALID_MARKDOWN_POLICY', 'maxChangedChars must be a non-negative integer.');\n }\n policy.maxChangedChars = value.maxChangedChars;\n }\n\n if (value.maxChangedLines !== undefined) {\n if (!isNonNegativeInteger(value.maxChangedLines)) {\n throw createAppError(400, 'INVALID_MARKDOWN_POLICY', 'maxChangedLines must be a non-negative integer.');\n }\n policy.maxChangedLines = value.maxChangedLines;\n }\n\n if (value.diffPreviewMaxChars !== undefined) {\n if (!isNonNegativeInteger(value.diffPreviewMaxChars)) {\n throw createAppError(400, 'INVALID_MARKDOWN_POLICY', 'diffPreviewMaxChars must be a non-negative integer.');\n }\n policy.diffPreviewMaxChars = value.diffPreviewMaxChars;\n }\n\n if (value.preserveTags !== undefined) {\n if (!PRESERVATION_POLICIES.has(value.preserveTags)) {\n throw createAppError(400, 'INVALID_MARKDOWN_POLICY', 'preserveTags must be boolean or warn.');\n }\n policy.preserveTags = value.preserveTags as MarkdownChangePolicy['preserveTags'];\n }\n\n if (value.preserveReferences !== undefined) {\n if (!PRESERVATION_POLICIES.has(value.preserveReferences)) {\n throw createAppError(400, 'INVALID_MARKDOWN_POLICY', 'preserveReferences must be boolean or warn.');\n }\n policy.preserveReferences = value.preserveReferences as MarkdownChangePolicy['preserveReferences'];\n }\n\n return policy;\n};\n\nconst resolvePatchSelector = (value: unknown): MarkdownPatchSelector => {\n if (!isRecord(value)) {\n throw createAppError(400, 'INVALID_PATCH_SELECTOR', 'Patch selector must be an object.');\n }\n\n if (value.type === 'exact_text') {\n if (typeof value.text !== 'string') {\n throw createAppError(400, 'INVALID_PATCH_SELECTOR', 'Exact text selector requires text.');\n }\n\n return {\n type: 'exact_text',\n text: value.text,\n ...(value.before !== undefined\n ? {\n before: resolveOptionalString(\n value.before,\n 'INVALID_PATCH_SELECTOR',\n 'Selector before must be a string.',\n ),\n }\n : {}),\n ...(value.after !== undefined\n ? {\n after: resolveOptionalString(\n value.after,\n 'INVALID_PATCH_SELECTOR',\n 'Selector after must be a string.',\n ),\n }\n : {}),\n };\n }\n\n if (value.type === 'match_candidate') {\n const { text, matchIndex, lineStart, matchSha256, surroundingHash, positionHint } = value;\n\n if (\n typeof text !== 'string' ||\n !isNonNegativeInteger(matchIndex) ||\n !isPositiveInteger(lineStart) ||\n typeof matchSha256 !== 'string' ||\n typeof surroundingHash !== 'string'\n ) {\n throw createAppError(400, 'INVALID_PATCH_SELECTOR', 'Match candidate selector has invalid fields.');\n }\n\n if (positionHint !== undefined && !POSITION_HINTS.has(String(positionHint))) {\n throw createAppError(400, 'INVALID_PATCH_SELECTOR', 'positionHint must be first or last.');\n }\n\n return {\n type: 'match_candidate',\n text,\n matchIndex,\n lineStart,\n matchSha256,\n surroundingHash,\n ...(positionHint ? { positionHint: positionHint as 'first' | 'last' } : {}),\n };\n }\n\n throw createAppError(400, 'INVALID_PATCH_SELECTOR', 'Unsupported patch selector type.');\n};\n\nconst resolvePatchOperation = (value: unknown): MarkdownPatchOperation => {\n if (!isRecord(value)) {\n throw createAppError(400, 'INVALID_PATCH_OPERATION', 'Patch operation must be an object.');\n }\n\n if (value.type === 'replace') {\n if (typeof value.replacement !== 'string') {\n throw createAppError(400, 'INVALID_PATCH_OPERATION', 'Replace operation requires replacement.');\n }\n\n return {\n type: 'replace',\n replacement: value.replacement,\n };\n }\n\n if (value.type === 'insert_before' || value.type === 'insert_after') {\n if (typeof value.insertion !== 'string') {\n throw createAppError(400, 'INVALID_PATCH_OPERATION', 'Insert operation requires insertion.');\n }\n\n return {\n type: value.type,\n insertion: value.insertion,\n };\n }\n\n throw createAppError(400, 'INVALID_PATCH_OPERATION', 'Unsupported patch operation type.');\n};\n\nconst resolveAppendPlacement = (value: unknown): MarkdownAppendPlacement | undefined => {\n if (value === undefined) {\n return undefined;\n }\n\n if (!isRecord(value)) {\n throw createAppError(400, 'INVALID_APPEND_PLACEMENT', 'Append placement must be an object.');\n }\n\n if (value.type === 'end') {\n return { type: 'end' };\n }\n\n if (value.type === 'after_heading') {\n if (typeof value.heading !== 'string') {\n throw createAppError(400, 'INVALID_APPEND_PLACEMENT', 'after_heading placement requires heading.');\n }\n\n const { heading, level } = value;\n\n if (typeof heading !== 'string') {\n throw createAppError(400, 'INVALID_APPEND_PLACEMENT', 'after_heading placement requires heading.');\n }\n\n if (level !== undefined && (typeof level !== 'number' || !Number.isInteger(level) || level < 1 || level > 6)) {\n throw createAppError(400, 'INVALID_APPEND_PLACEMENT', 'Heading level must be an integer from 1 to 6.');\n }\n\n return {\n type: 'after_heading',\n heading,\n ...(level !== undefined ? { level } : {}),\n };\n }\n\n throw createAppError(400, 'INVALID_APPEND_PLACEMENT', 'Unsupported append placement type.');\n};\n\nconst resolveSeparator = (value: unknown) => {\n if (value === undefined) {\n return undefined;\n }\n\n if (value === '\\n' || value === '\\n\\n') {\n return value;\n }\n\n throw createAppError(400, 'INVALID_SEPARATOR', 'Separator must be \"\\\\n\" or \"\\\\n\\\\n\".');\n};\n\ntype EmitServerEvent = (event: ServerEventInput) => unknown;\n\nexport const createMcpCreateNoteHandler = (\n createNote = createNoteFromMarkdown,\n emitEvent: EmitServerEvent = emitServerEvent,\n): Controller => {\n return async (req, res) => {\n const { title, markdown, layout } = req.body ?? {};\n const resolvedLayout = resolveNoteLayout(layout);\n\n if (typeof title !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_TITLE', 'A note title is required.');\n }\n\n if (markdown !== undefined && typeof markdown !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_MARKDOWN', 'Note markdown must be a string.');\n }\n\n if (layout !== undefined && resolvedLayout === null) {\n throw createAppError(400, 'INVALID_NOTE_LAYOUT', 'Note layout must be one of narrow, wide, or full.');\n }\n\n try {\n const note = await createNote({\n title,\n ...(markdown !== undefined ? { markdown } : {}),\n ...(resolvedLayout ? { layout: resolvedLayout } : {}),\n });\n\n emitEvent({\n type: 'mcp.note.created',\n source: 'mcp',\n noteId: note.id,\n updatedAt: note.updatedAt,\n });\n\n res.status(200)\n .json({\n created: true,\n note,\n })\n .end();\n } catch (error) {\n if (error instanceof InvalidNoteAuthoringInputError) {\n throw createAppError(400, 'INVALID_NOTE_INPUT', error.message);\n }\n\n throw error;\n }\n };\n};\n\nexport const createMcpUpdateNoteHandler = (\n updateNote = updateNoteFromMarkdown,\n emitEvent: EmitServerEvent = emitServerEvent,\n): Controller => {\n return async (req, res) => {\n const { id, title, markdown, layout, editSessionId } = req.body ?? {};\n const noteId = Number(id);\n const resolvedLayout = resolveNoteLayout(layout);\n\n if (!Number.isInteger(noteId) || noteId <= 0) {\n throw createAppError(400, 'INVALID_NOTE_ID', 'A valid note id is required.');\n }\n\n if (title !== undefined && typeof title !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_TITLE', 'Note title must be a string.');\n }\n\n if (markdown !== undefined && typeof markdown !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_MARKDOWN', 'Note markdown must be a string.');\n }\n\n if (layout !== undefined && resolvedLayout === null) {\n throw createAppError(400, 'INVALID_NOTE_LAYOUT', 'Note layout must be one of narrow, wide, or full.');\n }\n\n if (editSessionId !== undefined && typeof editSessionId !== 'string') {\n throw createAppError(400, 'INVALID_EDIT_SESSION_ID', 'Edit session id must be a string.');\n }\n\n if (title === undefined && markdown === undefined && layout === undefined) {\n throw createAppError(400, 'INVALID_NOTE_INPUT', 'At least one note field must be provided for update.');\n }\n\n try {\n const note = await updateNote({\n id: noteId,\n ...(title !== undefined ? { title } : {}),\n ...(markdown !== undefined ? { markdown } : {}),\n ...(resolvedLayout ? { layout: resolvedLayout } : {}),\n ...(editSessionId !== undefined ? { editSessionId } : {}),\n snapshotMeta: MCP_SNAPSHOT_META,\n });\n\n if (!note) {\n throw createAppError(404, 'NOTE_NOT_FOUND', 'The requested note was not found.');\n }\n\n emitEvent({\n type: 'mcp.note.updated',\n source: 'mcp',\n noteId: note.id,\n updatedAt: note.updatedAt,\n });\n\n res.status(200)\n .json({\n updated: true,\n note,\n })\n .end();\n } catch (error) {\n if (error instanceof InvalidNoteAuthoringInputError) {\n throw createAppError(400, 'INVALID_NOTE_INPUT', error.message);\n }\n\n throw error;\n }\n };\n};\n\nexport const createMcpNoteWriteBaselineHandler = (\n findNoteBaseline: (id: number) => Promise<{ id: number; updatedAt: Date } | null> = async (id) =>\n models.note.findUnique({\n where: { id },\n select: {\n id: true,\n updatedAt: true,\n },\n }),\n): Controller => {\n return async (req, res) => {\n const noteId = resolvePositiveNoteId(req.body?.id);\n const note = await findNoteBaseline(noteId);\n\n if (!note) {\n throw createAppError(404, 'NOTE_NOT_FOUND', 'The requested note was not found.');\n }\n\n res.status(200)\n .json({\n note: serializeNoteWriteBaseline(note),\n })\n .end();\n };\n};\n\nexport const createMcpPatchNoteMarkdownHandler = (\n patchMarkdown = patchNoteMarkdown,\n emitEvent: EmitServerEvent = emitServerEvent,\n): Controller => {\n return async (req, res) => {\n const { id, expectedUpdatedAt, baseMarkdownSha256, intent, selector, operation, policy, dryRun } =\n req.body ?? {};\n const noteId = resolvePositiveNoteId(id);\n const resolvedExpectedUpdatedAt = resolveOptionalString(\n expectedUpdatedAt,\n 'INVALID_NOTE_VERSION',\n 'expectedUpdatedAt must be a string.',\n );\n const resolvedBaseMarkdownSha256 = resolveOptionalString(\n baseMarkdownSha256,\n 'INVALID_MARKDOWN_HASH',\n 'baseMarkdownSha256 must be a string.',\n );\n const resolvedDryRun = resolveOptionalBoolean(dryRun, 'INVALID_DRY_RUN', 'dryRun must be a boolean.');\n\n if (typeof intent !== 'string') {\n throw createAppError(400, 'INVALID_PATCH_INTENT', 'Patch intent must be a string.');\n }\n\n const result = await patchMarkdown({\n id: noteId,\n expectedUpdatedAt: resolvedExpectedUpdatedAt,\n baseMarkdownSha256: resolvedBaseMarkdownSha256,\n intent,\n selector: resolvePatchSelector(selector),\n operation: resolvePatchOperation(operation),\n policy: resolveMarkdownWritePolicy(policy),\n dryRun: resolvedDryRun,\n });\n\n if (result.status === 'applied') {\n emitEvent({\n type: 'mcp.note.updated',\n source: 'mcp',\n noteId: result.note.id,\n updatedAt: result.note.updatedAt,\n });\n }\n\n res.status(200).json(result).end();\n };\n};\n\nexport const createMcpAppendNoteMarkdownHandler = (\n appendMarkdown = appendNoteMarkdown,\n emitEvent: EmitServerEvent = emitServerEvent,\n): Controller => {\n return async (req, res) => {\n const { id, expectedUpdatedAt, baseMarkdownSha256, intent, insertion, placement, separator, policy, dryRun } =\n req.body ?? {};\n const noteId = resolvePositiveNoteId(id);\n const resolvedExpectedUpdatedAt = resolveOptionalString(\n expectedUpdatedAt,\n 'INVALID_NOTE_VERSION',\n 'expectedUpdatedAt must be a string.',\n );\n const resolvedBaseMarkdownSha256 = resolveOptionalString(\n baseMarkdownSha256,\n 'INVALID_MARKDOWN_HASH',\n 'baseMarkdownSha256 must be a string.',\n );\n const resolvedDryRun = resolveOptionalBoolean(dryRun, 'INVALID_DRY_RUN', 'dryRun must be a boolean.');\n\n if (typeof intent !== 'string') {\n throw createAppError(400, 'INVALID_APPEND_INTENT', 'Append intent must be a string.');\n }\n\n if (typeof insertion !== 'string') {\n throw createAppError(400, 'INVALID_APPEND_INSERTION', 'Append insertion must be a string.');\n }\n\n const result = await appendMarkdown({\n id: noteId,\n expectedUpdatedAt: resolvedExpectedUpdatedAt,\n baseMarkdownSha256: resolvedBaseMarkdownSha256,\n intent,\n insertion,\n placement: resolveAppendPlacement(placement),\n separator: resolveSeparator(separator),\n policy: resolveMarkdownWritePolicy(policy),\n dryRun: resolvedDryRun,\n });\n\n if (result.status === 'applied') {\n emitEvent({\n type: 'mcp.note.updated',\n source: 'mcp',\n noteId: result.note.id,\n updatedAt: result.note.updatedAt,\n });\n }\n\n res.status(200).json(result).end();\n };\n};\n\nexport const createMcpReplaceNoteMarkdownHandler = (\n replaceMarkdown = replaceNoteMarkdown,\n emitEvent: EmitServerEvent = emitServerEvent,\n): Controller => {\n return async (req, res) => {\n const { id, expectedUpdatedAt, baseMarkdownSha256, intent, replacement, policy, dryRun } = req.body ?? {};\n const noteId = resolvePositiveNoteId(id);\n const resolvedExpectedUpdatedAt = resolveOptionalString(\n expectedUpdatedAt,\n 'INVALID_NOTE_VERSION',\n 'expectedUpdatedAt must be a string.',\n );\n const resolvedBaseMarkdownSha256 = resolveOptionalString(\n baseMarkdownSha256,\n 'INVALID_MARKDOWN_HASH',\n 'baseMarkdownSha256 must be a string.',\n );\n const resolvedDryRun = resolveOptionalBoolean(dryRun, 'INVALID_DRY_RUN', 'dryRun must be a boolean.');\n\n if (typeof intent !== 'string') {\n throw createAppError(400, 'INVALID_REPLACE_INTENT', 'Replace intent must be a string.');\n }\n\n if (typeof replacement !== 'string') {\n throw createAppError(400, 'INVALID_REPLACE_MARKDOWN', 'Replacement markdown must be a string.');\n }\n\n const result = await replaceMarkdown({\n id: noteId,\n expectedUpdatedAt: resolvedExpectedUpdatedAt,\n baseMarkdownSha256: resolvedBaseMarkdownSha256,\n intent,\n replacement,\n policy: resolveMarkdownWritePolicy(policy),\n dryRun: resolvedDryRun,\n });\n\n if (result.status === 'applied') {\n emitEvent({\n type: 'mcp.note.updated',\n source: 'mcp',\n noteId: result.note.id,\n updatedAt: result.note.updatedAt,\n });\n }\n\n res.status(200).json(result).end();\n };\n};\n\nexport const createMcpUpdateNoteMetadataHandler = (\n updateMetadata = updateNoteMetadata,\n emitEvent: EmitServerEvent = emitServerEvent,\n): Controller => {\n return async (req, res) => {\n const { id, expectedUpdatedAt, title, layout, properties, dryRun } = req.body ?? {};\n const noteId = resolvePositiveNoteId(id);\n const resolvedLayout = resolveNoteLayout(layout);\n const resolvedProperties = resolveMetadataPropertyPatch(properties);\n const resolvedDryRun = resolveOptionalBoolean(dryRun, 'INVALID_DRY_RUN', 'dryRun must be a boolean.');\n\n if (typeof expectedUpdatedAt !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_VERSION', 'expectedUpdatedAt must be a string.');\n }\n\n if (title !== undefined && typeof title !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_TITLE', 'Note title must be a string.');\n }\n\n if (layout !== undefined && resolvedLayout === null) {\n throw createAppError(400, 'INVALID_NOTE_LAYOUT', 'Note layout must be one of narrow, wide, or full.');\n }\n\n if (title === undefined && layout === undefined && resolvedProperties === undefined) {\n throw createAppError(400, 'INVALID_NOTE_INPUT', 'At least one metadata field must be provided.');\n }\n\n const result = await updateMetadata({\n id: noteId,\n expectedUpdatedAt,\n ...(title !== undefined ? { title } : {}),\n ...(resolvedLayout ? { layout: resolvedLayout } : {}),\n ...(resolvedProperties !== undefined ? { properties: resolvedProperties } : {}),\n dryRun: resolvedDryRun,\n });\n\n if (result.status === 'applied') {\n emitEvent({\n type: 'mcp.note.updated',\n source: 'mcp',\n noteId: result.note.id,\n updatedAt: result.note.updatedAt,\n });\n }\n\n res.status(200).json(result).end();\n };\n};\n\nexport const createMcpDeleteNoteHandler = (\n deleteNote = deleteNoteById,\n emitEvent: EmitServerEvent = emitServerEvent,\n): Controller => {\n return async (req, res) => {\n const id = Number(req.body?.id);\n\n if (!Number.isInteger(id) || id <= 0) {\n throw createAppError(400, 'INVALID_NOTE_ID', 'A valid note id is required.');\n }\n\n const deletedNote = await deleteNote(id);\n\n if (!deletedNote) {\n throw createAppError(404, 'NOTE_NOT_FOUND', 'The requested note was not found.');\n }\n\n emitEvent({\n type: 'mcp.note.deleted',\n source: 'mcp',\n noteId: deletedNote.id,\n });\n\n res.status(200)\n .json({\n deleted: true,\n note: deletedNote,\n })\n .end();\n };\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/features/note/http/mcp.ts"],"sourcesContent":["import {\n createNoteFromMarkdown,\n InvalidNoteAuthoringInputError,\n updateNoteFromMarkdown,\n} from '~/features/note/services/authoring.js';\nimport { deleteNoteById } from '~/features/note/services/cleanup.js';\nimport {\n appendNoteMarkdown,\n patchNoteMarkdown,\n replaceNoteMarkdown,\n updateNoteMetadata,\n} from '~/features/note/services/markdown-intent-write.js';\nimport type {\n MarkdownAppendPlacement,\n MarkdownChangePolicy,\n MarkdownPatchOperation,\n MarkdownPatchSelector,\n} from '~/features/note/services/markdown-patch.js';\nimport type { NotePropertiesByKeyPatchInput } from '~/features/note/services/properties.js';\nimport { MCP_SNAPSHOT_META } from '~/features/note/services/snapshot.js';\nimport models, { type NoteLayout } from '~/models.js';\nimport { createAppError } from '~/modules/error-handler.js';\nimport { emitServerEvent, type ServerEventInput } from '~/modules/server-events.js';\nimport type { Controller } from '~/types/index.js';\n\nconst NOTE_LAYOUTS = new Set<NoteLayout>(['narrow', 'wide', 'full']);\n\nconst POSITION_HINTS = new Set(['first', 'last']);\nconst PRESERVATION_POLICIES = new Set<unknown>([true, false, 'warn']);\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return typeof value === 'object' && value !== null;\n};\n\nconst resolveNoteLayout = (value: unknown): NoteLayout | null | undefined => {\n if (value === undefined) {\n return undefined;\n }\n\n if (typeof value === 'string' && NOTE_LAYOUTS.has(value as NoteLayout)) {\n return value as NoteLayout;\n }\n\n return null;\n};\n\nconst resolveOptionalString = (value: unknown, code: string, message: string) => {\n if (value === undefined) {\n return undefined;\n }\n\n if (typeof value === 'string') {\n return value;\n }\n\n throw createAppError(400, code, message);\n};\n\nconst resolveMetadataPropertyPatch = (value: unknown): NotePropertiesByKeyPatchInput | undefined => {\n if (value === undefined) {\n return undefined;\n }\n\n if (!isRecord(value)) {\n throw createAppError(400, 'INVALID_NOTE_PROPERTIES', 'Properties patch must be an object.');\n }\n\n const set =\n value.set === undefined\n ? undefined\n : Array.isArray(value.set)\n ? value.set.map((item) => {\n if (!isRecord(item) || typeof item.key !== 'string' || typeof item.value !== 'string') {\n throw createAppError(\n 400,\n 'INVALID_NOTE_PROPERTIES',\n 'Property set items must include string key and value fields.',\n );\n }\n\n return {\n key: item.key,\n value: item.value,\n };\n })\n : null;\n\n if (set === null) {\n throw createAppError(400, 'INVALID_NOTE_PROPERTIES', 'Property set must be an array.');\n }\n\n const deleteKeys =\n value.deleteKeys === undefined\n ? undefined\n : Array.isArray(value.deleteKeys)\n ? value.deleteKeys.map((key) => {\n if (typeof key !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_PROPERTIES', 'Property deleteKeys must be strings.');\n }\n\n return key;\n })\n : null;\n\n if (deleteKeys === null) {\n throw createAppError(400, 'INVALID_NOTE_PROPERTIES', 'Property deleteKeys must be an array.');\n }\n\n return {\n ...(set !== undefined ? { set } : {}),\n ...(deleteKeys !== undefined ? { deleteKeys } : {}),\n };\n};\n\nconst resolvePositiveNoteId = (value: unknown) => {\n const noteId = Number(value);\n\n if (!Number.isInteger(noteId) || noteId <= 0) {\n throw createAppError(400, 'INVALID_NOTE_ID', 'A valid note id is required.');\n }\n\n return noteId;\n};\n\nconst serializeNoteWriteBaseline = (note: { id: number | string; updatedAt: Date | string }) => {\n return {\n id: String(note.id),\n updatedAt: note.updatedAt instanceof Date ? note.updatedAt.toISOString() : note.updatedAt,\n };\n};\n\nconst isNonNegativeInteger = (value: unknown): value is number => {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n};\n\nconst isPositiveInteger = (value: unknown): value is number => {\n return typeof value === 'number' && Number.isInteger(value) && value > 0;\n};\n\nconst resolveMarkdownWritePolicy = (value: unknown): MarkdownChangePolicy | undefined => {\n if (value === undefined) {\n return undefined;\n }\n\n if (!isRecord(value)) {\n throw createAppError(400, 'INVALID_MARKDOWN_POLICY', 'Markdown write policy must be an object.');\n }\n\n const policy: MarkdownChangePolicy = {};\n\n if (value.allowNoop !== undefined) {\n if (typeof value.allowNoop !== 'boolean') {\n throw createAppError(400, 'INVALID_MARKDOWN_POLICY', 'allowNoop must be a boolean.');\n }\n policy.allowNoop = value.allowNoop;\n }\n\n if (value.preserveTags !== undefined) {\n if (!PRESERVATION_POLICIES.has(value.preserveTags)) {\n throw createAppError(400, 'INVALID_MARKDOWN_POLICY', 'preserveTags must be boolean or warn.');\n }\n policy.preserveTags = value.preserveTags as MarkdownChangePolicy['preserveTags'];\n }\n\n if (value.preserveReferences !== undefined) {\n if (!PRESERVATION_POLICIES.has(value.preserveReferences)) {\n throw createAppError(400, 'INVALID_MARKDOWN_POLICY', 'preserveReferences must be boolean or warn.');\n }\n policy.preserveReferences = value.preserveReferences as MarkdownChangePolicy['preserveReferences'];\n }\n\n return policy;\n};\n\nconst resolvePatchSelector = (value: unknown): MarkdownPatchSelector => {\n if (!isRecord(value)) {\n throw createAppError(400, 'INVALID_PATCH_SELECTOR', 'Patch selector must be an object.');\n }\n\n if (value.type === 'exact_text') {\n if (typeof value.text !== 'string') {\n throw createAppError(400, 'INVALID_PATCH_SELECTOR', 'Exact text selector requires text.');\n }\n\n return {\n type: 'exact_text',\n text: value.text,\n ...(value.before !== undefined\n ? {\n before: resolveOptionalString(\n value.before,\n 'INVALID_PATCH_SELECTOR',\n 'Selector before must be a string.',\n ),\n }\n : {}),\n ...(value.after !== undefined\n ? {\n after: resolveOptionalString(\n value.after,\n 'INVALID_PATCH_SELECTOR',\n 'Selector after must be a string.',\n ),\n }\n : {}),\n };\n }\n\n if (value.type === 'match_candidate') {\n const { text, matchIndex, lineStart, matchSha256, surroundingHash, positionHint } = value;\n\n if (\n typeof text !== 'string' ||\n !isNonNegativeInteger(matchIndex) ||\n !isPositiveInteger(lineStart) ||\n typeof matchSha256 !== 'string' ||\n typeof surroundingHash !== 'string'\n ) {\n throw createAppError(400, 'INVALID_PATCH_SELECTOR', 'Match candidate selector has invalid fields.');\n }\n\n if (positionHint !== undefined && !POSITION_HINTS.has(String(positionHint))) {\n throw createAppError(400, 'INVALID_PATCH_SELECTOR', 'positionHint must be first or last.');\n }\n\n return {\n type: 'match_candidate',\n text,\n matchIndex,\n lineStart,\n matchSha256,\n surroundingHash,\n ...(positionHint ? { positionHint: positionHint as 'first' | 'last' } : {}),\n };\n }\n\n throw createAppError(400, 'INVALID_PATCH_SELECTOR', 'Unsupported patch selector type.');\n};\n\nconst resolvePatchOperation = (value: unknown): MarkdownPatchOperation => {\n if (!isRecord(value)) {\n throw createAppError(400, 'INVALID_PATCH_OPERATION', 'Patch operation must be an object.');\n }\n\n if (value.type === 'replace') {\n if (typeof value.replacement !== 'string') {\n throw createAppError(400, 'INVALID_PATCH_OPERATION', 'Replace operation requires replacement.');\n }\n\n return {\n type: 'replace',\n replacement: value.replacement,\n };\n }\n\n if (value.type === 'insert_before' || value.type === 'insert_after') {\n if (typeof value.insertion !== 'string') {\n throw createAppError(400, 'INVALID_PATCH_OPERATION', 'Insert operation requires insertion.');\n }\n\n return {\n type: value.type,\n insertion: value.insertion,\n };\n }\n\n throw createAppError(400, 'INVALID_PATCH_OPERATION', 'Unsupported patch operation type.');\n};\n\nconst resolveAppendPlacement = (value: unknown): MarkdownAppendPlacement | undefined => {\n if (value === undefined) {\n return undefined;\n }\n\n if (!isRecord(value)) {\n throw createAppError(400, 'INVALID_APPEND_PLACEMENT', 'Append placement must be an object.');\n }\n\n if (value.type === 'end') {\n return { type: 'end' };\n }\n\n if (value.type === 'after_heading') {\n if (typeof value.heading !== 'string') {\n throw createAppError(400, 'INVALID_APPEND_PLACEMENT', 'after_heading placement requires heading.');\n }\n\n const { heading, level } = value;\n\n if (typeof heading !== 'string') {\n throw createAppError(400, 'INVALID_APPEND_PLACEMENT', 'after_heading placement requires heading.');\n }\n\n if (level !== undefined && (typeof level !== 'number' || !Number.isInteger(level) || level < 1 || level > 6)) {\n throw createAppError(400, 'INVALID_APPEND_PLACEMENT', 'Heading level must be an integer from 1 to 6.');\n }\n\n return {\n type: 'after_heading',\n heading,\n ...(level !== undefined ? { level } : {}),\n };\n }\n\n throw createAppError(400, 'INVALID_APPEND_PLACEMENT', 'Unsupported append placement type.');\n};\n\nconst resolveSeparator = (value: unknown) => {\n if (value === undefined) {\n return undefined;\n }\n\n if (value === '\\n' || value === '\\n\\n') {\n return value;\n }\n\n throw createAppError(400, 'INVALID_SEPARATOR', 'Separator must be \"\\\\n\" or \"\\\\n\\\\n\".');\n};\n\ntype EmitServerEvent = (event: ServerEventInput) => unknown;\n\nexport const createMcpCreateNoteHandler = (\n createNote = createNoteFromMarkdown,\n emitEvent: EmitServerEvent = emitServerEvent,\n): Controller => {\n return async (req, res) => {\n const { title, markdown, layout } = req.body ?? {};\n const resolvedLayout = resolveNoteLayout(layout);\n\n if (typeof title !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_TITLE', 'A note title is required.');\n }\n\n if (markdown !== undefined && typeof markdown !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_MARKDOWN', 'Note markdown must be a string.');\n }\n\n if (layout !== undefined && resolvedLayout === null) {\n throw createAppError(400, 'INVALID_NOTE_LAYOUT', 'Note layout must be one of narrow, wide, or full.');\n }\n\n try {\n const note = await createNote({\n title,\n ...(markdown !== undefined ? { markdown } : {}),\n ...(resolvedLayout ? { layout: resolvedLayout } : {}),\n });\n\n emitEvent({\n type: 'mcp.note.created',\n source: 'mcp',\n noteId: note.id,\n updatedAt: note.updatedAt,\n });\n\n res.status(200)\n .json({\n created: true,\n note,\n })\n .end();\n } catch (error) {\n if (error instanceof InvalidNoteAuthoringInputError) {\n throw createAppError(400, 'INVALID_NOTE_INPUT', error.message);\n }\n\n throw error;\n }\n };\n};\n\nexport const createMcpUpdateNoteHandler = (\n updateNote = updateNoteFromMarkdown,\n emitEvent: EmitServerEvent = emitServerEvent,\n): Controller => {\n return async (req, res) => {\n const { id, title, markdown, layout, editSessionId } = req.body ?? {};\n const noteId = Number(id);\n const resolvedLayout = resolveNoteLayout(layout);\n\n if (!Number.isInteger(noteId) || noteId <= 0) {\n throw createAppError(400, 'INVALID_NOTE_ID', 'A valid note id is required.');\n }\n\n if (title !== undefined && typeof title !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_TITLE', 'Note title must be a string.');\n }\n\n if (markdown !== undefined && typeof markdown !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_MARKDOWN', 'Note markdown must be a string.');\n }\n\n if (layout !== undefined && resolvedLayout === null) {\n throw createAppError(400, 'INVALID_NOTE_LAYOUT', 'Note layout must be one of narrow, wide, or full.');\n }\n\n if (editSessionId !== undefined && typeof editSessionId !== 'string') {\n throw createAppError(400, 'INVALID_EDIT_SESSION_ID', 'Edit session id must be a string.');\n }\n\n if (title === undefined && markdown === undefined && layout === undefined) {\n throw createAppError(400, 'INVALID_NOTE_INPUT', 'At least one note field must be provided for update.');\n }\n\n try {\n const note = await updateNote({\n id: noteId,\n ...(title !== undefined ? { title } : {}),\n ...(markdown !== undefined ? { markdown } : {}),\n ...(resolvedLayout ? { layout: resolvedLayout } : {}),\n ...(editSessionId !== undefined ? { editSessionId } : {}),\n snapshotMeta: MCP_SNAPSHOT_META,\n });\n\n if (!note) {\n throw createAppError(404, 'NOTE_NOT_FOUND', 'The requested note was not found.');\n }\n\n emitEvent({\n type: 'mcp.note.updated',\n source: 'mcp',\n noteId: note.id,\n updatedAt: note.updatedAt,\n });\n\n res.status(200)\n .json({\n updated: true,\n note,\n })\n .end();\n } catch (error) {\n if (error instanceof InvalidNoteAuthoringInputError) {\n throw createAppError(400, 'INVALID_NOTE_INPUT', error.message);\n }\n\n throw error;\n }\n };\n};\n\nexport const createMcpNoteWriteBaselineHandler = (\n findNoteBaseline: (id: number) => Promise<{ id: number; updatedAt: Date } | null> = async (id) =>\n models.note.findUnique({\n where: { id },\n select: {\n id: true,\n updatedAt: true,\n },\n }),\n): Controller => {\n return async (req, res) => {\n const noteId = resolvePositiveNoteId(req.body?.id);\n const note = await findNoteBaseline(noteId);\n\n if (!note) {\n throw createAppError(404, 'NOTE_NOT_FOUND', 'The requested note was not found.');\n }\n\n res.status(200)\n .json({\n note: serializeNoteWriteBaseline(note),\n })\n .end();\n };\n};\n\nexport const createMcpPatchNoteMarkdownHandler = (\n patchMarkdown = patchNoteMarkdown,\n emitEvent: EmitServerEvent = emitServerEvent,\n): Controller => {\n return async (req, res) => {\n const { id, expectedUpdatedAt, baseMarkdownSha256, intent, selector, operation, policy } = req.body ?? {};\n const noteId = resolvePositiveNoteId(id);\n const resolvedExpectedUpdatedAt = resolveOptionalString(\n expectedUpdatedAt,\n 'INVALID_NOTE_VERSION',\n 'expectedUpdatedAt must be a string.',\n );\n const resolvedBaseMarkdownSha256 = resolveOptionalString(\n baseMarkdownSha256,\n 'INVALID_MARKDOWN_HASH',\n 'baseMarkdownSha256 must be a string.',\n );\n\n if (typeof intent !== 'string') {\n throw createAppError(400, 'INVALID_PATCH_INTENT', 'Patch intent must be a string.');\n }\n\n const result = await patchMarkdown({\n id: noteId,\n expectedUpdatedAt: resolvedExpectedUpdatedAt,\n baseMarkdownSha256: resolvedBaseMarkdownSha256,\n intent,\n selector: resolvePatchSelector(selector),\n operation: resolvePatchOperation(operation),\n policy: resolveMarkdownWritePolicy(policy),\n });\n\n if (result.status === 'applied') {\n emitEvent({\n type: 'mcp.note.updated',\n source: 'mcp',\n noteId: result.note.id,\n updatedAt: result.note.updatedAt,\n });\n }\n\n res.status(200).json(result).end();\n };\n};\n\nexport const createMcpAppendNoteMarkdownHandler = (\n appendMarkdown = appendNoteMarkdown,\n emitEvent: EmitServerEvent = emitServerEvent,\n): Controller => {\n return async (req, res) => {\n const { id, expectedUpdatedAt, baseMarkdownSha256, intent, insertion, placement, separator, policy } =\n req.body ?? {};\n const noteId = resolvePositiveNoteId(id);\n const resolvedExpectedUpdatedAt = resolveOptionalString(\n expectedUpdatedAt,\n 'INVALID_NOTE_VERSION',\n 'expectedUpdatedAt must be a string.',\n );\n const resolvedBaseMarkdownSha256 = resolveOptionalString(\n baseMarkdownSha256,\n 'INVALID_MARKDOWN_HASH',\n 'baseMarkdownSha256 must be a string.',\n );\n\n if (typeof intent !== 'string') {\n throw createAppError(400, 'INVALID_APPEND_INTENT', 'Append intent must be a string.');\n }\n\n if (typeof insertion !== 'string') {\n throw createAppError(400, 'INVALID_APPEND_INSERTION', 'Append insertion must be a string.');\n }\n\n const result = await appendMarkdown({\n id: noteId,\n expectedUpdatedAt: resolvedExpectedUpdatedAt,\n baseMarkdownSha256: resolvedBaseMarkdownSha256,\n intent,\n insertion,\n placement: resolveAppendPlacement(placement),\n separator: resolveSeparator(separator),\n policy: resolveMarkdownWritePolicy(policy),\n });\n\n if (result.status === 'applied') {\n emitEvent({\n type: 'mcp.note.updated',\n source: 'mcp',\n noteId: result.note.id,\n updatedAt: result.note.updatedAt,\n });\n }\n\n res.status(200).json(result).end();\n };\n};\n\nexport const createMcpReplaceNoteMarkdownHandler = (\n replaceMarkdown = replaceNoteMarkdown,\n emitEvent: EmitServerEvent = emitServerEvent,\n): Controller => {\n return async (req, res) => {\n const { id, expectedUpdatedAt, baseMarkdownSha256, intent, replacement, policy } = req.body ?? {};\n const noteId = resolvePositiveNoteId(id);\n const resolvedExpectedUpdatedAt = resolveOptionalString(\n expectedUpdatedAt,\n 'INVALID_NOTE_VERSION',\n 'expectedUpdatedAt must be a string.',\n );\n const resolvedBaseMarkdownSha256 = resolveOptionalString(\n baseMarkdownSha256,\n 'INVALID_MARKDOWN_HASH',\n 'baseMarkdownSha256 must be a string.',\n );\n\n if (typeof intent !== 'string') {\n throw createAppError(400, 'INVALID_REPLACE_INTENT', 'Replace intent must be a string.');\n }\n\n if (typeof replacement !== 'string') {\n throw createAppError(400, 'INVALID_REPLACE_MARKDOWN', 'Replacement markdown must be a string.');\n }\n\n const result = await replaceMarkdown({\n id: noteId,\n expectedUpdatedAt: resolvedExpectedUpdatedAt,\n baseMarkdownSha256: resolvedBaseMarkdownSha256,\n intent,\n replacement,\n policy: resolveMarkdownWritePolicy(policy),\n });\n\n if (result.status === 'applied') {\n emitEvent({\n type: 'mcp.note.updated',\n source: 'mcp',\n noteId: result.note.id,\n updatedAt: result.note.updatedAt,\n });\n }\n\n res.status(200).json(result).end();\n };\n};\n\nexport const createMcpUpdateNoteMetadataHandler = (\n updateMetadata = updateNoteMetadata,\n emitEvent: EmitServerEvent = emitServerEvent,\n): Controller => {\n return async (req, res) => {\n const { id, expectedUpdatedAt, title, layout, properties } = req.body ?? {};\n const noteId = resolvePositiveNoteId(id);\n const resolvedLayout = resolveNoteLayout(layout);\n const resolvedProperties = resolveMetadataPropertyPatch(properties);\n\n if (typeof expectedUpdatedAt !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_VERSION', 'expectedUpdatedAt must be a string.');\n }\n\n if (title !== undefined && typeof title !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_TITLE', 'Note title must be a string.');\n }\n\n if (layout !== undefined && resolvedLayout === null) {\n throw createAppError(400, 'INVALID_NOTE_LAYOUT', 'Note layout must be one of narrow, wide, or full.');\n }\n\n if (title === undefined && layout === undefined && resolvedProperties === undefined) {\n throw createAppError(400, 'INVALID_NOTE_INPUT', 'At least one metadata field must be provided.');\n }\n\n const result = await updateMetadata({\n id: noteId,\n expectedUpdatedAt,\n ...(title !== undefined ? { title } : {}),\n ...(resolvedLayout ? { layout: resolvedLayout } : {}),\n ...(resolvedProperties !== undefined ? { properties: resolvedProperties } : {}),\n });\n\n if (result.status === 'applied') {\n emitEvent({\n type: 'mcp.note.updated',\n source: 'mcp',\n noteId: result.note.id,\n updatedAt: result.note.updatedAt,\n });\n }\n\n res.status(200).json(result).end();\n };\n};\n\nexport const createMcpDeleteNoteHandler = (\n deleteNote = deleteNoteById,\n emitEvent: EmitServerEvent = emitServerEvent,\n): Controller => {\n return async (req, res) => {\n const id = Number(req.body?.id);\n\n if (!Number.isInteger(id) || id <= 0) {\n throw createAppError(400, 'INVALID_NOTE_ID', 'A valid note id is required.');\n }\n\n const deletedNote = await deleteNote(id);\n\n if (!deletedNote) {\n throw createAppError(404, 'NOTE_NOT_FOUND', 'The requested note was not found.');\n }\n\n emitEvent({\n type: 'mcp.note.deleted',\n source: 'mcp',\n noteId: deletedNote.id,\n });\n\n res.status(200)\n .json({\n deleted: true,\n note: deletedNote,\n })\n .end();\n };\n};\n"],"mappings":"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","names":[]}
@@ -76,8 +76,8 @@ const createNoteCleanupService = (deps) => {
76
76
  })),
77
77
  orphanedTagNames: orphanedTags.map((tag) => tag.name),
78
78
  orphanedTagIds: orphanedTags.map((tag) => tag.id),
79
- requiresForce: candidate.requiresForce || orphanedTags.length > 0,
80
- forceReasons: [...candidate.forceReasons, ...orphanedTags.length > 0 ? ["orphan_tags"] : []]
79
+ requiresForce: candidate.requiresForce,
80
+ forceReasons: candidate.forceReasons
81
81
  };
82
82
  };
83
83
  const getDeletePreview = async (id) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/features/note/services/cleanup.ts"],"sourcesContent":["import models from '~/models.js';\nimport { contentReferencesNote } from './content-blocks.js';\nimport { trashNoteById as moveNoteToTrashById } from './trash.js';\n\nexport interface NoteCleanupBackReference {\n id: string;\n title: string;\n}\n\nexport interface NoteCleanupPreview {\n id: string;\n title: string;\n updatedAt: string;\n pinned: boolean;\n tagNames: string[];\n reminderCount: number;\n backReferences: NoteCleanupBackReference[];\n orphanedTagNames: string[];\n requiresForce: boolean;\n forceReasons: string[];\n}\n\nexport interface NoteCleanupCandidate {\n id: string;\n title: string;\n updatedAt: string;\n pinned: boolean;\n tagNames: string[];\n reminderCount: number;\n backReferenceCount: number;\n matchedTerms: string[];\n reasons: string[];\n requiresForce: boolean;\n forceReasons: string[];\n}\n\nexport interface NoteCleanupCandidatesResult {\n keywords: string[];\n limit: number;\n offset: number;\n olderThanDays: number;\n notes: NoteCleanupCandidate[];\n totalCount: number;\n}\n\nexport interface NoteCleanupService {\n deleteNoteById: (id: number) => Promise<NoteCleanupPreview | null>;\n getDeletePreview: (id: number) => Promise<NoteCleanupPreview | null>;\n listCleanupCandidates: (input?: {\n keywords?: string[];\n limit?: number;\n offset?: number;\n olderThanDays?: number;\n query?: string;\n }) => Promise<NoteCleanupCandidatesResult>;\n}\n\ninterface NoteRecord {\n id: number;\n title: string;\n content: string;\n updatedAt: Date;\n pinned: boolean;\n tags: Array<{\n id: number;\n name: string;\n }>;\n}\n\ninterface NoteCleanupPreviewInternal extends NoteCleanupPreview {\n orphanedTagIds: number[];\n}\n\nconst DEFAULT_CLEANUP_KEYWORDS = ['temp', 'temporary', 'tmp', 'draft', 'test', 'wip'];\n\nexport const normalizeCleanupKeywords = (keywords?: string[], query?: string) => {\n const queryKeywords = typeof query === 'string' ? query.split(/[,\\s]+/).map((keyword) => keyword.trim()) : [];\n const source =\n keywords && keywords.length > 0\n ? keywords\n : queryKeywords.length > 0\n ? queryKeywords\n : DEFAULT_CLEANUP_KEYWORDS;\n\n return Array.from(new Set(source.map((keyword) => keyword.trim().toLowerCase()).filter(Boolean)));\n};\n\nconst buildForceReasons = (input: { pinned: boolean; reminderCount: number; backReferenceCount: number }) => {\n const forceReasons: string[] = [];\n\n if (input.pinned) {\n forceReasons.push('note_is_pinned');\n }\n\n if (input.reminderCount > 0) {\n forceReasons.push('has_reminders');\n }\n\n if (input.backReferenceCount > 0) {\n forceReasons.push('has_back_references');\n }\n\n return forceReasons;\n};\n\nexport const createNoteCleanupService = (deps: {\n countCandidateNotes: (keywords: string[], olderThanDays: number) => Promise<number>;\n countReminders: (noteId: number) => Promise<number>;\n deleteNoteAndPruneTags: (noteId: number, orphanTagIds: number[]) => Promise<void>;\n findBackReferences: (noteId: number) => Promise<Array<{ id: number; title: string }>>;\n findCandidateNotes: (\n keywords: string[],\n skip: number,\n take: number,\n olderThanDays: number,\n ) => Promise<NoteRecord[]>;\n findNote: (id: number) => Promise<NoteRecord | null>;\n getTagNoteCounts: (tagIds: number[]) => Promise<Map<number, number>>;\n}): NoteCleanupService => {\n const buildCandidate = async (note: NoteRecord, matchedTerms?: string[]): Promise<NoteCleanupCandidate> => {\n const [reminderCount, backReferences] = await Promise.all([\n deps.countReminders(note.id),\n deps.findBackReferences(note.id),\n ]);\n const normalizedMatchedTerms = matchedTerms ?? [];\n const forceReasons = buildForceReasons({\n pinned: note.pinned,\n reminderCount,\n backReferenceCount: backReferences.length,\n });\n\n return {\n id: String(note.id),\n title: note.title,\n updatedAt: note.updatedAt.toISOString(),\n pinned: note.pinned,\n tagNames: note.tags.map((tag) => tag.name),\n reminderCount,\n backReferenceCount: backReferences.length,\n matchedTerms: normalizedMatchedTerms,\n reasons: [\n ...(normalizedMatchedTerms.length > 0 ? [`matched_terms:${normalizedMatchedTerms.join(',')}`] : []),\n ...(note.pinned ? [] : ['not_pinned']),\n ...(note.tags.length === 0 ? ['tagless'] : []),\n ...(reminderCount === 0 ? ['no_reminders'] : []),\n ...(backReferences.length === 0 ? ['no_back_references'] : []),\n ],\n requiresForce: forceReasons.length > 0,\n forceReasons,\n };\n };\n\n const getDeletePreviewInternal = async (id: number): Promise<NoteCleanupPreviewInternal | null> => {\n const note = await deps.findNote(id);\n\n if (!note) {\n return null;\n }\n\n const [candidate, backReferences, tagNoteCounts] = await Promise.all([\n buildCandidate(note),\n deps.findBackReferences(note.id),\n deps.getTagNoteCounts(note.tags.map((tag) => tag.id)),\n ]);\n\n const orphanedTags = note.tags.filter((tag) => (tagNoteCounts.get(tag.id) ?? 0) <= 1);\n\n return {\n id: candidate.id,\n title: candidate.title,\n updatedAt: candidate.updatedAt,\n pinned: candidate.pinned,\n tagNames: candidate.tagNames,\n reminderCount: candidate.reminderCount,\n backReferences: backReferences.map((backReference) => ({\n id: String(backReference.id),\n title: backReference.title,\n })),\n orphanedTagNames: orphanedTags.map((tag) => tag.name),\n orphanedTagIds: orphanedTags.map((tag) => tag.id),\n requiresForce: candidate.requiresForce || orphanedTags.length > 0,\n forceReasons: [...candidate.forceReasons, ...(orphanedTags.length > 0 ? ['orphan_tags'] : [])],\n };\n };\n\n const getDeletePreview = async (id: number): Promise<NoteCleanupPreview | null> => {\n const preview = await getDeletePreviewInternal(id);\n\n if (!preview) {\n return null;\n }\n\n const { orphanedTagIds, ...publicPreview } = preview;\n void orphanedTagIds;\n return publicPreview;\n };\n\n return {\n listCleanupCandidates: async (input = {}) => {\n const limit = Math.max(1, Number(input.limit ?? 20));\n const offset = Math.max(0, Number(input.offset ?? 0));\n const olderThanDays = Math.max(0, Number(input.olderThanDays ?? 0));\n const keywords = normalizeCleanupKeywords(input.keywords, input.query);\n\n const [totalCount, notes] = await Promise.all([\n deps.countCandidateNotes(keywords, olderThanDays),\n deps.findCandidateNotes(keywords, offset, limit, olderThanDays),\n ]);\n\n const candidates = await Promise.all(\n notes.map((note) => {\n const haystack = `${note.title}\\n${note.content}`.toLowerCase();\n const matchedTerms = keywords.filter((keyword) => haystack.includes(keyword));\n return buildCandidate(note, matchedTerms);\n }),\n );\n\n return {\n keywords,\n limit,\n offset,\n olderThanDays,\n notes: candidates,\n totalCount,\n };\n },\n getDeletePreview,\n deleteNoteById: async (id: number) => {\n const preview = await getDeletePreviewInternal(id);\n\n if (!preview) {\n return null;\n }\n\n await deps.deleteNoteAndPruneTags(id, preview.orphanedTagIds);\n\n const { orphanedTagIds, ...publicPreview } = preview;\n void orphanedTagIds;\n return publicPreview;\n },\n };\n};\n\nconst buildKeywordClauses = (keywords: string[]) => {\n return keywords.flatMap((keyword) => [{ title: { contains: keyword } }, { content: { contains: keyword } }]);\n};\n\nconst buildStaleWhere = (olderThanDays: number) => {\n if (olderThanDays <= 0) {\n return {};\n }\n\n return { updatedAt: { lte: new Date(Date.now() - olderThanDays * 24 * 60 * 60 * 1000) } };\n};\n\nconst noteCleanupService = createNoteCleanupService({\n countCandidateNotes: (keywords: string[], olderThanDays: number) =>\n models.note.count({\n where: {\n ...buildStaleWhere(olderThanDays),\n OR: buildKeywordClauses(keywords),\n },\n }),\n countReminders: (noteId: number) => models.reminder.count({ where: { noteId } }),\n deleteNoteAndPruneTags: async (noteId: number, orphanTagIds: number[]) => {\n void orphanTagIds;\n await moveNoteToTrashById(noteId);\n },\n findBackReferences: (noteId: number) =>\n models.note\n .findMany({\n select: {\n id: true,\n title: true,\n content: true,\n },\n where: {\n NOT: { id: noteId },\n },\n orderBy: [{ pinned: 'desc' }, { updatedAt: 'desc' }],\n })\n .then((notes) => notes.filter((note) => contentReferencesNote(note.content, noteId))),\n findCandidateNotes: (keywords: string[], skip: number, take: number, olderThanDays: number) =>\n models.note.findMany({\n include: { tags: true },\n orderBy: { updatedAt: 'asc' },\n skip,\n take,\n where: {\n ...buildStaleWhere(olderThanDays),\n OR: buildKeywordClauses(keywords),\n },\n }),\n findNote: (id: number) =>\n models.note.findUnique({\n where: { id },\n include: { tags: true },\n }),\n getTagNoteCounts: async (tagIds: number[]) => {\n if (tagIds.length === 0) {\n return new Map<number, number>();\n }\n\n const tags = await models.tag.findMany({\n where: { id: { in: tagIds } },\n include: { _count: { select: { notes: true } } },\n });\n\n return new Map(tags.map((tag) => [tag.id, tag._count.notes]));\n },\n});\n\nexport const listNoteCleanupCandidates = noteCleanupService.listCleanupCandidates;\nexport const getNoteCleanupPreview = noteCleanupService.getDeletePreview;\nexport const deleteNoteById = noteCleanupService.deleteNoteById;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/features/note/services/cleanup.ts"],"sourcesContent":["import models from '~/models.js';\nimport { contentReferencesNote } from './content-blocks.js';\nimport { trashNoteById as moveNoteToTrashById } from './trash.js';\n\nexport interface NoteCleanupBackReference {\n id: string;\n title: string;\n}\n\nexport interface NoteCleanupPreview {\n id: string;\n title: string;\n updatedAt: string;\n pinned: boolean;\n tagNames: string[];\n reminderCount: number;\n backReferences: NoteCleanupBackReference[];\n orphanedTagNames: string[];\n requiresForce: boolean;\n forceReasons: string[];\n}\n\nexport interface NoteCleanupCandidate {\n id: string;\n title: string;\n updatedAt: string;\n pinned: boolean;\n tagNames: string[];\n reminderCount: number;\n backReferenceCount: number;\n matchedTerms: string[];\n reasons: string[];\n requiresForce: boolean;\n forceReasons: string[];\n}\n\nexport interface NoteCleanupCandidatesResult {\n keywords: string[];\n limit: number;\n offset: number;\n olderThanDays: number;\n notes: NoteCleanupCandidate[];\n totalCount: number;\n}\n\nexport interface NoteCleanupService {\n deleteNoteById: (id: number) => Promise<NoteCleanupPreview | null>;\n getDeletePreview: (id: number) => Promise<NoteCleanupPreview | null>;\n listCleanupCandidates: (input?: {\n keywords?: string[];\n limit?: number;\n offset?: number;\n olderThanDays?: number;\n query?: string;\n }) => Promise<NoteCleanupCandidatesResult>;\n}\n\ninterface NoteRecord {\n id: number;\n title: string;\n content: string;\n updatedAt: Date;\n pinned: boolean;\n tags: Array<{\n id: number;\n name: string;\n }>;\n}\n\ninterface NoteCleanupPreviewInternal extends NoteCleanupPreview {\n orphanedTagIds: number[];\n}\n\nconst DEFAULT_CLEANUP_KEYWORDS = ['temp', 'temporary', 'tmp', 'draft', 'test', 'wip'];\n\nexport const normalizeCleanupKeywords = (keywords?: string[], query?: string) => {\n const queryKeywords = typeof query === 'string' ? query.split(/[,\\s]+/).map((keyword) => keyword.trim()) : [];\n const source =\n keywords && keywords.length > 0\n ? keywords\n : queryKeywords.length > 0\n ? queryKeywords\n : DEFAULT_CLEANUP_KEYWORDS;\n\n return Array.from(new Set(source.map((keyword) => keyword.trim().toLowerCase()).filter(Boolean)));\n};\n\nconst buildForceReasons = (input: { pinned: boolean; reminderCount: number; backReferenceCount: number }) => {\n const forceReasons: string[] = [];\n\n if (input.pinned) {\n forceReasons.push('note_is_pinned');\n }\n\n if (input.reminderCount > 0) {\n forceReasons.push('has_reminders');\n }\n\n if (input.backReferenceCount > 0) {\n forceReasons.push('has_back_references');\n }\n\n return forceReasons;\n};\n\nexport const createNoteCleanupService = (deps: {\n countCandidateNotes: (keywords: string[], olderThanDays: number) => Promise<number>;\n countReminders: (noteId: number) => Promise<number>;\n deleteNoteAndPruneTags: (noteId: number, orphanTagIds: number[]) => Promise<void>;\n findBackReferences: (noteId: number) => Promise<Array<{ id: number; title: string }>>;\n findCandidateNotes: (\n keywords: string[],\n skip: number,\n take: number,\n olderThanDays: number,\n ) => Promise<NoteRecord[]>;\n findNote: (id: number) => Promise<NoteRecord | null>;\n getTagNoteCounts: (tagIds: number[]) => Promise<Map<number, number>>;\n}): NoteCleanupService => {\n const buildCandidate = async (note: NoteRecord, matchedTerms?: string[]): Promise<NoteCleanupCandidate> => {\n const [reminderCount, backReferences] = await Promise.all([\n deps.countReminders(note.id),\n deps.findBackReferences(note.id),\n ]);\n const normalizedMatchedTerms = matchedTerms ?? [];\n const forceReasons = buildForceReasons({\n pinned: note.pinned,\n reminderCount,\n backReferenceCount: backReferences.length,\n });\n\n return {\n id: String(note.id),\n title: note.title,\n updatedAt: note.updatedAt.toISOString(),\n pinned: note.pinned,\n tagNames: note.tags.map((tag) => tag.name),\n reminderCount,\n backReferenceCount: backReferences.length,\n matchedTerms: normalizedMatchedTerms,\n reasons: [\n ...(normalizedMatchedTerms.length > 0 ? [`matched_terms:${normalizedMatchedTerms.join(',')}`] : []),\n ...(note.pinned ? [] : ['not_pinned']),\n ...(note.tags.length === 0 ? ['tagless'] : []),\n ...(reminderCount === 0 ? ['no_reminders'] : []),\n ...(backReferences.length === 0 ? ['no_back_references'] : []),\n ],\n requiresForce: forceReasons.length > 0,\n forceReasons,\n };\n };\n\n const getDeletePreviewInternal = async (id: number): Promise<NoteCleanupPreviewInternal | null> => {\n const note = await deps.findNote(id);\n\n if (!note) {\n return null;\n }\n\n const [candidate, backReferences, tagNoteCounts] = await Promise.all([\n buildCandidate(note),\n deps.findBackReferences(note.id),\n deps.getTagNoteCounts(note.tags.map((tag) => tag.id)),\n ]);\n\n const orphanedTags = note.tags.filter((tag) => (tagNoteCounts.get(tag.id) ?? 0) <= 1);\n\n return {\n id: candidate.id,\n title: candidate.title,\n updatedAt: candidate.updatedAt,\n pinned: candidate.pinned,\n tagNames: candidate.tagNames,\n reminderCount: candidate.reminderCount,\n backReferences: backReferences.map((backReference) => ({\n id: String(backReference.id),\n title: backReference.title,\n })),\n orphanedTagNames: orphanedTags.map((tag) => tag.name),\n orphanedTagIds: orphanedTags.map((tag) => tag.id),\n requiresForce: candidate.requiresForce,\n forceReasons: candidate.forceReasons,\n };\n };\n\n const getDeletePreview = async (id: number): Promise<NoteCleanupPreview | null> => {\n const preview = await getDeletePreviewInternal(id);\n\n if (!preview) {\n return null;\n }\n\n const { orphanedTagIds, ...publicPreview } = preview;\n void orphanedTagIds;\n return publicPreview;\n };\n\n return {\n listCleanupCandidates: async (input = {}) => {\n const limit = Math.max(1, Number(input.limit ?? 20));\n const offset = Math.max(0, Number(input.offset ?? 0));\n const olderThanDays = Math.max(0, Number(input.olderThanDays ?? 0));\n const keywords = normalizeCleanupKeywords(input.keywords, input.query);\n\n const [totalCount, notes] = await Promise.all([\n deps.countCandidateNotes(keywords, olderThanDays),\n deps.findCandidateNotes(keywords, offset, limit, olderThanDays),\n ]);\n\n const candidates = await Promise.all(\n notes.map((note) => {\n const haystack = `${note.title}\\n${note.content}`.toLowerCase();\n const matchedTerms = keywords.filter((keyword) => haystack.includes(keyword));\n return buildCandidate(note, matchedTerms);\n }),\n );\n\n return {\n keywords,\n limit,\n offset,\n olderThanDays,\n notes: candidates,\n totalCount,\n };\n },\n getDeletePreview,\n deleteNoteById: async (id: number) => {\n const preview = await getDeletePreviewInternal(id);\n\n if (!preview) {\n return null;\n }\n\n await deps.deleteNoteAndPruneTags(id, preview.orphanedTagIds);\n\n const { orphanedTagIds, ...publicPreview } = preview;\n void orphanedTagIds;\n return publicPreview;\n },\n };\n};\n\nconst buildKeywordClauses = (keywords: string[]) => {\n return keywords.flatMap((keyword) => [{ title: { contains: keyword } }, { content: { contains: keyword } }]);\n};\n\nconst buildStaleWhere = (olderThanDays: number) => {\n if (olderThanDays <= 0) {\n return {};\n }\n\n return { updatedAt: { lte: new Date(Date.now() - olderThanDays * 24 * 60 * 60 * 1000) } };\n};\n\nconst noteCleanupService = createNoteCleanupService({\n countCandidateNotes: (keywords: string[], olderThanDays: number) =>\n models.note.count({\n where: {\n ...buildStaleWhere(olderThanDays),\n OR: buildKeywordClauses(keywords),\n },\n }),\n countReminders: (noteId: number) => models.reminder.count({ where: { noteId } }),\n deleteNoteAndPruneTags: async (noteId: number, orphanTagIds: number[]) => {\n void orphanTagIds;\n await moveNoteToTrashById(noteId);\n },\n findBackReferences: (noteId: number) =>\n models.note\n .findMany({\n select: {\n id: true,\n title: true,\n content: true,\n },\n where: {\n NOT: { id: noteId },\n },\n orderBy: [{ pinned: 'desc' }, { updatedAt: 'desc' }],\n })\n .then((notes) => notes.filter((note) => contentReferencesNote(note.content, noteId))),\n findCandidateNotes: (keywords: string[], skip: number, take: number, olderThanDays: number) =>\n models.note.findMany({\n include: { tags: true },\n orderBy: { updatedAt: 'asc' },\n skip,\n take,\n where: {\n ...buildStaleWhere(olderThanDays),\n OR: buildKeywordClauses(keywords),\n },\n }),\n findNote: (id: number) =>\n models.note.findUnique({\n where: { id },\n include: { tags: true },\n }),\n getTagNoteCounts: async (tagIds: number[]) => {\n if (tagIds.length === 0) {\n return new Map<number, number>();\n }\n\n const tags = await models.tag.findMany({\n where: { id: { in: tagIds } },\n include: { _count: { select: { notes: true } } },\n });\n\n return new Map(tags.map((tag) => [tag.id, tag._count.notes]));\n },\n});\n\nexport const listNoteCleanupCandidates = noteCleanupService.listCleanupCandidates;\nexport const getNoteCleanupPreview = noteCleanupService.getDeletePreview;\nexport const deleteNoteById = noteCleanupService.deleteNoteById;\n"],"mappings":"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","names":[]}
@@ -50,14 +50,6 @@ const serializeSnapshot = (snapshot) => {
50
50
  createdAt: isRecord(snapshot) && typeof snapshot.createdAt === "string" ? snapshot.createdAt : ""
51
51
  };
52
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
53
  const toTagIds = (tagIds) => {
62
54
  return tagIds.map((tagId) => Number(tagId)).filter((tagId) => Number.isSafeInteger(tagId) && tagId > 0);
63
55
  };
@@ -188,12 +180,9 @@ const applyMarkdownPlan = async (deps, input) => {
188
180
  };
189
181
  };
190
182
  const mapPlanResult = async (deps, input) => {
191
- if (input.plan.status !== "dry_run") {
183
+ if (input.plan.status !== "planned") {
192
184
  return input.plan;
193
185
  }
194
- if (input.dryRun ?? true) {
195
- return toDryRun(input.plan);
196
- }
197
186
  return applyMarkdownPlan(deps, {
198
187
  noteId: input.noteId,
199
188
  noteUpdatedAt: input.noteUpdatedAt,
@@ -234,7 +223,6 @@ const createMarkdownIntentWriteService = (deps) => ({
234
223
  noteUpdatedAt: noteSnapshot.updatedAt,
235
224
  beforeContentJson: note.content,
236
225
  plan,
237
- dryRun: input.dryRun,
238
226
  expectedUpdatedAt: input.expectedUpdatedAt,
239
227
  policy: input.policy,
240
228
  summary: input.intent
@@ -269,7 +257,6 @@ const createMarkdownIntentWriteService = (deps) => ({
269
257
  noteUpdatedAt: noteSnapshot.updatedAt,
270
258
  beforeContentJson: note.content,
271
259
  plan,
272
- dryRun: input.dryRun,
273
260
  expectedUpdatedAt: input.expectedUpdatedAt,
274
261
  policy: input.policy,
275
262
  summary: input.intent
@@ -302,7 +289,6 @@ const createMarkdownIntentWriteService = (deps) => ({
302
289
  noteUpdatedAt: noteSnapshot.updatedAt,
303
290
  beforeContentJson: note.content,
304
291
  plan,
305
- dryRun: input.dryRun,
306
292
  expectedUpdatedAt: input.expectedUpdatedAt,
307
293
  policy: input.policy,
308
294
  summary: input.intent
@@ -343,26 +329,11 @@ const createMarkdownIntentWriteService = (deps) => ({
343
329
  message: "The metadata update would not change the note."
344
330
  };
345
331
  }
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: []
332
+ const proposed = {
333
+ ...nextTitle !== void 0 ? { title: nextTitle } : {},
334
+ ...input.layout !== void 0 ? { layout: input.layout } : {},
335
+ ...resolvedPropertyPatch ? { properties: resolvedPropertyPatch } : {}
359
336
  };
360
- },
361
- applyNoteMetadata: async (input) => {
362
- const preview = await createMarkdownIntentWriteService(deps).updateNoteMetadata(input);
363
- if (preview.status !== "dry_run") {
364
- return preview;
365
- }
366
337
  if (input.properties !== void 0) {
367
338
  if (!deps.updateProperties) {
368
339
  throw new Error("Metadata property write dependency is not configured.");
@@ -371,11 +342,11 @@ const createMarkdownIntentWriteService = (deps) => ({
371
342
  try {
372
343
  updateResult2 = await deps.updateProperties({
373
344
  id: input.id,
374
- patch: preview.proposed.properties ?? { set: [], deleteKeys: [] },
345
+ patch: proposed.properties ?? { set: [], deleteKeys: [] },
375
346
  expectedUpdatedAt: input.expectedUpdatedAt,
376
347
  noteData: {
377
- ...preview.proposed.title !== void 0 ? { title: preview.proposed.title } : {},
378
- ...preview.proposed.layout !== void 0 ? { layout: preview.proposed.layout } : {}
348
+ ...proposed.title !== void 0 ? { title: proposed.title } : {},
349
+ ...proposed.layout !== void 0 ? { layout: proposed.layout } : {}
379
350
  },
380
351
  snapshotMeta: MCP_SNAPSHOT_META
381
352
  });
@@ -412,8 +383,8 @@ const createMarkdownIntentWriteService = (deps) => ({
412
383
  updateResult = await deps.updateNote({
413
384
  id: input.id,
414
385
  data: {
415
- ...preview.proposed.title !== void 0 ? { title: preview.proposed.title } : {},
416
- ...preview.proposed.layout !== void 0 ? { layout: preview.proposed.layout } : {}
386
+ ...proposed.title !== void 0 ? { title: proposed.title } : {},
387
+ ...proposed.layout !== void 0 ? { layout: proposed.layout } : {}
417
388
  },
418
389
  expectedUpdatedAt: input.expectedUpdatedAt,
419
390
  snapshotMeta: MCP_SNAPSHOT_META
@@ -475,10 +446,7 @@ const replaceNoteMarkdown = async (input) => {
475
446
  return defaultMarkdownIntentWriteService.replaceNoteMarkdown(input);
476
447
  };
477
448
  const updateNoteMetadata = async (input) => {
478
- if (input.dryRun ?? true) {
479
- return defaultMarkdownIntentWriteService.updateNoteMetadata(input);
480
- }
481
- return defaultMarkdownIntentWriteService.applyNoteMetadata(input);
449
+ return defaultMarkdownIntentWriteService.updateNoteMetadata(input);
482
450
  };
483
451
  const calculateNoteMarkdownSha256 = (markdown) => {
484
452
  return calculateMarkdownSha256(markdown);