ocean-brain 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/mcp.js +660 -31
  2. package/package.json +2 -1
  3. package/server/client/dist/assets/{Calendar-BU9XgX2N.js → Calendar-BytW4PeT.js} +1 -1
  4. package/server/client/dist/assets/{Callout-C6tVCxOT.js → Callout-9sJgGNRb.js} +1 -1
  5. package/server/client/dist/assets/Graph-o5u-NzrA.js +1 -0
  6. package/server/client/dist/assets/{Image.es-BjGK7y6Y.js → Image.es-B0LL3pb7.js} +1 -1
  7. package/server/client/dist/assets/Note-CYoYzZNu.js +21 -0
  8. package/server/client/dist/assets/{Plus.es-EcmtS_uw.js → Plus.es-DpxzgRtY.js} +1 -1
  9. package/server/client/dist/assets/Reminders-DAepTZg1.js +1 -0
  10. package/server/client/dist/assets/Search-6KH7An44.js +1 -0
  11. package/server/client/dist/assets/{SurfaceCard-CO0oVxeL.js → SurfaceCard-EMs50xSF.js} +1 -1
  12. package/server/client/dist/assets/Tag-C89j8x56.js +1 -0
  13. package/server/client/dist/assets/TagNotes-BTbu-f6v.js +1 -0
  14. package/server/client/dist/assets/{Trash.es-DmwfSy3l.js → Trash.es-C5x35NKF.js} +1 -1
  15. package/server/client/dist/assets/ViewNotes-DPEuki3y.js +1 -0
  16. package/server/client/dist/assets/Views-BGkuNhVd.js +1 -0
  17. package/server/client/dist/assets/{image.api-DeF9ck7g.js → image.api-DRhRQ0Gf.js} +1 -1
  18. package/server/client/dist/assets/{index-BZUGWdOU.css → index-Cd81UxEh.css} +1 -1
  19. package/server/client/dist/assets/{index-BvKBTjQq.js → index-DYlYUrjH.js} +118 -37
  20. package/server/client/dist/assets/index-DswSFFMb.js +1 -0
  21. package/server/client/dist/assets/manage-image-C6sHhWnI.js +1 -0
  22. package/server/client/dist/assets/manage-image-detail-CJkfybR9.js +1 -0
  23. package/server/client/dist/assets/{mcp-Bh743HBz.js → mcp-piouFDNm.js} +1 -1
  24. package/server/client/dist/assets/{placeholder-XQqo1Fvr.js → placeholder-DGz3CHej.js} +5 -5
  25. package/server/client/dist/assets/properties-CM4khczg.js +1 -0
  26. package/server/client/dist/assets/trash-C2lItz-b.js +1 -0
  27. package/server/client/dist/assets/{useReminderMutate-D21PurIS.js → useReminderMutate-DHjDDHKg.js} +1 -1
  28. package/server/client/dist/assets/view-dashboard-C17WsdL7.js +99 -0
  29. package/server/client/dist/index.html +2 -2
  30. package/server/dist/features/note/graphql/note.field.resolver.js +2 -0
  31. package/server/dist/features/note/graphql/note.field.resolver.js.map +1 -1
  32. package/server/dist/features/note/graphql/note.mutation.resolver.js +119 -0
  33. package/server/dist/features/note/graphql/note.mutation.resolver.js.map +1 -1
  34. package/server/dist/features/note/graphql/note.query.resolver.js +14 -0
  35. package/server/dist/features/note/graphql/note.query.resolver.js.map +1 -1
  36. package/server/dist/features/note/graphql/note.type-defs.js +100 -0
  37. package/server/dist/features/note/graphql/note.type-defs.js.map +1 -1
  38. package/server/dist/features/note/http/mcp.js +394 -1
  39. package/server/dist/features/note/http/mcp.js.map +1 -1
  40. package/server/dist/features/note/services/markdown-intent-write.js +478 -0
  41. package/server/dist/features/note/services/markdown-intent-write.js.map +1 -0
  42. package/server/dist/features/note/services/markdown-patch.js +601 -0
  43. package/server/dist/features/note/services/markdown-patch.js.map +1 -0
  44. package/server/dist/features/note/services/properties.js +874 -0
  45. package/server/dist/features/note/services/properties.js.map +1 -0
  46. package/server/dist/features/note/services/snapshot.js +94 -12
  47. package/server/dist/features/note/services/snapshot.js.map +1 -1
  48. package/server/dist/features/note/services/trash.js +70 -2
  49. package/server/dist/features/note/services/trash.js.map +1 -1
  50. package/server/dist/features/note/services/write.js +21 -7
  51. package/server/dist/features/note/services/write.js.map +1 -1
  52. package/server/dist/features/view/graphql/view.query.resolver.js +31 -1
  53. package/server/dist/features/view/graphql/view.query.resolver.js.map +1 -1
  54. package/server/dist/features/view/graphql/view.type-defs.js +57 -1
  55. package/server/dist/features/view/graphql/view.type-defs.js.map +1 -1
  56. package/server/dist/features/view/services/workspace.js +367 -43
  57. package/server/dist/features/view/services/workspace.js.map +1 -1
  58. package/server/dist/modules/blocknote.js +47 -2
  59. package/server/dist/modules/blocknote.js.map +1 -1
  60. package/server/dist/routes/mcp.js +21 -1
  61. package/server/dist/routes/mcp.js.map +1 -1
  62. package/server/prisma/migrations/20260527073000_0017_note_properties/migration.sql +105 -0
  63. package/server/prisma/migrations/20260531073000_0018_view_query/migration.sql +3 -0
  64. package/server/prisma/schema.prisma +226 -130
  65. package/server/client/dist/assets/Graph-Dond2hGK.js +0 -1
  66. package/server/client/dist/assets/Note-Cr6GtXUM.js +0 -21
  67. package/server/client/dist/assets/Reminders-BlLLT_x0.js +0 -1
  68. package/server/client/dist/assets/Search-CrZ0ap8x.js +0 -1
  69. package/server/client/dist/assets/Tag-vws5AfNW.js +0 -1
  70. package/server/client/dist/assets/TagNotes-Fmf1Kgim.js +0 -1
  71. package/server/client/dist/assets/ViewNotes-BALN7IfH.js +0 -1
  72. package/server/client/dist/assets/Views-Ccc_Ml5U.js +0 -1
  73. package/server/client/dist/assets/index-BSVE2cGd.js +0 -1
  74. package/server/client/dist/assets/manage-image-IoTXaMBP.js +0 -1
  75. package/server/client/dist/assets/manage-image-detail-BRTXwOsh.js +0 -1
  76. package/server/client/dist/assets/trash-hiJIg6-c.js +0 -1
  77. package/server/client/dist/assets/view-dashboard-BuaZ4MvI.js +0 -90
