ocean-brain 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mcp.js +79 -24
- package/package.json +2 -1
- package/server/client/dist/assets/{Calendar-DbPut8EU.js → Calendar-B2_OJcHD.js} +1 -1
- package/server/client/dist/assets/{Callout-DfX-gIUB.js → Callout-BvXAlA5k.js} +1 -1
- package/server/client/dist/assets/{Graph-yHE9m5fy.js → Graph-DO35UCPM.js} +1 -1
- package/server/client/dist/assets/{Image.es-CtMc7BW4.js → Image.es-DLqLiGdW.js} +1 -1
- package/server/client/dist/assets/Note-AaTlS352.js +22 -0
- package/server/client/dist/assets/{Plus.es-BGVIIQtM.js → Plus.es-I7xuoJ9B.js} +1 -1
- package/server/client/dist/assets/{Reminders-CvEJf0eQ.js → Reminders-B0LJeSlu.js} +1 -1
- package/server/client/dist/assets/{Search-CKZhztuV.js → Search-xbDSlNOT.js} +1 -1
- package/server/client/dist/assets/{SurfaceCard-Bnfo5EOl.js → SurfaceCard-Brd1cMxi.js} +1 -1
- package/server/client/dist/assets/{Tag-C4oAwjs0.js → Tag-2PlhkjwY.js} +1 -1
- package/server/client/dist/assets/{TagNotes-Rl1ZSJP6.js → TagNotes-1yUBLqhX.js} +1 -1
- package/server/client/dist/assets/{Trash.es-BcwUz2yM.js → Trash.es-B-7U25B6.js} +1 -1
- package/server/client/dist/assets/{ViewNotes-B9Yc0A87.js → ViewNotes-D4X-MCTk.js} +1 -1
- package/server/client/dist/assets/{ViewSectionTableRenderer-C5yJBO7C.js → ViewSectionTableRenderer-FuqBpQts.js} +1 -1
- package/server/client/dist/assets/{Views-Bqq0pUEE.js → Views-CBEimWY8.js} +1 -1
- package/server/client/dist/assets/{image.api-CuGTgzyQ.js → image.api-BtadKO98.js} +1 -1
- package/server/client/dist/assets/{index-CDjYEIVf.css → index-BFkZTZ6v.css} +1 -1
- package/server/client/dist/assets/{index-B43ulIPo.js → index-BgnmVjeF.js} +45 -11
- package/server/client/dist/assets/{index-BQDR6hIA.js → index-sGhvnErO.js} +1 -1
- package/server/client/dist/assets/{manage-image-Bs4Kmevx.js → manage-image-B4UZ-ZQx.js} +1 -1
- package/server/client/dist/assets/{manage-image-detail-WARala-v.js → manage-image-detail-ejAh3nCL.js} +1 -1
- package/server/client/dist/assets/{mcp-C0Z3vKBa.js → mcp-aIwuouT9.js} +1 -1
- package/server/client/dist/assets/{placeholder-D080guzn.js → placeholder-B_9Hnm7h.js} +4 -4
- package/server/client/dist/assets/{properties-DbnmfbT5.js → properties-D8oLyTCD.js} +1 -1
- package/server/client/dist/assets/{trash-D5ZiZfTk.js → trash-w7Hhxckg.js} +1 -1
- package/server/client/dist/assets/{useReminderMutate-h7d_S_X2.js → useReminderMutate--RlAj_Gg.js} +1 -1
- package/server/client/dist/index.html +2 -2
- package/server/dist/features/note/graphql/note.query.resolver.js +88 -47
- package/server/dist/features/note/graphql/note.query.resolver.js.map +1 -1
- package/server/dist/features/note/graphql/note.type-defs.js +32 -0
- package/server/dist/features/note/graphql/note.type-defs.js.map +1 -1
- package/server/dist/features/note/http/mcp.js +32 -0
- package/server/dist/features/note/http/mcp.js.map +1 -1
- package/server/dist/features/note/services/markdown-intent-write.js +3 -3
- package/server/dist/features/note/services/markdown-intent-write.js.map +1 -1
- package/server/dist/features/note/services/markdown-patch.js +34 -4
- package/server/dist/features/note/services/markdown-patch.js.map +1 -1
- package/server/dist/features/note/services/snapshot.js +159 -0
- package/server/dist/features/note/services/snapshot.js.map +1 -1
- package/server/dist/modules/blocknote.js +274 -24
- package/server/dist/modules/blocknote.js.map +1 -1
- package/server/dist/routes/mcp.js +5 -0
- package/server/dist/routes/mcp.js.map +1 -1
- package/server/client/dist/assets/Note-BECn-AoI.js +0 -21
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/features/note/graphql/note.query.resolver.ts"],"sourcesContent":["import type { IResolvers } from '@graphql-tools/utils';\nimport { getNoteCleanupPreview, listNoteCleanupCandidates } from '~/features/note/services/cleanup.js';\nimport {\n buildNoteGraph,\n contentReferencesNote,\n extractReferenceBlocksFromContent,\n normalizeReferenceId,\n syncReferenceTitlesInContent,\n} from '~/features/note/services/content-blocks.js';\nimport { listNotePropertyKeys } from '~/features/note/services/properties.js';\nimport {\n buildNoteSearchProjection,\n filterNotesBySearchQuery,\n NOTE_SEARCH_TEXT_SCHEMA_VERSION,\n parseNoteSearchQuery,\n} from '~/features/note/services/search.js';\nimport { getNoteSnapshot, listNoteSnapshots } from '~/features/note/services/snapshot.js';\nimport {\n buildNoteTagNamesWhere,\n type NoteTagMatchMode,\n normalizeNoteTagNames,\n} from '~/features/note/services/tag-filter.js';\nimport { getTrashedNoteById, listTrashedNotes } from '~/features/note/services/trash.js';\nimport type { Note, Prisma } from '~/models.js';\nimport models from '~/models.js';\nimport { runDataMaintenanceInBackground } from '~/modules/data-maintenance.js';\nimport type { Pagination, SearchFilter } from '~/types/index.js';\n\ninterface AllNotesResolverDeps {\n countNotes: (args: { where?: Prisma.NoteWhereInput }) => Promise<number>;\n findNotes: (args: {\n orderBy: Prisma.NoteOrderByWithRelationInput[];\n where?: Prisma.NoteWhereInput;\n take?: number;\n skip?: number;\n }) => Promise<Note[]>;\n triggerSearchBackfill: () => void;\n}\n\nconst buildAllNotesOrderBy = (searchFilter: SearchFilter) => {\n const sortBy = searchFilter.sortBy || 'updatedAt';\n const sortOrder = searchFilter.sortOrder || 'desc';\n const pinnedFirst = searchFilter.pinnedFirst || false;\n const orderBy: Prisma.NoteOrderByWithRelationInput[] = [];\n\n if (pinnedFirst) {\n orderBy.push({ pinned: 'desc' });\n }\n\n if (sortBy === 'createdAt') {\n orderBy.push({ createdAt: sortOrder as 'asc' | 'desc' });\n } else {\n orderBy.push({ updatedAt: sortOrder as 'asc' | 'desc' });\n }\n\n return orderBy;\n};\n\nconst buildAllNotesSearchWhere = (searchFilter: SearchFilter) => {\n const parsedQuery = parseNoteSearchQuery(searchFilter.query);\n\n if (!parsedQuery.hasFilters) {\n return undefined;\n }\n\n return {\n AND: [\n { searchableTextVersion: NOTE_SEARCH_TEXT_SCHEMA_VERSION },\n ...parsedQuery.included.map((keyword) => ({ searchableText: { contains: keyword } })),\n ...parsedQuery.excluded.map((keyword) => ({ NOT: { searchableText: { contains: keyword } } })),\n ],\n } satisfies Prisma.NoteWhereInput;\n};\n\nconst buildAllNotesStaleCandidateWhere = (searchFilter: SearchFilter) => {\n const parsedQuery = parseNoteSearchQuery(searchFilter.query);\n\n return {\n AND: [\n { searchableTextVersion: { not: NOTE_SEARCH_TEXT_SCHEMA_VERSION } },\n ...parsedQuery.included.map((keyword) => ({\n OR: [{ title: { contains: keyword } }, { content: { contains: keyword } }],\n })),\n ],\n } satisfies Prisma.NoteWhereInput;\n};\n\nconst compareNotesForSearch = (left: Note, right: Note, searchFilter: SearchFilter) => {\n if (searchFilter.pinnedFirst && left.pinned !== right.pinned) {\n return left.pinned ? -1 : 1;\n }\n\n const sortBy = searchFilter.sortBy || 'updatedAt';\n const sortOrder = searchFilter.sortOrder || 'desc';\n const leftValue = sortBy === 'createdAt' ? left.createdAt.getTime() : left.updatedAt.getTime();\n const rightValue = sortBy === 'createdAt' ? right.createdAt.getTime() : right.updatedAt.getTime();\n\n if (leftValue === rightValue) {\n return 0;\n }\n\n return sortOrder === 'asc' ? leftValue - rightValue : rightValue - leftValue;\n};\n\nconst mergeSortedNotesForSearch = (left: Note[], right: Note[], searchFilter: SearchFilter) => {\n const merged: Note[] = [];\n let leftIndex = 0;\n let rightIndex = 0;\n\n while (leftIndex < left.length && rightIndex < right.length) {\n if (compareNotesForSearch(left[leftIndex], right[rightIndex], searchFilter) <= 0) {\n merged.push(left[leftIndex]);\n leftIndex += 1;\n } else {\n merged.push(right[rightIndex]);\n rightIndex += 1;\n }\n }\n\n while (leftIndex < left.length) {\n merged.push(left[leftIndex]);\n leftIndex += 1;\n }\n\n while (rightIndex < right.length) {\n merged.push(right[rightIndex]);\n rightIndex += 1;\n }\n\n return merged;\n};\n\nconst isRecordNotFoundError = (error: unknown) => {\n return (\n typeof error === 'object' && error !== null && 'code' in error && (error as { code?: unknown }).code === 'P2025'\n );\n};\n\nexport const createAllNotesQueryResolver = (\n deps: AllNotesResolverDeps = {\n countNotes: ({ where }) => models.note.count({ where }),\n findNotes: ({ orderBy, where, take, skip }) =>\n models.note.findMany({\n orderBy,\n where,\n take,\n skip,\n }),\n triggerSearchBackfill: () => {\n void runDataMaintenanceInBackground();\n },\n },\n) => {\n return async (\n _: unknown,\n {\n searchFilter,\n pagination,\n }: {\n searchFilter: SearchFilter;\n pagination: Pagination;\n },\n ) => {\n const orderBy = buildAllNotesOrderBy(searchFilter);\n const limit = Number(pagination.limit);\n const offset = Number(pagination.offset);\n const where = buildAllNotesSearchWhere(searchFilter);\n\n if (!where) {\n const [notes, totalCount] = await Promise.all([\n deps.findNotes({\n orderBy,\n take: limit,\n skip: offset,\n }),\n deps.countNotes({}),\n ]);\n\n return {\n totalCount,\n notes,\n };\n }\n\n const staleCandidateNotes = await deps.findNotes({\n orderBy,\n where: buildAllNotesStaleCandidateWhere(searchFilter),\n });\n\n if (staleCandidateNotes.length === 0) {\n const [notes, totalCount] = await Promise.all([\n deps.findNotes({\n orderBy,\n where,\n take: limit,\n skip: offset,\n }),\n deps.countNotes({ where }),\n ]);\n\n return {\n totalCount,\n notes,\n };\n }\n\n deps.triggerSearchBackfill();\n\n const parsedQuery = parseNoteSearchQuery(searchFilter.query);\n const staleNotes = filterNotesBySearchQuery(staleCandidateNotes, parsedQuery);\n\n if (staleNotes.length === 0) {\n const [notes, totalCount] = await Promise.all([\n deps.findNotes({\n orderBy,\n where,\n take: limit,\n skip: offset,\n }),\n deps.countNotes({ where }),\n ]);\n\n return {\n totalCount,\n notes,\n };\n }\n\n const [freshNotesPrefix, freshTotalCount] = await Promise.all([\n deps.findNotes({\n orderBy,\n where,\n take: offset + limit,\n }),\n deps.countNotes({ where }),\n ]);\n\n const mergedNotes = mergeSortedNotesForSearch(freshNotesPrefix, staleNotes, searchFilter);\n\n return {\n totalCount: freshTotalCount + staleNotes.length,\n notes: mergedNotes.slice(offset, offset + limit),\n };\n };\n};\n\ntype NoteQueryResolvers = NonNullable<IResolvers['Query']>;\n\ninterface BackReferencesQueryResolverDeps {\n findCandidateNotes: (noteId: number) => Promise<Note[]>;\n}\n\nexport const createBackReferencesQueryResolver = (\n deps: BackReferencesQueryResolverDeps = {\n findCandidateNotes: (noteId) =>\n models.note.findMany({\n orderBy: [{ pinned: 'desc' }, { updatedAt: 'desc' }],\n where: {\n NOT: { id: noteId },\n },\n }),\n },\n) => {\n return async (_: unknown, { id }: { id: string }) => {\n const notes = await deps.findCandidateNotes(Number(id));\n\n return notes.filter((note) => contentReferencesNote(note.content, id));\n };\n};\n\ninterface NoteGraphQueryResolverDeps {\n findNotes: () => Promise<Array<Pick<Note, 'id' | 'title' | 'content'>>>;\n}\n\nexport const createNoteGraphQueryResolver = (\n deps: NoteGraphQueryResolverDeps = {\n findNotes: () =>\n models.note.findMany({\n select: {\n id: true,\n title: true,\n content: true,\n },\n }),\n },\n) => {\n return async () => {\n const notes = await deps.findNotes();\n\n return buildNoteGraph(notes);\n };\n};\n\nexport const noteQueryResolvers: NoteQueryResolvers = {\n allNotes: createAllNotesQueryResolver(),\n notesInDateRange: async (\n _,\n {\n dateRange,\n }: {\n dateRange: {\n start: string;\n end: string;\n };\n },\n ) => {\n const where: Prisma.NoteWhereInput = {\n OR: [\n {\n updatedAt: {\n gte: new Date(dateRange.start),\n lte: new Date(dateRange.end),\n },\n },\n {\n createdAt: {\n gte: new Date(dateRange.start),\n lte: new Date(dateRange.end),\n },\n },\n ],\n };\n\n return models.note.findMany({\n orderBy: { createdAt: 'asc' },\n where,\n });\n },\n tagNotes: async (\n _,\n {\n searchFilter,\n pagination,\n }: {\n searchFilter: SearchFilter;\n pagination: Pagination;\n },\n ) => {\n const where: Prisma.NoteWhereInput = { tags: { some: { id: Number(searchFilter.query) } } };\n const notes = models.note.findMany({\n orderBy: { updatedAt: 'desc' },\n where,\n take: Number(pagination.limit),\n skip: Number(pagination.offset),\n });\n\n return {\n totalCount: models.note.count({ where }),\n notes,\n };\n },\n notesByTagNames: async (\n _,\n {\n tagNames,\n mode,\n pagination,\n }: {\n tagNames: string[];\n mode: NoteTagMatchMode;\n pagination: Pagination;\n },\n ) => {\n const normalizedTagNames = normalizeNoteTagNames(tagNames);\n\n if (normalizedTagNames.length === 0) {\n return {\n totalCount: 0,\n notes: [],\n };\n }\n\n const where = buildNoteTagNamesWhere(normalizedTagNames, mode);\n const notes = models.note.findMany({\n orderBy: { updatedAt: 'desc' },\n where,\n take: Number(pagination.limit),\n skip: Number(pagination.offset),\n });\n\n return {\n totalCount: models.note.count({ where }),\n notes,\n };\n },\n pinnedNotes: async () =>\n models.note.findMany({\n orderBy: [{ order: 'asc' }, { updatedAt: 'desc' }],\n where: { pinned: true },\n }),\n imageNotes: async (_, { src }: { src: string }) =>\n models.note.findMany({\n orderBy: { updatedAt: 'desc' },\n where: { content: { contains: src } },\n }),\n backReferences: createBackReferencesQueryResolver(),\n note: async (_, { id }: { id: string }) => {\n const note = await models.note.findUnique({ where: { id: Number(id) } });\n\n if (!note) {\n throw 'NOT FOUND';\n }\n\n if (!note.content) {\n return note;\n }\n\n const blocks = extractReferenceBlocksFromContent(note.content);\n\n if (blocks.length === 0) {\n return note;\n }\n\n const referenceIds = Array.from(\n new Set(\n blocks\n .map((block) => normalizeReferenceId(block.props?.id))\n .filter((referenceId): referenceId is string => referenceId !== null)\n .map(Number)\n .filter(Number.isFinite),\n ),\n );\n const references = await models.note.findMany({ where: { id: { in: referenceIds } } });\n const titlesById = new Map(\n references.map((referenceNote: Note) => [String(referenceNote.id), referenceNote.title]),\n );\n const newContent = syncReferenceTitlesInContent(note.content, titlesById);\n\n if (!newContent || newContent === note.content) {\n return note;\n }\n\n try {\n return await models.note.update({\n where: {\n id: note.id,\n updatedAt: note.updatedAt,\n },\n data: {\n content: newContent,\n ...buildNoteSearchProjection({\n title: note.title,\n content: newContent,\n }),\n },\n });\n } catch (error) {\n if (isRecordNotFoundError(error)) {\n return note;\n }\n\n throw error;\n }\n },\n noteCleanupCandidates: async (\n _,\n {\n query,\n pagination = {\n limit: 20,\n offset: 0,\n },\n }: {\n query?: string;\n pagination: Pagination;\n },\n ) => {\n const result = await listNoteCleanupCandidates({\n keywords: query\n ? query\n .split(/[,\\s]+/)\n .map((keyword) => keyword.trim())\n .filter(Boolean)\n : undefined,\n limit: Number(pagination.limit),\n offset: Number(pagination.offset),\n });\n\n return result.notes;\n },\n noteCleanupPreview: async (_, { id }: { id: string }) => {\n return getNoteCleanupPreview(Number(id));\n },\n noteSnapshots: async (\n _,\n {\n id,\n limit = 10,\n }: {\n id: string;\n limit?: number;\n },\n ) => {\n return listNoteSnapshots(Number(id), Number(limit));\n },\n noteSnapshot: async (_, { id }: { id: string }) => {\n return getNoteSnapshot(Number(id));\n },\n notePropertyKeys: async (\n _,\n {\n query,\n pagination = {\n limit: 50,\n offset: 0,\n },\n }: {\n query?: string;\n pagination: Pagination;\n },\n ) => {\n return listNotePropertyKeys({\n query,\n limit: Number(pagination.limit),\n offset: Number(pagination.offset),\n });\n },\n trashedNote: async (_, { id }: { id: string }) => {\n return getTrashedNoteById(Number(id));\n },\n trashedNotes: async (\n _,\n {\n pagination = {\n limit: 25,\n offset: 0,\n },\n }: {\n pagination: Pagination;\n },\n ) => {\n return listTrashedNotes({\n limit: Number(pagination.limit),\n offset: Number(pagination.offset),\n });\n },\n noteGraph: createNoteGraphQueryResolver(),\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/features/note/graphql/note.query.resolver.ts"],"sourcesContent":["import type { IResolvers } from '@graphql-tools/utils';\nimport { getNoteCleanupPreview, listNoteCleanupCandidates } from '~/features/note/services/cleanup.js';\nimport {\n buildNoteGraph,\n contentReferencesNote,\n extractReferenceBlocksFromContent,\n normalizeReferenceId,\n syncReferenceTitlesInContent,\n} from '~/features/note/services/content-blocks.js';\nimport { listNotePropertyKeys } from '~/features/note/services/properties.js';\nimport {\n buildNoteSearchProjection,\n filterNotesBySearchQuery,\n NOTE_SEARCH_TEXT_SCHEMA_VERSION,\n parseNoteSearchQuery,\n} from '~/features/note/services/search.js';\nimport { diffNoteSnapshot, getNoteSnapshot, listNoteSnapshots } from '~/features/note/services/snapshot.js';\nimport {\n buildNoteTagNamesWhere,\n type NoteTagMatchMode,\n normalizeNoteTagNames,\n} from '~/features/note/services/tag-filter.js';\nimport { getTrashedNoteById, listTrashedNotes } from '~/features/note/services/trash.js';\nimport type { Note, Prisma } from '~/models.js';\nimport models from '~/models.js';\nimport { runDataMaintenanceInBackground } from '~/modules/data-maintenance.js';\nimport type { Pagination, SearchFilter } from '~/types/index.js';\n\ninterface AllNotesResolverDeps {\n countNotes: (args: { where?: Prisma.NoteWhereInput }) => Promise<number>;\n findNotes: (args: {\n orderBy: Prisma.NoteOrderByWithRelationInput[];\n where?: Prisma.NoteWhereInput;\n take?: number;\n skip?: number;\n }) => Promise<Note[]>;\n triggerSearchBackfill: () => void;\n}\n\nconst MAX_SQLITE_INT_ID = 2_147_483_647;\n\nconst isValidNoteIdString = (id: string) => {\n if (!/^[1-9]\\d*$/.test(id)) {\n return false;\n }\n\n const numericId = Number(id);\n\n return Number.isSafeInteger(numericId) && numericId <= MAX_SQLITE_INT_ID;\n};\n\ninterface NoteResolverDeps {\n findNote: (id: number) => Promise<Note | null>;\n findReferenceNotes: (ids: number[]) => Promise<Note[]>;\n updateNoteContent: (input: {\n id: number;\n updatedAt: Date;\n content: string;\n searchableText: string;\n searchableTextVersion: number;\n }) => Promise<Note>;\n isRecordNotFoundError: (error: unknown) => boolean;\n}\n\nconst buildAllNotesOrderBy = (searchFilter: SearchFilter) => {\n const sortBy = searchFilter.sortBy || 'updatedAt';\n const sortOrder = searchFilter.sortOrder || 'desc';\n const pinnedFirst = searchFilter.pinnedFirst || false;\n const orderBy: Prisma.NoteOrderByWithRelationInput[] = [];\n\n if (pinnedFirst) {\n orderBy.push({ pinned: 'desc' });\n }\n\n if (sortBy === 'createdAt') {\n orderBy.push({ createdAt: sortOrder as 'asc' | 'desc' });\n } else {\n orderBy.push({ updatedAt: sortOrder as 'asc' | 'desc' });\n }\n\n return orderBy;\n};\n\nconst buildAllNotesSearchWhere = (searchFilter: SearchFilter) => {\n const parsedQuery = parseNoteSearchQuery(searchFilter.query);\n\n if (!parsedQuery.hasFilters) {\n return undefined;\n }\n\n return {\n AND: [\n { searchableTextVersion: NOTE_SEARCH_TEXT_SCHEMA_VERSION },\n ...parsedQuery.included.map((keyword) => ({ searchableText: { contains: keyword } })),\n ...parsedQuery.excluded.map((keyword) => ({ NOT: { searchableText: { contains: keyword } } })),\n ],\n } satisfies Prisma.NoteWhereInput;\n};\n\nconst buildAllNotesStaleCandidateWhere = (searchFilter: SearchFilter) => {\n const parsedQuery = parseNoteSearchQuery(searchFilter.query);\n\n return {\n AND: [\n { searchableTextVersion: { not: NOTE_SEARCH_TEXT_SCHEMA_VERSION } },\n ...parsedQuery.included.map((keyword) => ({\n OR: [{ title: { contains: keyword } }, { content: { contains: keyword } }],\n })),\n ],\n } satisfies Prisma.NoteWhereInput;\n};\n\nconst compareNotesForSearch = (left: Note, right: Note, searchFilter: SearchFilter) => {\n if (searchFilter.pinnedFirst && left.pinned !== right.pinned) {\n return left.pinned ? -1 : 1;\n }\n\n const sortBy = searchFilter.sortBy || 'updatedAt';\n const sortOrder = searchFilter.sortOrder || 'desc';\n const leftValue = sortBy === 'createdAt' ? left.createdAt.getTime() : left.updatedAt.getTime();\n const rightValue = sortBy === 'createdAt' ? right.createdAt.getTime() : right.updatedAt.getTime();\n\n if (leftValue === rightValue) {\n return 0;\n }\n\n return sortOrder === 'asc' ? leftValue - rightValue : rightValue - leftValue;\n};\n\nconst mergeSortedNotesForSearch = (left: Note[], right: Note[], searchFilter: SearchFilter) => {\n const merged: Note[] = [];\n let leftIndex = 0;\n let rightIndex = 0;\n\n while (leftIndex < left.length && rightIndex < right.length) {\n if (compareNotesForSearch(left[leftIndex], right[rightIndex], searchFilter) <= 0) {\n merged.push(left[leftIndex]);\n leftIndex += 1;\n } else {\n merged.push(right[rightIndex]);\n rightIndex += 1;\n }\n }\n\n while (leftIndex < left.length) {\n merged.push(left[leftIndex]);\n leftIndex += 1;\n }\n\n while (rightIndex < right.length) {\n merged.push(right[rightIndex]);\n rightIndex += 1;\n }\n\n return merged;\n};\n\nconst isRecordNotFoundError = (error: unknown) => {\n return (\n typeof error === 'object' && error !== null && 'code' in error && (error as { code?: unknown }).code === 'P2025'\n );\n};\n\nexport const createAllNotesQueryResolver = (\n deps: AllNotesResolverDeps = {\n countNotes: ({ where }) => models.note.count({ where }),\n findNotes: ({ orderBy, where, take, skip }) =>\n models.note.findMany({\n orderBy,\n where,\n take,\n skip,\n }),\n triggerSearchBackfill: () => {\n void runDataMaintenanceInBackground();\n },\n },\n) => {\n return async (\n _: unknown,\n {\n searchFilter,\n pagination,\n }: {\n searchFilter: SearchFilter;\n pagination: Pagination;\n },\n ) => {\n const orderBy = buildAllNotesOrderBy(searchFilter);\n const limit = Number(pagination.limit);\n const offset = Number(pagination.offset);\n const where = buildAllNotesSearchWhere(searchFilter);\n\n if (!where) {\n const [notes, totalCount] = await Promise.all([\n deps.findNotes({\n orderBy,\n take: limit,\n skip: offset,\n }),\n deps.countNotes({}),\n ]);\n\n return {\n totalCount,\n notes,\n };\n }\n\n const staleCandidateNotes = await deps.findNotes({\n orderBy,\n where: buildAllNotesStaleCandidateWhere(searchFilter),\n });\n\n if (staleCandidateNotes.length === 0) {\n const [notes, totalCount] = await Promise.all([\n deps.findNotes({\n orderBy,\n where,\n take: limit,\n skip: offset,\n }),\n deps.countNotes({ where }),\n ]);\n\n return {\n totalCount,\n notes,\n };\n }\n\n deps.triggerSearchBackfill();\n\n const parsedQuery = parseNoteSearchQuery(searchFilter.query);\n const staleNotes = filterNotesBySearchQuery(staleCandidateNotes, parsedQuery);\n\n if (staleNotes.length === 0) {\n const [notes, totalCount] = await Promise.all([\n deps.findNotes({\n orderBy,\n where,\n take: limit,\n skip: offset,\n }),\n deps.countNotes({ where }),\n ]);\n\n return {\n totalCount,\n notes,\n };\n }\n\n const [freshNotesPrefix, freshTotalCount] = await Promise.all([\n deps.findNotes({\n orderBy,\n where,\n take: offset + limit,\n }),\n deps.countNotes({ where }),\n ]);\n\n const mergedNotes = mergeSortedNotesForSearch(freshNotesPrefix, staleNotes, searchFilter);\n\n return {\n totalCount: freshTotalCount + staleNotes.length,\n notes: mergedNotes.slice(offset, offset + limit),\n };\n };\n};\n\ntype NoteQueryResolvers = NonNullable<IResolvers['Query']>;\n\ninterface BackReferencesQueryResolverDeps {\n findCandidateNotes: (noteId: number) => Promise<Note[]>;\n}\n\nexport const createBackReferencesQueryResolver = (\n deps: BackReferencesQueryResolverDeps = {\n findCandidateNotes: (noteId) =>\n models.note.findMany({\n orderBy: [{ pinned: 'desc' }, { updatedAt: 'desc' }],\n where: {\n NOT: { id: noteId },\n },\n }),\n },\n) => {\n return async (_: unknown, { id }: { id: string }) => {\n const notes = await deps.findCandidateNotes(Number(id));\n\n return notes.filter((note) => contentReferencesNote(note.content, id));\n };\n};\n\ninterface NoteGraphQueryResolverDeps {\n findNotes: () => Promise<Array<Pick<Note, 'id' | 'title' | 'content'>>>;\n}\n\nexport const createNoteGraphQueryResolver = (\n deps: NoteGraphQueryResolverDeps = {\n findNotes: () =>\n models.note.findMany({\n select: {\n id: true,\n title: true,\n content: true,\n },\n }),\n },\n) => {\n return async () => {\n const notes = await deps.findNotes();\n\n return buildNoteGraph(notes);\n };\n};\n\nexport const createNoteQueryResolver = (\n deps: NoteResolverDeps = {\n findNote: (id) => models.note.findUnique({ where: { id } }),\n findReferenceNotes: (ids) => models.note.findMany({ where: { id: { in: ids } } }),\n updateNoteContent: ({ id, updatedAt, content, searchableText, searchableTextVersion }) =>\n models.note.update({\n where: {\n id,\n updatedAt,\n },\n data: {\n content,\n searchableText,\n searchableTextVersion,\n },\n }),\n isRecordNotFoundError,\n },\n) => {\n return async (_: unknown, { id }: { id: string }) => {\n const note = await deps.findNote(Number(id));\n\n if (!note) {\n throw 'NOT FOUND';\n }\n\n if (!note.content) {\n return note;\n }\n\n const blocks = extractReferenceBlocksFromContent(note.content);\n\n if (blocks.length === 0) {\n return note;\n }\n\n const referenceIds = Array.from(\n new Set(\n blocks\n .map((block) => normalizeReferenceId(block.props?.id))\n .filter(\n (referenceId): referenceId is string =>\n referenceId !== null && isValidNoteIdString(referenceId),\n )\n .map(Number),\n ),\n );\n const references = await deps.findReferenceNotes(referenceIds);\n const titlesById = new Map(\n references.map((referenceNote: Note) => [String(referenceNote.id), referenceNote.title]),\n );\n const newContent = syncReferenceTitlesInContent(note.content, titlesById);\n\n if (!newContent || newContent === note.content) {\n return note;\n }\n\n try {\n return await deps.updateNoteContent({\n id: note.id,\n updatedAt: note.updatedAt,\n content: newContent,\n ...buildNoteSearchProjection({\n title: note.title,\n content: newContent,\n }),\n });\n } catch (error) {\n if (deps.isRecordNotFoundError(error)) {\n return note;\n }\n\n throw error;\n }\n };\n};\n\nexport const noteQueryResolvers: NoteQueryResolvers = {\n allNotes: createAllNotesQueryResolver(),\n notesInDateRange: async (\n _,\n {\n dateRange,\n }: {\n dateRange: {\n start: string;\n end: string;\n };\n },\n ) => {\n const where: Prisma.NoteWhereInput = {\n OR: [\n {\n updatedAt: {\n gte: new Date(dateRange.start),\n lte: new Date(dateRange.end),\n },\n },\n {\n createdAt: {\n gte: new Date(dateRange.start),\n lte: new Date(dateRange.end),\n },\n },\n ],\n };\n\n return models.note.findMany({\n orderBy: { createdAt: 'asc' },\n where,\n });\n },\n tagNotes: async (\n _,\n {\n searchFilter,\n pagination,\n }: {\n searchFilter: SearchFilter;\n pagination: Pagination;\n },\n ) => {\n const where: Prisma.NoteWhereInput = { tags: { some: { id: Number(searchFilter.query) } } };\n const notes = models.note.findMany({\n orderBy: { updatedAt: 'desc' },\n where,\n take: Number(pagination.limit),\n skip: Number(pagination.offset),\n });\n\n return {\n totalCount: models.note.count({ where }),\n notes,\n };\n },\n notesByTagNames: async (\n _,\n {\n tagNames,\n mode,\n pagination,\n }: {\n tagNames: string[];\n mode: NoteTagMatchMode;\n pagination: Pagination;\n },\n ) => {\n const normalizedTagNames = normalizeNoteTagNames(tagNames);\n\n if (normalizedTagNames.length === 0) {\n return {\n totalCount: 0,\n notes: [],\n };\n }\n\n const where = buildNoteTagNamesWhere(normalizedTagNames, mode);\n const notes = models.note.findMany({\n orderBy: { updatedAt: 'desc' },\n where,\n take: Number(pagination.limit),\n skip: Number(pagination.offset),\n });\n\n return {\n totalCount: models.note.count({ where }),\n notes,\n };\n },\n pinnedNotes: async () =>\n models.note.findMany({\n orderBy: [{ order: 'asc' }, { updatedAt: 'desc' }],\n where: { pinned: true },\n }),\n imageNotes: async (_, { src }: { src: string }) =>\n models.note.findMany({\n orderBy: { updatedAt: 'desc' },\n where: { content: { contains: src } },\n }),\n backReferences: createBackReferencesQueryResolver(),\n note: createNoteQueryResolver(),\n noteCleanupCandidates: async (\n _,\n {\n query,\n pagination = {\n limit: 20,\n offset: 0,\n },\n }: {\n query?: string;\n pagination: Pagination;\n },\n ) => {\n const result = await listNoteCleanupCandidates({\n keywords: query\n ? query\n .split(/[,\\s]+/)\n .map((keyword) => keyword.trim())\n .filter(Boolean)\n : undefined,\n limit: Number(pagination.limit),\n offset: Number(pagination.offset),\n });\n\n return result.notes;\n },\n noteCleanupPreview: async (_, { id }: { id: string }) => {\n return getNoteCleanupPreview(Number(id));\n },\n noteSnapshots: async (\n _,\n {\n id,\n limit = 10,\n }: {\n id: string;\n limit?: number;\n },\n ) => {\n return listNoteSnapshots(Number(id), Number(limit));\n },\n noteSnapshot: async (_, { id }: { id: string }) => {\n return getNoteSnapshot(Number(id));\n },\n noteSnapshotDiff: async (\n _,\n {\n id,\n compareToSnapshotId,\n target,\n contextLines,\n }: {\n id: string;\n compareToSnapshotId?: string;\n target?: 'NEXT' | 'PREVIOUS' | 'CURRENT';\n contextLines?: number | null;\n },\n ) => {\n const normalizedContextLines = contextLines ?? 3;\n\n if (normalizedContextLines < 0 || normalizedContextLines > 20) {\n throw new Error('INVALID_SNAPSHOT_DIFF_CONTEXT_LINES');\n }\n\n return diffNoteSnapshot(Number(id), {\n ...(compareToSnapshotId !== undefined ? { compareToSnapshotId: Number(compareToSnapshotId) } : {}),\n ...(target !== undefined ? { target: target.toLowerCase() as 'next' | 'previous' | 'current' } : {}),\n contextLines: normalizedContextLines,\n });\n },\n notePropertyKeys: async (\n _,\n {\n query,\n pagination = {\n limit: 50,\n offset: 0,\n },\n }: {\n query?: string;\n pagination: Pagination;\n },\n ) => {\n return listNotePropertyKeys({\n query,\n limit: Number(pagination.limit),\n offset: Number(pagination.offset),\n });\n },\n trashedNote: async (_, { id }: { id: string }) => {\n return getTrashedNoteById(Number(id));\n },\n trashedNotes: async (\n _,\n {\n pagination = {\n limit: 25,\n offset: 0,\n },\n }: {\n pagination: Pagination;\n },\n ) => {\n return listTrashedNotes({\n limit: Number(pagination.limit),\n offset: Number(pagination.offset),\n });\n },\n noteGraph: createNoteGraphQueryResolver(),\n};\n"],"mappings":"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","names":[]}
|
|
@@ -199,6 +199,37 @@ const noteType = gql`
|
|
|
199
199
|
meta: NoteSnapshotMeta!
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
+
enum NoteSnapshotDiffTarget {
|
|
203
|
+
NEXT
|
|
204
|
+
PREVIOUS
|
|
205
|
+
CURRENT
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
type NoteSnapshotDiffEndpoint {
|
|
209
|
+
kind: String!
|
|
210
|
+
id: ID!
|
|
211
|
+
title: String!
|
|
212
|
+
createdAt: String
|
|
213
|
+
updatedAt: String
|
|
214
|
+
meta: NoteSnapshotMeta
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
type NoteSnapshotDiffDetail {
|
|
218
|
+
markdown: String!
|
|
219
|
+
changedLineCount: Int!
|
|
220
|
+
changedCharCount: Int!
|
|
221
|
+
beforeMarkdownSha256: String!
|
|
222
|
+
afterMarkdownSha256: String!
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
type NoteSnapshotDiff {
|
|
226
|
+
noteId: ID!
|
|
227
|
+
mode: String!
|
|
228
|
+
before: NoteSnapshotDiffEndpoint!
|
|
229
|
+
after: NoteSnapshotDiffEndpoint!
|
|
230
|
+
diff: NoteSnapshotDiffDetail!
|
|
231
|
+
}
|
|
232
|
+
|
|
202
233
|
type DeletedNote {
|
|
203
234
|
id: ID!
|
|
204
235
|
title: String!
|
|
@@ -248,6 +279,7 @@ const noteQuery = gql`
|
|
|
248
279
|
noteCleanupPreview(id: ID!): NoteCleanupPreview
|
|
249
280
|
noteSnapshots(id: ID!, limit: Int): [NoteSnapshot!]!
|
|
250
281
|
noteSnapshot(id: ID!): NoteSnapshot
|
|
282
|
+
noteSnapshotDiff(id: ID!, compareToSnapshotId: ID, target: NoteSnapshotDiffTarget, contextLines: Int): NoteSnapshotDiff
|
|
251
283
|
notePropertyKeys(query: String, pagination: PaginationInput): NotePropertyKeys!
|
|
252
284
|
trashedNote(id: ID!): DeletedNote
|
|
253
285
|
trashedNotes(pagination: PaginationInput): DeletedNotes!
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/features/note/graphql/note.type-defs.ts"],"sourcesContent":["import { gql } from '~/modules/graphql.js';\n\nexport const noteType = gql`\n input PaginationInput {\n limit: Int!\n offset: Int!\n }\n\n input SearchFilterInput {\n query: String!\n sortBy: String\n sortOrder: String\n pinnedFirst: Boolean\n }\n\n input DateRangeInput {\n start: String!\n end: String!\n }\n\n enum NoteLayout {\n narrow\n wide\n full\n }\n\n enum TagMatchMode {\n and\n or\n }\n\n enum NotePropertyValueType {\n text\n url\n number\n date\n boolean\n select\n }\n\n input NoteInput {\n title: String\n content: String\n layout: NoteLayout\n }\n\n input NotePropertySetInput {\n key: String!\n name: String\n value: String!\n valueType: NotePropertyValueType!\n }\n\n input NotePropertyOptionInput {\n label: String!\n value: String\n color: String\n order: Int\n }\n\n input NotePropertyOptionUpdateInput {\n id: ID\n label: String!\n value: String\n color: String\n order: Int\n }\n\n input NotePropertyDefinitionInput {\n key: String!\n name: String\n valueType: NotePropertyValueType!\n options: [NotePropertyOptionInput!]\n }\n\n input NotePropertyDefinitionUpdateInput {\n name: String\n options: [NotePropertyOptionUpdateInput!]\n }\n\n input NotePropertiesPatchInput {\n set: [NotePropertySetInput!]\n deleteKeys: [String!]\n }\n\n input NoteOrderInput {\n id: ID!\n order: Int!\n }\n\n type Tag {\n id: ID!\n name: String!\n createdAt: String!\n updatedAt: String!\n }\n\n type Note {\n id: ID!\n title: String!\n content: String!\n contentAsMarkdown: String!\n createdAt: String!\n updatedAt: String!\n pinned: Boolean!\n order: Int!\n layout: NoteLayout!\n tags: [Tag!]!\n properties: [NoteProperty!]!\n }\n\n type NoteProperty {\n key: String!\n name: String!\n value: String!\n valueType: NotePropertyValueType!\n createdAt: String!\n option: NotePropertyOption\n updatedAt: String!\n }\n\n type NotePropertyOption {\n id: ID!\n label: String!\n value: String!\n color: String\n order: Int!\n }\n\n type NotePropertyKey {\n key: String!\n name: String!\n valueType: NotePropertyValueType!\n noteCount: Int!\n options: [NotePropertyOption!]!\n updatedAt: String!\n }\n\n type NotePropertyKeys {\n totalCount: Int!\n keys: [NotePropertyKey!]!\n }\n\n type NotePropertyDeleteResult {\n key: String!\n name: String!\n valueType: NotePropertyValueType!\n affectedNoteCount: Int!\n deleted: Boolean!\n }\n\n type Notes {\n totalCount: Int!\n notes: [Note!]!\n }\n\n type NoteCleanupBackReference {\n id: ID!\n title: String!\n }\n\n type NoteCleanupCandidate {\n id: ID!\n title: String!\n updatedAt: String!\n pinned: Boolean!\n tagNames: [String!]!\n reminderCount: Int!\n backReferenceCount: Int!\n matchedTerms: [String!]!\n reasons: [String!]!\n requiresForce: Boolean!\n forceReasons: [String!]!\n }\n\n type NoteCleanupPreview {\n id: ID!\n title: String!\n updatedAt: String!\n pinned: Boolean!\n tagNames: [String!]!\n reminderCount: Int!\n backReferences: [NoteCleanupBackReference!]!\n orphanedTagNames: [String!]!\n requiresForce: Boolean!\n forceReasons: [String!]!\n }\n\n type NoteSnapshotMeta {\n entrypoint: String\n label: String\n }\n\n type NoteSnapshot {\n id: ID!\n title: String!\n contentPreview: String!\n contentAsMarkdown: String!\n createdAt: String!\n meta: NoteSnapshotMeta!\n }\n\n type DeletedNote {\n id: ID!\n title: String!\n createdAt: String!\n updatedAt: String!\n deletedAt: String!\n contentPreview: String!\n contentAsMarkdown: String\n pinned: Boolean!\n order: Int!\n layout: NoteLayout!\n tagNames: [String!]!\n }\n\n type DeletedNotes {\n totalCount: Int!\n notes: [DeletedNote!]!\n }\n`;\n\nexport const noteQuery = gql`\n type GraphNode {\n id: ID!\n title: String!\n connections: Int!\n }\n\n type GraphLink {\n source: ID!\n target: ID!\n }\n\n type NoteGraph {\n nodes: [GraphNode!]!\n links: [GraphLink!]!\n }\n\n type Query {\n allNotes(searchFilter: SearchFilterInput, pagination: PaginationInput): Notes!\n tagNotes(searchFilter: SearchFilterInput, pagination: PaginationInput): Notes!\n notesByTagNames(tagNames: [String!]!, mode: TagMatchMode!, pagination: PaginationInput): Notes!\n notesInDateRange(dateRange: DateRangeInput): [Note!]!\n pinnedNotes: [Note!]!\n imageNotes(src: String!): [Note!]!\n backReferences(id: ID!): [Note]!\n note(id: ID!): Note!\n noteCleanupCandidates(query: String, pagination: PaginationInput): [NoteCleanupCandidate!]!\n noteCleanupPreview(id: ID!): NoteCleanupPreview\n noteSnapshots(id: ID!, limit: Int): [NoteSnapshot!]!\n noteSnapshot(id: ID!): NoteSnapshot\n notePropertyKeys(query: String, pagination: PaginationInput): NotePropertyKeys!\n trashedNote(id: ID!): DeletedNote\n trashedNotes(pagination: PaginationInput): DeletedNotes!\n noteGraph: NoteGraph!\n }\n`;\n\nexport const noteMutation = gql`\n type Mutation {\n createNote(note: NoteInput!): Note!\n updateNote(id: ID!, note: NoteInput!, editSessionId: String, expectedUpdatedAt: String, force: Boolean): Note!\n deleteNote(id: ID!): Boolean!\n restoreNoteSnapshot(id: ID!): Note!\n restoreTrashedNote(id: ID!): Note!\n purgeTrashedNote(id: ID!): Boolean!\n createNotePropertyKey(input: NotePropertyDefinitionInput!): NotePropertyKey!\n updateNotePropertyKey(key: String!, input: NotePropertyDefinitionUpdateInput!): NotePropertyKey!\n deleteNotePropertyKey(key: String!, confirmImpact: Boolean): NotePropertyDeleteResult!\n updateNoteProperties(\n id: ID!\n patch: NotePropertiesPatchInput!\n editSessionId: String\n expectedUpdatedAt: String!\n force: Boolean\n ): Note!\n pinNote(id: ID!, pinned: Boolean!): Note!\n reorderNotes(notes: [NoteOrderInput!]!): [Note!]!\n }\n`;\n\nexport const noteTypeDefs = `\n ${noteType}\n ${noteQuery}\n ${noteMutation}\n`;\n"],"mappings":"AAAA,SAAS,WAAW;AAEb,MAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
1
|
+
{"version":3,"sources":["../../../../src/features/note/graphql/note.type-defs.ts"],"sourcesContent":["import { gql } from '~/modules/graphql.js';\n\nexport const noteType = gql`\n input PaginationInput {\n limit: Int!\n offset: Int!\n }\n\n input SearchFilterInput {\n query: String!\n sortBy: String\n sortOrder: String\n pinnedFirst: Boolean\n }\n\n input DateRangeInput {\n start: String!\n end: String!\n }\n\n enum NoteLayout {\n narrow\n wide\n full\n }\n\n enum TagMatchMode {\n and\n or\n }\n\n enum NotePropertyValueType {\n text\n url\n number\n date\n boolean\n select\n }\n\n input NoteInput {\n title: String\n content: String\n layout: NoteLayout\n }\n\n input NotePropertySetInput {\n key: String!\n name: String\n value: String!\n valueType: NotePropertyValueType!\n }\n\n input NotePropertyOptionInput {\n label: String!\n value: String\n color: String\n order: Int\n }\n\n input NotePropertyOptionUpdateInput {\n id: ID\n label: String!\n value: String\n color: String\n order: Int\n }\n\n input NotePropertyDefinitionInput {\n key: String!\n name: String\n valueType: NotePropertyValueType!\n options: [NotePropertyOptionInput!]\n }\n\n input NotePropertyDefinitionUpdateInput {\n name: String\n options: [NotePropertyOptionUpdateInput!]\n }\n\n input NotePropertiesPatchInput {\n set: [NotePropertySetInput!]\n deleteKeys: [String!]\n }\n\n input NoteOrderInput {\n id: ID!\n order: Int!\n }\n\n type Tag {\n id: ID!\n name: String!\n createdAt: String!\n updatedAt: String!\n }\n\n type Note {\n id: ID!\n title: String!\n content: String!\n contentAsMarkdown: String!\n createdAt: String!\n updatedAt: String!\n pinned: Boolean!\n order: Int!\n layout: NoteLayout!\n tags: [Tag!]!\n properties: [NoteProperty!]!\n }\n\n type NoteProperty {\n key: String!\n name: String!\n value: String!\n valueType: NotePropertyValueType!\n createdAt: String!\n option: NotePropertyOption\n updatedAt: String!\n }\n\n type NotePropertyOption {\n id: ID!\n label: String!\n value: String!\n color: String\n order: Int!\n }\n\n type NotePropertyKey {\n key: String!\n name: String!\n valueType: NotePropertyValueType!\n noteCount: Int!\n options: [NotePropertyOption!]!\n updatedAt: String!\n }\n\n type NotePropertyKeys {\n totalCount: Int!\n keys: [NotePropertyKey!]!\n }\n\n type NotePropertyDeleteResult {\n key: String!\n name: String!\n valueType: NotePropertyValueType!\n affectedNoteCount: Int!\n deleted: Boolean!\n }\n\n type Notes {\n totalCount: Int!\n notes: [Note!]!\n }\n\n type NoteCleanupBackReference {\n id: ID!\n title: String!\n }\n\n type NoteCleanupCandidate {\n id: ID!\n title: String!\n updatedAt: String!\n pinned: Boolean!\n tagNames: [String!]!\n reminderCount: Int!\n backReferenceCount: Int!\n matchedTerms: [String!]!\n reasons: [String!]!\n requiresForce: Boolean!\n forceReasons: [String!]!\n }\n\n type NoteCleanupPreview {\n id: ID!\n title: String!\n updatedAt: String!\n pinned: Boolean!\n tagNames: [String!]!\n reminderCount: Int!\n backReferences: [NoteCleanupBackReference!]!\n orphanedTagNames: [String!]!\n requiresForce: Boolean!\n forceReasons: [String!]!\n }\n\n type NoteSnapshotMeta {\n entrypoint: String\n label: String\n }\n\n type NoteSnapshot {\n id: ID!\n title: String!\n contentPreview: String!\n contentAsMarkdown: String!\n createdAt: String!\n meta: NoteSnapshotMeta!\n }\n\n enum NoteSnapshotDiffTarget {\n NEXT\n PREVIOUS\n CURRENT\n }\n\n type NoteSnapshotDiffEndpoint {\n kind: String!\n id: ID!\n title: String!\n createdAt: String\n updatedAt: String\n meta: NoteSnapshotMeta\n }\n\n type NoteSnapshotDiffDetail {\n markdown: String!\n changedLineCount: Int!\n changedCharCount: Int!\n beforeMarkdownSha256: String!\n afterMarkdownSha256: String!\n }\n\n type NoteSnapshotDiff {\n noteId: ID!\n mode: String!\n before: NoteSnapshotDiffEndpoint!\n after: NoteSnapshotDiffEndpoint!\n diff: NoteSnapshotDiffDetail!\n }\n\n type DeletedNote {\n id: ID!\n title: String!\n createdAt: String!\n updatedAt: String!\n deletedAt: String!\n contentPreview: String!\n contentAsMarkdown: String\n pinned: Boolean!\n order: Int!\n layout: NoteLayout!\n tagNames: [String!]!\n }\n\n type DeletedNotes {\n totalCount: Int!\n notes: [DeletedNote!]!\n }\n`;\n\nexport const noteQuery = gql`\n type GraphNode {\n id: ID!\n title: String!\n connections: Int!\n }\n\n type GraphLink {\n source: ID!\n target: ID!\n }\n\n type NoteGraph {\n nodes: [GraphNode!]!\n links: [GraphLink!]!\n }\n\n type Query {\n allNotes(searchFilter: SearchFilterInput, pagination: PaginationInput): Notes!\n tagNotes(searchFilter: SearchFilterInput, pagination: PaginationInput): Notes!\n notesByTagNames(tagNames: [String!]!, mode: TagMatchMode!, pagination: PaginationInput): Notes!\n notesInDateRange(dateRange: DateRangeInput): [Note!]!\n pinnedNotes: [Note!]!\n imageNotes(src: String!): [Note!]!\n backReferences(id: ID!): [Note]!\n note(id: ID!): Note!\n noteCleanupCandidates(query: String, pagination: PaginationInput): [NoteCleanupCandidate!]!\n noteCleanupPreview(id: ID!): NoteCleanupPreview\n noteSnapshots(id: ID!, limit: Int): [NoteSnapshot!]!\n noteSnapshot(id: ID!): NoteSnapshot\n noteSnapshotDiff(id: ID!, compareToSnapshotId: ID, target: NoteSnapshotDiffTarget, contextLines: Int): NoteSnapshotDiff\n notePropertyKeys(query: String, pagination: PaginationInput): NotePropertyKeys!\n trashedNote(id: ID!): DeletedNote\n trashedNotes(pagination: PaginationInput): DeletedNotes!\n noteGraph: NoteGraph!\n }\n`;\n\nexport const noteMutation = gql`\n type Mutation {\n createNote(note: NoteInput!): Note!\n updateNote(id: ID!, note: NoteInput!, editSessionId: String, expectedUpdatedAt: String, force: Boolean): Note!\n deleteNote(id: ID!): Boolean!\n restoreNoteSnapshot(id: ID!): Note!\n restoreTrashedNote(id: ID!): Note!\n purgeTrashedNote(id: ID!): Boolean!\n createNotePropertyKey(input: NotePropertyDefinitionInput!): NotePropertyKey!\n updateNotePropertyKey(key: String!, input: NotePropertyDefinitionUpdateInput!): NotePropertyKey!\n deleteNotePropertyKey(key: String!, confirmImpact: Boolean): NotePropertyDeleteResult!\n updateNoteProperties(\n id: ID!\n patch: NotePropertiesPatchInput!\n editSessionId: String\n expectedUpdatedAt: String!\n force: Boolean\n ): Note!\n pinNote(id: ID!, pinned: Boolean!): Note!\n reorderNotes(notes: [NoteOrderInput!]!): [Note!]!\n }\n`;\n\nexport const noteTypeDefs = `\n ${noteType}\n ${noteQuery}\n ${noteMutation}\n`;\n"],"mappings":"AAAA,SAAS,WAAW;AAEb,MAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2PjB,MAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsClB,MAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBrB,MAAM,eAAe;AAAA,MACtB,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,YAAY;AAAA;","names":[]}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
updateNoteMetadata
|
|
12
12
|
} from "../../../features/note/services/markdown-intent-write.js";
|
|
13
13
|
import { MCP_SNAPSHOT_META } from "../../../features/note/services/snapshot.js";
|
|
14
|
+
import models from "../../../models.js";
|
|
14
15
|
import { createAppError } from "../../../modules/error-handler.js";
|
|
15
16
|
import { emitServerEvent } from "../../../modules/server-events.js";
|
|
16
17
|
const NOTE_LAYOUTS = /* @__PURE__ */ new Set(["narrow", "wide", "full"]);
|
|
@@ -90,6 +91,12 @@ const resolvePositiveNoteId = (value) => {
|
|
|
90
91
|
}
|
|
91
92
|
return noteId;
|
|
92
93
|
};
|
|
94
|
+
const serializeNoteWriteBaseline = (note) => {
|
|
95
|
+
return {
|
|
96
|
+
id: String(note.id),
|
|
97
|
+
updatedAt: note.updatedAt instanceof Date ? note.updatedAt.toISOString() : note.updatedAt
|
|
98
|
+
};
|
|
99
|
+
};
|
|
93
100
|
const isNonNegativeInteger = (value) => {
|
|
94
101
|
return typeof value === "number" && Number.isInteger(value) && value >= 0;
|
|
95
102
|
};
|
|
@@ -122,6 +129,12 @@ const resolveMarkdownWritePolicy = (value) => {
|
|
|
122
129
|
}
|
|
123
130
|
policy.maxChangedLines = value.maxChangedLines;
|
|
124
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
|
+
}
|
|
125
138
|
if (value.preserveTags !== void 0) {
|
|
126
139
|
if (!PRESERVATION_POLICIES.has(value.preserveTags)) {
|
|
127
140
|
throw createAppError(400, "INVALID_MARKDOWN_POLICY", "preserveTags must be boolean or warn.");
|
|
@@ -335,6 +348,24 @@ const createMcpUpdateNoteHandler = (updateNote = updateNoteFromMarkdown, emitEve
|
|
|
335
348
|
}
|
|
336
349
|
};
|
|
337
350
|
};
|
|
351
|
+
const createMcpNoteWriteBaselineHandler = (findNoteBaseline = async (id) => models.note.findUnique({
|
|
352
|
+
where: { id },
|
|
353
|
+
select: {
|
|
354
|
+
id: true,
|
|
355
|
+
updatedAt: true
|
|
356
|
+
}
|
|
357
|
+
})) => {
|
|
358
|
+
return async (req, res) => {
|
|
359
|
+
const noteId = resolvePositiveNoteId(req.body?.id);
|
|
360
|
+
const note = await findNoteBaseline(noteId);
|
|
361
|
+
if (!note) {
|
|
362
|
+
throw createAppError(404, "NOTE_NOT_FOUND", "The requested note was not found.");
|
|
363
|
+
}
|
|
364
|
+
res.status(200).json({
|
|
365
|
+
note: serializeNoteWriteBaseline(note)
|
|
366
|
+
}).end();
|
|
367
|
+
};
|
|
368
|
+
};
|
|
338
369
|
const createMcpPatchNoteMarkdownHandler = (patchMarkdown = patchNoteMarkdown, emitEvent = emitServerEvent) => {
|
|
339
370
|
return async (req, res) => {
|
|
340
371
|
const { id, expectedUpdatedAt, baseMarkdownSha256, intent, selector, operation, policy, dryRun } = req.body ?? {};
|
|
@@ -521,6 +552,7 @@ export {
|
|
|
521
552
|
createMcpAppendNoteMarkdownHandler,
|
|
522
553
|
createMcpCreateNoteHandler,
|
|
523
554
|
createMcpDeleteNoteHandler,
|
|
555
|
+
createMcpNoteWriteBaselineHandler,
|
|
524
556
|
createMcpPatchNoteMarkdownHandler,
|
|
525
557
|
createMcpReplaceNoteMarkdownHandler,
|
|
526
558
|
createMcpUpdateNoteHandler,
|
|
@@ -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 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 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.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 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":"AAAA;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,OACG;AACP,SAAS,sBAAsB;AAC/B;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AAQP,SAAS,yBAAyB;AAElC,SAAS,sBAAsB;AAC/B,SAAS,uBAA8C;AAGvD,MAAM,eAAe,oBAAI,IAAgB,CAAC,UAAU,QAAQ,MAAM,CAAC;AAEnE,MAAM,iBAAiB,oBAAI,IAAI,CAAC,SAAS,MAAM,CAAC;AAChD,MAAM,wBAAwB,oBAAI,IAAa,CAAC,MAAM,OAAO,MAAM,CAAC;AAEpE,MAAM,WAAW,CAAC,UAAqD;AACnE,SAAO,OAAO,UAAU,YAAY,UAAU;AAClD;AAEA,MAAM,oBAAoB,CAAC,UAAkD;AACzE,MAAI,UAAU,QAAW;AACrB,WAAO;AAAA,EACX;AAEA,MAAI,OAAO,UAAU,YAAY,aAAa,IAAI,KAAmB,GAAG;AACpE,WAAO;AAAA,EACX;AAEA,SAAO;AACX;AAEA,MAAM,wBAAwB,CAAC,OAAgB,MAAc,YAAoB;AAC7E,MAAI,UAAU,QAAW;AACrB,WAAO;AAAA,EACX;AAEA,MAAI,OAAO,UAAU,UAAU;AAC3B,WAAO;AAAA,EACX;AAEA,QAAM,eAAe,KAAK,MAAM,OAAO;AAC3C;AAEA,MAAM,yBAAyB,CAAC,OAAgB,MAAc,YAAoB;AAC9E,MAAI,UAAU,QAAW;AACrB,WAAO;AAAA,EACX;AAEA,MAAI,OAAO,UAAU,WAAW;AAC5B,WAAO;AAAA,EACX;AAEA,QAAM,eAAe,KAAK,MAAM,OAAO;AAC3C;AAEA,MAAM,+BAA+B,CAAC,UAA8D;AAChG,MAAI,UAAU,QAAW;AACrB,WAAO;AAAA,EACX;AAEA,MAAI,CAAC,SAAS,KAAK,GAAG;AAClB,UAAM,eAAe,KAAK,2BAA2B,qCAAqC;AAAA,EAC9F;AAEA,QAAM,MACF,MAAM,QAAQ,SACR,SACA,MAAM,QAAQ,MAAM,GAAG,IACrB,MAAM,IAAI,IAAI,CAAC,SAAS;AACpB,QAAI,CAAC,SAAS,IAAI,KAAK,OAAO,KAAK,QAAQ,YAAY,OAAO,KAAK,UAAU,UAAU;AACnF,YAAM;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,MACJ;AAAA,IACJ;AAEA,WAAO;AAAA,MACH,KAAK,KAAK;AAAA,MACV,OAAO,KAAK;AAAA,IAChB;AAAA,EACJ,CAAC,IACD;AAEZ,MAAI,QAAQ,MAAM;AACd,UAAM,eAAe,KAAK,2BAA2B,gCAAgC;AAAA,EACzF;AAEA,QAAM,aACF,MAAM,eAAe,SACf,SACA,MAAM,QAAQ,MAAM,UAAU,IAC5B,MAAM,WAAW,IAAI,CAAC,QAAQ;AAC1B,QAAI,OAAO,QAAQ,UAAU;AACzB,YAAM,eAAe,KAAK,2BAA2B,sCAAsC;AAAA,IAC/F;AAEA,WAAO;AAAA,EACX,CAAC,IACD;AAEZ,MAAI,eAAe,MAAM;AACrB,UAAM,eAAe,KAAK,2BAA2B,uCAAuC;AAAA,EAChG;AAEA,SAAO;AAAA,IACH,GAAI,QAAQ,SAAY,EAAE,IAAI,IAAI,CAAC;AAAA,IACnC,GAAI,eAAe,SAAY,EAAE,WAAW,IAAI,CAAC;AAAA,EACrD;AACJ;AAEA,MAAM,wBAAwB,CAAC,UAAmB;AAC9C,QAAM,SAAS,OAAO,KAAK;AAE3B,MAAI,CAAC,OAAO,UAAU,MAAM,KAAK,UAAU,GAAG;AAC1C,UAAM,eAAe,KAAK,mBAAmB,8BAA8B;AAAA,EAC/E;AAEA,SAAO;AACX;AAEA,MAAM,uBAAuB,CAAC,UAAoC;AAC9D,SAAO,OAAO,UAAU,YAAY,OAAO,UAAU,KAAK,KAAK,SAAS;AAC5E;AAEA,MAAM,oBAAoB,CAAC,UAAoC;AAC3D,SAAO,OAAO,UAAU,YAAY,OAAO,UAAU,KAAK,KAAK,QAAQ;AAC3E;AAEA,MAAM,6BAA6B,CAAC,UAAqD;AACrF,MAAI,UAAU,QAAW;AACrB,WAAO;AAAA,EACX;AAEA,MAAI,CAAC,SAAS,KAAK,GAAG;AAClB,UAAM,eAAe,KAAK,2BAA2B,0CAA0C;AAAA,EACnG;AAEA,QAAM,SAA+B,CAAC;AAEtC,MAAI,MAAM,cAAc,QAAW;AAC/B,QAAI,OAAO,MAAM,cAAc,WAAW;AACtC,YAAM,eAAe,KAAK,2BAA2B,8BAA8B;AAAA,IACvF;AACA,WAAO,YAAY,MAAM;AAAA,EAC7B;AAEA,MAAI,MAAM,oBAAoB,QAAW;AACrC,QAAI,CAAC,qBAAqB,MAAM,eAAe,GAAG;AAC9C,YAAM,eAAe,KAAK,2BAA2B,iDAAiD;AAAA,IAC1G;AACA,WAAO,kBAAkB,MAAM;AAAA,EACnC;AAEA,MAAI,MAAM,oBAAoB,QAAW;AACrC,QAAI,CAAC,qBAAqB,MAAM,eAAe,GAAG;AAC9C,YAAM,eAAe,KAAK,2BAA2B,iDAAiD;AAAA,IAC1G;AACA,WAAO,kBAAkB,MAAM;AAAA,EACnC;AAEA,MAAI,MAAM,iBAAiB,QAAW;AAClC,QAAI,CAAC,sBAAsB,IAAI,MAAM,YAAY,GAAG;AAChD,YAAM,eAAe,KAAK,2BAA2B,uCAAuC;AAAA,IAChG;AACA,WAAO,eAAe,MAAM;AAAA,EAChC;AAEA,MAAI,MAAM,uBAAuB,QAAW;AACxC,QAAI,CAAC,sBAAsB,IAAI,MAAM,kBAAkB,GAAG;AACtD,YAAM,eAAe,KAAK,2BAA2B,6CAA6C;AAAA,IACtG;AACA,WAAO,qBAAqB,MAAM;AAAA,EACtC;AAEA,SAAO;AACX;AAEA,MAAM,uBAAuB,CAAC,UAA0C;AACpE,MAAI,CAAC,SAAS,KAAK,GAAG;AAClB,UAAM,eAAe,KAAK,0BAA0B,mCAAmC;AAAA,EAC3F;AAEA,MAAI,MAAM,SAAS,cAAc;AAC7B,QAAI,OAAO,MAAM,SAAS,UAAU;AAChC,YAAM,eAAe,KAAK,0BAA0B,oCAAoC;AAAA,IAC5F;AAEA,WAAO;AAAA,MACH,MAAM;AAAA,MACN,MAAM,MAAM;AAAA,MACZ,GAAI,MAAM,WAAW,SACf;AAAA,QACI,QAAQ;AAAA,UACJ,MAAM;AAAA,UACN;AAAA,UACA;AAAA,QACJ;AAAA,MACJ,IACA,CAAC;AAAA,MACP,GAAI,MAAM,UAAU,SACd;AAAA,QACI,OAAO;AAAA,UACH,MAAM;AAAA,UACN;AAAA,UACA;AAAA,QACJ;AAAA,MACJ,IACA,CAAC;AAAA,IACX;AAAA,EACJ;AAEA,MAAI,MAAM,SAAS,mBAAmB;AAClC,UAAM,EAAE,MAAM,YAAY,WAAW,aAAa,iBAAiB,aAAa,IAAI;AAEpF,QACI,OAAO,SAAS,YAChB,CAAC,qBAAqB,UAAU,KAChC,CAAC,kBAAkB,SAAS,KAC5B,OAAO,gBAAgB,YACvB,OAAO,oBAAoB,UAC7B;AACE,YAAM,eAAe,KAAK,0BAA0B,8CAA8C;AAAA,IACtG;AAEA,QAAI,iBAAiB,UAAa,CAAC,eAAe,IAAI,OAAO,YAAY,CAAC,GAAG;AACzE,YAAM,eAAe,KAAK,0BAA0B,qCAAqC;AAAA,IAC7F;AAEA,WAAO;AAAA,MACH,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAI,eAAe,EAAE,aAA+C,IAAI,CAAC;AAAA,IAC7E;AAAA,EACJ;AAEA,QAAM,eAAe,KAAK,0BAA0B,kCAAkC;AAC1F;AAEA,MAAM,wBAAwB,CAAC,UAA2C;AACtE,MAAI,CAAC,SAAS,KAAK,GAAG;AAClB,UAAM,eAAe,KAAK,2BAA2B,oCAAoC;AAAA,EAC7F;AAEA,MAAI,MAAM,SAAS,WAAW;AAC1B,QAAI,OAAO,MAAM,gBAAgB,UAAU;AACvC,YAAM,eAAe,KAAK,2BAA2B,yCAAyC;AAAA,IAClG;AAEA,WAAO;AAAA,MACH,MAAM;AAAA,MACN,aAAa,MAAM;AAAA,IACvB;AAAA,EACJ;AAEA,MAAI,MAAM,SAAS,mBAAmB,MAAM,SAAS,gBAAgB;AACjE,QAAI,OAAO,MAAM,cAAc,UAAU;AACrC,YAAM,eAAe,KAAK,2BAA2B,sCAAsC;AAAA,IAC/F;AAEA,WAAO;AAAA,MACH,MAAM,MAAM;AAAA,MACZ,WAAW,MAAM;AAAA,IACrB;AAAA,EACJ;AAEA,QAAM,eAAe,KAAK,2BAA2B,mCAAmC;AAC5F;AAEA,MAAM,yBAAyB,CAAC,UAAwD;AACpF,MAAI,UAAU,QAAW;AACrB,WAAO;AAAA,EACX;AAEA,MAAI,CAAC,SAAS,KAAK,GAAG;AAClB,UAAM,eAAe,KAAK,4BAA4B,qCAAqC;AAAA,EAC/F;AAEA,MAAI,MAAM,SAAS,OAAO;AACtB,WAAO,EAAE,MAAM,MAAM;AAAA,EACzB;AAEA,MAAI,MAAM,SAAS,iBAAiB;AAChC,QAAI,OAAO,MAAM,YAAY,UAAU;AACnC,YAAM,eAAe,KAAK,4BAA4B,2CAA2C;AAAA,IACrG;AAEA,UAAM,EAAE,SAAS,MAAM,IAAI;AAE3B,QAAI,OAAO,YAAY,UAAU;AAC7B,YAAM,eAAe,KAAK,4BAA4B,2CAA2C;AAAA,IACrG;AAEA,QAAI,UAAU,WAAc,OAAO,UAAU,YAAY,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ,IAAI;AAC1G,YAAM,eAAe,KAAK,4BAA4B,+CAA+C;AAAA,IACzG;AAEA,WAAO;AAAA,MACH,MAAM;AAAA,MACN;AAAA,MACA,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,IAC3C;AAAA,EACJ;AAEA,QAAM,eAAe,KAAK,4BAA4B,oCAAoC;AAC9F;AAEA,MAAM,mBAAmB,CAAC,UAAmB;AACzC,MAAI,UAAU,QAAW;AACrB,WAAO;AAAA,EACX;AAEA,MAAI,UAAU,QAAQ,UAAU,QAAQ;AACpC,WAAO;AAAA,EACX;AAEA,QAAM,eAAe,KAAK,qBAAqB,sCAAsC;AACzF;AAIO,MAAM,6BAA6B,CACtC,aAAa,wBACb,YAA6B,oBAChB;AACb,SAAO,OAAO,KAAK,QAAQ;AACvB,UAAM,EAAE,OAAO,UAAU,OAAO,IAAI,IAAI,QAAQ,CAAC;AACjD,UAAM,iBAAiB,kBAAkB,MAAM;AAE/C,QAAI,OAAO,UAAU,UAAU;AAC3B,YAAM,eAAe,KAAK,sBAAsB,2BAA2B;AAAA,IAC/E;AAEA,QAAI,aAAa,UAAa,OAAO,aAAa,UAAU;AACxD,YAAM,eAAe,KAAK,yBAAyB,iCAAiC;AAAA,IACxF;AAEA,QAAI,WAAW,UAAa,mBAAmB,MAAM;AACjD,YAAM,eAAe,KAAK,uBAAuB,mDAAmD;AAAA,IACxG;AAEA,QAAI;AACA,YAAM,OAAO,MAAM,WAAW;AAAA,QAC1B;AAAA,QACA,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,QAC7C,GAAI,iBAAiB,EAAE,QAAQ,eAAe,IAAI,CAAC;AAAA,MACvD,CAAC;AAED,gBAAU;AAAA,QACN,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,QAAQ,KAAK;AAAA,QACb,WAAW,KAAK;AAAA,MACpB,CAAC;AAED,UAAI,OAAO,GAAG,EACT,KAAK;AAAA,QACF,SAAS;AAAA,QACT;AAAA,MACJ,CAAC,EACA,IAAI;AAAA,IACb,SAAS,OAAO;AACZ,UAAI,iBAAiB,gCAAgC;AACjD,cAAM,eAAe,KAAK,sBAAsB,MAAM,OAAO;AAAA,MACjE;AAEA,YAAM;AAAA,IACV;AAAA,EACJ;AACJ;AAEO,MAAM,6BAA6B,CACtC,aAAa,wBACb,YAA6B,oBAChB;AACb,SAAO,OAAO,KAAK,QAAQ;AACvB,UAAM,EAAE,IAAI,OAAO,UAAU,QAAQ,cAAc,IAAI,IAAI,QAAQ,CAAC;AACpE,UAAM,SAAS,OAAO,EAAE;AACxB,UAAM,iBAAiB,kBAAkB,MAAM;AAE/C,QAAI,CAAC,OAAO,UAAU,MAAM,KAAK,UAAU,GAAG;AAC1C,YAAM,eAAe,KAAK,mBAAmB,8BAA8B;AAAA,IAC/E;AAEA,QAAI,UAAU,UAAa,OAAO,UAAU,UAAU;AAClD,YAAM,eAAe,KAAK,sBAAsB,8BAA8B;AAAA,IAClF;AAEA,QAAI,aAAa,UAAa,OAAO,aAAa,UAAU;AACxD,YAAM,eAAe,KAAK,yBAAyB,iCAAiC;AAAA,IACxF;AAEA,QAAI,WAAW,UAAa,mBAAmB,MAAM;AACjD,YAAM,eAAe,KAAK,uBAAuB,mDAAmD;AAAA,IACxG;AAEA,QAAI,kBAAkB,UAAa,OAAO,kBAAkB,UAAU;AAClE,YAAM,eAAe,KAAK,2BAA2B,mCAAmC;AAAA,IAC5F;AAEA,QAAI,UAAU,UAAa,aAAa,UAAa,WAAW,QAAW;AACvE,YAAM,eAAe,KAAK,sBAAsB,sDAAsD;AAAA,IAC1G;AAEA,QAAI;AACA,YAAM,OAAO,MAAM,WAAW;AAAA,QAC1B,IAAI;AAAA,QACJ,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,QACvC,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,QAC7C,GAAI,iBAAiB,EAAE,QAAQ,eAAe,IAAI,CAAC;AAAA,QACnD,GAAI,kBAAkB,SAAY,EAAE,cAAc,IAAI,CAAC;AAAA,QACvD,cAAc;AAAA,MAClB,CAAC;AAED,UAAI,CAAC,MAAM;AACP,cAAM,eAAe,KAAK,kBAAkB,mCAAmC;AAAA,MACnF;AAEA,gBAAU;AAAA,QACN,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,QAAQ,KAAK;AAAA,QACb,WAAW,KAAK;AAAA,MACpB,CAAC;AAED,UAAI,OAAO,GAAG,EACT,KAAK;AAAA,QACF,SAAS;AAAA,QACT;AAAA,MACJ,CAAC,EACA,IAAI;AAAA,IACb,SAAS,OAAO;AACZ,UAAI,iBAAiB,gCAAgC;AACjD,cAAM,eAAe,KAAK,sBAAsB,MAAM,OAAO;AAAA,MACjE;AAEA,YAAM;AAAA,IACV;AAAA,EACJ;AACJ;AAEO,MAAM,oCAAoC,CAC7C,gBAAgB,mBAChB,YAA6B,oBAChB;AACb,SAAO,OAAO,KAAK,QAAQ;AACvB,UAAM,EAAE,IAAI,mBAAmB,oBAAoB,QAAQ,UAAU,WAAW,QAAQ,OAAO,IAC3F,IAAI,QAAQ,CAAC;AACjB,UAAM,SAAS,sBAAsB,EAAE;AACvC,UAAM,4BAA4B;AAAA,MAC9B;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,UAAM,6BAA6B;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,UAAM,iBAAiB,uBAAuB,QAAQ,mBAAmB,2BAA2B;AAEpG,QAAI,OAAO,WAAW,UAAU;AAC5B,YAAM,eAAe,KAAK,wBAAwB,gCAAgC;AAAA,IACtF;AAEA,UAAM,SAAS,MAAM,cAAc;AAAA,MAC/B,IAAI;AAAA,MACJ,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,MACpB;AAAA,MACA,UAAU,qBAAqB,QAAQ;AAAA,MACvC,WAAW,sBAAsB,SAAS;AAAA,MAC1C,QAAQ,2BAA2B,MAAM;AAAA,MACzC,QAAQ;AAAA,IACZ,CAAC;AAED,QAAI,OAAO,WAAW,WAAW;AAC7B,gBAAU;AAAA,QACN,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,QAAQ,OAAO,KAAK;AAAA,QACpB,WAAW,OAAO,KAAK;AAAA,MAC3B,CAAC;AAAA,IACL;AAEA,QAAI,OAAO,GAAG,EAAE,KAAK,MAAM,EAAE,IAAI;AAAA,EACrC;AACJ;AAEO,MAAM,qCAAqC,CAC9C,iBAAiB,oBACjB,YAA6B,oBAChB;AACb,SAAO,OAAO,KAAK,QAAQ;AACvB,UAAM,EAAE,IAAI,mBAAmB,oBAAoB,QAAQ,WAAW,WAAW,WAAW,QAAQ,OAAO,IACvG,IAAI,QAAQ,CAAC;AACjB,UAAM,SAAS,sBAAsB,EAAE;AACvC,UAAM,4BAA4B;AAAA,MAC9B;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,UAAM,6BAA6B;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,UAAM,iBAAiB,uBAAuB,QAAQ,mBAAmB,2BAA2B;AAEpG,QAAI,OAAO,WAAW,UAAU;AAC5B,YAAM,eAAe,KAAK,yBAAyB,iCAAiC;AAAA,IACxF;AAEA,QAAI,OAAO,cAAc,UAAU;AAC/B,YAAM,eAAe,KAAK,4BAA4B,oCAAoC;AAAA,IAC9F;AAEA,UAAM,SAAS,MAAM,eAAe;AAAA,MAChC,IAAI;AAAA,MACJ,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,MACpB;AAAA,MACA;AAAA,MACA,WAAW,uBAAuB,SAAS;AAAA,MAC3C,WAAW,iBAAiB,SAAS;AAAA,MACrC,QAAQ,2BAA2B,MAAM;AAAA,MACzC,QAAQ;AAAA,IACZ,CAAC;AAED,QAAI,OAAO,WAAW,WAAW;AAC7B,gBAAU;AAAA,QACN,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,QAAQ,OAAO,KAAK;AAAA,QACpB,WAAW,OAAO,KAAK;AAAA,MAC3B,CAAC;AAAA,IACL;AAEA,QAAI,OAAO,GAAG,EAAE,KAAK,MAAM,EAAE,IAAI;AAAA,EACrC;AACJ;AAEO,MAAM,sCAAsC,CAC/C,kBAAkB,qBAClB,YAA6B,oBAChB;AACb,SAAO,OAAO,KAAK,QAAQ;AACvB,UAAM,EAAE,IAAI,mBAAmB,oBAAoB,QAAQ,aAAa,QAAQ,OAAO,IAAI,IAAI,QAAQ,CAAC;AACxG,UAAM,SAAS,sBAAsB,EAAE;AACvC,UAAM,4BAA4B;AAAA,MAC9B;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,UAAM,6BAA6B;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,UAAM,iBAAiB,uBAAuB,QAAQ,mBAAmB,2BAA2B;AAEpG,QAAI,OAAO,WAAW,UAAU;AAC5B,YAAM,eAAe,KAAK,0BAA0B,kCAAkC;AAAA,IAC1F;AAEA,QAAI,OAAO,gBAAgB,UAAU;AACjC,YAAM,eAAe,KAAK,4BAA4B,wCAAwC;AAAA,IAClG;AAEA,UAAM,SAAS,MAAM,gBAAgB;AAAA,MACjC,IAAI;AAAA,MACJ,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,MACpB;AAAA,MACA;AAAA,MACA,QAAQ,2BAA2B,MAAM;AAAA,MACzC,QAAQ;AAAA,IACZ,CAAC;AAED,QAAI,OAAO,WAAW,WAAW;AAC7B,gBAAU;AAAA,QACN,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,QAAQ,OAAO,KAAK;AAAA,QACpB,WAAW,OAAO,KAAK;AAAA,MAC3B,CAAC;AAAA,IACL;AAEA,QAAI,OAAO,GAAG,EAAE,KAAK,MAAM,EAAE,IAAI;AAAA,EACrC;AACJ;AAEO,MAAM,qCAAqC,CAC9C,iBAAiB,oBACjB,YAA6B,oBAChB;AACb,SAAO,OAAO,KAAK,QAAQ;AACvB,UAAM,EAAE,IAAI,mBAAmB,OAAO,QAAQ,YAAY,OAAO,IAAI,IAAI,QAAQ,CAAC;AAClF,UAAM,SAAS,sBAAsB,EAAE;AACvC,UAAM,iBAAiB,kBAAkB,MAAM;AAC/C,UAAM,qBAAqB,6BAA6B,UAAU;AAClE,UAAM,iBAAiB,uBAAuB,QAAQ,mBAAmB,2BAA2B;AAEpG,QAAI,OAAO,sBAAsB,UAAU;AACvC,YAAM,eAAe,KAAK,wBAAwB,qCAAqC;AAAA,IAC3F;AAEA,QAAI,UAAU,UAAa,OAAO,UAAU,UAAU;AAClD,YAAM,eAAe,KAAK,sBAAsB,8BAA8B;AAAA,IAClF;AAEA,QAAI,WAAW,UAAa,mBAAmB,MAAM;AACjD,YAAM,eAAe,KAAK,uBAAuB,mDAAmD;AAAA,IACxG;AAEA,QAAI,UAAU,UAAa,WAAW,UAAa,uBAAuB,QAAW;AACjF,YAAM,eAAe,KAAK,sBAAsB,+CAA+C;AAAA,IACnG;AAEA,UAAM,SAAS,MAAM,eAAe;AAAA,MAChC,IAAI;AAAA,MACJ;AAAA,MACA,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,MACvC,GAAI,iBAAiB,EAAE,QAAQ,eAAe,IAAI,CAAC;AAAA,MACnD,GAAI,uBAAuB,SAAY,EAAE,YAAY,mBAAmB,IAAI,CAAC;AAAA,MAC7E,QAAQ;AAAA,IACZ,CAAC;AAED,QAAI,OAAO,WAAW,WAAW;AAC7B,gBAAU;AAAA,QACN,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,QAAQ,OAAO,KAAK;AAAA,QACpB,WAAW,OAAO,KAAK;AAAA,MAC3B,CAAC;AAAA,IACL;AAEA,QAAI,OAAO,GAAG,EAAE,KAAK,MAAM,EAAE,IAAI;AAAA,EACrC;AACJ;AAEO,MAAM,6BAA6B,CACtC,aAAa,gBACb,YAA6B,oBAChB;AACb,SAAO,OAAO,KAAK,QAAQ;AACvB,UAAM,KAAK,OAAO,IAAI,MAAM,EAAE;AAE9B,QAAI,CAAC,OAAO,UAAU,EAAE,KAAK,MAAM,GAAG;AAClC,YAAM,eAAe,KAAK,mBAAmB,8BAA8B;AAAA,IAC/E;AAEA,UAAM,cAAc,MAAM,WAAW,EAAE;AAEvC,QAAI,CAAC,aAAa;AACd,YAAM,eAAe,KAAK,kBAAkB,mCAAmC;AAAA,IACnF;AAEA,cAAU;AAAA,MACN,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ,YAAY;AAAA,IACxB,CAAC;AAED,QAAI,OAAO,GAAG,EACT,KAAK;AAAA,MACF,SAAS;AAAA,MACT,MAAM;AAAA,IACV,CAAC,EACA,IAAI;AAAA,EACb;AACJ;","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 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":[]}
|
|
@@ -64,7 +64,7 @@ const toTagIds = (tagIds) => {
|
|
|
64
64
|
const baselineMismatchFailure = () => ({
|
|
65
65
|
status: "failed",
|
|
66
66
|
reason: "BASELINE_MISMATCH",
|
|
67
|
-
message: "The markdown write baseline does not match the current note."
|
|
67
|
+
message: "The markdown write baseline does not match the current note. expectedUpdatedAt accepts an ISO datetime string or epoch milliseconds string."
|
|
68
68
|
});
|
|
69
69
|
const missingBaselineFailure = () => ({
|
|
70
70
|
status: "failed",
|
|
@@ -143,7 +143,7 @@ const applyMarkdownPlan = async (deps, input) => {
|
|
|
143
143
|
}
|
|
144
144
|
const beforeReferenceCount = deps.countReferenceInlines?.(input.beforeContentJson) ?? 0;
|
|
145
145
|
const afterReferenceCount = deps.countReferenceInlines?.(content) ?? 0;
|
|
146
|
-
if (input.policy?.preserveReferences
|
|
146
|
+
if (input.policy?.preserveReferences === true && afterReferenceCount < beforeReferenceCount) {
|
|
147
147
|
return referenceStructureFailure();
|
|
148
148
|
}
|
|
149
149
|
const tagIds = toTagIds(deps.extractTagIds(content));
|
|
@@ -321,7 +321,7 @@ const createMarkdownIntentWriteService = (deps) => ({
|
|
|
321
321
|
return {
|
|
322
322
|
status: "failed",
|
|
323
323
|
reason: input.expectedUpdatedAt ? "BASELINE_MISMATCH" : "MISSING_BASELINE",
|
|
324
|
-
message: "The metadata update baseline does not match the current note."
|
|
324
|
+
message: "The metadata update baseline does not match the current note. expectedUpdatedAt accepts an ISO datetime string or epoch milliseconds string."
|
|
325
325
|
};
|
|
326
326
|
}
|
|
327
327
|
const nextTitle = input.title?.trim();
|