ocean-brain 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/index.js +5 -0
  2. package/package.json +2 -1
  3. package/server/client/dist/assets/{Calendar-CSXEuWmQ.js → Calendar-D4KkvcU8.js} +1 -1
  4. package/server/client/dist/assets/{Callout-Ap1OcxWN.js → Callout-CaSzc-1y.js} +1 -1
  5. package/server/client/dist/assets/{Graph-C0Ax9qjI.js → Graph-C8pBdJzV.js} +1 -1
  6. package/server/client/dist/assets/{Image-CSbcG-5a.js → Image-DlJ4MDo3.js} +1 -1
  7. package/server/client/dist/assets/{Image.es-Fbe7aDDo.js → Image.es-C8g5NwNt.js} +1 -1
  8. package/server/client/dist/assets/Note-ODOESft3.js +21 -0
  9. package/server/client/dist/assets/Plus.es-Bkl1ZXE0.js +1 -0
  10. package/server/client/dist/assets/Reminders-FrTR9ny8.js +1 -0
  11. package/server/client/dist/assets/Search-BPf2LO1Y.js +1 -0
  12. package/server/client/dist/assets/{SurfaceCard-Br6TjX5W.js → SurfaceCard-WSk7zWeM.js} +1 -1
  13. package/server/client/dist/assets/Tag-uArdLjo1.js +1 -0
  14. package/server/client/dist/assets/TagNotes-DDvXHB9I.js +1 -0
  15. package/server/client/dist/assets/{Trash.es-BfCEiL3-.js → Trash.es-DumPfiUz.js} +1 -1
  16. package/server/client/dist/assets/ViewNotes-BVu9lEs-.js +1 -0
  17. package/server/client/dist/assets/Views-D4LGh30P.js +1 -0
  18. package/server/client/dist/assets/{image.api-DGXlQ_Ca.js → image.api-D3Ei3fbf.js} +1 -1
  19. package/server/client/dist/assets/index-46ZUXbW5.js +232 -0
  20. package/server/client/dist/assets/{index-B28TO4FC.js → index-C7YGbIuA.js} +1 -1
  21. package/server/client/dist/assets/{index-Bm9l_L20.css → index-D2gRB1ig.css} +1 -1
  22. package/server/client/dist/assets/manage-image-DiuREdeE.js +1 -0
  23. package/server/client/dist/assets/{manage-image-detail-hk6jWyiB.js → manage-image-detail-D8Eorq3u.js} +1 -1
  24. package/server/client/dist/assets/{mcp-CSjmBjFR.js → mcp-CvCGaYSz.js} +1 -1
  25. package/server/client/dist/assets/{note-vendor-5N5mRkIT.js → note-vendor-B0t5F04o.js} +3 -3
  26. package/server/client/dist/assets/{placeholder-Bmiowo28.js → placeholder-znZDfNAE.js} +4 -4
  27. package/server/client/dist/assets/trash-R0sww0ur.js +1 -0
  28. package/server/client/dist/assets/{useReminderMutate-DsIvVpCQ.js → useReminderMutate-Bkj-oIm4.js} +2 -2
  29. package/server/client/dist/assets/{view-dashboard-CP8nhfxQ.js → view-dashboard-ClpF_qLM.js} +1 -1
  30. package/server/client/dist/index.html +3 -3
  31. package/server/dist/app.js +1 -1
  32. package/server/dist/app.js.map +1 -1
  33. package/server/dist/features/auth/http/api.js +2 -5
  34. package/server/dist/features/auth/http/api.js.map +1 -1
  35. package/server/dist/features/auth/http/login-page.js +1 -1
  36. package/server/dist/features/auth/http/pages.js +1 -1
  37. package/server/dist/features/auth/http/pages.js.map +1 -1
  38. package/server/dist/features/auth/service.js +11 -42
  39. package/server/dist/features/auth/service.js.map +1 -1
  40. package/server/dist/features/note/graphql/note.query.resolver.js +4 -1
  41. package/server/dist/features/note/graphql/note.query.resolver.js.map +1 -1
  42. package/server/dist/features/note/graphql/note.type-defs.js +3 -0
  43. package/server/dist/features/note/graphql/note.type-defs.js.map +1 -1
  44. package/server/dist/features/note/services/trash.js +37 -12
  45. package/server/dist/features/note/services/trash.js.map +1 -1
  46. package/server/dist/modules/auth-guard.js +13 -19
  47. package/server/dist/modules/auth-guard.js.map +1 -1
  48. package/server/dist/modules/auth-mode.js +16 -39
  49. package/server/dist/modules/auth-mode.js.map +1 -1
  50. package/server/dist/routes/client.js +2 -2
  51. package/server/dist/routes/client.js.map +1 -1
  52. package/server/client/dist/assets/ModalActionRow-DjI5b4bl.js +0 -1
  53. package/server/client/dist/assets/Note-BY6WgYLq.js +0 -1
  54. package/server/client/dist/assets/Reminders-vRksvSQE.js +0 -1
  55. package/server/client/dist/assets/Search-Cq4tuiJO.js +0 -1
  56. package/server/client/dist/assets/Tag-ARDLA-Pb.js +0 -1
  57. package/server/client/dist/assets/TagNotes-CDGVrCJU.js +0 -1
  58. package/server/client/dist/assets/ViewNotes-ZBOQ1adH.js +0 -1
  59. package/server/client/dist/assets/Views-DQHPfdwM.js +0 -1
  60. package/server/client/dist/assets/index-Bsx4P7EA.js +0 -210
  61. package/server/client/dist/assets/manage-image-Dg297A_h.js +0 -1
  62. package/server/client/dist/assets/trash-CM7SbVtW.js +0 -1
@@ -4,24 +4,35 @@ import {
4
4
  RECOVERY_CLEANUP_BATCH_LIMIT,
5
5
  TRASH_RETENTION_DAYS
6
6
  } from "../../../modules/recovery-retention.js";
7
- import { buildNoteSearchProjection } from "./search.js";
7
+ import { buildNoteSearchProjection, extractVisibleSearchTextFromContent } from "./search.js";
8
+ const TRASHED_NOTE_CONTENT_PREVIEW_MAX_LENGTH = 240;
8
9
  class NoteRestoreConflictError extends Error {
9
10
  constructor(message = "A live note with the same id already exists.") {
10
11
  super(message);
11
12
  this.name = "NoteRestoreConflictError";
12
13
  }
13
14
  }