@@ -6,6 +6,7 @@ import {
6
6
  normalizeReferenceId,
7
7
  syncReferenceTitlesInContent
8
8
  } from "../../../features/note/services/content-blocks.js";
9
+ import { listNotePropertyKeys } from "../../../features/note/services/properties.js";
9
10
  import {
10
11
  buildNoteSearchProjection,
11
12
  filterNotesBySearchQuery,
@@ -358,6 +359,19 @@ const noteQueryResolvers = {
358
359
  noteSnapshot: async (_, { id }) => {
359
360
  return getNoteSnapshot(Number(id));
360
361
  },
362
+ notePropertyKeys: async (_, {
363
+ query,
364
+ pagination = {
365
+ limit: 50,
366
+ offset: 0
367
+ }
368
+ }) => {
369
+ return listNotePropertyKeys({
370
+ query,
371
+ limit: Number(pagination.limit),
372
+ offset: Number(pagination.offset)
373
+ });
374
+ },
361
375
  trashedNote: async (_, { id }) => {
362
376
  return getTrashedNoteById(Number(id));
363
377
  },
@@ -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 {\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 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 { 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":[]}
@@ -28,12 +28,60 @@ const noteType = gql`
28
28
  or
29
29
  }
30
30
 
31
+ enum NotePropertyValueType {
32
+ text
33
+ url
34
+ number
35
+ date
36
+ boolean
37
+ select
38
+ }
39
+
31
40
  input NoteInput {
32
41
  title: String
33
42
  content: String
34
43
  layout: NoteLayout
35
44
  }
36
45
 
46
+ input NotePropertySetInput {
47
+ key: String!
48
+ name: String
49
+ value: String!
50
+ valueType: NotePropertyValueType!
51
+ }
52
+
53
+ input NotePropertyOptionInput {
54
+ label: String!
55
+ value: String
56
+ color: String
57
+ order: Int
58
+ }
59
+
60
+ input NotePropertyOptionUpdateInput {
61
+ id: ID
62
+ label: String!
63
+ value: String
64
+ color: String
65
+ order: Int
66
+ }
67
+
68
+ input NotePropertyDefinitionInput {
69
+ key: String!
70
+ name: String
71
+ valueType: NotePropertyValueType!
72
+ options: [NotePropertyOptionInput!]
73
+ }
74
+
75
+ input NotePropertyDefinitionUpdateInput {
76
+ name: String
77
+ options: [NotePropertyOptionUpdateInput!]
78
+ }
79
+
80
+ input NotePropertiesPatchInput {
81
+ set: [NotePropertySetInput!]
82
+ deleteKeys: [String!]
83
+ }
84
+
37
85
  input NoteOrderInput {
38
86
  id: ID!
39
87
  order: Int!
@@ -57,6 +105,47 @@ const noteType = gql`
57
105
  order: Int!
58
106
  layout: NoteLayout!
59
107
  tags: [Tag!]!
108
+ properties: [NoteProperty!]!
109
+ }
110
+
111
+ type NoteProperty {
112
+ key: String!
113
+ name: String!
114
+ value: String!
115
+ valueType: NotePropertyValueType!
116
+ createdAt: String!
117
+ option: NotePropertyOption
118
+ updatedAt: String!
119
+ }
120
+
121
+ type NotePropertyOption {
122
+ id: ID!
123
+ label: String!
124
+ value: String!
125
+ color: String
126
+ order: Int!
127
+ }
128
+
129
+ type NotePropertyKey {
130
+ key: String!
131
+ name: String!
132
+ valueType: NotePropertyValueType!
133
+ noteCount: Int!
134
+ options: [NotePropertyOption!]!
135
+ updatedAt: String!
136
+ }
137
+
138
+ type NotePropertyKeys {
139
+ totalCount: Int!
140
+ keys: [NotePropertyKey!]!
141
+ }
142
+
143
+ type NotePropertyDeleteResult {
144
+ key: String!
145
+ name: String!
146
+ valueType: NotePropertyValueType!
147
+ affectedNoteCount: Int!
148
+ deleted: Boolean!
60
149
  }
61
150
 
62
151
  type Notes {
@@ -159,6 +248,7 @@ const noteQuery = gql`
159
248
  noteCleanupPreview(id: ID!): NoteCleanupPreview
160
249
  noteSnapshots(id: ID!, limit: Int): [NoteSnapshot!]!
161
250
  noteSnapshot(id: ID!): NoteSnapshot
251
+ notePropertyKeys(query: String, pagination: PaginationInput): NotePropertyKeys!
162
252
  trashedNote(id: ID!): DeletedNote
163
253
  trashedNotes(pagination: PaginationInput): DeletedNotes!
164
254
  noteGraph: NoteGraph!
@@ -172,6 +262,16 @@ const noteMutation = gql`
172
262
  restoreNoteSnapshot(id: ID!): Note!
173
263
  restoreTrashedNote(id: ID!): Note!
174
264
  purgeTrashedNote(id: ID!): Boolean!
265
+ createNotePropertyKey(input: NotePropertyDefinitionInput!): NotePropertyKey!
266
+ updateNotePropertyKey(key: String!, input: NotePropertyDefinitionUpdateInput!): NotePropertyKey!
267
+ deleteNotePropertyKey(key: String!, confirmImpact: Boolean): NotePropertyDeleteResult!
268
+ updateNoteProperties(
269
+ id: ID!
270
+ patch: NotePropertiesPatchInput!
271
+ editSessionId: String
272
+ expectedUpdatedAt: String!
273
+ force: Boolean
274
+ ): Note!
175
275
  pinNote(id: ID!, pinned: Boolean!): Note!
176
276
  reorderNotes(notes: [NoteOrderInput!]!): [Note!]!
177
277
  }
@@ -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 input NoteInput {\n title: String\n content: String\n layout: NoteLayout\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 }\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 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 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;AAmIjB,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;AAoClB,MAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAarB,MAAM,eAAe;AAAA,MACtB,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,YAAY;AAAA;","names":[]}
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;AA4NjB,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;AAqClB,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":[]}