14
- const serializeTrashedNote = (note) => ({
15
- id: String(note.id),
16
- title: note.title,
17
- createdAt: note.createdAt.toISOString(),
18
- updatedAt: note.updatedAt.toISOString(),
19
- deletedAt: note.deletedAt.toISOString(),
20
- pinned: note.pinned,
21
- order: note.order,
22
- layout: note.layout,
23
- tagNames: note.tags.map((tag) => tag.name)
24
- });
15
+ const buildTrashedNoteContentPreview = (content) => {
16
+ const text = extractVisibleSearchTextFromContent(content);
17
+ if (text.length <= TRASHED_NOTE_CONTENT_PREVIEW_MAX_LENGTH) {
18
+ return text;
19
+ }
20
+ return `${text.slice(0, TRASHED_NOTE_CONTENT_PREVIEW_MAX_LENGTH).trimEnd()}\u2026`;
21
+ };
22
+ const serializeTrashedNote = (note) => {
23
+ return {
24
+ id: String(note.id),
25
+ title: note.title,
26
+ createdAt: note.createdAt.toISOString(),
27
+ updatedAt: note.updatedAt.toISOString(),
28
+ deletedAt: note.deletedAt.toISOString(),
29
+ contentPreview: buildTrashedNoteContentPreview(note.content),
30
+ pinned: note.pinned,
31
+ order: note.order,
32
+ layout: note.layout,
33
+ tagNames: note.tags.map((tag) => tag.name)
34
+ };
35
+ };
25
36
  const restoreTagIdsInContent = (content, tagIdByName) => {
26
37
  const rewriteNodes = (nodes) => {
27
38
  return nodes.map((node) => ({
@@ -73,6 +84,18 @@ const createNoteTrashService = (deps) => ({
73
84
  const trashedNote = await deps.moveNoteToTrash(note);
74
85
  return serializeTrashedNote(trashedNote);
75
86
  },
87
+ getNoteById: async (id) => {
88
+ await deps.purgeExpiredDeletedNotes(createRetentionCutoff(TRASH_RETENTION_DAYS), RECOVERY_CLEANUP_BATCH_LIMIT);
89
+ const deletedNote = await deps.findDeletedNote(id);
90
+ if (!deletedNote) {
91
+ return null;
92
+ }
93
+ const { blocksToMarkdown } = await import("../../../modules/blocknote.js");
94
+ return {
95
+ ...serializeTrashedNote(deletedNote),
96
+ contentAsMarkdown: await blocksToMarkdown(deletedNote.content)
97
+ };
98
+ },
76
99
  restoreNoteById: async (id) => {
77
100
  await deps.purgeExpiredDeletedNotes(createRetentionCutoff(TRASH_RETENTION_DAYS), RECOVERY_CLEANUP_BATCH_LIMIT);
78
101
  const deletedNote = await deps.findDeletedNote(id);
@@ -249,6 +272,7 @@ const noteTrashService = createNoteTrashService({
249
272
  }
250
273
  });
251
274
  const listTrashedNotes = noteTrashService.listTrashedNotes;
275
+ const getTrashedNoteById = noteTrashService.getNoteById;
252
276
  const trashNoteById = noteTrashService.trashNoteById;
253
277
  const restoreTrashedNoteById = noteTrashService.restoreNoteById;
254
278
  const purgeTrashedNoteById = noteTrashService.purgeNoteById;
@@ -258,6 +282,7 @@ const purgeExpiredTrashedNotes = async () => {
258
282
  export {
259
283
  NoteRestoreConflictError,
260
284
  createNoteTrashService,
285
+ getTrashedNoteById,
261
286
  listTrashedNotes,
262
287
  purgeExpiredTrashedNotes,
263
288
  purgeTrashedNoteById,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/features/note/services/trash.ts"],"sourcesContent":["import models, { type NoteLayout, type ReminderPriority } from '~/models.js';\nimport {\n createRetentionCutoff,\n RECOVERY_CLEANUP_BATCH_LIMIT,\n TRASH_RETENTION_DAYS,\n} from '~/modules/recovery-retention.js';\nimport { buildNoteSearchProjection } from './search.js';\n\ninterface LiveTagRecord {\n id: number;\n name: string;\n}\n\ninterface LiveReminderRecord {\n id: number;\n reminderDate: Date;\n completed: boolean;\n priority: ReminderPriority;\n content: string | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\ninterface LiveNoteRecord {\n id: number;\n title: string;\n content: string;\n createdAt: Date;\n updatedAt: Date;\n pinned: boolean;\n order: number;\n layout: NoteLayout;\n tags: LiveTagRecord[];\n reminders: LiveReminderRecord[];\n}\n\ninterface RestoredNoteRecord {\n id: number;\n title: string;\n content: string;\n createdAt: Date;\n updatedAt: Date;\n pinned: boolean;\n order: number;\n layout: NoteLayout;\n}\n\ninterface DeletedTagRecord {\n name: string;\n}\n\ninterface DeletedReminderRecord {\n originalId: number | null;\n reminderDate: Date;\n completed: boolean;\n priority: ReminderPriority;\n content: string | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\ninterface DeletedNoteRecord {\n id: number;\n title: string;\n content: string;\n createdAt: Date;\n updatedAt: Date;\n deletedAt: Date;\n pinned: boolean;\n order: number;\n layout: NoteLayout;\n tags: DeletedTagRecord[];\n reminders: DeletedReminderRecord[];\n}\n\ninterface BlockNoteNode {\n type: string;\n props?: Record<string, unknown>;\n content?: BlockNoteNode[];\n children?: BlockNoteNode[];\n}\n\nexport interface TrashedNoteSummary {\n id: string;\n title: string;\n createdAt: string;\n updatedAt: string;\n deletedAt: string;\n pinned: boolean;\n order: number;\n layout: NoteLayout;\n tagNames: string[];\n}\n\nexport interface TrashedNotesResult {\n totalCount: number;\n notes: TrashedNoteSummary[];\n}\n\nexport class NoteRestoreConflictError extends Error {\n constructor(message = 'A live note with the same id already exists.') {\n super(message);\n this.name = 'NoteRestoreConflictError';\n }\n}\n\ninterface NoteTrashServiceDeps {\n countDeletedNotes: () => Promise<number>;\n findDeletedNote: (id: number) => Promise<DeletedNoteRecord | null>;\n findLiveNote: (id: number) => Promise<LiveNoteRecord | null>;\n listDeletedNotes: (skip: number, take: number) => Promise<DeletedNoteRecord[]>;\n liveNoteExists: (id: number) => Promise<boolean>;\n moveNoteToTrash: (note: LiveNoteRecord) => Promise<DeletedNoteRecord>;\n purgeDeletedNote: (note: DeletedNoteRecord) => Promise<void>;\n purgeExpiredDeletedNotes: (before: Date, limit: number) => Promise<number>;\n restoreDeletedNote: (note: DeletedNoteRecord) => Promise<RestoredNoteRecord>;\n}\n\nconst serializeTrashedNote = (note: DeletedNoteRecord): TrashedNoteSummary => ({\n id: String(note.id),\n title: note.title,\n createdAt: note.createdAt.toISOString(),\n updatedAt: note.updatedAt.toISOString(),\n deletedAt: note.deletedAt.toISOString(),\n pinned: note.pinned,\n order: note.order,\n layout: note.layout,\n tagNames: note.tags.map((tag) => tag.name),\n});\n\nconst restoreTagIdsInContent = (content: string, tagIdByName: Map<string, number>) => {\n const rewriteNodes = (nodes: BlockNoteNode[]): BlockNoteNode[] => {\n return nodes.map((node) => ({\n ...node,\n content: node.content?.map((contentNode) => {\n if (contentNode.type !== 'tag') {\n return contentNode;\n }\n\n const tagName = typeof contentNode.props?.tag === 'string' ? contentNode.props.tag : null;\n const restoredTagId = tagName ? tagIdByName.get(tagName) : null;\n\n if (!restoredTagId) {\n return contentNode;\n }\n\n return {\n ...contentNode,\n props: {\n ...contentNode.props,\n id: String(restoredTagId),\n },\n };\n }),\n children: node.children ? rewriteNodes(node.children) : node.children,\n }));\n };\n\n try {\n const parsed = JSON.parse(content) as BlockNoteNode[];\n return JSON.stringify(rewriteNodes(parsed));\n } catch {\n return content;\n }\n};\n\nexport const createNoteTrashService = (deps: NoteTrashServiceDeps) => ({\n listTrashedNotes: async (input?: { limit?: number; offset?: number }): Promise<TrashedNotesResult> => {\n await deps.purgeExpiredDeletedNotes(createRetentionCutoff(TRASH_RETENTION_DAYS), RECOVERY_CLEANUP_BATCH_LIMIT);\n\n const limit = Math.max(1, Number(input?.limit ?? 25));\n const offset = Math.max(0, Number(input?.offset ?? 0));\n const [totalCount, notes] = await Promise.all([deps.countDeletedNotes(), deps.listDeletedNotes(offset, limit)]);\n\n return {\n totalCount,\n notes: notes.map(serializeTrashedNote),\n };\n },\n\n trashNoteById: async (id: number): Promise<TrashedNoteSummary | null> => {\n await deps.purgeExpiredDeletedNotes(createRetentionCutoff(TRASH_RETENTION_DAYS), RECOVERY_CLEANUP_BATCH_LIMIT);\n\n const note = await deps.findLiveNote(id);\n\n if (!note) {\n return null;\n }\n\n const trashedNote = await deps.moveNoteToTrash(note);\n return serializeTrashedNote(trashedNote);\n },\n\n restoreNoteById: async (id: number) => {\n await deps.purgeExpiredDeletedNotes(createRetentionCutoff(TRASH_RETENTION_DAYS), RECOVERY_CLEANUP_BATCH_LIMIT);\n\n const deletedNote = await deps.findDeletedNote(id);\n\n if (!deletedNote) {\n return null;\n }\n\n if (await deps.liveNoteExists(id)) {\n throw new NoteRestoreConflictError();\n }\n\n return deps.restoreDeletedNote(deletedNote);\n },\n\n purgeNoteById: async (id: number): Promise<TrashedNoteSummary | null> => {\n await deps.purgeExpiredDeletedNotes(createRetentionCutoff(TRASH_RETENTION_DAYS), RECOVERY_CLEANUP_BATCH_LIMIT);\n\n const deletedNote = await deps.findDeletedNote(id);\n\n if (!deletedNote) {\n return null;\n }\n\n const summary = serializeTrashedNote(deletedNote);\n await deps.purgeDeletedNote(deletedNote);\n return summary;\n },\n});\n\nconst includeDeletedNote = {\n reminders: { orderBy: { reminderDate: 'asc' as const } },\n tags: { orderBy: { name: 'asc' as const } },\n};\n\nconst defaultPurgeExpiredDeletedNotes = async (before: Date, limit: number) => {\n const expiredNotes = await models.deletedNote.findMany({\n where: { deletedAt: { lt: before } },\n orderBy: { deletedAt: 'asc' },\n take: limit,\n select: { id: true },\n });\n\n if (expiredNotes.length === 0) {\n return 0;\n }\n\n const deleted = await models.deletedNote.deleteMany({ where: { id: { in: expiredNotes.map((note) => note.id) } } });\n\n return deleted.count;\n};\n\nconst noteTrashService = createNoteTrashService({\n countDeletedNotes: async () => models.deletedNote.count(),\n findDeletedNote: async (id) => {\n return models.deletedNote.findUnique({\n where: { id },\n include: includeDeletedNote,\n });\n },\n findLiveNote: async (id) => {\n return models.note.findUnique({\n where: { id },\n include: {\n reminders: { orderBy: { reminderDate: 'asc' } },\n tags: { orderBy: { name: 'asc' } },\n },\n });\n },\n listDeletedNotes: async (skip, take) => {\n return models.deletedNote.findMany({\n skip,\n take,\n orderBy: { deletedAt: 'desc' },\n include: includeDeletedNote,\n });\n },\n liveNoteExists: async (id) => {\n const note = await models.note.findUnique({\n where: { id },\n select: { id: true },\n });\n return Boolean(note);\n },\n purgeExpiredDeletedNotes: defaultPurgeExpiredDeletedNotes,\n purgeDeletedNote: async (deletedNote) => {\n await models.deletedNote.delete({ where: { id: deletedNote.id } });\n },\n moveNoteToTrash: async (note) => {\n return models.$transaction(async (tx) => {\n await tx.deletedNote.create({\n data: {\n id: note.id,\n title: note.title,\n content: note.content,\n createdAt: note.createdAt,\n updatedAt: note.updatedAt,\n pinned: note.pinned,\n order: note.order,\n layout: note.layout,\n tags: { create: note.tags.map((tag) => ({ name: tag.name })) },\n reminders: {\n create: note.reminders.map((reminder) => ({\n originalId: reminder.id,\n reminderDate: reminder.reminderDate,\n completed: reminder.completed,\n priority: reminder.priority,\n content: reminder.content,\n createdAt: reminder.createdAt,\n updatedAt: reminder.updatedAt,\n })),\n },\n },\n });\n\n await tx.note.delete({ where: { id: note.id } });\n\n if (note.tags.length > 0) {\n await tx.tag.deleteMany({\n where: {\n id: { in: note.tags.map((tag) => tag.id) },\n notes: { none: {} },\n },\n });\n }\n\n return tx.deletedNote.findUniqueOrThrow({\n where: { id: note.id },\n include: includeDeletedNote,\n });\n });\n },\n restoreDeletedNote: async (deletedNote) => {\n return models.$transaction(async (tx) => {\n const tagNames = Array.from(new Set(deletedNote.tags.map((tag) => tag.name).filter(Boolean)));\n\n if (tagNames.length > 0) {\n const existingTags = await tx.tag.findMany({\n where: { name: { in: tagNames } },\n select: { name: true },\n });\n const existingTagNames = new Set(existingTags.map((tag) => tag.name));\n const missingTagNames = tagNames.filter((tagName) => !existingTagNames.has(tagName));\n\n for (const tagName of missingTagNames) {\n await tx.tag.create({ data: { name: tagName } });\n }\n }\n\n const restoreTagIds =\n tagNames.length > 0\n ? await tx.tag.findMany({\n where: { name: { in: tagNames } },\n select: {\n id: true,\n name: true,\n },\n })\n : [];\n\n const restoredContent =\n restoreTagIds.length > 0\n ? restoreTagIdsInContent(\n deletedNote.content,\n new Map(restoreTagIds.map((tag) => [tag.name, tag.id])),\n )\n : deletedNote.content;\n\n const note = await tx.note.create({\n data: {\n id: deletedNote.id,\n title: deletedNote.title,\n content: restoredContent,\n ...buildNoteSearchProjection({\n title: deletedNote.title,\n content: restoredContent,\n }),\n createdAt: deletedNote.createdAt,\n updatedAt: deletedNote.updatedAt,\n pinned: deletedNote.pinned,\n order: deletedNote.order,\n layout: deletedNote.layout,\n ...(restoreTagIds.length > 0\n ? { tags: { connect: restoreTagIds.map((tag) => ({ id: tag.id })) } }\n : {}),\n ...(deletedNote.reminders.length > 0\n ? {\n reminders: {\n create: deletedNote.reminders.map((reminder) => ({\n reminderDate: reminder.reminderDate,\n completed: reminder.completed,\n priority: reminder.priority,\n content: reminder.content,\n createdAt: reminder.createdAt,\n updatedAt: reminder.updatedAt,\n })),\n },\n }\n : {}),\n },\n });\n\n await tx.deletedNote.delete({ where: { id: deletedNote.id } });\n\n return note;\n });\n },\n});\n\nexport const listTrashedNotes = noteTrashService.listTrashedNotes;\nexport const trashNoteById = noteTrashService.trashNoteById;\nexport const restoreTrashedNoteById = noteTrashService.restoreNoteById;\nexport const purgeTrashedNoteById = noteTrashService.purgeNoteById;\nexport const purgeExpiredTrashedNotes = async () => {\n return defaultPurgeExpiredDeletedNotes(createRetentionCutoff(TRASH_RETENTION_DAYS), RECOVERY_CLEANUP_BATCH_LIMIT);\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/features/note/services/trash.ts"],"sourcesContent":["import models, { type NoteLayout, type ReminderPriority } from '~/models.js';\nimport {\n createRetentionCutoff,\n RECOVERY_CLEANUP_BATCH_LIMIT,\n TRASH_RETENTION_DAYS,\n} from '~/modules/recovery-retention.js';\nimport { buildNoteSearchProjection, extractVisibleSearchTextFromContent } from './search.js';\n\nconst TRASHED_NOTE_CONTENT_PREVIEW_MAX_LENGTH = 240;\n\ninterface LiveTagRecord {\n id: number;\n name: string;\n}\n\ninterface LiveReminderRecord {\n id: number;\n reminderDate: Date;\n completed: boolean;\n priority: ReminderPriority;\n content: string | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\ninterface LiveNoteRecord {\n id: number;\n title: string;\n content: string;\n createdAt: Date;\n updatedAt: Date;\n pinned: boolean;\n order: number;\n layout: NoteLayout;\n tags: LiveTagRecord[];\n reminders: LiveReminderRecord[];\n}\n\ninterface RestoredNoteRecord {\n id: number;\n title: string;\n content: string;\n createdAt: Date;\n updatedAt: Date;\n pinned: boolean;\n order: number;\n layout: NoteLayout;\n}\n\ninterface DeletedTagRecord {\n name: string;\n}\n\ninterface DeletedReminderRecord {\n originalId: number | null;\n reminderDate: Date;\n completed: boolean;\n priority: ReminderPriority;\n content: string | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\ninterface DeletedNoteRecord {\n id: number;\n title: string;\n content: string;\n createdAt: Date;\n updatedAt: Date;\n deletedAt: Date;\n pinned: boolean;\n order: number;\n layout: NoteLayout;\n tags: DeletedTagRecord[];\n reminders: DeletedReminderRecord[];\n}\n\ninterface BlockNoteNode {\n type: string;\n props?: Record<string, unknown>;\n content?: BlockNoteNode[];\n children?: BlockNoteNode[];\n}\n\nexport interface TrashedNoteSummary {\n id: string;\n title: string;\n createdAt: string;\n updatedAt: string;\n deletedAt: string;\n contentPreview: string;\n pinned: boolean;\n order: number;\n layout: NoteLayout;\n tagNames: string[];\n}\n\nexport interface TrashedNotesResult {\n totalCount: number;\n notes: TrashedNoteSummary[];\n}\n\nexport interface TrashedNoteDetail extends TrashedNoteSummary {\n contentAsMarkdown: string;\n}\n\nexport class NoteRestoreConflictError extends Error {\n constructor(message = 'A live note with the same id already exists.') {\n super(message);\n this.name = 'NoteRestoreConflictError';\n }\n}\n\ninterface NoteTrashServiceDeps {\n countDeletedNotes: () => Promise<number>;\n findDeletedNote: (id: number) => Promise<DeletedNoteRecord | null>;\n findLiveNote: (id: number) => Promise<LiveNoteRecord | null>;\n listDeletedNotes: (skip: number, take: number) => Promise<DeletedNoteRecord[]>;\n liveNoteExists: (id: number) => Promise<boolean>;\n moveNoteToTrash: (note: LiveNoteRecord) => Promise<DeletedNoteRecord>;\n purgeDeletedNote: (note: DeletedNoteRecord) => Promise<void>;\n purgeExpiredDeletedNotes: (before: Date, limit: number) => Promise<number>;\n restoreDeletedNote: (note: DeletedNoteRecord) => Promise<RestoredNoteRecord>;\n}\n\nconst buildTrashedNoteContentPreview = (content: string) => {\n const text = extractVisibleSearchTextFromContent(content);\n\n if (text.length <= TRASHED_NOTE_CONTENT_PREVIEW_MAX_LENGTH) {\n return text;\n }\n\n return `${text.slice(0, TRASHED_NOTE_CONTENT_PREVIEW_MAX_LENGTH).trimEnd()}…`;\n};\n\nconst serializeTrashedNote = (note: DeletedNoteRecord): TrashedNoteSummary => {\n return {\n id: String(note.id),\n title: note.title,\n createdAt: note.createdAt.toISOString(),\n updatedAt: note.updatedAt.toISOString(),\n deletedAt: note.deletedAt.toISOString(),\n contentPreview: buildTrashedNoteContentPreview(note.content),\n pinned: note.pinned,\n order: note.order,\n layout: note.layout,\n tagNames: note.tags.map((tag) => tag.name),\n };\n};\n\nconst restoreTagIdsInContent = (content: string, tagIdByName: Map<string, number>) => {\n const rewriteNodes = (nodes: BlockNoteNode[]): BlockNoteNode[] => {\n return nodes.map((node) => ({\n ...node,\n content: node.content?.map((contentNode) => {\n if (contentNode.type !== 'tag') {\n return contentNode;\n }\n\n const tagName = typeof contentNode.props?.tag === 'string' ? contentNode.props.tag : null;\n const restoredTagId = tagName ? tagIdByName.get(tagName) : null;\n\n if (!restoredTagId) {\n return contentNode;\n }\n\n return {\n ...contentNode,\n props: {\n ...contentNode.props,\n id: String(restoredTagId),\n },\n };\n }),\n children: node.children ? rewriteNodes(node.children) : node.children,\n }));\n };\n\n try {\n const parsed = JSON.parse(content) as BlockNoteNode[];\n return JSON.stringify(rewriteNodes(parsed));\n } catch {\n return content;\n }\n};\n\nexport const createNoteTrashService = (deps: NoteTrashServiceDeps) => ({\n listTrashedNotes: async (input?: { limit?: number; offset?: number }): Promise<TrashedNotesResult> => {\n await deps.purgeExpiredDeletedNotes(createRetentionCutoff(TRASH_RETENTION_DAYS), RECOVERY_CLEANUP_BATCH_LIMIT);\n\n const limit = Math.max(1, Number(input?.limit ?? 25));\n const offset = Math.max(0, Number(input?.offset ?? 0));\n const [totalCount, notes] = await Promise.all([deps.countDeletedNotes(), deps.listDeletedNotes(offset, limit)]);\n\n return {\n totalCount,\n notes: notes.map(serializeTrashedNote),\n };\n },\n\n trashNoteById: async (id: number): Promise<TrashedNoteSummary | null> => {\n await deps.purgeExpiredDeletedNotes(createRetentionCutoff(TRASH_RETENTION_DAYS), RECOVERY_CLEANUP_BATCH_LIMIT);\n\n const note = await deps.findLiveNote(id);\n\n if (!note) {\n return null;\n }\n\n const trashedNote = await deps.moveNoteToTrash(note);\n return serializeTrashedNote(trashedNote);\n },\n\n getNoteById: async (id: number): Promise<TrashedNoteDetail | null> => {\n await deps.purgeExpiredDeletedNotes(createRetentionCutoff(TRASH_RETENTION_DAYS), RECOVERY_CLEANUP_BATCH_LIMIT);\n\n const deletedNote = await deps.findDeletedNote(id);\n\n if (!deletedNote) {\n return null;\n }\n\n const { blocksToMarkdown } = await import('~/modules/blocknote.js');\n\n return {\n ...serializeTrashedNote(deletedNote),\n contentAsMarkdown: await blocksToMarkdown(deletedNote.content),\n };\n },\n\n restoreNoteById: async (id: number) => {\n await deps.purgeExpiredDeletedNotes(createRetentionCutoff(TRASH_RETENTION_DAYS), RECOVERY_CLEANUP_BATCH_LIMIT);\n\n const deletedNote = await deps.findDeletedNote(id);\n\n if (!deletedNote) {\n return null;\n }\n\n if (await deps.liveNoteExists(id)) {\n throw new NoteRestoreConflictError();\n }\n\n return deps.restoreDeletedNote(deletedNote);\n },\n\n purgeNoteById: async (id: number): Promise<TrashedNoteSummary | null> => {\n await deps.purgeExpiredDeletedNotes(createRetentionCutoff(TRASH_RETENTION_DAYS), RECOVERY_CLEANUP_BATCH_LIMIT);\n\n const deletedNote = await deps.findDeletedNote(id);\n\n if (!deletedNote) {\n return null;\n }\n\n const summary = serializeTrashedNote(deletedNote);\n await deps.purgeDeletedNote(deletedNote);\n return summary;\n },\n});\n\nconst includeDeletedNote = {\n reminders: { orderBy: { reminderDate: 'asc' as const } },\n tags: { orderBy: { name: 'asc' as const } },\n};\n\nconst defaultPurgeExpiredDeletedNotes = async (before: Date, limit: number) => {\n const expiredNotes = await models.deletedNote.findMany({\n where: { deletedAt: { lt: before } },\n orderBy: { deletedAt: 'asc' },\n take: limit,\n select: { id: true },\n });\n\n if (expiredNotes.length === 0) {\n return 0;\n }\n\n const deleted = await models.deletedNote.deleteMany({ where: { id: { in: expiredNotes.map((note) => note.id) } } });\n\n return deleted.count;\n};\n\nconst noteTrashService = createNoteTrashService({\n countDeletedNotes: async () => models.deletedNote.count(),\n findDeletedNote: async (id) => {\n return models.deletedNote.findUnique({\n where: { id },\n include: includeDeletedNote,\n });\n },\n findLiveNote: async (id) => {\n return models.note.findUnique({\n where: { id },\n include: {\n reminders: { orderBy: { reminderDate: 'asc' } },\n tags: { orderBy: { name: 'asc' } },\n },\n });\n },\n listDeletedNotes: async (skip, take) => {\n return models.deletedNote.findMany({\n skip,\n take,\n orderBy: { deletedAt: 'desc' },\n include: includeDeletedNote,\n });\n },\n liveNoteExists: async (id) => {\n const note = await models.note.findUnique({\n where: { id },\n select: { id: true },\n });\n return Boolean(note);\n },\n purgeExpiredDeletedNotes: defaultPurgeExpiredDeletedNotes,\n purgeDeletedNote: async (deletedNote) => {\n await models.deletedNote.delete({ where: { id: deletedNote.id } });\n },\n moveNoteToTrash: async (note) => {\n return models.$transaction(async (tx) => {\n await tx.deletedNote.create({\n data: {\n id: note.id,\n title: note.title,\n content: note.content,\n createdAt: note.createdAt,\n updatedAt: note.updatedAt,\n pinned: note.pinned,\n order: note.order,\n layout: note.layout,\n tags: { create: note.tags.map((tag) => ({ name: tag.name })) },\n reminders: {\n create: note.reminders.map((reminder) => ({\n originalId: reminder.id,\n reminderDate: reminder.reminderDate,\n completed: reminder.completed,\n priority: reminder.priority,\n content: reminder.content,\n createdAt: reminder.createdAt,\n updatedAt: reminder.updatedAt,\n })),\n },\n },\n });\n\n await tx.note.delete({ where: { id: note.id } });\n\n if (note.tags.length > 0) {\n await tx.tag.deleteMany({\n where: {\n id: { in: note.tags.map((tag) => tag.id) },\n notes: { none: {} },\n },\n });\n }\n\n return tx.deletedNote.findUniqueOrThrow({\n where: { id: note.id },\n include: includeDeletedNote,\n });\n });\n },\n restoreDeletedNote: async (deletedNote) => {\n return models.$transaction(async (tx) => {\n const tagNames = Array.from(new Set(deletedNote.tags.map((tag) => tag.name).filter(Boolean)));\n\n if (tagNames.length > 0) {\n const existingTags = await tx.tag.findMany({\n where: { name: { in: tagNames } },\n select: { name: true },\n });\n const existingTagNames = new Set(existingTags.map((tag) => tag.name));\n const missingTagNames = tagNames.filter((tagName) => !existingTagNames.has(tagName));\n\n for (const tagName of missingTagNames) {\n await tx.tag.create({ data: { name: tagName } });\n }\n }\n\n const restoreTagIds =\n tagNames.length > 0\n ? await tx.tag.findMany({\n where: { name: { in: tagNames } },\n select: {\n id: true,\n name: true,\n },\n })\n : [];\n\n const restoredContent =\n restoreTagIds.length > 0\n ? restoreTagIdsInContent(\n deletedNote.content,\n new Map(restoreTagIds.map((tag) => [tag.name, tag.id])),\n )\n : deletedNote.content;\n\n const note = await tx.note.create({\n data: {\n id: deletedNote.id,\n title: deletedNote.title,\n content: restoredContent,\n ...buildNoteSearchProjection({\n title: deletedNote.title,\n content: restoredContent,\n }),\n createdAt: deletedNote.createdAt,\n updatedAt: deletedNote.updatedAt,\n pinned: deletedNote.pinned,\n order: deletedNote.order,\n layout: deletedNote.layout,\n ...(restoreTagIds.length > 0\n ? { tags: { connect: restoreTagIds.map((tag) => ({ id: tag.id })) } }\n : {}),\n ...(deletedNote.reminders.length > 0\n ? {\n reminders: {\n create: deletedNote.reminders.map((reminder) => ({\n reminderDate: reminder.reminderDate,\n completed: reminder.completed,\n priority: reminder.priority,\n content: reminder.content,\n createdAt: reminder.createdAt,\n updatedAt: reminder.updatedAt,\n })),\n },\n }\n : {}),\n },\n });\n\n await tx.deletedNote.delete({ where: { id: deletedNote.id } });\n\n return note;\n });\n },\n});\n\nexport const listTrashedNotes = noteTrashService.listTrashedNotes;\nexport const getTrashedNoteById = noteTrashService.getNoteById;\nexport const trashNoteById = noteTrashService.trashNoteById;\nexport const restoreTrashedNoteById = noteTrashService.restoreNoteById;\nexport const purgeTrashedNoteById = noteTrashService.purgeNoteById;\nexport const purgeExpiredTrashedNotes = async () => {\n return defaultPurgeExpiredDeletedNotes(createRetentionCutoff(TRASH_RETENTION_DAYS), RECOVERY_CLEANUP_BATCH_LIMIT);\n};\n"],"mappings":"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","names":[]}
@@ -1,37 +1,28 @@
1
+ import { buildUnauthorizedGraphqlPayload, buildUnauthorizedPayload } from "@baejino/auth";
1
2
  import session from "express-session";
2
3
  import { GraphQLError } from "graphql";
3
4
  const JSON_HEADERS = { "Content-Type": "application/json" };
4
- const buildUnauthorizedPayload = () => ({
5
- code: "UNAUTHORIZED",
6
- message: "Authentication required"
7
- });
8
- const buildUnauthorizedGraphqlPayload = () => ({
9
- errors: [
10
- {
11
- message: "Authentication required",
12
- extensions: { code: "UNAUTHORIZED" }
13
- }
14
- ]
15
- });
16
5
  const isAuthenticatedRequest = (req) => Boolean(req.session?.authenticated);
17
6
  const createSessionMiddleware = (authConfig) => {
18
- if (authConfig.mode !== "password" || !authConfig.sessionSecret) {
7
+ if (authConfig.mode !== "password") {
19
8
  return (_req, _res, next) => next();
20
9
  }
21
10
  return session({
22
11
  secret: authConfig.sessionSecret,
23
- name: "ocean-brain.sid",
12
+ name: authConfig.cookieName,
24
13
  resave: false,
25
14
  saveUninitialized: false,
26
15
  cookie: {
27
16
  httpOnly: true,
28
- sameSite: "lax"
17
+ sameSite: "lax",
18
+ secure: process.env.NODE_ENV === "production",
19
+ path: "/"
29
20
  }
30
21
  });
31
22
  };
32
23
  const requireSessionForWrite = (authConfig) => {
33
24
  return (req, res, next) => {
34
- if (authConfig.mode === "disabled" || isAuthenticatedRequest(req)) {
25
+ if (authConfig.mode === "open" || isAuthenticatedRequest(req)) {
35
26
  next();
36
27
  return;
37
28
  }
@@ -40,7 +31,7 @@ const requireSessionForWrite = (authConfig) => {
40
31
  };
41
32
  const requireSessionForGraphql = (authConfig) => {
42
33
  return (req, res, next) => {
43
- if (authConfig.mode === "disabled" || isAuthenticatedRequest(req)) {
34
+ if (authConfig.mode === "open" || isAuthenticatedRequest(req)) {
44
35
  next();
45
36
  return;
46
37
  }
@@ -54,10 +45,13 @@ const createMutationAuthValidationRule = () => {
54
45
  if (node.operation !== "mutation") {
55
46
  return;
56
47
  }
48
+ const unauthorizedError = buildUnauthorizedGraphqlPayload().errors[0];
57
49
  context.reportError(
58
- new GraphQLError("Authentication required", {
50
+ new GraphQLError(unauthorizedError.message, {
59
51
  nodes: [node],
60
- extensions: { code: "UNAUTHORIZED" }
52
+ extensions: {
53
+ code: unauthorizedError.extensions.code
54
+ }
61
55
  })
62
56
  );
63
57
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/auth-guard.ts"],"sourcesContent":["import type { NextFunction, Request, RequestHandler, Response } from 'express';\nimport session from 'express-session';\nimport type { ValidationRule } from 'graphql';\nimport { GraphQLError } from 'graphql';\n\nimport type { AuthConfig } from './auth-mode.js';\n\nconst JSON_HEADERS = { 'Content-Type': 'application/json' };\n\nconst buildUnauthorizedPayload = () => ({\n code: 'UNAUTHORIZED',\n message: 'Authentication required',\n});\n\nconst buildUnauthorizedGraphqlPayload = () => ({\n errors: [\n {\n message: 'Authentication required',\n extensions: { code: 'UNAUTHORIZED' },\n },\n ],\n});\n\nexport const isAuthenticatedRequest = (req: Request) => Boolean(req.session?.authenticated);\n\nexport const createSessionMiddleware = (authConfig: AuthConfig): RequestHandler => {\n if (authConfig.mode !== 'password' || !authConfig.sessionSecret) {\n return (_req, _res, next) => next();\n }\n\n return session({\n secret: authConfig.sessionSecret,\n name: 'ocean-brain.sid',\n resave: false,\n saveUninitialized: false,\n cookie: {\n httpOnly: true,\n sameSite: 'lax',\n },\n });\n};\n\nexport const requireSessionForWrite = (authConfig: AuthConfig): RequestHandler => {\n return (req: Request, res: Response, next: NextFunction) => {\n if (authConfig.mode === 'disabled' || isAuthenticatedRequest(req)) {\n next();\n return;\n }\n\n res.status(401).set(JSON_HEADERS).json(buildUnauthorizedPayload()).end();\n };\n};\n\nexport const requireSessionForGraphql = (authConfig: AuthConfig): RequestHandler => {\n return (req: Request, res: Response, next: NextFunction) => {\n if (authConfig.mode === 'disabled' || isAuthenticatedRequest(req)) {\n next();\n return;\n }\n\n res.status(401).set(JSON_HEADERS).json(buildUnauthorizedGraphqlPayload()).end();\n };\n};\n\nexport const createMutationAuthValidationRule = (): ValidationRule => {\n return (context) => {\n return {\n OperationDefinition(node) {\n if (node.operation !== 'mutation') {\n return;\n }\n\n context.reportError(\n new GraphQLError('Authentication required', {\n nodes: [node],\n extensions: { code: 'UNAUTHORIZED' },\n }),\n );\n },\n };\n };\n};\n"],"mappings":"AACA,OAAO,aAAa;AAEpB,SAAS,oBAAoB;AAI7B,MAAM,eAAe,EAAE,gBAAgB,mBAAmB;AAE1D,MAAM,2BAA2B,OAAO;AAAA,EACpC,MAAM;AAAA,EACN,SAAS;AACb;AAEA,MAAM,kCAAkC,OAAO;AAAA,EAC3C,QAAQ;AAAA,IACJ;AAAA,MACI,SAAS;AAAA,MACT,YAAY,EAAE,MAAM,eAAe;AAAA,IACvC;AAAA,EACJ;AACJ;AAEO,MAAM,yBAAyB,CAAC,QAAiB,QAAQ,IAAI,SAAS,aAAa;AAEnF,MAAM,0BAA0B,CAAC,eAA2C;AAC/E,MAAI,WAAW,SAAS,cAAc,CAAC,WAAW,eAAe;AAC7D,WAAO,CAAC,MAAM,MAAM,SAAS,KAAK;AAAA,EACtC;AAEA,SAAO,QAAQ;AAAA,IACX,QAAQ,WAAW;AAAA,IACnB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,mBAAmB;AAAA,IACnB,QAAQ;AAAA,MACJ,UAAU;AAAA,MACV,UAAU;AAAA,IACd;AAAA,EACJ,CAAC;AACL;AAEO,MAAM,yBAAyB,CAAC,eAA2C;AAC9E,SAAO,CAAC,KAAc,KAAe,SAAuB;AACxD,QAAI,WAAW,SAAS,cAAc,uBAAuB,GAAG,GAAG;AAC/D,WAAK;AACL;AAAA,IACJ;AAEA,QAAI,OAAO,GAAG,EAAE,IAAI,YAAY,EAAE,KAAK,yBAAyB,CAAC,EAAE,IAAI;AAAA,EAC3E;AACJ;AAEO,MAAM,2BAA2B,CAAC,eAA2C;AAChF,SAAO,CAAC,KAAc,KAAe,SAAuB;AACxD,QAAI,WAAW,SAAS,cAAc,uBAAuB,GAAG,GAAG;AAC/D,WAAK;AACL;AAAA,IACJ;AAEA,QAAI,OAAO,GAAG,EAAE,IAAI,YAAY,EAAE,KAAK,gCAAgC,CAAC,EAAE,IAAI;AAAA,EAClF;AACJ;AAEO,MAAM,mCAAmC,MAAsB;AAClE,SAAO,CAAC,YAAY;AAChB,WAAO;AAAA,MACH,oBAAoB,MAAM;AACtB,YAAI,KAAK,cAAc,YAAY;AAC/B;AAAA,QACJ;AAEA,gBAAQ;AAAA,UACJ,IAAI,aAAa,2BAA2B;AAAA,YACxC,OAAO,CAAC,IAAI;AAAA,YACZ,YAAY,EAAE,MAAM,eAAe;AAAA,UACvC,CAAC;AAAA,QACL;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ;","names":[]}
1
+ {"version":3,"sources":["../../src/modules/auth-guard.ts"],"sourcesContent":["import { buildUnauthorizedGraphqlPayload, buildUnauthorizedPayload } from '@baejino/auth';\nimport type { NextFunction, Request, RequestHandler, Response } from 'express';\nimport session from 'express-session';\nimport type { ValidationRule } from 'graphql';\nimport { GraphQLError } from 'graphql';\n\nimport type { AuthConfig } from './auth-mode.js';\n\nconst JSON_HEADERS = { 'Content-Type': 'application/json' };\n\nexport const isAuthenticatedRequest = (req: Request) => Boolean(req.session?.authenticated);\n\nexport const createSessionMiddleware = (authConfig: AuthConfig): RequestHandler => {\n if (authConfig.mode !== 'password') {\n return (_req, _res, next) => next();\n }\n\n return session({\n secret: authConfig.sessionSecret,\n name: authConfig.cookieName,\n resave: false,\n saveUninitialized: false,\n cookie: {\n httpOnly: true,\n sameSite: 'lax',\n secure: process.env.NODE_ENV === 'production',\n path: '/',\n },\n });\n};\n\nexport const requireSessionForWrite = (authConfig: AuthConfig): RequestHandler => {\n return (req: Request, res: Response, next: NextFunction) => {\n if (authConfig.mode === 'open' || isAuthenticatedRequest(req)) {\n next();\n return;\n }\n\n res.status(401).set(JSON_HEADERS).json(buildUnauthorizedPayload()).end();\n };\n};\n\nexport const requireSessionForGraphql = (authConfig: AuthConfig): RequestHandler => {\n return (req: Request, res: Response, next: NextFunction) => {\n if (authConfig.mode === 'open' || isAuthenticatedRequest(req)) {\n next();\n return;\n }\n\n res.status(401).set(JSON_HEADERS).json(buildUnauthorizedGraphqlPayload()).end();\n };\n};\n\nexport const createMutationAuthValidationRule = (): ValidationRule => {\n return (context) => {\n return {\n OperationDefinition(node) {\n if (node.operation !== 'mutation') {\n return;\n }\n\n const unauthorizedError = buildUnauthorizedGraphqlPayload().errors[0];\n\n context.reportError(\n new GraphQLError(unauthorizedError.message, {\n nodes: [node],\n extensions: {\n code: unauthorizedError.extensions.code,\n },\n }),\n );\n },\n };\n };\n};\n"],"mappings":"AAAA,SAAS,iCAAiC,gCAAgC;AAE1E,OAAO,aAAa;AAEpB,SAAS,oBAAoB;AAI7B,MAAM,eAAe,EAAE,gBAAgB,mBAAmB;AAEnD,MAAM,yBAAyB,CAAC,QAAiB,QAAQ,IAAI,SAAS,aAAa;AAEnF,MAAM,0BAA0B,CAAC,eAA2C;AAC/E,MAAI,WAAW,SAAS,YAAY;AAChC,WAAO,CAAC,MAAM,MAAM,SAAS,KAAK;AAAA,EACtC;AAEA,SAAO,QAAQ;AAAA,IACX,QAAQ,WAAW;AAAA,IACnB,MAAM,WAAW;AAAA,IACjB,QAAQ;AAAA,IACR,mBAAmB;AAAA,IACnB,QAAQ;AAAA,MACJ,UAAU;AAAA,MACV,UAAU;AAAA,MACV,QAAQ,QAAQ,IAAI,aAAa;AAAA,MACjC,MAAM;AAAA,IACV;AAAA,EACJ,CAAC;AACL;AAEO,MAAM,yBAAyB,CAAC,eAA2C;AAC9E,SAAO,CAAC,KAAc,KAAe,SAAuB;AACxD,QAAI,WAAW,SAAS,UAAU,uBAAuB,GAAG,GAAG;AAC3D,WAAK;AACL;AAAA,IACJ;AAEA,QAAI,OAAO,GAAG,EAAE,IAAI,YAAY,EAAE,KAAK,yBAAyB,CAAC,EAAE,IAAI;AAAA,EAC3E;AACJ;AAEO,MAAM,2BAA2B,CAAC,eAA2C;AAChF,SAAO,CAAC,KAAc,KAAe,SAAuB;AACxD,QAAI,WAAW,SAAS,UAAU,uBAAuB,GAAG,GAAG;AAC3D,WAAK;AACL;AAAA,IACJ;AAEA,QAAI,OAAO,GAAG,EAAE,IAAI,YAAY,EAAE,KAAK,gCAAgC,CAAC,EAAE,IAAI;AAAA,EAClF;AACJ;AAEO,MAAM,mCAAmC,MAAsB;AAClE,SAAO,CAAC,YAAY;AAChB,WAAO;AAAA,MACH,oBAAoB,MAAM;AACtB,YAAI,KAAK,cAAc,YAAY;AAC/B;AAAA,QACJ;AAEA,cAAM,oBAAoB,gCAAgC,EAAE,OAAO,CAAC;AAEpE,gBAAQ;AAAA,UACJ,IAAI,aAAa,kBAAkB,SAAS;AAAA,YACxC,OAAO,CAAC,IAAI;AAAA,YACZ,YAAY;AAAA,cACR,MAAM,kBAAkB,WAAW;AAAA,YACvC;AAAA,UACJ,CAAC;AAAA,QACL;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ;","names":[]}
@@ -1,48 +1,25 @@
1
- const isTruthy = (value) => {
2
- if (!value) {
3
- return false;
4
- }
5
- return ["1", "true", "yes", "on"].includes(value.trim().toLowerCase());
6
- };
7
- const ensurePasswordModeRequirements = (env) => {
8
- if (!env.OCEAN_BRAIN_PASSWORD) {
9
- throw new Error("Missing OCEAN_BRAIN_PASSWORD. Set OCEAN_BRAIN_PASSWORD to enable password auth mode.");
10
- }
11
- if (!env.OCEAN_BRAIN_SESSION_SECRET) {
12
- throw new Error(
13
- "Missing OCEAN_BRAIN_SESSION_SECRET. Set OCEAN_BRAIN_SESSION_SECRET when password auth mode is enabled."
14
- );
15
- }
16
- };
17
- const resolveAuthConfig = (env) => {
18
- const allowInsecureNoAuth = isTruthy(env.OCEAN_BRAIN_ALLOW_INSECURE_NO_AUTH);
19
- if (allowInsecureNoAuth) {
20
- return {
21
- mode: "disabled",
22
- source: "auto"
23
- };
24
- }
25
- if (env.OCEAN_BRAIN_PASSWORD) {
26
- ensurePasswordModeRequirements(env);
27
- return {
28
- mode: "password",
29
- password: env.OCEAN_BRAIN_PASSWORD,
30
- sessionSecret: env.OCEAN_BRAIN_SESSION_SECRET,
31
- source: "auto"
32
- };
33
- }
34
- throw new Error(
35
- "Unable to resolve auth mode. Set OCEAN_BRAIN_PASSWORD and OCEAN_BRAIN_SESSION_SECRET for password mode, or set OCEAN_BRAIN_ALLOW_INSECURE_NO_AUTH=true for disabled mode."
36
- );
37
- };
1
+ import { resolvePasswordAuthConfig } from "@baejino/auth";
2
+ const AUTH_SESSION_COOKIE_NAME = "ocean-brain.sid";
3
+ const resolveAuthConfig = (env) => resolvePasswordAuthConfig({
4
+ env,
5
+ passwordEnv: "OCEAN_BRAIN_PASSWORD",
6
+ sessionSecretEnv: "OCEAN_BRAIN_SESSION_SECRET",
7
+ allowOpenEnv: "OCEAN_BRAIN_ALLOW_INSECURE_NO_AUTH",
8
+ requireExplicitOpen: true,
9
+ allowPasswordAsSessionSecret: false,
10
+ cookieName: AUTH_SESSION_COOKIE_NAME
11
+ });
38
12
  const logAuthConfig = (authConfig) => {
39
- if (authConfig.mode === "disabled") {
40
- process.stderr.write("[auth] Running in disabled mode. Authentication is not required for write access.\n");
13
+ if (authConfig.mode === "open") {
14
+ process.stderr.write(
15
+ "[auth] Running in explicit open mode. Authentication is not required for write access.\n"
16
+ );
41
17
  return;
42
18
  }
43
19
  process.stdout.write("[auth] Running in password mode. Write access requires an authenticated session.\n");
44
20
  };
45
21
  export {
22
+ AUTH_SESSION_COOKIE_NAME,
46
23
  logAuthConfig,
47
24
  resolveAuthConfig
48
25
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/auth-mode.ts"],"sourcesContent":["export type AuthMode = 'password' | 'disabled';\n\nexport interface AuthConfig {\n mode: AuthMode;\n password?: string;\n sessionSecret?: string;\n source: 'auto' | 'override';\n}\n\nexport interface AuthModeEnvironment {\n [key: string]: string | undefined;\n OCEAN_BRAIN_ALLOW_INSECURE_NO_AUTH?: string;\n OCEAN_BRAIN_PASSWORD?: string;\n OCEAN_BRAIN_SESSION_SECRET?: string;\n}\n\nconst isTruthy = (value?: string) => {\n if (!value) {\n return false;\n }\n\n return ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase());\n};\n\nconst ensurePasswordModeRequirements = (env: AuthModeEnvironment) => {\n if (!env.OCEAN_BRAIN_PASSWORD) {\n throw new Error('Missing OCEAN_BRAIN_PASSWORD. Set OCEAN_BRAIN_PASSWORD to enable password auth mode.');\n }\n\n if (!env.OCEAN_BRAIN_SESSION_SECRET) {\n throw new Error(\n 'Missing OCEAN_BRAIN_SESSION_SECRET. Set OCEAN_BRAIN_SESSION_SECRET when password auth mode is enabled.',\n );\n }\n};\n\nexport const resolveAuthConfig = (env: AuthModeEnvironment): AuthConfig => {\n const allowInsecureNoAuth = isTruthy(env.OCEAN_BRAIN_ALLOW_INSECURE_NO_AUTH);\n\n if (allowInsecureNoAuth) {\n return {\n mode: 'disabled',\n source: 'auto',\n };\n }\n\n if (env.OCEAN_BRAIN_PASSWORD) {\n ensurePasswordModeRequirements(env);\n\n return {\n mode: 'password',\n password: env.OCEAN_BRAIN_PASSWORD,\n sessionSecret: env.OCEAN_BRAIN_SESSION_SECRET,\n source: 'auto',\n };\n }\n\n throw new Error(\n 'Unable to resolve auth mode. Set OCEAN_BRAIN_PASSWORD and OCEAN_BRAIN_SESSION_SECRET for password mode, or set OCEAN_BRAIN_ALLOW_INSECURE_NO_AUTH=true for disabled mode.',\n );\n};\n\nexport const logAuthConfig = (authConfig: AuthConfig) => {\n if (authConfig.mode === 'disabled') {\n process.stderr.write('[auth] Running in disabled mode. Authentication is not required for write access.\\n');\n return;\n }\n\n process.stdout.write('[auth] Running in password mode. Write access requires an authenticated session.\\n');\n};\n"],"mappings":"AAgBA,MAAM,WAAW,CAAC,UAAmB;AACjC,MAAI,CAAC,OAAO;AACR,WAAO;AAAA,EACX;AAEA,SAAO,CAAC,KAAK,QAAQ,OAAO,IAAI,EAAE,SAAS,MAAM,KAAK,EAAE,YAAY,CAAC;AACzE;AAEA,MAAM,iCAAiC,CAAC,QAA6B;AACjE,MAAI,CAAC,IAAI,sBAAsB;AAC3B,UAAM,IAAI,MAAM,sFAAsF;AAAA,EAC1G;AAEA,MAAI,CAAC,IAAI,4BAA4B;AACjC,UAAM,IAAI;AAAA,MACN;AAAA,IACJ;AAAA,EACJ;AACJ;AAEO,MAAM,oBAAoB,CAAC,QAAyC;AACvE,QAAM,sBAAsB,SAAS,IAAI,kCAAkC;AAE3E,MAAI,qBAAqB;AACrB,WAAO;AAAA,MACH,MAAM;AAAA,MACN,QAAQ;AAAA,IACZ;AAAA,EACJ;AAEA,MAAI,IAAI,sBAAsB;AAC1B,mCAA+B,GAAG;AAElC,WAAO;AAAA,MACH,MAAM;AAAA,MACN,UAAU,IAAI;AAAA,MACd,eAAe,IAAI;AAAA,MACnB,QAAQ;AAAA,IACZ;AAAA,EACJ;AAEA,QAAM,IAAI;AAAA,IACN;AAAA,EACJ;AACJ;AAEO,MAAM,gBAAgB,CAAC,eAA2B;AACrD,MAAI,WAAW,SAAS,YAAY;AAChC,YAAQ,OAAO,MAAM,qFAAqF;AAC1G;AAAA,EACJ;AAEA,UAAQ,OAAO,MAAM,oFAAoF;AAC7G;","names":[]}
1
+ {"version":3,"sources":["../../src/modules/auth-mode.ts"],"sourcesContent":["import { type AuthConfig, type AuthEnvironment, resolvePasswordAuthConfig } from '@baejino/auth';\n\nexport type { AuthConfig, AuthMode } from '@baejino/auth';\n\nexport const AUTH_SESSION_COOKIE_NAME = 'ocean-brain.sid';\n\nexport interface AuthModeEnvironment extends AuthEnvironment {\n [key: string]: string | undefined;\n OCEAN_BRAIN_ALLOW_INSECURE_NO_AUTH?: string;\n OCEAN_BRAIN_PASSWORD?: string;\n OCEAN_BRAIN_SESSION_SECRET?: string;\n}\n\nexport const resolveAuthConfig = (env: AuthModeEnvironment): AuthConfig =>\n resolvePasswordAuthConfig({\n env,\n passwordEnv: 'OCEAN_BRAIN_PASSWORD',\n sessionSecretEnv: 'OCEAN_BRAIN_SESSION_SECRET',\n allowOpenEnv: 'OCEAN_BRAIN_ALLOW_INSECURE_NO_AUTH',\n requireExplicitOpen: true,\n allowPasswordAsSessionSecret: false,\n cookieName: AUTH_SESSION_COOKIE_NAME,\n });\n\nexport const logAuthConfig = (authConfig: AuthConfig) => {\n if (authConfig.mode === 'open') {\n process.stderr.write(\n '[auth] Running in explicit open mode. Authentication is not required for write access.\\n',\n );\n return;\n }\n\n process.stdout.write('[auth] Running in password mode. Write access requires an authenticated session.\\n');\n};\n"],"mappings":"AAAA,SAAgD,iCAAiC;AAI1E,MAAM,2BAA2B;AASjC,MAAM,oBAAoB,CAAC,QAC9B,0BAA0B;AAAA,EACtB;AAAA,EACA,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,cAAc;AAAA,EACd,qBAAqB;AAAA,EACrB,8BAA8B;AAAA,EAC9B,YAAY;AAChB,CAAC;AAEE,MAAM,gBAAgB,CAAC,eAA2B;AACrD,MAAI,WAAW,SAAS,QAAQ;AAC5B,YAAQ,OAAO;AAAA,MACX;AAAA,IACJ;AACA;AAAA,EACJ;AAEA,UAAQ,OAAO,MAAM,oFAAoF;AAC7G;","names":[]}
@@ -6,7 +6,7 @@ const shouldBlockClientRoute = (authConfig, requestPath, authenticated) => {
6
6
  if (authConfig.mode !== "password" || authenticated) {
7
7
  return false;
8
8
  }
9
- if (requestPath.startsWith("/api") || requestPath.startsWith("/graphql") || requestPath.startsWith("/auth")) {
9
+ if (requestPath.startsWith("/api") || requestPath.startsWith("/graphql") || requestPath === "/login" || requestPath === "/logout") {
10
10
  return false;
11
11
  }
12
12
  return path.extname(requestPath) === "";
@@ -14,7 +14,7 @@ const shouldBlockClientRoute = (authConfig, requestPath, authenticated) => {
14
14
  const createClientRouter = (authConfig) => Router().use("/assets/images", express.static(paths.imageDir)).use((req, res, next) => {
15
15
  if (shouldBlockClientRoute(authConfig, req.path, isAuthenticatedRequest(req))) {
16
16
  const redirectPath = encodeURIComponent(req.originalUrl || "/");
17
- res.redirect(303, `/auth/login?next=${redirectPath}`);
17
+ res.redirect(303, `/login?next=${redirectPath}`);
18
18
  return;
19
19
  }
20
20
  next();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/client.ts"],"sourcesContent":["import express, { Router } from 'express';\nimport path from 'path';\nimport { isAuthenticatedRequest } from '../modules/auth-guard.js';\nimport type { AuthConfig } from '../modules/auth-mode.js';\nimport { paths } from '../paths.js';\n\nconst shouldBlockClientRoute = (authConfig: AuthConfig, requestPath: string, authenticated: boolean) => {\n if (authConfig.mode !== 'password' || authenticated) {\n return false;\n }\n\n if (requestPath.startsWith('/api') || requestPath.startsWith('/graphql') || requestPath.startsWith('/auth')) {\n return false;\n }\n\n return path.extname(requestPath) === '';\n};\n\nexport const createClientRouter = (authConfig: AuthConfig) =>\n Router()\n .use('/assets/images', express.static(paths.imageDir))\n .use((req, res, next) => {\n if (shouldBlockClientRoute(authConfig, req.path, isAuthenticatedRequest(req))) {\n const redirectPath = encodeURIComponent(req.originalUrl || '/');\n res.redirect(303, `/auth/login?next=${redirectPath}`);\n return;\n }\n\n next();\n })\n .use(express.static(paths.clientDist, { extensions: ['html'] }))\n .get(/.*/, (_req, res) => {\n res.sendFile(paths.clientIndex);\n });\n"],"mappings":"AAAA,OAAO,WAAW,cAAc;AAChC,OAAO,UAAU;AACjB,SAAS,8BAA8B;AAEvC,SAAS,aAAa;AAEtB,MAAM,yBAAyB,CAAC,YAAwB,aAAqB,kBAA2B;AACpG,MAAI,WAAW,SAAS,cAAc,eAAe;AACjD,WAAO;AAAA,EACX;AAEA,MAAI,YAAY,WAAW,MAAM,KAAK,YAAY,WAAW,UAAU,KAAK,YAAY,WAAW,OAAO,GAAG;AACzG,WAAO;AAAA,EACX;AAEA,SAAO,KAAK,QAAQ,WAAW,MAAM;AACzC;AAEO,MAAM,qBAAqB,CAAC,eAC/B,OAAO,EACF,IAAI,kBAAkB,QAAQ,OAAO,MAAM,QAAQ,CAAC,EACpD,IAAI,CAAC,KAAK,KAAK,SAAS;AACrB,MAAI,uBAAuB,YAAY,IAAI,MAAM,uBAAuB,GAAG,CAAC,GAAG;AAC3E,UAAM,eAAe,mBAAmB,IAAI,eAAe,GAAG;AAC9D,QAAI,SAAS,KAAK,oBAAoB,YAAY,EAAE;AACpD;AAAA,EACJ;AAEA,OAAK;AACT,CAAC,EACA,IAAI,QAAQ,OAAO,MAAM,YAAY,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,EAC9D,IAAI,MAAM,CAAC,MAAM,QAAQ;AACtB,MAAI,SAAS,MAAM,WAAW;AAClC,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/routes/client.ts"],"sourcesContent":["import express, { Router } from 'express';\nimport path from 'path';\nimport { isAuthenticatedRequest } from '../modules/auth-guard.js';\nimport type { AuthConfig } from '../modules/auth-mode.js';\nimport { paths } from '../paths.js';\n\nconst shouldBlockClientRoute = (authConfig: AuthConfig, requestPath: string, authenticated: boolean) => {\n if (authConfig.mode !== 'password' || authenticated) {\n return false;\n }\n\n if (\n requestPath.startsWith('/api') ||\n requestPath.startsWith('/graphql') ||\n requestPath === '/login' ||\n requestPath === '/logout'\n ) {\n return false;\n }\n\n return path.extname(requestPath) === '';\n};\n\nexport const createClientRouter = (authConfig: AuthConfig) =>\n Router()\n .use('/assets/images', express.static(paths.imageDir))\n .use((req, res, next) => {\n if (shouldBlockClientRoute(authConfig, req.path, isAuthenticatedRequest(req))) {\n const redirectPath = encodeURIComponent(req.originalUrl || '/');\n res.redirect(303, `/login?next=${redirectPath}`);\n return;\n }\n\n next();\n })\n .use(express.static(paths.clientDist, { extensions: ['html'] }))\n .get(/.*/, (_req, res) => {\n res.sendFile(paths.clientIndex);\n });\n"],"mappings":"AAAA,OAAO,WAAW,cAAc;AAChC,OAAO,UAAU;AACjB,SAAS,8BAA8B;AAEvC,SAAS,aAAa;AAEtB,MAAM,yBAAyB,CAAC,YAAwB,aAAqB,kBAA2B;AACpG,MAAI,WAAW,SAAS,cAAc,eAAe;AACjD,WAAO;AAAA,EACX;AAEA,MACI,YAAY,WAAW,MAAM,KAC7B,YAAY,WAAW,UAAU,KACjC,gBAAgB,YAChB,gBAAgB,WAClB;AACE,WAAO;AAAA,EACX;AAEA,SAAO,KAAK,QAAQ,WAAW,MAAM;AACzC;AAEO,MAAM,qBAAqB,CAAC,eAC/B,OAAO,EACF,IAAI,kBAAkB,QAAQ,OAAO,MAAM,QAAQ,CAAC,EACpD,IAAI,CAAC,KAAK,KAAK,SAAS;AACrB,MAAI,uBAAuB,YAAY,IAAI,MAAM,uBAAuB,GAAG,CAAC,GAAG;AAC3E,UAAM,eAAe,mBAAmB,IAAI,eAAe,GAAG;AAC9D,QAAI,SAAS,KAAK,eAAe,YAAY,EAAE;AAC/C;AAAA,EACJ;AAEA,OAAK;AACT,CAAC,EACA,IAAI,QAAQ,OAAO,MAAM,YAAY,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,EAC9D,IAAI,MAAM,CAAC,MAAM,QAAQ;AACtB,MAAI,SAAS,MAAM,WAAW;AAClC,CAAC;","names":[]}
@@ -1 +0,0 @@
1
- import{a as e}from"./graph-vendor-CUxe67Lr.js";import{p as n}from"./index-Bsx4P7EA.js";import{j as r}from"./note-vendor-5N5mRkIT.js";const m=new Map([["bold",e.createElement(e.Fragment,null,e.createElement("path",{d:"M228,128a12,12,0,0,1-12,12H140v76a12,12,0,0,1-24,0V140H40a12,12,0,0,1,0-24h76V40a12,12,0,0,1,24,0v76h76A12,12,0,0,1,228,128Z"}))],["duotone",e.createElement(e.Fragment,null,e.createElement("path",{d:"M216,56V200a16,16,0,0,1-16,16H56a16,16,0,0,1-16-16V56A16,16,0,0,1,56,40H200A16,16,0,0,1,216,56Z",opacity:"0.2"}),e.createElement("path",{d:"M224,128a8,8,0,0,1-8,8H136v80a8,8,0,0,1-16,0V136H40a8,8,0,0,1,0-16h80V40a8,8,0,0,1,16,0v80h80A8,8,0,0,1,224,128Z"}))],["fill",e.createElement(e.Fragment,null,e.createElement("path",{d:"M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM184,136H136v48a8,8,0,0,1-16,0V136H72a8,8,0,0,1,0-16h48V72a8,8,0,0,1,16,0v48h48a8,8,0,0,1,0,16Z"}))],["light",e.createElement(e.Fragment,null,e.createElement("path",{d:"M222,128a6,6,0,0,1-6,6H134v82a6,6,0,0,1-12,0V134H40a6,6,0,0,1,0-12h82V40a6,6,0,0,1,12,0v82h82A6,6,0,0,1,222,128Z"}))],["regular",e.createElement(e.Fragment,null,e.createElement("path",{d:"M224,128a8,8,0,0,1-8,8H136v80a8,8,0,0,1-16,0V136H40a8,8,0,0,1,0-16h80V40a8,8,0,0,1,16,0v80h80A8,8,0,0,1,224,128Z"}))],["thin",e.createElement(e.Fragment,null,e.createElement("path",{d:"M220,128a4,4,0,0,1-4,4H132v84a4,4,0,0,1-8,0V132H40a4,4,0,0,1,0-8h84V40a4,4,0,0,1,8,0v84h84A4,4,0,0,1,220,128Z"}))]]),t=e.forwardRef((a,l)=>e.createElement(n,{ref:l,...a,weights:m}));t.displayName="PlusIcon";const s=t;function p({children:a}){return r.jsx("div",{className:"flex w-full flex-col-reverse gap-2 sm:flex-row sm:justify-end",children:a})}export{p as M,s as n};
@@ -1 +0,0 @@
1
- import{j as e,i as $,k as je,U as ee,y as te,v as we,X as Ne,F as Ce}from"./note-vendor-5N5mRkIT.js";import{p as Y,T as p,c as H,a4 as ae,ad as He,q as C,M as j,B as M,v as ne,w as Me,u as Ee,ae as ke,af as Ve,ag as Ae,d as N,l as F,I as Re,m as Se,n as Te,o as B,g as Ze,ah as De,Z as Le,D as se,k as re,ai as oe,aj as Fe,ak as le,a2 as ie,N as z,ab as Be,x as Ie,al as Oe,a3 as Pe,_ as O,P as _,a1 as P,j as $e,i as T,am as Ye,an as ze,ao as _e,ap as Ue,aq as Q,ar as qe,L as Ke,as as W}from"./index-Bsx4P7EA.js";import{a}from"./graph-vendor-CUxe67Lr.js";import{M as ce,n as Qe}from"./ModalActionRow-DjI5b4bl.js";import{C as We}from"./Callout-Ap1OcxWN.js";import{u as Ge,R as Je}from"./useReminderMutate-DsIvVpCQ.js";import{u as Xe}from"./image.api-DGXlQ_Ca.js";import{A as et,F as tt,a2 as de,a3 as at}from"./note-core-GgFcksAF.js";const nt=new Map([["bold",a.createElement(a.Fragment,null,a.createElement("path",{d:"M216,28H88A12,12,0,0,0,76,40V76H40A12,12,0,0,0,28,88V216a12,12,0,0,0,12,12H168a12,12,0,0,0,12-12V180h36a12,12,0,0,0,12-12V40A12,12,0,0,0,216,28ZM156,204H52V100H156Zm48-48H180V88a12,12,0,0,0-12-12H100V52H204Z"}))],["duotone",a.createElement(a.Fragment,null,a.createElement("path",{d:"M216,40V168H168V88H88V40Z",opacity:"0.2"}),a.createElement("path",{d:"M216,32H88a8,8,0,0,0-8,8V80H40a8,8,0,0,0-8,8V216a8,8,0,0,0,8,8H168a8,8,0,0,0,8-8V176h40a8,8,0,0,0,8-8V40A8,8,0,0,0,216,32ZM160,208H48V96H160Zm48-48H176V88a8,8,0,0,0-8-8H96V48H208Z"}))],["fill",a.createElement(a.Fragment,null,a.createElement("path",{d:"M216,32H88a8,8,0,0,0-8,8V80H40a8,8,0,0,0-8,8V216a8,8,0,0,0,8,8H168a8,8,0,0,0,8-8V176h40a8,8,0,0,0,8-8V40A8,8,0,0,0,216,32Zm-8,128H176V88a8,8,0,0,0-8-8H96V48H208Z"}))],["light",a.createElement(a.Fragment,null,a.createElement("path",{d:"M216,34H88a6,6,0,0,0-6,6V82H40a6,6,0,0,0-6,6V216a6,6,0,0,0,6,6H168a6,6,0,0,0,6-6V174h42a6,6,0,0,0,6-6V40A6,6,0,0,0,216,34ZM162,210H46V94H162Zm48-48H174V88a6,6,0,0,0-6-6H94V46H210Z"}))],["regular",a.createElement(a.Fragment,null,a.createElement("path",{d:"M216,32H88a8,8,0,0,0-8,8V80H40a8,8,0,0,0-8,8V216a8,8,0,0,0,8,8H168a8,8,0,0,0,8-8V176h40a8,8,0,0,0,8-8V40A8,8,0,0,0,216,32ZM160,208H48V96H160Zm48-48H176V88a8,8,0,0,0-8-8H96V48H208Z"}))],["thin",a.createElement(a.Fragment,null,a.createElement("path",{d:"M216,36H88a4,4,0,0,0-4,4V84H40a4,4,0,0,0-4,4V216a4,4,0,0,0,4,4H168a4,4,0,0,0,4-4V172h44a4,4,0,0,0,4-4V40A4,4,0,0,0,216,36ZM164,212H44V92H164Zm48-48H172V88a4,4,0,0,0-4-4H92V44H212Z"}))]]),st=new Map([["bold",a.createElement(a.Fragment,null,a.createElement("path",{d:"M216.49,79.52l-56-56A12,12,0,0,0,152,20H56A20,20,0,0,0,36,40V216a20,20,0,0,0,20,20H200a20,20,0,0,0,20-20V88A12,12,0,0,0,216.49,79.52ZM160,57l23,23H160ZM60,212V44h76V92a12,12,0,0,0,12,12h48V212Z"}))],["duotone",a.createElement(a.Fragment,null,a.createElement("path",{d:"M208,88H152V32Z",opacity:"0.2"}),a.createElement("path",{d:"M213.66,82.34l-56-56A8,8,0,0,0,152,24H56A16,16,0,0,0,40,40V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V88A8,8,0,0,0,213.66,82.34ZM160,51.31,188.69,80H160ZM200,216H56V40h88V88a8,8,0,0,0,8,8h48V216Z"}))],["fill",a.createElement(a.Fragment,null,a.createElement("path",{d:"M213.66,82.34l-56-56A8,8,0,0,0,152,24H56A16,16,0,0,0,40,40V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V88A8,8,0,0,0,213.66,82.34ZM152,88V44l44,44Z"}))],["light",a.createElement(a.Fragment,null,a.createElement("path",{d:"M212.24,83.76l-56-56A6,6,0,0,0,152,26H56A14,14,0,0,0,42,40V216a14,14,0,0,0,14,14H200a14,14,0,0,0,14-14V88A6,6,0,0,0,212.24,83.76ZM158,46.48,193.52,82H158ZM200,218H56a2,2,0,0,1-2-2V40a2,2,0,0,1,2-2h90V88a6,6,0,0,0,6,6h50V216A2,2,0,0,1,200,218Z"}))],["regular",a.createElement(a.Fragment,null,a.createElement("path",{d:"M213.66,82.34l-56-56A8,8,0,0,0,152,24H56A16,16,0,0,0,40,40V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V88A8,8,0,0,0,213.66,82.34ZM160,51.31,188.69,80H160ZM200,216H56V40h88V88a8,8,0,0,0,8,8h48V216Z"}))],["thin",a.createElement(a.Fragment,null,a.createElement("path",{d:"M210.83,85.17l-56-56A4,4,0,0,0,152,28H56A12,12,0,0,0,44,40V216a12,12,0,0,0,12,12H200a12,12,0,0,0,12-12V88A4,4,0,0,0,210.83,85.17ZM156,41.65,198.34,84H156ZM200,220H56a4,4,0,0,1-4-4V40a4,4,0,0,1,4-4h92V88a4,4,0,0,0,4,4h52V216A4,4,0,0,1,200,220Z"}))]]),rt=new Map([["bold",a.createElement(a.Fragment,null,a.createElement("path",{d:"M87.5,151.52l64-64a12,12,0,0,1,17,17l-64,64a12,12,0,0,1-17-17Zm131-114a60.08,60.08,0,0,0-84.87,0L103.51,67.61a12,12,0,0,0,17,17l30.07-30.06a36,36,0,0,1,50.93,50.92L171.4,135.52a12,12,0,1,0,17,17l30.08-30.06A60.09,60.09,0,0,0,218.45,37.55ZM135.52,171.4l-30.07,30.08a36,36,0,0,1-50.92-50.93l30.06-30.07a12,12,0,0,0-17-17L37.55,133.58a60,60,0,0,0,84.88,84.87l30.06-30.07a12,12,0,0,0-17-17Z"}))],["duotone",a.createElement(a.Fragment,null,a.createElement("path",{d:"M209.94,113.94l-96,96a48,48,0,0,1-67.88-67.88l96-96a48,48,0,0,1,67.88,67.88Z",opacity:"0.2"}),a.createElement("path",{d:"M165.66,90.34a8,8,0,0,1,0,11.32l-64,64a8,8,0,0,1-11.32-11.32l64-64A8,8,0,0,1,165.66,90.34ZM215.6,40.4a56,56,0,0,0-79.2,0L106.34,70.45a8,8,0,0,0,11.32,11.32l30.06-30a40,40,0,0,1,56.57,56.56l-30.07,30.06a8,8,0,0,0,11.31,11.32L215.6,119.6a56,56,0,0,0,0-79.2ZM138.34,174.22l-30.06,30.06a40,40,0,1,1-56.56-56.57l30.05-30.05a8,8,0,0,0-11.32-11.32L40.4,136.4a56,56,0,0,0,79.2,79.2l30.06-30.07a8,8,0,0,0-11.32-11.31Z"}))],["fill",a.createElement(a.Fragment,null,a.createElement("path",{d:"M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM144.56,173.66l-21.45,21.45a44,44,0,0,1-62.22-62.22l21.45-21.46a8,8,0,0,1,11.32,11.31L72.2,144.2a28,28,0,0,0,39.6,39.6l21.45-21.46a8,8,0,0,1,11.31,11.32Zm-34.9-16a8,8,0,0,1-11.32-11.32l48-48a8,8,0,0,1,11.32,11.32Zm85.45-34.55-21.45,21.45a8,8,0,0,1-11.32-11.31L183.8,111.8a28,28,0,0,0-39.6-39.6L122.74,93.66a8,8,0,0,1-11.31-11.32l21.46-21.45a44,44,0,0,1,62.22,62.22Z"}))],["light",a.createElement(a.Fragment,null,a.createElement("path",{d:"M164.25,91.75a6,6,0,0,1,0,8.49l-64,64a6,6,0,0,1-8.49-8.48l64-64A6,6,0,0,1,164.25,91.75ZM214.2,41.8a54.07,54.07,0,0,0-76.38,0L107.75,71.85a6,6,0,0,0,8.49,8.49l30.07-30.06a42,42,0,0,1,59.41,59.41l-30.08,30.07a6,6,0,1,0,8.49,8.49l30.07-30.07A54,54,0,0,0,214.2,41.8ZM139.76,175.64l-30.07,30.08a42,42,0,0,1-59.41-59.41l30.06-30.07a6,6,0,0,0-8.49-8.49l-30,30.07a54,54,0,0,0,76.38,76.39l30.07-30.08a6,6,0,0,0-8.49-8.49Z"}))],["regular",a.createElement(a.Fragment,null,a.createElement("path",{d:"M165.66,90.34a8,8,0,0,1,0,11.32l-64,64a8,8,0,0,1-11.32-11.32l64-64A8,8,0,0,1,165.66,90.34ZM215.6,40.4a56,56,0,0,0-79.2,0L106.34,70.45a8,8,0,0,0,11.32,11.32l30.06-30a40,40,0,0,1,56.57,56.56l-30.07,30.06a8,8,0,0,0,11.31,11.32L215.6,119.6a56,56,0,0,0,0-79.2ZM138.34,174.22l-30.06,30.06a40,40,0,1,1-56.56-56.57l30.05-30.05a8,8,0,0,0-11.32-11.32L40.4,136.4a56,56,0,0,0,79.2,79.2l30.06-30.07a8,8,0,0,0-11.32-11.31Z"}))],["thin",a.createElement(a.Fragment,null,a.createElement("path",{d:"M162.84,93.16a4,4,0,0,1,0,5.66l-64,64a4,4,0,0,1-5.66-5.66l64-64A4,4,0,0,1,162.84,93.16Zm49.95-49.95a52.07,52.07,0,0,0-73.56,0L109.17,73.27a4,4,0,0,0,5.65,5.66l30.07-30.06a44,44,0,0,1,62.24,62.24l-30.07,30.06a4,4,0,0,0,5.66,5.66l30.07-30.06A52.07,52.07,0,0,0,212.79,43.21ZM141.17,177.06l-30.06,30.07a44,44,0,0,1-62.24-62.24l30.06-30.06a4,4,0,0,0-5.66-5.66L43.21,139.23a52,52,0,0,0,73.56,73.56l30.06-30.07a4,4,0,1,0-5.66-5.66Z"}))]]),ue=a.forwardRef((t,n)=>a.createElement(Y,{ref:n,...t,weights:nt}));ue.displayName="CopyIcon";const ot=ue,me=a.forwardRef((t,n)=>a.createElement(Y,{ref:n,...t,weights:st}));me.displayName="FileIcon";const lt=me,pe=a.forwardRef((t,n)=>a.createElement(Y,{ref:n,...t,weights:rt}));pe.displayName="LinkSimpleIcon";const it=pe;function U({icon:t,title:n,className:o}){return e.jsxs("div",{className:H("flex items-center gap-2",o),children:[e.jsx("div",{className:"flex h-3.5 w-3.5 shrink-0 items-center justify-center text-current",children:t}),e.jsx(p,{as:"span",variant:"label",weight:"semibold",className:"text-current",children:n})]})}function ct({title:t,description:n,selected:o=!1,onClick:l,children:s}){return e.jsxs("button",{type:"button","aria-pressed":o,className:`focus-ring-soft flex w-full items-start justify-between gap-3 p-3 text-left transition-colors sm:p-4 ${o?"surface-floating bg-elevated":"rounded-[14px] border border-border-subtle bg-transparent hover:border-border-secondary hover:bg-hover-subtle"}`,onClick:l,children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx(p,{as:"div",variant:"body",weight:"semibold",tone:o?"default":"secondary",children:t}),e.jsx(p,{as:"div",variant:"meta",weight:"medium",tone:o?"secondary":"tertiary",className:"mt-1",children:n})]}),s?e.jsx("div",{className:"shrink-0",children:s}):null]})}const dt=t=>{const{data:n}=ae({queryKey:C.notes.backReferences(t.noteId),async queryFn(){const o=await He(t.noteId);if(o.type==="error")throw o;return o.backReferences}});return t.render(n)},ut=[{value:"narrow",label:"Narrow",description:"Optimized for reading long-form content"},{value:"wide",label:"Wide",description:"Balanced width suitable for most content"},{value:"full",label:"Full Width",description:"Maximize screen space utilization"}];function mt({isOpen:t,onClose:n,onSave:o,currentLayout:l="wide"}){const[s,c]=a.useState(l);a.useEffect(()=>{t&&c(l)},[t,l]);const i=()=>{o(s),n()};return e.jsxs(j,{isOpen:t,onClose:n,variant:"compact",children:[e.jsx(j.Header,{title:"Layout Settings",onClose:n}),e.jsx(j.Body,{children:e.jsx("div",{className:"flex flex-col gap-3 sm:gap-4",children:e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(p,{as:"div",variant:"body",weight:"semibold",tone:"secondary",children:"Note layout"}),e.jsx("div",{className:"flex flex-col gap-2",children:ut.map(r=>e.jsx(ct,{title:r.label,description:r.description,selected:s===r.value,onClick:()=>c(r.value)},r.value))})]})})}),e.jsx(j.Footer,{children:e.jsxs(ce,{children:[e.jsx(M,{variant:"ghost",size:"sm",onClick:n,children:"Cancel"}),e.jsx(M,{variant:"primary",size:"sm",onClick:i,children:"Apply"})]})})]})}const pt=(t,n)=>t||(n==="mobile"?"Mobile browser":n==="mcp"?"MCP":"Web browser");function ht({isOpen:t,noteId:n,onClose:o,onRestored:l}){const s=ne(),c=Me(),i=Ee({queryKey:C.notes.snapshots(n),queryFn:async()=>{const m=await ke(n);if(m.type==="error")throw m;return m.noteSnapshots},enabled:t}),r=Ve({mutationFn:Ae,onSuccess:async m=>{if(m.type==="error"){s(m.errors[0].message);return}await Promise.all([c.invalidateQueries({queryKey:C.notes.detail(n),exact:!0}),c.invalidateQueries({queryKey:C.notes.listAll(),exact:!1}),c.invalidateQueries({queryKey:C.notes.tagListAll(),exact:!1}),c.invalidateQueries({queryKey:C.notes.pinned(),exact:!0}),c.invalidateQueries({queryKey:C.notes.backReferences(n),exact:!0}),c.invalidateQueries({queryKey:C.notes.snapshots(n),exact:!1})]),s("Previous version restored."),l?.(m.restoreNoteSnapshot),o()}});return e.jsxs(j,{isOpen:t,onClose:o,variant:"inspect",children:[e.jsx(j.Header,{title:"Restore Previous Version",onClose:o}),e.jsx(j.Body,{children:e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx(p,{as:"p",variant:"meta",tone:"secondary",children:"Choose a previous snapshot to restore this note back to that state."}),i.isLoading&&e.jsx(p,{as:"div",variant:"meta",tone:"secondary",children:"Loading previous versions..."}),!i.isLoading&&i.data?.length===0&&e.jsx(p,{as:"div",variant:"meta",tone:"secondary",className:"rounded-[14px] border border-border-subtle bg-hover-subtle/50 px-4 py-3",children:"A recovery snapshot appears before the first edit in a session. Up to five recent snapshots are kept automatically, and identical versions are skipped."}),!i.isLoading&&i.data&&i.data.length>0&&e.jsx("div",{className:"flex flex-col gap-2",children:i.data.map(m=>e.jsx("div",{className:"surface-base p-3",children:e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs(p,{as:"p",variant:"body",weight:"semibold",children:["Before"," ",pt(m.meta.label,m.meta.entrypoint)," ","edit"]}),e.jsx(p,{as:"p",variant:"meta",truncate:!0,tone:"secondary",children:m.title}),e.jsx(p,{as:"p",variant:"label",tone:"tertiary",children:N(m.createdAt).format("YYYY-MM-DD HH:mm:ss")})]}),e.jsx(M,{size:"sm",isLoading:r.isPending,onClick:()=>r.mutate(m.id),children:"Restore"})]})},m.id))})]})})]})}const G={low:{active:"border-border-secondary bg-elevated text-fg-default",inactive:"border-transparent bg-transparent text-fg-muted hover:bg-hover-subtle"},medium:{active:"border-border-secondary bg-elevated text-fg-default",inactive:"border-transparent bg-transparent text-fg-muted hover:bg-hover-subtle"},high:{active:"border-border-secondary bg-elevated text-fg-default",inactive:"border-transparent bg-transparent text-fg-muted hover:bg-hover-subtle"}};function ft({isOpen:t,onClose:n,onSave:o,reminder:l,mode:s}){const[c,i]=a.useState(new Date),[r,m]=a.useState("medium"),[b,x]=a.useState("");a.useEffect(()=>{t&&s==="edit"&&l?(i(new Date(Number(l.reminderDate))),m(l.priority||"medium"),x(l.content||"")):t&&s==="create"&&(i(new Date),m("medium"),x(""))},[t,s,l]);const E=()=>{o(c,r,b||void 0),n()},y=g=>r===g?G[g].active:G[g].inactive;return e.jsxs(j,{isOpen:t,onClose:n,variant:"form",children:[e.jsx(j.Header,{title:s==="create"?"Create Reminder":"Edit Reminder",onClose:n}),e.jsx(j.Body,{children:e.jsxs("div",{className:"flex flex-col gap-3 sm:gap-4",children:[e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(F,{children:"Date & Time"}),e.jsx(Re,{type:"datetime-local",size:"sm",value:N(c).format("YYYY-MM-DDTHH:mm"),onChange:g=>i(new Date(g.target.value))})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(F,{children:"Content"}),e.jsx(Se,{size:"sm",placeholder:"Enter reminder content (optional)",value:b,onChange:g=>x(g.target.value)})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(F,{children:"Priority"}),e.jsxs(Te,{type:"single",value:r,onValueChange:g=>g&&m(g),className:"gap-1.5 border-none rounded-[14px] bg-muted/70 p-1 sm:gap-2",children:[e.jsx(B,{value:"low",className:`flex-1 rounded-[10px] border ${y("low")}`,children:e.jsx(p,{as:"span",weight:"medium",className:"text-current",children:"Low"})}),e.jsx(B,{value:"medium",className:`flex-1 rounded-[10px] border ${y("medium")}`,children:e.jsx(p,{as:"span",weight:"medium",className:"text-current",children:"Medium"})}),e.jsx(B,{value:"high",className:`flex-1 rounded-[10px] border ${y("high")}`,children:e.jsx(p,{as:"span",weight:"medium",className:"text-current",children:"High"})})]})]})]})}),e.jsx(j.Footer,{children:e.jsxs(ce,{children:[e.jsx(M,{variant:"ghost",size:"sm",onClick:n,children:"Cancel"}),e.jsx(M,{variant:"primary",size:"sm",onClick:E,children:s==="create"?"Create":"Save"})]})})]})}function xt({noteId:t}){const[n,o]=a.useState(!1),[l,s]=a.useState(!1),[c,i]=a.useState("create"),[r,m]=a.useState(void 0),{onCreate:b,onUpdate:x,onDelete:E}=Ge(),y=()=>{i("create"),m(void 0),s(!0)},g=h=>{i("edit"),m(h),s(!0)},V=(h,f,u)=>{c==="create"?b(t,h,f,()=>{s(!1)},u):c==="edit"&&r&&x(r.id,t,{reminderDate:h,priority:f,content:u},()=>{s(!1)})},A=h=>{x(h.id,t,{completed:!h.completed})},S=h=>{const f=N(Number(h)),u=N();return f.isSame(u,"day")?`Today at ${f.format("HH:mm")}`:f.isSame(u.add(1,"day"),"day")?`Tomorrow at ${f.format("HH:mm")}`:f.format("YYYY-MM-DD HH:mm")},Z=h=>{const f=N(Number(h)),u=N(),w=f.diff(u,"hour");return w<=6?"high":w<=24?"medium":"low"},L=h=>{const f=N(Number(h)),u=N(),w=f.diff(u,"hour"),k=f.diff(u,"minute")%60;return w<0||k<0?"Overdue":w===0?`${k}m remaining`:`${w}h ${k}m remaining`};return e.jsxs("div",{className:"surface-base mb-5 p-4",children:[e.jsxs("div",{className:H("flex items-center justify-between",!n&&"mb-3"),children:[e.jsx("button",{type:"button",onClick:()=>o(!n),className:"focus-ring-soft flex items-center gap-2 rounded-[10px] px-2 py-1.5 text-fg-tertiary transition-colors hover:bg-hover-subtle hover:text-fg-default",children:e.jsx(U,{icon:n?e.jsx(Ze,{size:12}):e.jsx(De,{size:12}),title:"Reminders"})}),!n&&e.jsxs(M,{size:"sm",variant:"ghost",onClick:y,children:[e.jsx(Qe,{className:"w-3 h-3"}),e.jsx(p,{as:"span",variant:"label",className:"hidden sm:inline",children:"Add"})]})]}),!n&&e.jsx(Je,{noteId:t,searchParams:{offset:0,limit:9999},render:({reminders:h,totalCount:f})=>e.jsx("div",{className:"flex flex-col gap-2",children:h.length===0?e.jsx(p,{as:"p",variant:"meta",tone:"secondary",className:"py-3 text-center",children:f===0?"No reminders yet":"All reminders complete"}):e.jsx("div",{className:"flex flex-col",children:h.map(u=>{const w=u.priority||Z(u.reminderDate),k=L(u.reminderDate),D=k==="Overdue";return e.jsxs("div",{className:H("flex items-center gap-2.5 px-2 py-1.5"),children:[e.jsx(Le,{checked:u.completed,onChange:()=>A(u),size:"sm"}),e.jsx(p,{as:"div",variant:"body",weight:"medium",className:H("truncate flex-1 min-w-0",u.completed&&"line-through opacity-40"),children:u.content||S(u.reminderDate)}),e.jsxs("div",{className:H("shrink-0 flex items-center gap-1",u.completed&&"opacity-40"),children:[u.content&&e.jsx(p,{as:"span",variant:"meta",tone:"secondary",children:S(u.reminderDate)}),!u.completed&&e.jsx(p,{as:"span",variant:"label",weight:"medium",tone:D||w==="high"?"error":"tertiary",className:H(u.content&&'before:content-["·"] before:mr-1'),children:k})]}),e.jsx(se,{button:e.jsx(re,{label:"Reminder actions"}),items:[{name:"Edit",onClick:()=>g(u)},{name:"Delete",onClick:()=>E(u.id,t)}]})]},u.id)})})})}),e.jsx(ft,{isOpen:l,onClose:()=>s(!1),onSave:V,reminder:r,mode:c})]})}const gt=({editor:t})=>e.jsx($,{triggerCharacter:"/",getItems:async n=>et([...je(t).filter(o=>o.title!=="Audio"&&o.title!=="Video"&&o.title!=="File"),{title:"Table of Contents",subtext:"Insert a table of contents based on headings",onItemClick:()=>{t.insertBlocks([{type:"tableOfContents"}],t.getTextCursorPosition().block,"after")},aliases:["toc","table of contents","contents","outline","index"],group:"Other",icon:e.jsx(oe,{})}],n)}),yt=(t,n)=>n?t.filter(o=>o.id!==n):t,bt=({currentNoteId:t,onClick:n})=>e.jsx($,{triggerCharacter:"[",getItems:async o=>{const l=await Fe({query:o,limit:5});return l.type==="error"?[]:yt(l.allNotes.notes,t).map(c=>({title:c.title,onItemClick:()=>n({type:"reference",props:{id:c.id,title:c.title}})}))}}),vt="pointer-events-auto inline-flex h-7 cursor-pointer select-none items-center gap-1.5 rounded-[8px] border border-white/10 bg-white/10 px-2.5 text-xs font-medium text-white/60 opacity-75 shadow-[0_8px_18px_-14px_rgba(0,0,0,0.45)] backdrop-blur-sm transition-colors hover:bg-white/20 hover:text-white/90 hover:opacity-100 focus-ring-soft focus:text-white/90 focus:opacity-100",jt={idle:"",copied:"text-accent-success hover:text-accent-success focus:text-accent-success",failed:"text-fg-error hover:text-fg-error focus:text-fg-error"},wt={idle:"Copy",copied:"Copied",failed:"Copy failed"},Nt=({getText:t,resetDelayMs:n=2e3})=>{const[o,l]=a.useState("idle"),s=a.useRef(null),c=a.useCallback(()=>{s.current&&(clearTimeout(s.current),s.current=null)},[]),i=a.useCallback(()=>{c(),s.current=setTimeout(()=>{l("idle"),s.current=null},n)},[c,n]);a.useEffect(()=>c,[c]);const r=x=>{x.stopPropagation()},m=x=>{x.preventDefault(),x.stopPropagation()},b=async x=>{r(x);try{await navigator.clipboard.writeText(t()),l("copied")}catch{l("failed")}i()};return e.jsx("div",{className:"pointer-events-none absolute right-3 top-2 z-[1]",contentEditable:!1,onMouseDown:m,children:e.jsxs("button",{type:"button",className:H(vt,jt[o]),contentEditable:!1,onClick:b,children:[e.jsx(ot,{className:"h-3.5 w-3.5"}),e.jsx("span",{"aria-live":"polite",children:wt[o]})]})})},Ct=({contentRef:t})=>{const n=a.useRef(null),o=a.useCallback(l=>{n.current=l,t(l)},[t]);return e.jsxs(e.Fragment,{children:[e.jsx("pre",{children:e.jsx("code",{ref:o})}),e.jsx(Nt,{getText:()=>n.current?.textContent?.trimEnd()??""})]})},Ht="_Reference_102im_1",Mt={Reference:Ht},Et=le.bind(Mt),kt={type:"reference",propSchema:{id:{default:""},title:{default:"Unknown"}},content:"none"};function Vt(t){const n=ie(),o=()=>{t.editor.blur(),n({to:z,params:{id:t.inlineContent.props.id}})},l=s=>{s.preventDefault(),s.stopPropagation()};return e.jsx("span",{role:"link",tabIndex:0,contentEditable:!1,className:Et("Reference"),onMouseDown:l,onClick:s=>{l(s),o()},onKeyDown:s=>{s.key!=="Enter"&&s.key!==" "||(l(s),o())},children:e.jsxs("span",{children:["[",t.inlineContent.props.title,"]"]})})}const At=ee(kt,{render:t=>e.jsx(Vt,{...t})}),Rt=()=>{const t=we(),[n,o]=a.useState([]),l={1:"pl-3",2:"pl-[26px]",3:"pl-[40px]",4:"pl-[54px]",5:"pl-[68px]",6:"pl-[82px]"};a.useEffect(()=>{const i=()=>{const m=t.document,b=[],x=E=>{for(const y of E){if(y.type==="heading"){const g=y,V=g.props.level||1,A=g.content?.map(S=>S.text||"").join("")||"";A.trim()&&b.push({id:y.id,level:V,text:A})}y.children&&Array.isArray(y.children)&&x(y.children)}};x(m),o(b)};i();const r=t.onChange?.(i);return()=>{r&&r()}},[t]);const s=i=>{t.setTextCursorPosition(i);const r=document.querySelector(`[data-id="${i}"]`);r&&r.scrollIntoView({behavior:"smooth",block:"center"})},c=e.jsx(U,{icon:e.jsx(oe,{className:"h-3.5 w-3.5"}),title:"Table of Contents",className:"text-fg-tertiary"});return n.length===0?e.jsxs("div",{className:"surface-base w-full p-4",children:[c,e.jsx(p,{as:"p",variant:"meta",tone:"secondary",className:"mt-2",children:"Add headings to your document to generate a table of contents"})]}):e.jsxs("div",{className:"surface-base w-full p-4",children:[e.jsx("div",{className:"mb-2",children:c}),e.jsx("nav",{className:"space-y-0.5",children:n.map(i=>{const r=i.level===1;return e.jsxs("button",{type:"button",onClick:()=>s(i.id),className:H("focus-ring-soft","flex","w-full","items-center","gap-2","rounded-[10px]","px-2.5","py-1.5",l[i.level]??"pl-2.5","text-left","transition-colors","hover:bg-hover-subtle",r?"text-fg-default":"text-fg-secondary"),children:[e.jsxs(p,{as:"span",variant:"label",weight:"medium",tone:"tertiary",className:"min-w-[1.5rem]",children:["H",i.level]}),e.jsx(p,{as:"span",variant:"body",weight:r?"semibold":"medium",className:"line-clamp-2 text-current",children:i.text})]},i.id)})})]})},St=te({type:"tableOfContents",propSchema:{},content:"none"},{render:()=>e.jsx(Rt,{})})(),Tt="_Tag_1gb8h_1",Zt={Tag:Tt},Dt=le.bind(Zt),Lt={type:"tag",propSchema:{id:{default:""},tag:{default:"@Unknown"}},content:"none"};function Ft(t){const n=ie(),o=()=>{t.editor.blur(),n({to:Be,params:{id:t.inlineContent.props.id},search:{page:1}})},l=s=>{s.preventDefault(),s.stopPropagation()};return e.jsx("span",{role:"link",tabIndex:0,contentEditable:!1,className:Dt("Tag"),onMouseDown:l,onClick:s=>{l(s),o()},onKeyDown:s=>{s.key!=="Enter"&&s.key!==" "||(l(s),o())},children:e.jsx("span",{children:t.inlineContent.props.tag})})}const Bt=ee(Lt,{render:t=>e.jsx(Ft,{...t})}),It=t=>t,Ot=t=>t,Pt=It({tag:Bt,reference:At}),$t=Ot({tableOfContents:St}),R=de.codeBlock,J=te(R.config,{meta:R.implementation.meta,parse:R.implementation.parse,parseContent:R.implementation.parseContent,runsBefore:R.implementation.runsBefore,render:Ct})(),Yt={...J,extensions:R.extensions,implementation:{...J.implementation,toExternalHTML:R.implementation.toExternalHTML}},zt=tt.create({inlineContentSpecs:{...at,...Pt},blockSpecs:{...de,codeBlock:Yt,...$t}}),_t=(t,n)=>n.some(o=>o.name===`@${t}`),Ut=({onClick:t})=>e.jsx($,{triggerCharacter:"@",getItems:async n=>{const o=await Ie({query:n,limit:5});if(o.type==="error")return[];const{tags:l}=o.allTags,s=_t(n,l),c=[{title:"Add a new tag",onItemClick:async()=>{const i=await Oe({name:"@"+n});if(i.type==="error")return;const{id:r,name:m}=i.createTag;t({type:"tag",props:{id:r,tag:m}})}}];return l.length===0?c:l.map(i=>({title:i.name,onItemClick:()=>t({type:"tag",props:{id:i.id,tag:i.name}})})).concat(n&&!s?c:[])}});async function qt(t){return new Promise((n,o)=>{const l=new FileReader;l.readAsDataURL(t),l.onload=()=>n(l.result),l.onerror=s=>o(s)})}const Kt=a.forwardRef(({content:t,currentNoteId:n,editable:o,onChange:l},s)=>{const{theme:c}=Pe(r=>r),i=Ne({schema:zt,initialContent:t&&JSON.parse(t)||void 0,uploadFile:async r=>Xe({base64:await qt(r)})},[]);return a.useImperativeHandle(s,()=>({getContent:()=>JSON.stringify(i.document)})),e.jsxs(Ce,{slashMenu:!1,theme:c,editor:i,editable:o,onChange:l,children:[e.jsx(gt,{editor:i}),e.jsx(bt,{currentNoteId:n,onClick:r=>{i.insertInlineContent([r," "])}}),e.jsx(Ut,{onClick:r=>{i.insertInlineContent([r," "])}})]})}),he=$e(z),X=t=>N(Number(t)).format("YYYY-MM-DD HH:mm:ss"),I=()=>typeof globalThis.crypto?.randomUUID=="function"?globalThis.crypto.randomUUID():`${Date.now()}-${Math.random().toString(16).slice(2)}`,Qt={narrow:"max-w-[640px]",wide:"max-w-[896px]",full:"max-w-full px-4"},Wt=e.jsx(_,{title:"Loading note",variant:"none",children:e.jsxs("main",{className:"mx-auto max-w-[896px]",children:[e.jsx(T,{className:"mb-8",height:"66px"}),e.jsx(T,{className:"ml-12 mb-8",height:"150px"}),e.jsx(T,{className:"mb-5",height:"80px"}),e.jsx(T,{height:"80px"})]})});function Gt({id:t}){const n=ne(),o=he.useNavigate(),l=a.useRef(null),s=a.useRef(null),c=a.useRef(I()),i=ae({queryKey:C.notes.detail(t),queryFn:async()=>{const d=await Ye(t);if(d.type==="error")throw d;return d.note},gcTime:0}),r=i.data,[m,b]=a.useState(r.title),[x,E]=a.useState(()=>X(r.updatedAt)),[y,g]=a.useState(r.pinned),[V,A]=a.useState(r.layout||"wide"),[S,Z]=a.useState(!1),[L,h]=a.useState(!1),[f,u]=a.useState(null),[w,k]=ze(1e3);a.useEffect(()=>{b(r.title),g(r.pinned),A(r.layout||"wide"),E(X(r.updatedAt))},[r.layout,r.pinned,r.title,r.updatedAt]),a.useEffect(()=>{c.current=I(),u(null)},[t]),a.useEffect(()=>{u(d=>d?.type==="updated"&&d.updatedAt===r.updatedAt?null:d)},[r.updatedAt]),a.useEffect(()=>_e(d=>{if(d.noteId===t){if(d.type==="mcp.note.updated"){if(d.updatedAt===r.updatedAt)return;u({type:"updated",updatedAt:d.updatedAt});return}d.type==="mcp.note.deleted"&&u({type:"deleted"})}}),[t,r.updatedAt]);const D=async({title:d="",content:v=""})=>{k(async()=>{const K=await W({id:t,title:d,content:v,editSessionId:c.current});if(K.type==="error"){n(K.errors[0].message);return}b(d),E(N().format("YYYY-MM-DD HH:mm:ss"))})},q=()=>{D({title:m,content:l.current?.getContent()})},fe=d=>{b(d),D({title:d,content:l.current?.getContent()})},xe=async d=>{const v=await W({id:t,layout:d,editSessionId:c.current});if(v.type==="error"){n(v.errors[0].message);return}A(d),n("Layout has been updated.")},ge=async()=>{const d=await i.refetch();if(d.error||!d.data){n("Failed to reload the latest note state.");return}u(null)},{onCreate:ye,onDelete:be,onPinned:ve}=Ue();return e.jsx(_,{title:m,variant:"none",children:e.jsxs("main",{className:H("mx-auto",Qt[V]),children:[e.jsx("div",{className:"surface-floating sticky top-20 z-[1001] mb-7 px-5 pt-4 pb-3.5",children:e.jsxs("div",{className:"flex flex-col gap-3.5",children:[e.jsxs("div",{className:"flex items-start justify-between gap-5",children:[e.jsxs("div",{className:"min-w-0 flex-1 pt-0.5",children:[e.jsx(p,{as:"div",variant:"micro",weight:"semibold",tracking:"widest",transform:"uppercase",tone:"tertiary",className:"mb-1.5",children:"Thought in progress"}),e.jsx("input",{ref:s,placeholder:"Title",className:"text-heading sm:text-display w-full bg-transparent font-semibold leading-[1.25] tracking-[-0.02em] outline-none",type:"text",value:m,onChange:d=>fe(d.target.value)})]}),e.jsxs("div",{className:"flex shrink-0 items-center gap-2",children:[e.jsx(se,{button:e.jsx(re,{label:"Note actions",size:"lg"}),items:[{name:y?"Unpin":"Pin",onClick:()=>ve(t,y,()=>{g(d=>!d)})},{name:"Change layout",onClick:()=>Z(!0)},{type:"separator"},{name:"Clone this note",onClick:()=>ye(s.current?.value||"untitled",l.current?.getContent()||"",V)},{name:"Restore previous version",onClick:()=>h(!0)},{type:"separator"},{name:"Delete",onClick:()=>be(t,()=>{o({to:Q,search:{page:1}})})}]}),e.jsx(M,{size:"sm",variant:"subtle",isLoading:w,onClick:q,children:"Save"})]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-x-2.5 gap-y-1.5 border-t border-border-subtle/80 pt-3",children:[y&&e.jsxs(p,{as:"span",variant:"label",weight:"medium",tone:"secondary",className:"inline-flex items-center gap-1.5",children:[e.jsx(qe,{className:"h-3 w-3",weight:"fill"}),"Pinned"]}),y&&e.jsx("span",{className:"h-1 w-1 rounded-full bg-border-secondary"}),e.jsxs(p,{as:"span",variant:"label",weight:"medium",tone:"secondary",children:["Last saved ",x]})]})]})}),f&&e.jsx(We,{className:"mb-6",children:e.jsxs("div",{className:"flex w-full flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx("span",{children:f.type==="updated"?"This note changed in MCP. Reload to review the latest version.":"This note was moved to trash from MCP. Open trash to review it."}),f.type==="updated"?e.jsx(M,{type:"button",size:"sm",variant:"subtle",className:"self-start",isLoading:i.isRefetching,onClick:ge,children:"Reload"}):e.jsx(M,{type:"button",size:"sm",variant:"subtle",className:"self-start",onClick:()=>o({to:Q,search:{page:1}}),children:"Open trash"})]})}),e.jsx(Kt,{ref:l,content:r.content,currentNoteId:t,onChange:q},`${t}:${r.updatedAt}`),e.jsx(O,{fallback:e.jsx(T,{className:"mb-5",height:"80px"}),errorTitle:"Failed to load reminders",errorDescription:"Retry loading reminder details for this note.",renderError:({error:d,retry:v})=>e.jsx(P,{title:"Failed to load reminders",description:"Retry loading reminder details for this note.",error:d,onRetry:v,showBackAction:!1,showHomeAction:!1}),children:e.jsx(xt,{noteId:t})}),e.jsx(O,{fallback:e.jsx(T,{height:"80px"}),errorTitle:"Failed to load back references",errorDescription:"Retry loading notes that link back here.",renderError:({error:d,retry:v})=>e.jsx(P,{title:"Failed to load back references",description:"Retry loading notes that link back here.",error:d,onRetry:v,showBackAction:!1,showHomeAction:!1}),children:e.jsx(dt,{noteId:t,render:d=>d&&d.length>0&&e.jsxs("div",{className:"surface-base p-4",children:[e.jsx(U,{icon:e.jsx(it,{className:"h-3.5 w-3.5"}),title:"Back References",className:"mb-3 text-fg-tertiary"}),e.jsx("ul",{className:"flex flex-col",children:d.map(v=>e.jsx("li",{children:e.jsxs(Ke,{to:z,params:{id:v.id},className:"flex items-center gap-2 rounded-[10px] px-2.5 py-1.5 text-fg-secondary transition-colors hover:bg-hover-subtle hover:text-fg-default",children:[e.jsx(lt,{className:"h-3.5 w-3.5 shrink-0 text-fg-tertiary"}),e.jsx(p,{as:"span",variant:"body",weight:"medium",className:"text-current",children:v.title})]})},v.id))})]})})}),e.jsx(mt,{isOpen:S,onClose:()=>Z(!1),onSave:xe,currentLayout:V}),e.jsx(ht,{isOpen:L,noteId:t,onClose:()=>h(!1),onRestored:()=>{c.current=I()}})]})})}function oa(){const{id:t}=he.useParams();if(!t)throw new Error("Note id is required.");return e.jsx(O,{fallback:Wt,errorTitle:"Failed to load note",errorDescription:"Retry loading the note editor.",resetKeys:[t],renderError:({error:n,retry:o})=>e.jsx(_,{title:"Note",variant:"none",children:e.jsx(P,{title:"Failed to load note",description:"Retry loading the note editor.",error:n,onRetry:o})}),children:e.jsx(Gt,{id:t},t)})}export{oa as default};
@@ -1 +0,0 @@
1
- import{j as e}from"./note-vendor-5N5mRkIT.js";import{Z as k,T as h,L as H,N as M,D as E,k as L,d as x,_ as S,P as w,F as O,$ as C,i as o,j as U,a0 as I}from"./index-Bsx4P7EA.js";import"./graph-vendor-CUxe67Lr.js";import{u as P,R as Y}from"./useReminderMutate-DsIvVpCQ.js";import"./note-core-GgFcksAF.js";const u={high:"bg-priority-high",medium:"bg-priority-medium",low:"bg-priority-low"};function B({reminder:t,onUpdate:l,onDelete:g}){const f=y=>{const r=x(Number(y)),m=x();return r.isSame(m,"day")?`Today at ${r.format("HH:mm")}`:r.isSame(m.add(1,"day"),"day")?`Tomorrow at ${r.format("HH:mm")}`:r.format("YYYY-MM-DD HH:mm")},a=y=>{const r=x(Number(y)),m=x(),N=r.diff(m,"hour"),b=r.diff(m,"minute")%60;return N<0||b<0?"Overdue":N===0?`${b}m remaining`:`${N}h ${b}m remaining`},d=a(t.reminderDate)==="Overdue",i=t.priority||"low",s=i==="high"?"High":i==="medium"?"Medium":"Low",p=u[i],c=t.noteId.toString(),n=d?"text-fg-error":"text-fg-tertiary",j=t.content?.trim()||t.note?.title||"Untitled reminder",R=t.note?.title||"Untitled note",T=!!(t.content?.trim()&&t.note?.title),D=a(t.reminderDate),$=f(t.reminderDate);return e.jsxs("div",{className:"surface-base flex flex-col gap-2.5 px-4 py-3 sm:flex-row sm:items-center sm:gap-4",children:[e.jsxs("div",{className:"flex min-w-0 flex-1 items-start gap-2.5 sm:items-center",children:[e.jsx(k,{checked:t.completed,onChange:()=>l(t.id,c,{completed:!t.completed}),size:"sm"}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx(h,{as:"p",variant:"body",weight:"semibold",className:t.completed?"truncate line-through opacity-45":"truncate",children:j}),T&&e.jsx(h,{as:"div",variant:"meta",tone:"secondary",className:t.completed?"mt-0.5 truncate opacity-45":"mt-0.5 truncate",children:e.jsx(H,{to:M,params:{id:String(t.note?.id??t.noteId)},className:"transition-colors hover:text-fg-default hover:underline",children:R})})]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-x-2 gap-y-1 sm:shrink-0",children:[e.jsx("span",{className:`h-3 w-3 shrink-0 rounded-full border border-border-subtle ${p}`,"aria-label":`${s} priority`,title:`${s} priority`}),e.jsx(h,{as:"span",variant:"meta",weight:"medium",tone:"secondary",className:t.completed?"opacity-45":void 0,children:$}),e.jsx("span",{className:"h-1 w-1 rounded-full bg-border-secondary"}),e.jsx(h,{as:"span",variant:"label",weight:"medium",className:t.completed?"opacity-45":n,children:D})]}),e.jsx("div",{className:"flex items-center justify-end gap-1.5 sm:shrink-0",children:e.jsx(E,{button:e.jsx(L,{label:"Reminder actions",iconClassName:"h-5 w-5 text-current"}),items:[{name:"Delete",onClick:()=>g(t.id,c)}]})})]})}const v=U(I),_=[{label:"High",className:u.high},{label:"Medium",className:u.medium},{label:"Low",className:u.low}];function Z(){const t=v.useNavigate(),{page:l}=v.useSearch(),{onUpdate:g,onDelete:f}=P(),a=25,d=e.jsx("div",{className:"flex flex-wrap items-center gap-3",children:_.map(({label:i,className:s})=>e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:`h-2.5 w-2.5 rounded-full border border-border-subtle ${s}`,"aria-hidden":"true"}),e.jsx(h,{as:"span",variant:"label",weight:"medium",tone:"tertiary",children:i})]},i))});return e.jsx(S,{fallback:e.jsx(w,{title:"Reminders",heading:e.jsx(o,{width:164,height:24,className:"rounded-full"}),description:e.jsx(o,{width:224,height:16,className:"rounded-full"}),headerRight:d,children:e.jsxs("div",{className:"flex flex-col gap-2.5",children:[e.jsx(o,{height:"60px"}),e.jsx(o,{height:"60px"}),e.jsx(o,{height:"60px"}),e.jsx(o,{height:"60px"})]})}),errorTitle:"Failed to load reminders",errorDescription:"Retry loading the upcoming reminder list",resetKeys:[l,a],children:e.jsx(Y,{searchParams:{offset:(l-1)*a,limit:a},render:({reminders:i,totalCount:s})=>{const p=s>0?`Reminders (${s})`:void 0,c="Review reminders created from notes and mark them complete here";return i.length===0?e.jsx(w,{title:"Reminders",heading:p,description:c,headerRight:d,children:e.jsx(O,{title:"No upcoming reminders",description:"Add a reminder inside any note to see it here"})}):e.jsx(w,{title:"Reminders",heading:p,description:c,headerRight:d,children:e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx("div",{className:"flex flex-col gap-2.5",children:i.map(n=>e.jsx(B,{reminder:n,onUpdate:g,onDelete:f},n.id))}),s&&a<s&&e.jsx(C,{page:l,last:Math.ceil(s/a),onChange:n=>{t({search:j=>({...j,page:n})})}})]})})}})})}export{Z as default};
@@ -1 +0,0 @@
1
- import{j as e}from"./note-vendor-5N5mRkIT.js";import{P as m,F as f,_ as N,a7 as b,T as h,L as w,N as S,$ as k,j as E,a8 as $,i as d}from"./index-Bsx4P7EA.js";import{a as R}from"./graph-vendor-CUxe67Lr.js";import"./note-core-GgFcksAF.js";const L=t=>t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),g=({children:t,match:s})=>{const r=s.trim();if(!r)return e.jsx("span",{children:t});const a=L(r),n=new RegExp(`(${a})`,"gi"),c=new RegExp(`^${a}$`,"i"),l=t.split(n);return e.jsx("span",{children:l.map((i,o)=>c.test(i)?e.jsx("mark",{children:i},o):e.jsx(R.Fragment,{children:i},o))})},j=E($),v=180,x=t=>t.replace(/\s+/g," ").trim(),T=(t,s)=>{const r=x(t),a=x(s).toLowerCase();if(!a)return r;const n=r.toLowerCase().indexOf(a);if(n===-1)return r.length>v?`${r.slice(0,v-1).trimEnd()}…`:r;const c=Math.max(0,n-56),l=Math.min(r.length,n+a.length+84);let i=r.slice(c,l).trim();return c>0&&(i=`…${i}`),l<r.length&&(i=`${i}…`),i},A=t=>Array.isArray(t)?t.map(s=>{if(!s||typeof s!="object")return"";const r=s.text;return typeof r=="string"?r:""}).join(""):"",B=(t,s)=>t==="heading"?`Heading ${typeof s?.level=="number"?s.level:1}`:t==="bulletListItem"?"Bullet":t==="numberedListItem"?"Numbered":t==="checkListItem"?"Checklist":t==="quote"?"Quote":t==="codeBlock"?"Code":"Content",y=(t,s)=>{Array.isArray(t)&&t.forEach(r=>{if(!r||typeof r!="object")return;const a=typeof r.type=="string"?r.type:void 0,n=typeof r.props=="object"&&r.props?r.props:void 0,c=x(A(r.content));c&&s.push({label:B(a,n),text:c});const l=r.children;Array.isArray(l)&&y(l,s)})},C=(t,s)=>{try{const r=JSON.parse(t),a=[];if(y(r,a),a.length===0)return[];const n=x(s).toLowerCase(),c=n?a.filter(i=>i.text.toLowerCase().includes(n)):a;return(c.length>0?c:a).slice(0,2).map(i=>({...i,text:T(i.text,s)}))}catch{return[]}},P=t=>t===1?"1 result":`${t} results`,M=()=>"Open the note to inspect matching content.",_=(t,s)=>`${P(s)} for "${t}"`,z=()=>e.jsx(m,{title:"Search",variant:"default",description:e.jsx(d,{width:208,height:16,className:"rounded-full"}),children:e.jsx("main",{className:"flex flex-col gap-3",children:Array.from({length:2},(t,s)=>e.jsxs("div",{className:"surface-base flex flex-col gap-3 p-4",children:[e.jsx(d,{width:"34%",height:18,className:"rounded-full"}),e.jsx("div",{className:"rounded-[14px] bg-muted px-3 py-3",children:e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{children:[e.jsx(d,{width:84,height:12,className:"rounded-full"}),e.jsx(d,{width:"100%",height:14,className:"mt-2 rounded-full"}),e.jsx(d,{width:"82%",height:14,className:"mt-1.5 rounded-full"})]}),e.jsxs("div",{className:"border-t border-border-subtle pt-2",children:[e.jsx(d,{width:72,height:12,className:"rounded-full"}),e.jsx(d,{width:"94%",height:14,className:"mt-2 rounded-full"})]})]})})]},s))})});function F(){const t=j.useNavigate(),{page:s,query:r}=j.useSearch(),a=r.trim(),n=10;return a?e.jsx(N,{fallback:e.jsx(z,{}),errorTitle:"Failed to load search results",errorDescription:`Retry loading results for "${a}".`,resetKeys:[a,s],children:e.jsx(b,{searchParams:{query:a,limit:n,offset:(s-1)*n,fields:["content"]},render:({notes:c,totalCount:l})=>e.jsx(m,{title:"Search",description:_(a,l),variant:"default",children:e.jsxs("main",{className:"flex flex-col gap-4",children:[c.length>0?e.jsx("div",{className:"flex flex-col gap-3",children:c.map(i=>{const o=C(i.content,a);return e.jsxs("article",{className:"surface-base flex flex-col gap-3 p-4",children:[e.jsx(h,{as:"h2",variant:"body",weight:"semibold",tracking:"tight",children:e.jsx(w,{to:S,params:{id:i.id},className:"transition-colors hover:text-fg-default/85",children:e.jsx(g,{match:a,children:i.title||"Untitled"})})}),o.length>0?e.jsx("div",{className:"rounded-[14px] bg-muted px-3 py-3",children:e.jsx("div",{className:"flex flex-col gap-2",children:o.map((u,p)=>e.jsxs("div",{className:p>0?"border-t border-border-subtle pt-2":void 0,children:[e.jsx(h,{as:"div",variant:"micro",weight:"semibold",tracking:"wider",transform:"uppercase",tone:"tertiary",children:u.label}),e.jsx(h,{as:"p",variant:"meta",tone:"secondary",className:"mt-1 leading-[1.65]",children:e.jsx(g,{match:a,children:u.text})})]},`${i.id}:${u.label}:${p}`))})}):e.jsx(h,{as:"p",variant:"meta",tone:"secondary",className:"leading-[1.65]",children:M()})]},i.id)})}):e.jsx(f,{title:"No results found",description:"Try searching for a different word or phrase"}),l>n&&e.jsx(k,{page:s,last:Math.ceil(l/n),onChange:i=>{t({search:o=>({...o,page:i})})}})]})})})}):e.jsx(m,{title:"Search",description:"Search note titles and matching sections across your workspace",variant:"default",children:e.jsx("main",{children:e.jsx(f,{title:"Start searching",description:"Enter a keyword to look through note titles and matching content"})})})}export{F as default};
@@ -1 +0,0 @@
1
- import{j as e}from"./note-vendor-5N5mRkIT.js";import{a4 as p,x as m,q as u,a9 as f,_ as j,P as h,aa as o,L as y,ab as T,T as c,$ as w,F as b,i as a,j as v,ac as N}from"./index-Bsx4P7EA.js";import"./graph-vendor-CUxe67Lr.js";import"./note-core-GgFcksAF.js";const R=s=>{const{data:t}=p({queryKey:u.tags.list(s.searchParams),async queryFn(){const i=await m({offset:s.searchParams.offset,limit:s.searchParams.limit});if(i.type==="error")throw i;return i.allTags}});return s.render(t)},A=100,P=8,_=12,x=v(N);function q(){const s=x.useNavigate(),{page:t}=x.useSearch(),{containerRef:i,limit:n}=f({minItemWidth:A,gap:P,rows:_});return e.jsx("div",{ref:i,children:e.jsx(j,{fallback:e.jsx(h,{title:"Tags",heading:e.jsx(a,{width:120,height:24,className:"rounded-full"}),description:e.jsx(a,{width:188,height:16,className:"rounded-full"}),children:e.jsxs("div",{className:"flex flex-wrap gap-2.5",children:[e.jsx(a,{width:"90px",height:"36px"}),e.jsx(a,{width:"120px",height:"36px"}),e.jsx(a,{width:"80px",height:"36px"}),e.jsx(a,{width:"100px",height:"36px"}),e.jsx(a,{width:"110px",height:"36px"}),e.jsx(a,{width:"70px",height:"36px"})]})}),errorTitle:"Failed to load tags",errorDescription:"Retry loading the tag catalog",resetKeys:[t,n],children:e.jsx(R,{searchParams:{offset:(t-1)*n,limit:n},render:({tags:d,totalCount:l})=>e.jsx(h,{title:"Tags",heading:l>0?`Tags (${l})`:void 0,description:"Browse the tags you added with @ across your notes",children:e.jsx(o,{fallback:e.jsx(b,{title:"No tags yet",description:"Add @tags inside notes and they will appear here"}),children:d.length>0&&e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx("div",{className:"flex flex-wrap gap-2.5",children:d.map(r=>e.jsxs(y,{to:T,params:{id:r.id},search:{page:1},className:"inline-flex items-center gap-1.5 rounded-full border border-border-subtle bg-hover-subtle px-3 py-1.5 text-fg-secondary transition-colors hover:border-border-secondary hover:bg-hover hover:text-fg-default",children:[e.jsx(c,{as:"span",variant:"meta",weight:"medium",className:"text-current",children:r.name}),e.jsx(c,{as:"span",variant:"label",weight:"medium",tone:"tertiary",className:"text-current/70",children:r.referenceCount})]},r.id))}),e.jsx(o,{fallback:null,children:l&&n<l&&e.jsx(w,{page:t,last:Math.ceil(l/n),onChange:r=>{s({search:g=>({...g,page:r})})}})})]})})})})})})}export{q as default};
@@ -1 +0,0 @@
1
- import{j as e}from"./note-vendor-5N5mRkIT.js";import{a4 as f,at as p,q as j,ap as y,_ as N,P as g,aa as h,au as P,$ as T,F as v,i as d,j as q,ab as w}from"./index-Bsx4P7EA.js";import"./graph-vendor-CUxe67Lr.js";import"./note-core-GgFcksAF.js";const b=s=>{const{data:r}=f({queryKey:j.notes.tagList(s.searchParams),async queryFn(){const t=await p({query:s.searchParams.query,offset:s.searchParams.offset,limit:s.searchParams.limit});if(t.type==="error")throw t;return t.tagNotes}});return s.render(r)},c=q(w);function S(){const s=c.useNavigate(),{id:r}=c.useParams(),{page:t}=c.useSearch(),i=25,{onDelete:u,onPinned:m}=y();return e.jsx(N,{fallback:e.jsx(g,{title:"Tagged Notes",heading:e.jsx(d,{width:148,height:24,className:"rounded-full"}),description:e.jsx(d,{width:196,height:16,className:"rounded-full"}),variant:"default",children:e.jsxs("div",{className:"grid-auto-cards grid gap-5",children:[e.jsx(d,{height:"112px"}),e.jsx(d,{height:"112px"}),e.jsx(d,{height:"112px"})]})}),errorTitle:"Failed to load tagged notes",errorDescription:"Retry loading notes for this tag",resetKeys:[r,t,i],children:e.jsx(b,{searchParams:{query:r,offset:(t-1)*i,limit:i},render:({notes:o,totalCount:n})=>{const l=o.flatMap(a=>a.tags).find(a=>a.id===r)?.name;return e.jsx(g,{title:l??"Tagged Notes",heading:l?n>0?`${l} (${n})`:l:"Tagged Notes",description:"Browse every note linked to this tag",variant:"default",children:e.jsx(h,{fallback:e.jsx(v,{title:"No tagged notes yet",description:"Notes tagged with this label will appear here"}),children:o.length>0&&e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx("div",{className:"grid-auto-cards grid gap-5",children:o.map(a=>e.jsx(P,{...a,onPinned:()=>m(a.id,a.pinned),onDelete:()=>u(a.id)},a.id))}),e.jsx(h,{fallback:null,children:n&&i<n&&e.jsx(T,{page:t,last:Math.ceil(n/i),onChange:a=>{s({search:x=>({...x,page:a})})}})})]})})})}})})}export{S as default};
@@ -1 +0,0 @@
1
- import{j as e}from"./note-vendor-5N5mRkIT.js";import{P as d,F as x,_ as y,i as n,j as N,V as v,ap as b,u as V,q as h,a4 as S,aa as p,au as q,$ as C,T as R}from"./index-Bsx4P7EA.js";import{q as k,f as T,a as E}from"./view-dashboard-CP8nhfxQ.js";import"./graph-vendor-CUxe67Lr.js";import"./note-core-GgFcksAF.js";const u=N(v);function F(){const o=u.useNavigate(),{page:i,sectionId:r}=u.useSearch(),{onDelete:g,onPinned:f}=b(),a=25,{data:c}=V({queryKey:h.views.section(r),async queryFn(){const t=await k(r);if(t.type==="error")throw t;return t.viewSection}}),{data:s}=S({queryKey:h.views.sectionNotes(r,{limit:a,offset:(i-1)*a}),async queryFn(){const t=await T(r,{limit:a,offset:(i-1)*a});if(t.type==="error")throw t;return t.viewSectionNotes}}),l=c?.title||"View Notes",m=c?.tagNames??[],j=c?.mode??"and";return e.jsx(d,{title:l,heading:s.totalCount>0?`${l} (${s.totalCount})`:l,description:e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(R,{as:"span",variant:"meta",tone:"tertiary",children:E(j)}),e.jsx("div",{className:"flex flex-wrap gap-1.5",children:m.map(t=>e.jsx("span",{className:"inline-flex items-center rounded-full border border-border-subtle bg-hover-subtle px-2.5 py-1 text-xs font-medium text-fg-secondary",children:t},t))})]}),children:e.jsx(p,{fallback:e.jsx(x,{title:"No notes match this saved view",description:"Adjust the section tags or keep writing until matching notes appear."}),children:s.notes.length>0&&e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx("div",{className:"grid-auto-cards grid gap-5",children:s.notes.map(t=>e.jsx(q,{...t,onPinned:()=>f(t.id,t.pinned),onDelete:()=>g(t.id)},t.id))}),e.jsx(p,{fallback:null,children:s.totalCount&&a<s.totalCount&&e.jsx(C,{page:i,last:Math.ceil(s.totalCount/a),onChange:t=>{o({search:w=>({...w,page:t})})}})})]})})})}function M(){const{sectionId:o,page:i}=u.useSearch();return o?e.jsx(y,{fallback:e.jsx(d,{title:"View Notes",heading:e.jsx(n,{width:180,height:24,className:"rounded-full"}),description:e.jsx(n,{width:220,height:16,className:"rounded-full"}),children:e.jsxs("div",{className:"grid-auto-cards grid gap-5",children:[e.jsx(n,{height:"112px"}),e.jsx(n,{height:"112px"}),e.jsx(n,{height:"112px"})]})}),errorTitle:"Failed to load view notes",errorDescription:"Retry loading notes for this saved view section",resetKeys:[i,o],children:e.jsx(F,{})}):e.jsx(d,{title:"View Notes",description:"Saved view note lists require a section id.",children:e.jsx(x,{title:"No section selected",description:"Return to Views and open a section from there."})})}export{M as default};
@@ -1 +0,0 @@
1
- import{j as e}from"./note-vendor-5N5mRkIT.js";import{p as ue,u as O,q as N,T as u,L as H,V as P,D as te,k as se,B as w,N as pe,t as ge,M as S,l as D,I as ae,S as fe,e as F,m as be,n as ve,o as _,r as je,v as we,w as ye,x as Ne,y as Se,z as K,A as ke,K as Te,E as Ce,P as Ve,i as I,F as Q,G as Z,H as Ee,J as $,O as U,Q as De,R as Ae,U as Me,W as re,X as ie,c as R,Y as ne}from"./index-Bsx4P7EA.js";import{a as r}from"./graph-vendor-CUxe67Lr.js";import{b as ze,f as Fe,g as Le,n as B,a as G,c as Re,d as We,E as He,s as Ie,e as qe,r as Oe,h as Pe,i as _e,j as Ke,k as Qe,u as Ze,l as $e,m as Ue,o as Be,p as Ge}from"./view-dashboard-CP8nhfxQ.js";import{S as A}from"./SurfaceCard-Br6TjX5W.js";import{M as oe,n as q}from"./ModalActionRow-DjI5b4bl.js";import"./note-core-GgFcksAF.js";const Ye=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M224.49,136.49l-72,72a12,12,0,0,1-17-17L187,140H40a12,12,0,0,1,0-24H187L135.51,64.48a12,12,0,0,1,17-17l72,72A12,12,0,0,1,224.49,136.49Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M216,128l-72,72V56Z",opacity:"0.2"}),r.createElement("path",{d:"M221.66,122.34l-72-72A8,8,0,0,0,136,56v64H40a8,8,0,0,0,0,16h96v64a8,8,0,0,0,13.66,5.66l72-72A8,8,0,0,0,221.66,122.34ZM152,180.69V75.31L204.69,128Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M221.66,133.66l-72,72A8,8,0,0,1,136,200V136H40a8,8,0,0,1,0-16h96V56a8,8,0,0,1,13.66-5.66l72,72A8,8,0,0,1,221.66,133.66Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M220.24,132.24l-72,72a6,6,0,0,1-8.48-8.48L201.51,134H40a6,6,0,0,1,0-12H201.51L139.76,60.24a6,6,0,0,1,8.48-8.48l72,72A6,6,0,0,1,220.24,132.24Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M221.66,133.66l-72,72a8,8,0,0,1-11.32-11.32L196.69,136H40a8,8,0,0,1,0-16H196.69L138.34,61.66a8,8,0,0,1,11.32-11.32l72,72A8,8,0,0,1,221.66,133.66Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M218.83,130.83l-72,72a4,4,0,0,1-5.66-5.66L206.34,132H40a4,4,0,0,1,0-8H206.34L141.17,58.83a4,4,0,0,1,5.66-5.66l72,72A4,4,0,0,1,218.83,130.83Z"}))]]),le=r.forwardRef((s,i)=>r.createElement(ue,{ref:i,...s,weights:Ye}));le.displayName="ArrowRightIcon";const Je=le,Xe="flex items-start justify-between gap-3 rounded-[14px] border border-border-subtle/70 px-3 py-2.5 transition-colors hover:border-border-secondary hover:bg-hover-subtle";function et({section:s,onEdit:i,onDelete:n,dragHandle:c}){const x=ze(s),{data:l,isPending:m,isError:h,refetch:b}=O({queryKey:N.views.sectionNotes(s.id,{limit:s.limit,offset:0}),async queryFn(){const a=await Fe(s.id,{limit:s.limit,offset:0});if(a.type==="error")throw a;return a.viewSectionNotes}}),p=l?.notes??[],k=l?.totalCount??0,g=Le(s.mode);return e.jsxs(A,{className:"flex h-full flex-col gap-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[c&&e.jsx("div",{className:"-mr-1 shrink-0 self-center",children:c}),e.jsx("div",{className:"min-w-0",children:e.jsx(u,{as:"h2",variant:"subheading",weight:"semibold",tracking:"tight",className:"min-w-0",children:e.jsx(H,{to:P,search:x,className:"truncate hover:text-fg-default/85",children:s.title})})})]}),e.jsx("div",{className:"mt-3 flex flex-wrap gap-1.5",children:s.tagNames.map((a,C)=>e.jsxs("div",{className:"flex items-center gap-1.5",children:[C>0&&e.jsx("span",{className:"px-0.5 text-[10px] font-semibold tracking-[0.08em] text-fg-tertiary/85",children:g}),e.jsx("span",{className:"inline-flex items-center rounded-full border border-border-subtle/80 bg-transparent px-2.5 py-1 text-xs font-medium text-fg-secondary",children:a})]},a))})]}),e.jsx("div",{className:"shrink-0",children:e.jsx(te,{button:e.jsx(se,{label:"Section actions"}),items:[{name:"Edit section",onClick:i},{type:"separator"},{name:"Delete section",onClick:n}]})})]}),e.jsxs("div",{className:"flex flex-1 flex-col gap-2.5",children:[m&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"h-14 animate-pulse rounded-[14px] bg-hover-subtle"}),e.jsx("div",{className:"h-14 animate-pulse rounded-[14px] bg-hover-subtle"}),e.jsx("div",{className:"h-14 animate-pulse rounded-[14px] bg-hover-subtle"})]}),h&&e.jsxs("div",{className:"rounded-[16px] border border-border-subtle bg-hover-subtle/70 p-4",children:[e.jsx(u,{as:"p",variant:"body",weight:"semibold",children:"Failed to load this section"}),e.jsx(u,{as:"p",variant:"meta",tone:"tertiary",className:"mt-1",children:"Retry to refresh the tag-based note block."}),e.jsx("div",{className:"mt-3",children:e.jsx(w,{type:"button",variant:"ghost",size:"sm",onClick:()=>b(),children:"Retry"})})]}),!m&&!h&&p.length===0&&e.jsxs("div",{className:"rounded-[16px] border border-dashed border-border-subtle px-4 py-5",children:[e.jsx(u,{as:"p",variant:"body",weight:"semibold",children:"No notes match yet"}),e.jsx(u,{as:"p",variant:"meta",tone:"tertiary",className:"mt-1",children:"Add more notes with these tags, or edit the section filter."})]}),!m&&!h&&p.map(a=>e.jsxs(H,{to:pe,params:{id:a.id},className:Xe,children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx(u,{as:"div",variant:"body",weight:"semibold",className:"line-clamp-1",children:a.title||"Untitled"}),e.jsxs(u,{as:"div",variant:"meta",tone:"tertiary",className:"mt-1",children:["Updated ",ge(Number(a.updatedAt))]})]}),e.jsx(Je,{className:"mt-0.5 h-4 w-4 shrink-0 text-fg-tertiary"})]},a.id))]}),e.jsxs("div",{className:"flex items-center justify-between gap-3 border-t border-border-subtle/70 pt-4",children:[e.jsx(u,{as:"p",variant:"meta",tone:"tertiary",children:m?"Loading notes...":`Showing ${p.length} of ${k} notes`}),e.jsx(w,{asChild:!0,variant:"subtle",size:"sm",children:e.jsx(H,{to:P,search:x,children:"Open list"})})]})]})}const Y=s=>String(s?.limit??5),J=s=>s?.mode??"and",X=s=>s?s.tagNames.join(", "):"",ee=s=>s?.title??"";function tt({open:s,mode:i,initialSection:n=null,availableTags:c,isTagsLoading:x=!1,onClose:l,onSubmit:m}){const[h,b]=r.useState(ee(n)),[p,k]=r.useState(X(n)),[g,a]=r.useState(J(n)),[C,L]=r.useState(Y(n)),[V,E]=r.useState("");r.useEffect(()=>{s&&(b(ee(n)),k(X(n)),a(J(n)),L(Y(n)),E(""))},[n,s]);const f=B([p]),v=d=>{const y=f.includes(d)?f.filter(W=>W!==d):[...f,d];k(y.join(", ")),E("")};return e.jsxs(S,{isOpen:s,onClose:l,variant:"form",className:"sm:max-w-[640px]",children:[e.jsx(S.Header,{title:i==="create"?"Create section":"Edit section",onClose:l}),e.jsx(S.Body,{children:e.jsxs("form",{id:"view-section-form",className:"flex flex-col gap-5",onSubmit:d=>{d.preventDefault();const y=B([p]);if(y.length===0){E("Add at least one tag for this section.");return}m({title:h,tagNames:y,mode:g,limit:Number(C)})},children:[e.jsxs("div",{className:"grid gap-4 md:grid-cols-[minmax(0,1fr)_180px]",children:[e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(D,{htmlFor:"view-section-title",size:"md",children:"Section title"}),e.jsx(ae,{id:"view-section-title",value:h,onChange:d=>b(d.target.value),placeholder:"Agent work",autoFocus:!0})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(D,{htmlFor:"view-section-limit",size:"md",children:"Max notes"}),e.jsxs(fe,{value:C,onValueChange:L,children:[e.jsx(F,{value:"3",children:"3 notes"}),e.jsx(F,{value:"5",children:"5 notes"}),e.jsx(F,{value:"8",children:"8 notes"}),e.jsx(F,{value:"10",children:"10 notes"}),e.jsx(F,{value:"12",children:"12 notes"})]})]})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(D,{htmlFor:"view-section-tags",size:"md",children:"Tags"}),e.jsx(be,{id:"view-section-tags",value:p,onChange:d=>{k(d.target.value),E("")},placeholder:"@OceanBrain, @todo",size:"sm"}),e.jsx(u,{as:"p",variant:"meta",tone:V?"default":"tertiary",className:V?"text-fg-error":void 0,children:V||"Separate tags with commas. Plain words become @tags automatically."})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(D,{size:"md",children:"Tag match"}),e.jsxs(ve,{type:"single",value:g,onValueChange:d=>{(d==="and"||d==="or")&&a(d)},variant:"quiet",size:"sm",className:"self-start",children:[e.jsx(_,{value:"and","aria-label":G("and"),children:"Match all"}),e.jsx(_,{value:"or","aria-label":G("or"),children:"Match any"})]})]}),e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsx(D,{size:"md",children:"Existing tags"}),e.jsx(u,{as:"span",variant:"meta",tone:"tertiary",children:x?"Loading tag catalog...":`${c.length} tags available`})]}),c.length>0?e.jsx("div",{className:"max-h-44 overflow-y-auto rounded-[18px] border border-border-subtle bg-hover-subtle/60 p-3",children:e.jsx("div",{className:"flex flex-wrap gap-2",children:c.map(d=>{const y=f.includes(d.name);return e.jsx("button",{type:"button",className:`inline-flex items-center rounded-full border px-3 py-1.5 text-sm font-medium transition-colors ${y?"border-border-secondary bg-elevated text-fg-default":"border-border-subtle bg-transparent text-fg-secondary hover:border-border-secondary hover:bg-elevated hover:text-fg-default"}`,onClick:()=>v(d.name),children:d.name},d.id)})})}):e.jsx(u,{as:"p",variant:"meta",tone:"tertiary",children:"No tags yet. You can still type tag names manually."})]})]})}),e.jsx(S.Footer,{children:e.jsxs(oe,{children:[e.jsx(w,{type:"button",variant:"ghost",size:"sm",onClick:l,children:"Cancel"}),e.jsx(w,{type:"submit",size:"sm",form:"view-section-form",children:i==="create"?"Create section":"Save section"})]})})]})}function st({open:s,mode:i,initialTitle:n="",onClose:c,onSubmit:x}){const[l,m]=r.useState(n);return r.useEffect(()=>{s&&m(n)},[n,s]),e.jsxs(S,{isOpen:s,onClose:c,variant:"form",className:"sm:max-w-[480px]",children:[e.jsx(S.Header,{title:i==="create"?"Create view tab":"Rename view tab",onClose:c}),e.jsx(S.Body,{children:e.jsxs("form",{id:"view-tab-form",className:"flex flex-col gap-4",onSubmit:h=>{h.preventDefault(),x(l)},children:[e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(D,{htmlFor:"view-tab-title",size:"md",children:"Tab name"}),e.jsx(ae,{id:"view-tab-title",value:l,onChange:h=>m(h.target.value),placeholder:"Now",autoFocus:!0})]}),e.jsx(u,{as:"p",variant:"meta",tone:"tertiary",children:"Each tab is one saved view inside the Views page."})]})}),e.jsx(S.Footer,{children:e.jsxs(oe,{children:[e.jsx(w,{type:"button",variant:"ghost",size:"sm",onClick:c,children:"Cancel"}),e.jsx(w,{type:"submit",size:"sm",form:"view-tab-form",children:i==="create"?"Create tab":"Save tab"})]})})]})}const at="Save tag-based views and switch between them without leaving your notes.",rt="focus-ring-soft inline-flex h-8 w-8 items-center justify-center rounded-[10px] text-fg-default/70 outline-none transition-colors hover:bg-hover-subtle hover:text-fg-default touch-none",it="group relative -mb-px flex h-10 min-w-[92px] max-w-[118px] shrink-0 items-center gap-0.5 rounded-t-[12px] border border-b-0 px-1.5 transition-[background-color,border-color,color,box-shadow]",nt="focus-ring-soft inline-flex min-w-0 flex-1 items-center gap-1 rounded-[9px] px-0.5 py-1.5 text-[13px] font-medium outline-none",ot="focus-ring-soft inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-[8px] text-current/55 outline-none transition-[background-color,color,opacity] hover:bg-hover-subtle hover:text-current touch-none",lt="focus-ring-soft relative mb-0.5 inline-flex h-9 shrink-0 items-center gap-1 rounded-[10px] px-2.5 text-[13px] font-medium text-fg-secondary outline-none transition-colors hover:bg-hover-subtle/85 hover:text-fg-default",ct=({tab:s,isActive:i,onSelect:n})=>{const{attributes:c,listeners:x,setNodeRef:l,setActivatorNodeRef:m,transform:h,transition:b,isDragging:p}=re({id:s.id});return e.jsxs("div",{ref:l,style:{transform:ne.Transform.toString(h),transition:b,opacity:p?.6:1},className:R(it,i?"z-10 border-border-secondary/75 bg-elevated text-fg-default shadow-[0_10px_18px_-20px_rgba(15,18,24,0.24)]":"border-transparent bg-hover-subtle/45 text-fg-secondary hover:bg-hover-subtle/75 hover:text-fg-default"),children:[e.jsx("button",{type:"button",ref:m,"aria-label":`Reorder view tab ${s.title}`,...c,...x,className:R(ot,p?"cursor-grabbing opacity-100":"cursor-grab opacity-70 group-hover:opacity-100"),children:e.jsx(ie,{className:"size-4"})}),e.jsxs("button",{type:"button",role:"tab","aria-selected":i,className:R(nt,i?"text-fg-default":"text-fg-secondary group-hover:text-fg-default"),onClick:n,children:[e.jsx("span",{className:"min-w-0 flex-1 truncate",children:s.title}),e.jsx("span",{className:"inline-flex min-w-4 shrink-0 items-center justify-center rounded-full bg-hover-subtle/75 px-1 py-0 text-[10px] leading-4 text-current/70",children:s.sections.length})]})]})},dt=({section:s,onEdit:i,onDelete:n})=>{const{attributes:c,listeners:x,setNodeRef:l,setActivatorNodeRef:m,transform:h,transition:b,isDragging:p}=re({id:s.id});return e.jsx("div",{ref:l,style:{transform:ne.Transform.toString(h),transition:b,opacity:p?.6:1},children:e.jsx(et,{section:s,onEdit:i,onDelete:n,dragHandle:e.jsx("button",{type:"button",ref:m,"aria-label":`Reorder section ${s.title}`,...c,...x,className:R(rt,p?"cursor-grabbing":"cursor-grab"),children:e.jsx(ie,{className:"size-4"})})})})};function bt(){const s=je(),i=we(),n=ye(),[c,x]=r.useState(null),[l,m]=r.useState(null),{data:h,isPending:b,isError:p,refetch:k}=O({queryKey:N.views.workspace(),async queryFn(){const t=await Re();if(t.type==="error")throw t;return t.viewWorkspace}}),g=h??He,a=We(g),{data:C,isPending:L}=O({queryKey:N.tags.list({limit:200}),async queryFn(){const t=await Ne({limit:200});if(t.type==="error")throw t;return t.allTags}}),V=Se(K(Ce,{activationConstraint:{distance:8}}),K(Te,{coordinateGetter:ke})),E=C?.tags??[],f=t=>{n.setQueryData(N.views.workspace(),t)},v=async()=>{await n.invalidateQueries({queryKey:N.views.all(),exact:!1})},d=async({active:t,over:o})=>{if(!o||t.id===o.id)return;const T=n.getQueryData(N.views.workspace())??g,j=Oe(T,String(t.id),String(o.id));f(j);const M=await Pe(j.tabs.map(z=>z.id));if(M.type==="error"){f(T),i(M.errors[0].message);return}await v()},y=async({active:t,over:o})=>{if(!a||!o||t.id===o.id)return;const T=n.getQueryData(N.views.workspace())??g,j=_e(T,a.id,String(t.id),String(o.id));f(j);const M=await Ke(a.id,j.tabs.find(z=>z.id===a.id)?.sections.map(z=>z.id)??[]);if(M.type==="error"){f(T),i(M.errors[0].message);return}await v()},W=async t=>{const o=await Qe(t);if(o.type==="error"){i(o.errors[0].message);return}await v(),x(null)},ce=async t=>{if(!a)return;const o=await Ze(a.id,t);if(o.type==="error"){i(o.errors[0].message);return}await v(),x(null)},de=async()=>{if(!a||!await s("Delete this view tab and all of its sections?"))return;const t=await $e(a.id);if(t.type==="error"){i(t.errors[0].message);return}await v()},me=async t=>{if(!a)return;const o=await Ue(a.id,t);if(o.type==="error"){i(o.errors[0].message);return}await v(),m(null)},xe=async t=>{if(!a||!l||l.mode!=="edit")return;const o=await Be(l.section.id,t);if(o.type==="error"){i(o.errors[0].message);return}await v(),m(null)},he=async t=>{if(!a||!await s("Delete this section from the current view tab?"))return;const o=await Ge(t);if(o.type==="error"){i(o.errors[0].message);return}await v()};return e.jsxs(e.Fragment,{children:[e.jsx(Ve,{title:"Views",description:at,children:b&&!h?e.jsx(A,{className:"px-6 py-8 sm:px-8 sm:py-10",children:e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx(I,{height:20,width:180,className:"rounded-full"}),e.jsx(I,{height:16,width:260,className:"rounded-full"}),e.jsx(I,{height:44,width:140,className:"rounded-[12px]"})]})}):p?e.jsxs(A,{className:"px-6 py-8 sm:px-8 sm:py-10",children:[e.jsx(u,{as:"p",variant:"body",weight:"semibold",children:"Failed to load saved views"}),e.jsx(u,{as:"p",variant:"meta",tone:"tertiary",className:"mt-1",children:"Retry loading your saved view tabs."}),e.jsx("div",{className:"mt-4",children:e.jsx(w,{type:"button",variant:"ghost",size:"sm",onClick:()=>{k()},children:"Retry"})})]}):g.tabs.length===0?e.jsxs(A,{className:"px-6 py-8 sm:px-8 sm:py-10",children:[e.jsx(Q,{title:"Create your first view tab",description:"Start with a saved view tab, then add tag-based sections inside it."}),e.jsx("div",{className:"mt-6 flex justify-center",children:e.jsxs(w,{type:"button",onClick:()=>x({mode:"create"}),children:[e.jsx(q,{className:"h-4 w-4"}),"Create first tab"]})})]}):e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx("div",{className:"border-b border-border-secondary/75",children:e.jsx(Z,{sensors:V,collisionDetection:$,modifiers:[Ee],onDragEnd:d,children:e.jsxs("div",{className:"flex items-end gap-1 overflow-x-auto overflow-y-hidden pb-px",children:[e.jsx(U,{items:g.tabs.map(t=>t.id),strategy:De,children:e.jsx("div",{role:"tablist","aria-label":"Views tab list",className:"flex min-w-0 items-end gap-1",children:g.tabs.map(t=>e.jsx(ct,{tab:t,isActive:t.id===a?.id,onSelect:async()=>{const o=n.getQueryData(N.views.workspace())??g,T=Ie(o,t.id);f(T);const j=await qe(t.id);if(j.type==="error"){f(o),i(j.errors[0].message);return}f(j.setActiveViewTab)}},t.id))})}),e.jsxs("button",{type:"button",className:lt,onClick:()=>x({mode:"create"}),children:[e.jsx(q,{className:"size-4"}),"Add tab"]})]})})}),a&&e.jsxs("div",{className:"flex flex-col gap-5",children:[e.jsxs(A,{className:"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between",children:[e.jsxs("div",{children:[e.jsx(u,{as:"h2",variant:"heading",weight:"bold",tracking:"tight",children:a.title}),e.jsx(u,{as:"p",variant:"meta",tone:"tertiary",className:"mt-1",children:a.sections.length>0?`${a.sections.length} section${a.sections.length===1?"":"s"} in this view`:"Add sections to build this view"})]}),e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsxs(w,{type:"button",size:"sm",onClick:()=>m({mode:"create"}),children:[e.jsx(q,{className:"h-4 w-4"}),"Add section"]}),e.jsx(te,{button:e.jsx(se,{label:"View tab actions"}),items:[{name:"Rename",onClick:()=>x({mode:"edit",tab:a})},{type:"separator"},{name:"Delete tab",onClick:()=>{de()}}]})]})]}),a.sections.length===0?e.jsx(A,{className:"px-6 py-8 sm:px-8 sm:py-10",children:e.jsx(Q,{title:"Add the first section to this tab",description:"Sections pull notes by tag."})}):e.jsx("div",{className:"flex flex-col",children:e.jsx(Z,{sensors:V,collisionDetection:$,modifiers:[Ae],onDragEnd:y,children:e.jsx(U,{items:a.sections.map(t=>t.id),strategy:Me,children:e.jsx("div",{className:"flex flex-col gap-4",children:a.sections.map(t=>e.jsx(dt,{section:t,onEdit:()=>m({mode:"edit",section:t}),onDelete:()=>{he(t.id)}},t.id))})})})})]})]})}),e.jsx(st,{open:c!==null,mode:c?.mode??"create",initialTitle:c?.mode==="edit"?c.tab.title:"",onClose:()=>x(null),onSubmit:t=>{if(c?.mode==="edit"){ce(t);return}W(t)}}),e.jsx(tt,{open:l!==null,mode:l?.mode??"create",initialSection:l?.mode==="edit"?l.section:null,availableTags:E,isTagsLoading:L,onClose:()=>m(null),onSubmit:t=>{if(l?.mode==="edit"){xe(t);return}me(t)}})]})}export{bt as default};