ocean-brain 0.12.0 → 0.12.2

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 (117) hide show
  1. package/README.md +1 -1
  2. package/package.json +4 -2
  3. package/server/client/dist/assets/{ArrowRight.es-DZTjsBaI.js → ArrowRight.es-CD1IMhU2.js} +1 -1
  4. package/server/client/dist/assets/{AuxiliaryPanelHeader-Bp3iRjm6.js → AuxiliaryPanelHeader-zoJGsYWR.js} +1 -1
  5. package/server/client/dist/assets/Calendar-6otw_EJn.js +25 -0
  6. package/server/client/dist/assets/{Callout-Cye6_6BM.js → Callout-C1QiCWCa.js} +1 -1
  7. package/server/client/dist/assets/{CheckCircle.es-BTloiuti.js → CheckCircle.es-C7fkzE3t.js} +1 -1
  8. package/server/client/dist/assets/{Copy.es-CkLUgwY-.js → Copy.es-D6rl6b78.js} +1 -1
  9. package/server/client/dist/assets/{File.es-c83QExqr.js → File.es-CcjtzE38.js} +1 -1
  10. package/server/client/dist/assets/{FlowArrow.es-DWiIXWQG.js → FlowArrow.es-CAIThqWk.js} +1 -1
  11. package/server/client/dist/assets/{Graph-jbPLcne9.js → Graph-BHsmPDPh.js} +1 -1
  12. package/server/client/dist/assets/{Image.es-vY-nTyOe.js → Image.es-BDpo5R66.js} +1 -1
  13. package/server/client/dist/assets/Note-Dq2Szaxd.js +19 -0
  14. package/server/client/dist/assets/{NotePropertiesPanel-uO-JKy19.js → NotePropertiesPanel-Cu3RgDic.js} +2 -2
  15. package/server/client/dist/assets/{Plus.es-CaRgmXc_.js → Plus.es-P9Fjwtud.js} +1 -1
  16. package/server/client/dist/assets/{Reminders-BAgZEUwV.js → Reminders-DKm0GFI2.js} +1 -1
  17. package/server/client/dist/assets/{Search-BxozUWkC.js → Search-DVROxY_B.js} +1 -1
  18. package/server/client/dist/assets/{SurfaceCard-BAlcul6z.js → SurfaceCard-D_OU_Oy6.js} +1 -1
  19. package/server/client/dist/assets/{Tag-BhCf_mil.js → Tag-wMHTRwlF.js} +1 -1
  20. package/server/client/dist/assets/{TagNotes-BIzhXqwp.js → TagNotes-BRza6i14.js} +1 -1
  21. package/server/client/dist/assets/{Trash.es-prxIxo9c.js → Trash.es-BeR1sZMe.js} +1 -1
  22. package/server/client/dist/assets/{ViewChip-Cq_YzRvB.js → ViewChip-D-Ax5PdL.js} +1 -1
  23. package/server/client/dist/assets/{Views-C26uWznP.js → Views-CL7rC05G.js} +1 -1
  24. package/server/client/dist/assets/{abnfDiagram-VRR7QNED-2cuaaDg0.js → abnfDiagram-N423BO3Z-D44O4T7q.js} +1 -1
  25. package/server/client/dist/assets/{app-DbQdHfMb.js → app-CyQtGTtn.js} +3 -3
  26. package/server/client/dist/assets/app-DGFNtdpS.css +1 -0
  27. package/server/client/dist/assets/{arc-Cr-oYJoQ.js → arc-Cil9fXuW.js} +1 -1
  28. package/server/client/dist/assets/architectureDiagram-T3A2C74G-Cjq6ayF2.js +36 -0
  29. package/server/client/dist/assets/{blockDiagram-677ZJIJ3-evR8rlpQ.js → blockDiagram-VBNYF7ZC-B2Xm5N0i.js} +1 -1
  30. package/server/client/dist/assets/{c4Diagram-LMCZKHZV-zCjuWUmC.js → c4Diagram-5PPSVZJV-Dp0y-lCR.js} +1 -1
  31. package/server/client/dist/assets/channel-DZFalh-h.js +1 -0
  32. package/server/client/dist/assets/{chunk-32BRIVSS-102-EyWU.js → chunk-2GRJ4B5K-CWaaNkFx.js} +1 -1
  33. package/server/client/dist/assets/{chunk-2Q5K7J3B-P0v1gRui.js → chunk-2Q5K7J3B-Ces-xz2S.js} +1 -1
  34. package/server/client/dist/assets/{chunk-EX3LRPZG-k5hlNinR.js → chunk-5RXB4S5H-B-4Chlfc.js} +1 -1
  35. package/server/client/dist/assets/{chunk-5VM5RSS4-uqI_1K1p.js → chunk-5VM5RSS4-C8_HVwuz.js} +1 -1
  36. package/server/client/dist/assets/{chunk-MOJQB5TN-B-LmIwhJ.js → chunk-6Q2QTUOP-xZ8ofRqk.js} +1 -1
  37. package/server/client/dist/assets/{chunk-V7JOEXUC-CmSzAkUx.js → chunk-GF5L2VYU-Bpa43a7s.js} +1 -1
  38. package/server/client/dist/assets/{chunk-JWPE2WC7-PLvgEy_B.js → chunk-JWPE2WC7-DsyTXbuq.js} +1 -1
  39. package/server/client/dist/assets/{chunk-VR4S4FIN-IiOfWaBG.js → chunk-KBJHAD2P-BDhjm9-8.js} +1 -1
  40. package/server/client/dist/assets/{chunk-RYQCIY6F-CaNSMki0.js → chunk-RYQCIY6F-Cn-jdp6I.js} +1 -1
  41. package/server/client/dist/assets/{chunk-XXDRQBXY-DRXrI6SM.js → chunk-XXDRQBXY-BKsc_0wh.js} +1 -1
  42. package/server/client/dist/assets/classDiagram-JCYQIIEL-CkEhFvVV.js +1 -0
  43. package/server/client/dist/assets/classDiagram-v2-OCEON4UE-CkEhFvVV.js +1 -0
  44. package/server/client/dist/assets/{cose-bilkent-JH36ORCC-COcEaZRS.js → cose-bilkent-JH36ORCC-jmn3Q4zj.js} +1 -1
  45. package/server/client/dist/assets/{cynefinDiagram-TSTJHNR4-CSHqcg9K.js → cynefinDiagram-MW4NZA55-BpLstuBJ.js} +1 -1
  46. package/server/client/dist/assets/{dagre-VKFMJZFB-XAWCPOS0.js → dagre-VZM6K2ZE-B5ft5Yzm.js} +1 -1
  47. package/server/client/dist/assets/{diagram-OA4YK3LP-CXTlHB5A.js → diagram-7IWD3JNH-B_W9IsWZ.js} +1 -1
  48. package/server/client/dist/assets/{diagram-FQU43EPY-scBCDUnE.js → diagram-B4RE2ZJO-32chS3GX.js} +1 -1
  49. package/server/client/dist/assets/{diagram-NH7WQ7WH-DcWalY4j.js → diagram-LBJQPF4R-Bqupdb3-.js} +1 -1
  50. package/server/client/dist/assets/{diagram-G47NLZAW-nPKP5kd8.js → diagram-Q27KOJAE-BD8jKBsv.js} +1 -1
  51. package/server/client/dist/assets/diagram-UB23O5K3-C40jAU8D.js +41 -0
  52. package/server/client/dist/assets/{ebnfDiagram-CCIWWBDH-nHt3vRNt.js → ebnfDiagram-BXEA7PRR-BQfW9mFA.js} +1 -1
  53. package/server/client/dist/assets/{erDiagram-Q63AITRT-K6stUUV2.js → erDiagram-JOGREHBK-ILZnLzz2.js} +1 -1
  54. package/server/client/dist/assets/{flowDiagram-23GEKE2U-DDWtKrEp.js → flowDiagram-UKHOOZJN-CDmwr2dI.js} +4 -4
  55. package/server/client/dist/assets/{ganttDiagram-NO4QXBWP-Daqh7b4I.js → ganttDiagram-PKOTCBZU-DBcrUc49.js} +1 -1
  56. package/server/client/dist/assets/{gitGraphDiagram-IHSO6WYX-D73CLkcG.js → gitGraphDiagram-DS77QQ5N-_xO6__FK.js} +1 -1
  57. package/server/client/dist/assets/{image.api-Bbwmcw0T.js → image.api-CtfyPwkV.js} +1 -1
  58. package/server/client/dist/assets/{index-8bsOoxxg.js → index-BEfKfbvr.js} +1 -1
  59. package/server/client/dist/assets/{infoDiagram-FWYZ7A6U-Bc1YI5Iu.js → infoDiagram-6WML65LV-CuIIcu-L.js} +1 -1
  60. package/server/client/dist/assets/{ishikawaDiagram-FXEZZL3T-BJDXbmaY.js → ishikawaDiagram-WSZJBQD7-BVtRGTOj.js} +1 -1
  61. package/server/client/dist/assets/{journeyDiagram-5HDEW3XC-DlyJx4xT.js → journeyDiagram-NVQOT4AX-D5-Nzb2N.js} +1 -1
  62. package/server/client/dist/assets/{kanban-definition-HUTT4EX6-AmTeXesc.js → kanban-definition-27J2QSJJ-DmOhgC8H.js} +1 -1
  63. package/server/client/dist/assets/{manage-image-detail-CPpeRZD4.js → manage-image-detail-BNYOCSmu.js} +1 -1
  64. package/server/client/dist/assets/{manage-image-DCBgglLx.js → manage-image-m-7v_Z1W.js} +1 -1
  65. package/server/client/dist/assets/{mcp-Y2p95Lm9.js → mcp-B-aGeAQD.js} +1 -1
  66. package/server/client/dist/assets/{mcp-admin-adapter-z9OaMVrl.js → mcp-admin-adapter-Cw6w5mfg.js} +1 -1
  67. package/server/client/dist/assets/mermaid.core-C2tL9tq7.js +308 -0
  68. package/server/client/dist/assets/{mindmap-definition-LN4V7U3C-C_6tKVmY.js → mindmap-definition-FAOFIHXS-DuvsPqrh.js} +1 -1
  69. package/server/client/dist/assets/{note-ui-Cv6quEYh.js → note-ui-CYsZc3DI.js} +1 -1
  70. package/server/client/dist/assets/{pegDiagram-2B236MQR-CGKCNdrV.js → pegDiagram-VL7TDLO6-D64crEZV.js} +1 -1
  71. package/server/client/dist/assets/{pieDiagram-ENE6RG2P-C3cMh7d5.js → pieDiagram-7S7Q4E2Y--kl7vopC.js} +1 -1
  72. package/server/client/dist/assets/{placeholder-CHRQt_T8.js → placeholder-C5fNzKrL.js} +1 -1
  73. package/server/client/dist/assets/{properties-CwxDtivz.js → properties-B93_V2uD.js} +1 -1
  74. package/server/client/dist/assets/{quadrantDiagram-ABIIQ3AL-CVVzGxBd.js → quadrantDiagram-CIZ2JOQS-DuvJ4M2y.js} +1 -1
  75. package/server/client/dist/assets/{railroadDiagram-RFXS5EU6-wa-4aJR9.js → railroadDiagram-AXF67PYL-BMKmCOY7.js} +1 -1
  76. package/server/client/dist/assets/{requirementDiagram-TGXJPOKE-DyuC9W7q.js → requirementDiagram-LRYGKXZP-DY1eJcy0.js} +1 -1
  77. package/server/client/dist/assets/route-preload.js +2 -2
  78. package/server/client/dist/assets/{sankeyDiagram-HTMAVEWB-B70y-MQg.js → sankeyDiagram-W5VNT64P-C3Ka4GKM.js} +1 -1
  79. package/server/client/dist/assets/{search-DCLnUWYd.js → search-BmXuuK26.js} +1 -1
  80. package/server/client/dist/assets/{search-admin-adapter-BLMYNm9w.js → search-admin-adapter-Dj0KKKrJ.js} +1 -1
  81. package/server/client/dist/assets/{sequenceDiagram-DBY2YBRQ-mGkh3IEy.js → sequenceDiagram-SI44F4Z6-Bhpwtk2s.js} +1 -1
  82. package/server/client/dist/assets/{sizeCapture-X5ZJPWSS-BhnCNP5z.js → sizeCapture-X5ZJPWSS-BFta71TW.js} +1 -1
  83. package/server/client/dist/assets/{stateDiagram-2N3HPSRC-BqSKSfKi.js → stateDiagram-OKZ733FA-D6GCn1io.js} +1 -1
  84. package/server/client/dist/assets/{stateDiagram-v2-6OUMAXLB-Wl7lGTf3.js → stateDiagram-v2-UEYNNEHI-g4yinGDn.js} +1 -1
  85. package/server/client/dist/assets/{swimlanes-5IMT3BWC-CZ7ckdmY.js → swimlanes-SLNWSIFB-DLFvOjUl.js} +2 -2
  86. package/server/client/dist/assets/swimlanesDiagram-ULZ7WXOC-Ci4mcvmo.js +8 -0
  87. package/server/client/dist/assets/{tag.api-bU52U0tT.js → tag.api-BJ6eaHui.js} +1 -1
  88. package/server/client/dist/assets/{time-DZKkPFUi.js → time-DI902Sxa.js} +1 -1
  89. package/server/client/dist/assets/{timeline-definition-FHXFAJF6-C-t9-x4M.js → timeline-definition-Z64GVDOM-DTSIekSM.js} +1 -1
  90. package/server/client/dist/assets/{trash-BNeUFJnC.js → trash-GulvRh9f.js} +1 -1
  91. package/server/client/dist/assets/{useNoteMutate-VJYw0Vt_.js → useNoteMutate-xEIypxi5.js} +1 -1
  92. package/server/client/dist/assets/{useReminderMutate-DaO0QssD.js → useReminderMutate-kTBRSjYc.js} +1 -1
  93. package/server/client/dist/assets/{vennDiagram-L72KCM5P-CP014Nl5.js → vennDiagram-T6HMQDX7-CMNqSI2X.js} +1 -1
  94. package/server/client/dist/assets/{wardleyDiagram-EHGQE667-B7Ghd-94.js → wardleyDiagram-T6FBY63Y-DV-JOYqB.js} +1 -1
  95. package/server/client/dist/assets/{xychartDiagram-FW5EYKEG-C4YGS0YJ.js → xychartDiagram-ELKLHX3M-BUIniF4m.js} +4 -4
  96. package/server/client/dist/index.html +4 -4
  97. package/server/dist/app.js +5 -5
  98. package/server/dist/features/note/graphql/note.query.resolver.js +18 -16
  99. package/server/dist/features/placeholder/graphql/placeholder.mutation.resolver.js +2 -3
  100. package/server/dist/features/placeholder/graphql/placeholder.query.resolver.js +4 -3
  101. package/server/dist/features/search/sqlite-vector-index.js +71 -138
  102. package/server/dist/features/view/graphql/view.query.resolver.js +15 -7
  103. package/server/dist/main.js +1 -35
  104. package/server/dist/modules/blocknote.js +33 -17
  105. package/server/dist/routes/api.js +6 -1
  106. package/server/dist/routes/client.js +15 -4
  107. package/server/dist/server.js +40 -0
  108. package/server/client/dist/assets/Calendar-BLiViCGr.js +0 -25
  109. package/server/client/dist/assets/Note-BTQLB80Y.js +0 -25
  110. package/server/client/dist/assets/app-CEkicO08.css +0 -1
  111. package/server/client/dist/assets/architectureDiagram-ZJ3FMSHR-HF8-bEM0.js +0 -36
  112. package/server/client/dist/assets/channel-Cq5ZBtfo.js +0 -1
  113. package/server/client/dist/assets/classDiagram-OUVF2IWQ-BqUaa8a6.js +0 -1
  114. package/server/client/dist/assets/classDiagram-v2-EOCWNBFH-BqUaa8a6.js +0 -1
  115. package/server/client/dist/assets/diagram-WEI45ONY-D1uvaJub.js +0 -41
  116. package/server/client/dist/assets/mermaid.core-B528P54n.js +0 -308
  117. package/server/client/dist/assets/swimlanesDiagram-G3AALYLV-BZL3DQ-c.js +0 -8
@@ -1,7 +1,8 @@
1
1
  import { mkdir } from "node:fs/promises";
2
2
  import path from "node:path";
3
+ import { DatabaseSync } from "node:sqlite";
4
+ import { setImmediate as yieldToEventLoop } from "node:timers/promises";
3
5
  import { getLoadablePath } from "sqlite-vec";
4
- import sqlite3 from "sqlite3";
5
6
  const SEMANTIC_INDEX_SCHEMA_VERSION = 2;
6
7
  const SEARCH_DATABASE_SCHEMA_VERSION = 1;
7
8
  const SEARCH_DATABASE_SCHEMA_SQL = `
@@ -50,69 +51,27 @@ const openDatabase = async (filePath) => {
50
51
  if (filePath !== ":memory:") {
51
52
  await mkdir(path.dirname(filePath), { recursive: true });
52
53
  }
53
- const database = await new Promise((resolve, reject) => {
54
- const db = new sqlite3.Database(filePath, (error) => {
55
- if (error) {
56
- reject(error);
57
- return;
58
- }
59
- resolve(db);
60
- });
61
- });
62
- await new Promise((resolve, reject) => {
63
- database.loadExtension(getLoadablePath(), (error) => {
64
- if (error) {
65
- reject(error);
66
- return;
67
- }
68
- resolve();
69
- });
70
- });
71
- return database;
54
+ const database = new DatabaseSync(filePath, { allowExtension: true });
55
+ try {
56
+ database.loadExtension(getLoadablePath());
57
+ database.enableLoadExtension(false);
58
+ return database;
59
+ } catch (error) {
60
+ database.close();
61
+ throw error;
62
+ }
72
63
  };
73
64
  const run = (database, sql, parameters = []) => {
74
- return new Promise((resolve, reject) => {
75
- database.run(sql, parameters, function onRun(error) {
76
- if (error) {
77
- reject(error);
78
- return;
79
- }
80
- resolve(this);
81
- });
82
- });
65
+ return database.prepare(sql).run(...parameters);
83
66
  };
84
67
  const get = (database, sql, parameters = []) => {
85
- return new Promise((resolve, reject) => {
86
- database.get(sql, parameters, (error, row) => {
87
- if (error) {
88
- reject(error);
89
- return;
90
- }
91
- resolve(row);
92
- });
93
- });
68
+ return database.prepare(sql).get(...parameters);
94
69
  };
95
70
  const all = (database, sql, parameters = []) => {
96
- return new Promise((resolve, reject) => {
97
- database.all(sql, parameters, (error, rows) => {
98
- if (error) {
99
- reject(error);
100
- return;
101
- }
102
- resolve(rows);
103
- });
104
- });
71
+ return database.prepare(sql).all(...parameters);
105
72
  };
106
73
  const exec = (database, sql) => {
107
- return new Promise((resolve, reject) => {
108
- database.exec(sql, (error) => {
109
- if (error) {
110
- reject(error);
111
- return;
112
- }
113
- resolve();
114
- });
115
- });
74
+ database.exec(sql);
116
75
  };
117
76
  const initializeSearchDatabase = async (database) => {
118
77
  await exec(
@@ -134,19 +93,35 @@ const initializeSearchDatabase = async (database) => {
134
93
  await exec(database, `PRAGMA user_version = ${SEARCH_DATABASE_SCHEMA_VERSION};`);
135
94
  };
136
95
  const close = (database) => {
137
- return new Promise((resolve, reject) => {
138
- database.close((error) => {
139
- if (error) {
140
- reject(error);
141
- return;
142
- }
143
- resolve();
144
- });
145
- });
96
+ database.close();
146
97
  };
147
98
  const serializeEmbedding = (embedding) => {
148
99
  return Buffer.from(Float32Array.from(embedding).buffer);
149
100
  };
101
+ const INSERT_YIELD_INTERVAL = 250;
102
+ const insertChunks = async (database, chunks) => {
103
+ const statement = database.prepare(`
104
+ INSERT INTO search_chunks (
105
+ note_id,
106
+ chunk_index,
107
+ source_hash,
108
+ text,
109
+ embedding
110
+ ) VALUES (?, ?, ?, ?, ?)
111
+ `);
112
+ for (const [index, chunk] of chunks.entries()) {
113
+ statement.run(
114
+ chunk.noteId,
115
+ chunk.chunkIndex,
116
+ chunk.sourceHash,
117
+ chunk.text,
118
+ serializeEmbedding(chunk.embedding)
119
+ );
120
+ if ((index + 1) % INSERT_YIELD_INTERVAL === 0 && index + 1 < chunks.length) {
121
+ await yieldToEventLoop();
122
+ }
123
+ }
124
+ };
150
125
  const isSemanticIndexProfile = (value) => {
151
126
  if (!value || typeof value !== "object") {
152
127
  return false;
@@ -217,27 +192,7 @@ class SqliteSemanticVectorIndex {
217
192
  try {
218
193
  await run(database, "DELETE FROM search_chunks");
219
194
  await run(database, "DELETE FROM search_index_state");
220
- for (const chunk of chunks) {
221
- await run(
222
- database,
223
- `
224
- INSERT INTO search_chunks (
225
- note_id,
226
- chunk_index,
227
- source_hash,
228
- text,
229
- embedding
230
- ) VALUES (?, ?, ?, ?, ?)
231
- `,
232
- [
233
- chunk.noteId,
234
- chunk.chunkIndex,
235
- chunk.sourceHash,
236
- chunk.text,
237
- serializeEmbedding(chunk.embedding)
238
- ]
239
- );
240
- }
195
+ await insertChunks(database, chunks);
241
196
  await run(
242
197
  database,
243
198
  `
@@ -472,37 +427,35 @@ class SqliteSemanticVectorIndex {
472
427
  async getNoteSyncQueueStatus() {
473
428
  return this.runExclusive(async () => {
474
429
  const database = await this.getDatabase();
475
- const [queue, state, latestError] = await Promise.all([
476
- get(
477
- database,
478
- `
479
- SELECT
480
- COUNT(*) AS pendingNoteCount,
481
- MIN(first_queued_at) AS oldestQueuedAt
482
- FROM search_note_sync_queue
483
- `
484
- ),
485
- get(
486
- database,
487
- `
488
- SELECT
489
- last_synced_at AS lastSyncedAt,
490
- last_reconciled_at AS lastReconciledAt
491
- FROM search_note_sync_state
492
- WHERE id = 1
493
- `
494
- ),
495
- get(
496
- database,
497
- `
498
- SELECT last_error AS error
499
- FROM search_note_sync_queue
500
- WHERE last_error IS NOT NULL
501
- ORDER BY next_attempt_at DESC, note_id ASC
502
- LIMIT 1
503
- `
504
- )
505
- ]);
430
+ const queue = get(
431
+ database,
432
+ `
433
+ SELECT
434
+ COUNT(*) AS pendingNoteCount,
435
+ MIN(first_queued_at) AS oldestQueuedAt
436
+ FROM search_note_sync_queue
437
+ `
438
+ );
439
+ const state = get(
440
+ database,
441
+ `
442
+ SELECT
443
+ last_synced_at AS lastSyncedAt,
444
+ last_reconciled_at AS lastReconciledAt
445
+ FROM search_note_sync_state
446
+ WHERE id = 1
447
+ `
448
+ );
449
+ const latestError = get(
450
+ database,
451
+ `
452
+ SELECT last_error AS error
453
+ FROM search_note_sync_queue
454
+ WHERE last_error IS NOT NULL
455
+ ORDER BY next_attempt_at DESC, note_id ASC
456
+ LIMIT 1
457
+ `
458
+ );
506
459
  return {
507
460
  pendingNoteCount: queue?.pendingNoteCount ?? 0,
508
461
  oldestQueuedAt: queue?.oldestQueuedAt === null || queue?.oldestQueuedAt === void 0 ? null : new Date(queue.oldestQueuedAt).toISOString(),
@@ -526,27 +479,7 @@ class SqliteSemanticVectorIndex {
526
479
  await exec(database, "BEGIN IMMEDIATE;");
527
480
  try {
528
481
  await run(database, "DELETE FROM search_chunks WHERE note_id = ?", [noteId]);
529
- for (const chunk of chunks) {
530
- await run(
531
- database,
532
- `
533
- INSERT INTO search_chunks (
534
- note_id,
535
- chunk_index,
536
- source_hash,
537
- text,
538
- embedding
539
- ) VALUES (?, ?, ?, ?, ?)
540
- `,
541
- [
542
- chunk.noteId,
543
- chunk.chunkIndex,
544
- chunk.sourceHash,
545
- chunk.text,
546
- serializeEmbedding(chunk.embedding)
547
- ]
548
- );
549
- }
482
+ await insertChunks(database, chunks);
550
483
  await this.refreshIndexCounts(database);
551
484
  await exec(database, "COMMIT;");
552
485
  } catch (error) {
@@ -7,12 +7,18 @@ import {
7
7
  getViewSectionNotes,
8
8
  getViewWorkspace
9
9
  } from "../../../features/view/services/workspace.js";
10
- const viewQueryResolvers = {
10
+ const createViewQueryResolvers = (deps = {
11
+ getNotesByProperties,
12
+ getViewSectionBoardColumn,
13
+ getViewSectionById,
14
+ getViewSectionNotes,
15
+ getViewWorkspace
16
+ }) => ({
11
17
  viewWorkspace: async () => {
12
- return getViewWorkspace();
18
+ return deps.getViewWorkspace();
13
19
  },
14
20
  viewSection: async (_, { id }) => {
15
- return getViewSectionById(id);
21
+ return deps.getViewSectionById(id);
16
22
  },
17
23
  viewSectionNotes: async (_, {
18
24
  id,
@@ -23,7 +29,7 @@ const viewQueryResolvers = {
23
29
  sortBy,
24
30
  sortOrder
25
31
  }) => {
26
- const sectionNotes = await getViewSectionNotes(
32
+ const sectionNotes = await deps.getViewSectionNotes(
27
33
  id,
28
34
  {
29
35
  limit: Number(pagination.limit),
@@ -45,7 +51,7 @@ const viewQueryResolvers = {
45
51
  }
46
52
  }) => {
47
53
  try {
48
- const columnNotes = await getViewSectionBoardColumn(id, optionValue, {
54
+ const columnNotes = await deps.getViewSectionBoardColumn(id, optionValue, {
49
55
  limit: Number(pagination.limit),
50
56
  offset: Number(pagination.offset)
51
57
  });
@@ -72,7 +78,7 @@ const viewQueryResolvers = {
72
78
  }
73
79
  }) => {
74
80
  try {
75
- return await getNotesByProperties(input, {
81
+ return await deps.getNotesByProperties(input, {
76
82
  limit: Number(pagination.limit),
77
83
  offset: Number(pagination.offset)
78
84
  });
@@ -87,7 +93,9 @@ const viewQueryResolvers = {
87
93
  throw error;
88
94
  }
89
95
  }
90
- };
96
+ });
97
+ const viewQueryResolvers = createViewQueryResolvers();
91
98
  export {
99
+ createViewQueryResolvers,
92
100
  viewQueryResolvers
93
101
  };
@@ -1,38 +1,4 @@
1
- import { createApp } from "./app.js";
2
- import { ensureNoteReferenceIndex } from "./features/note/services/note-reference-index.js";
3
- import { getDefaultSemanticSearchManager } from "./features/search/search-manager.js";
4
- import { logAuthConfig, resolveAuthConfig } from "./modules/auth-mode.js";
5
- import { startDataMaintenanceScheduler } from "./modules/data-maintenance.js";
6
- const PORT = Number(process.env.PORT || 6683);
7
- const HOST = process.env.HOST || "0.0.0.0";
8
- const startServer = async () => {
9
- const authConfig = resolveAuthConfig(process.env);
10
- logAuthConfig(authConfig);
11
- const app = createApp(authConfig);
12
- getDefaultSemanticSearchManager();
13
- const rebuiltReferenceCount = await ensureNoteReferenceIndex();
14
- if (rebuiltReferenceCount > 0) {
15
- process.stdout.write(`[maintenance] Rebuilt ${rebuiltReferenceCount} note reference rows
16
- `);
17
- }
18
- app.listen(PORT, HOST, () => {
19
- process.stdout.write(`http server listen on ${HOST}:${PORT} (auth: ${authConfig.mode})
20
- `);
21
- startDataMaintenanceScheduler({
22
- onResults: (results) => {
23
- for (const result of results) {
24
- process.stdout.write(`[maintenance] Reconciled ${result.processedCount} rows for ${result.key}
25
- `);
26
- }
27
- },
28
- onError: (error) => {
29
- const message = error instanceof Error ? error.message : "Unknown data maintenance error";
30
- process.stderr.write(`[maintenance] Background run failed: ${message}
31
- `);
32
- }
33
- });
34
- });
35
- };
1
+ import { startServer } from "./server.js";
36
2
  startServer().catch((error) => {
37
3
  const message = error instanceof Error ? error.message : "Unknown auth configuration error";
38
4
  process.stderr.write(`[auth] Startup failed: ${message}
@@ -62,12 +62,6 @@ function visitBlocks(blocks, visit) {
62
62
  }
63
63
  }
64
64
  }
65
- function createTagPlaceholder(index) {
66
- return `${TAG_PLACEHOLDER_PREFIX}${index}${TAG_PLACEHOLDER_SUFFIX}`;
67
- }
68
- function createReferencePlaceholder(index) {
69
- return `${REFERENCE_PLACEHOLDER_PREFIX}${index}${REFERENCE_PLACEHOLDER_SUFFIX}`;
70
- }
71
65
  function isValidNoteIdString(id) {
72
66
  if (!/^[1-9]\d*$/.test(id)) {
73
67
  return false;
@@ -143,7 +137,7 @@ function mapBlocks(blocks, mapContent) {
143
137
  children: block.children?.length ? mapBlocks(block.children, mapContent) : []
144
138
  }));
145
139
  }
146
- function preprocessCustomInlineContent(blocks, placeholderToTag, nextPlaceholderIndex) {
140
+ function preprocessCustomInlineContent(blocks, placeholderToTag, createTagPlaceholder) {
147
141
  return mapBlocks(
148
142
  blocks,
149
143
  (content) => mapBlockContent(content, (inline) => {
@@ -158,7 +152,7 @@ function preprocessCustomInlineContent(blocks, placeholderToTag, nextPlaceholder
158
152
  }
159
153
  if (inline.type === "tag") {
160
154
  const tag = inline.props?.tag || "";
161
- const placeholder = createTagPlaceholder(nextPlaceholderIndex.value++);
155
+ const placeholder = createTagPlaceholder();
162
156
  placeholderToTag.set(placeholder, tag);
163
157
  return {
164
158
  type: "text",
@@ -179,9 +173,13 @@ function restoreTagPlaceholdersInMarkdown(markdown, placeholderToTag) {
179
173
  }
180
174
  function preprocessMarkdownExplicitTags(markdown) {
181
175
  const placeholderToTag = /* @__PURE__ */ new Map();
182
- let nextPlaceholderIndex = 0;
176
+ const createPlaceholder = createProtectedTextPlaceholderFactory(
177
+ markdown,
178
+ TAG_PLACEHOLDER_PREFIX,
179
+ TAG_PLACEHOLDER_SUFFIX
180
+ );
183
181
  const preprocessedMarkdown = markdown.replace(/\[(@[^\s[\]]+)\]/g, (_match, tagToken) => {
184
- const placeholder = createTagPlaceholder(nextPlaceholderIndex++);
182
+ const placeholder = createPlaceholder();
185
183
  placeholderToTag.set(placeholder, tagToken);
186
184
  return placeholder;
187
185
  });
@@ -192,6 +190,11 @@ function preprocessMarkdownExplicitTags(markdown) {
192
190
  }
193
191
  function preprocessMarkdownExplicitReferences(markdown) {
194
192
  const placeholderToReference = /* @__PURE__ */ new Map();
193
+ const createPlaceholder = createProtectedTextPlaceholderFactory(
194
+ markdown,
195
+ REFERENCE_PLACEHOLDER_PREFIX,
196
+ REFERENCE_PLACEHOLDER_SUFFIX
197
+ );
195
198
  let activeFence = null;
196
199
  const preprocessedLines = markdown.split(/(?<=\n)/).map((line) => {
197
200
  const { body: lineBody, lineEnding } = splitMarkdownLineEnding(line);
@@ -212,31 +215,39 @@ function preprocessMarkdownExplicitReferences(markdown) {
212
215
  if (/^(?: {4,}|\t)/.test(lineBody)) {
213
216
  return line;
214
217
  }
215
- return `${replaceMarkdownLineExplicitReferences(lineBody, placeholderToReference)}${lineEnding}`;
218
+ return `${replaceMarkdownLineExplicitReferences(
219
+ lineBody,
220
+ placeholderToReference,
221
+ createPlaceholder
222
+ )}${lineEnding}`;
216
223
  });
217
224
  return {
218
225
  markdown: preprocessedLines.join(""),
219
226
  placeholderToReference
220
227
  };
221
228
  }
222
- function replaceMarkdownLineExplicitReferences(line, placeholderToReference) {
229
+ function replaceMarkdownLineExplicitReferences(line, placeholderToReference, createPlaceholder) {
223
230
  let result = "";
224
231
  let cursor = 0;
225
232
  while (cursor < line.length) {
226
233
  const codeSpan = findNextInlineCodeSpan(line, cursor);
227
234
  if (!codeSpan) {
228
- result += replaceExplicitReferenceTokens(line.slice(cursor), placeholderToReference);
235
+ result += replaceExplicitReferenceTokens(line.slice(cursor), placeholderToReference, createPlaceholder);
229
236
  break;
230
237
  }
231
- result += replaceExplicitReferenceTokens(line.slice(cursor, codeSpan.start), placeholderToReference);
238
+ result += replaceExplicitReferenceTokens(
239
+ line.slice(cursor, codeSpan.start),
240
+ placeholderToReference,
241
+ createPlaceholder
242
+ );
232
243
  result += line.slice(codeSpan.start, codeSpan.end);
233
244
  cursor = codeSpan.end;
234
245
  }
235
246
  return result;
236
247
  }
237
- function replaceExplicitReferenceTokens(text, placeholderToReference) {
248
+ function replaceExplicitReferenceTokens(text, placeholderToReference, createPlaceholder) {
238
249
  return text.replace(/\[\[([^\n]+?)\]\]\(note:([^)\s]+)\)/g, (token, title, id) => {
239
- const placeholder = createReferencePlaceholder(placeholderToReference.size);
250
+ const placeholder = createPlaceholder();
240
251
  placeholderToReference.set(placeholder, { id, title, token });
241
252
  return placeholder;
242
253
  });
@@ -1030,7 +1041,12 @@ async function blocksToMarkdown(contentJson) {
1030
1041
  const blocks = parseBlockNoteContent(contentJson);
1031
1042
  const supportedBlocks = stripUnsupportedMarkdownBlocks(blocks);
1032
1043
  const placeholderToTag = /* @__PURE__ */ new Map();
1033
- const processed = preprocessCustomInlineContent(supportedBlocks, placeholderToTag, { value: 0 });
1044
+ const createTagPlaceholder = createProtectedTextPlaceholderFactory(
1045
+ contentJson,
1046
+ TAG_PLACEHOLDER_PREFIX,
1047
+ TAG_PLACEHOLDER_SUFFIX
1048
+ );
1049
+ const processed = preprocessCustomInlineContent(supportedBlocks, placeholderToTag, createTagPlaceholder);
1034
1050
  const editor = getEditor();
1035
1051
  const markdown = await editor.blocksToMarkdownLossy(
1036
1052
  processed
@@ -83,7 +83,12 @@ const createApiRouter = (authConfig, mcpAdminService) => {
83
83
  requireSession,
84
84
  csrfProtection,
85
85
  useAsync(createSearchAdminReindexHandler())
86
- ).post("/image", sessionAccessRateLimit, requireSession, csrfProtection, useAsync(createUploadImageHandler())).get("/events", sessionAccessRateLimit, requireSession, csrfProtection, createServerEventsHandler());
86
+ ).post("/image", sessionAccessRateLimit, requireSession, csrfProtection, useAsync(createUploadImageHandler())).get("/events", sessionAccessRateLimit, requireSession, csrfProtection, createServerEventsHandler()).use((_req, res) => {
87
+ res.status(404).json({
88
+ code: "API_ROUTE_NOT_FOUND",
89
+ message: "The requested API route was not found."
90
+ }).end();
91
+ });
87
92
  };
88
93
  export {
89
94
  createApiRouter
@@ -4,6 +4,9 @@ import path from "path";
4
4
  import { createCsrfProtection, isAuthenticatedRequest } from "../modules/auth-guard.js";
5
5
  import { paths } from "../paths.js";
6
6
  const IMAGE_ASSET_RATE_LIMIT_MESSAGE = "Too many image asset requests. Please try again later.";
7
+ const isClientDocumentRequest = (req) => {
8
+ return req.method === "GET" && Boolean(req.headers.accept?.includes("text/html")) && path.extname(req.path) === "";
9
+ };
7
10
  const shouldBlockClientRoute = (authConfig, requestPath, authenticated) => {
8
11
  if (authConfig.mode !== "password" || authenticated) {
9
12
  return false;
@@ -52,7 +55,17 @@ const createClientRouteCsrfTokenMiddleware = (authConfig) => {
52
55
  csrfProtection(req, res, next);
53
56
  };
54
57
  };
55
- const createClientRouter = (authConfig) => Router().use(
58
+ const createProductionClientContentRouter = () => Router().use(express.static(paths.clientDist, { extensions: ["html"] })).get(/.*/, (req, res, next) => {
59
+ if (!isClientDocumentRequest(req)) {
60
+ next();
61
+ return;
62
+ }
63
+ res.sendFile("index.html", { root: paths.clientDist });
64
+ }).use((_req, res) => {
65
+ res.setHeader("X-Content-Type-Options", "nosniff");
66
+ res.status(404).end();
67
+ });
68
+ const createClientRouter = (authConfig, clientContentMiddleware = createProductionClientContentRouter()) => Router().use(
56
69
  "/assets/images",
57
70
  createImageAssetAuthRateLimit(authConfig),
58
71
  createProtectedImageAssetsMiddleware(authConfig),
@@ -78,9 +91,7 @@ const createClientRouter = (authConfig) => Router().use(
78
91
  return;
79
92
  }
80
93
  next();
81
- }).use(createClientRouteCsrfTokenMiddleware(authConfig)).use(express.static(paths.clientDist, { extensions: ["html"] })).get(/.*/, (_req, res) => {
82
- res.sendFile("index.html", { root: paths.clientDist });
83
- });
94
+ }).use(createClientRouteCsrfTokenMiddleware(authConfig)).use(clientContentMiddleware);
84
95
  export {
85
96
  createClientRouter
86
97
  };
@@ -0,0 +1,40 @@
1
+ import { createServer as createNodeHttpServer } from "node:http";
2
+ import { createApp } from "./app.js";
3
+ import { ensureNoteReferenceIndex } from "./features/note/services/note-reference-index.js";
4
+ import { getDefaultSemanticSearchManager } from "./features/search/search-manager.js";
5
+ import { logAuthConfig, resolveAuthConfig } from "./modules/auth-mode.js";
6
+ import { startDataMaintenanceScheduler } from "./modules/data-maintenance.js";
7
+ const startServer = async (options = {}) => {
8
+ const port = Number(process.env.PORT || 6683);
9
+ const host = process.env.HOST || "0.0.0.0";
10
+ const authConfig = resolveAuthConfig(process.env);
11
+ logAuthConfig(authConfig);
12
+ const httpServer = options.serverFactory ? await options.serverFactory(authConfig) : createNodeHttpServer(createApp(authConfig));
13
+ getDefaultSemanticSearchManager();
14
+ const rebuiltReferenceCount = await ensureNoteReferenceIndex();
15
+ if (rebuiltReferenceCount > 0) {
16
+ process.stdout.write(`[maintenance] Rebuilt ${rebuiltReferenceCount} note reference rows
17
+ `);
18
+ }
19
+ httpServer.listen(port, host, () => {
20
+ process.stdout.write(`http server listen on ${host}:${port} (auth: ${authConfig.mode})
21
+ `);
22
+ startDataMaintenanceScheduler({
23
+ onResults: (results) => {
24
+ for (const result of results) {
25
+ process.stdout.write(`[maintenance] Reconciled ${result.processedCount} rows for ${result.key}
26
+ `);
27
+ }
28
+ },
29
+ onError: (error) => {
30
+ const message = error instanceof Error ? error.message : "Unknown data maintenance error";
31
+ process.stderr.write(`[maintenance] Background run failed: ${message}
32
+ `);
33
+ }
34
+ });
35
+ });
36
+ return httpServer;
37
+ };
38
+ export {
39
+ startServer
40
+ };
@@ -1,25 +0,0 @@
1
- import{r as s,j as e}from"./floating-ui.react-dom-BWTnA00G.js";import{C as ae,T as b,F as re,c as _,m as f,M as H,y as ne,z as Y,B as Z,R as se,a2 as oe,q as P,g as Q,P as le,l as ie,h as ce}from"./time-DZKkPFUi.js";import{N as de,C as me}from"./url-BvjSC8PU.js";import{s as he,a as U}from"./useNoteMutate-VJYw0Vt_.js";import{e as ue}from"./app-DbQdHfMb.js";import{C as ge}from"./Callout-Cye6_6BM.js";import"./preload-helper-BXl3LOEh.js";import"./sortable.esm-DgSW3bAA.js";const pe=new Map([["bold",s.createElement(s.Fragment,null,s.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,12h48V212Zm112-80a12,12,0,0,1-12,12H96a12,12,0,0,1,0-24h64A12,12,0,0,1,172,132Zm0,40a12,12,0,0,1-12,12H96a12,12,0,0,1,0-24h64A12,12,0,0,1,172,172Z"}))],["duotone",s.createElement(s.Fragment,null,s.createElement("path",{d:"M208,88H152V32Z",opacity:"0.2"}),s.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,8h48V216Zm-32-80a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h64A8,8,0,0,1,168,136Zm0,32a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h64A8,8,0,0,1,168,168Z"}))],["fill",s.createElement(s.Fragment,null,s.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,176H96a8,8,0,0,1,0-16h64a8,8,0,0,1,0,16Zm0-32H96a8,8,0,0,1,0-16h64a8,8,0,0,1,0,16Zm-8-56V44l44,44Z"}))],["light",s.createElement(s.Fragment,null,s.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,218Zm-34-82a6,6,0,0,1-6,6H96a6,6,0,0,1,0-12h64A6,6,0,0,1,166,136Zm0,32a6,6,0,0,1-6,6H96a6,6,0,0,1,0-12h64A6,6,0,0,1,166,168Z"}))],["regular",s.createElement(s.Fragment,null,s.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,8h48V216Zm-32-80a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h64A8,8,0,0,1,168,136Zm0,32a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h64A8,8,0,0,1,168,168Z"}))],["thin",s.createElement(s.Fragment,null,s.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,220Zm-36-84a4,4,0,0,1-4,4H96a4,4,0,0,1,0-8h64A4,4,0,0,1,164,136Zm0,32a4,4,0,0,1-4,4H96a4,4,0,0,1,0-8h64A4,4,0,0,1,164,168Z"}))]]),B=s.forwardRef((a,t)=>s.createElement(ae,{ref:t,...a,weights:pe}));B.displayName="FileTextIcon";const xe=B,ye=({day:a,cellClassName:t,dayNumberClassName:r,isCurrentMonth:i,items:l,overflowCount:c,onOpenOverflow:h})=>e.jsxs("div",{className:`min-h-[196px] rounded-[16px] border p-2.5 ${t}`.trim(),children:[e.jsx("div",{className:"mb-2.5 flex justify-end",children:e.jsx(b,{as:"span",variant:"label",className:`flex h-7 w-7 items-center justify-center rounded-[10px] ${r}`.trim(),children:a})}),i&&l.length>0?e.jsxs("div",{className:"flex flex-col gap-1.5",children:[l,c>0?e.jsxs("button",{type:"button",onClick:h,className:"focus-ring-soft w-full rounded-[10px] border border-dashed border-border-subtle/70 bg-subtle/70 py-1 text-center text-micro font-semibold text-fg-tertiary outline-none transition-colors hover:border-border-secondary/70 hover:bg-hover-subtle hover:text-fg-secondary",children:["+",c," more"]}):null]}):null]}),K=({params:a,toneClassName:t="",header:r,title:i,meta:l,titleClassName:c=""})=>e.jsx(re,{to:de,params:a,className:"focus-ring-soft group block rounded-[8px] outline-none",children:e.jsxs("div",{className:_("flex items-start gap-1.5 rounded-[8px] px-1.5 py-1 transition-colors group-hover:bg-hover-subtle",t),children:[r?e.jsx("span",{className:"mt-[2px] flex h-4 w-4 shrink-0 items-center justify-center text-fg-tertiary",children:r}):e.jsx("span",{"aria-hidden":"true",className:"mt-[6px] h-1.5 w-1.5 shrink-0 rounded-full bg-fg-placeholder"}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx(b,{as:"div",variant:"label",weight:"medium",tone:"secondary",className:_("line-clamp-1",c),children:i}),l?e.jsx(b,{as:"div",variant:"micro",weight:"medium",tone:"tertiary",className:"mt-0.5",children:l}):null]})]})}),fe=({note:a,type:t})=>e.jsx(K,{params:{id:a.id},header:e.jsx(xe,{size:12}),title:a.title,meta:f(Number(t==="create"?a.createdAt:a.updatedAt)).format("HH:mm")}),be=({reminder:a})=>e.jsx(K,{params:{id:String(a.note?.id??a.noteId)},header:e.jsx(he,{size:12}),title:a.content||a.note?.title||"No title",titleClassName:a.completed?"line-through":"",meta:f(Number(a.reminderDate)).format("HH:mm")}),k=3,q=(a,t)=>a.map(r=>r.type==="note"?e.jsx(fe,{note:r.item,type:t},`note-${r.item.id}`):e.jsx(be,{reminder:r.item},`reminder-${r.item.id}`)),je=({year:a,month:t,day:r,isCurrentMonth:i,isSunday:l,isToday:c,isPast:h,notes:u,reminders:g,type:M})=>{const[v,N]=s.useState(!1),x=s.useMemo(()=>{const n=u.map(m=>({type:"note",item:m})),d=g.map(m=>({type:"reminder",item:m}));return h?[...n,...d]:[...d,...n]},[h,u,g]),D=x.length>k,R=s.useMemo(()=>q(x.slice(0,k),M),[x,M]),w=s.useMemo(()=>q(x,M),[x,M]),E=s.useCallback(()=>N(!0),[]),A=s.useCallback(()=>N(!1),[]),S=()=>i?c?"border-border-secondary/70 bg-[color:color-mix(in_srgb,var(--surface)_88%,var(--accent-soft-primary)_12%)]":"bg-surface border-border-subtle":"bg-muted/18 border-border-subtle/70",$=()=>c?"bg-cta text-fg-on-filled font-semibold":i?l?"text-fg-weekend font-bold":"text-fg-secondary font-bold":"text-fg-disabled opacity-55";return e.jsxs(e.Fragment,{children:[e.jsx(ye,{day:r,cellClassName:S(),dayNumberClassName:$(),isCurrentMonth:i,items:R,overflowCount:D?x.length-k:0,onOpenOverflow:E}),D&&e.jsxs(H,{isOpen:v,onClose:A,variant:"inspect",children:[e.jsx(H.Header,{title:`${a}/${String(t).padStart(2,"0")}/${String(r).padStart(2,"0")}`,onClose:A}),e.jsxs(H.Body,{children:[e.jsxs(H.Description,{className:"sr-only",children:["View all notes and reminders scheduled for day ",r,"."]}),e.jsx("div",{className:"flex max-h-[60vh] flex-col gap-2 overflow-y-auto",children:w})]})]})]})},Me=s.memo(je),Ne=["January","February","March","April","May","June","July","August","September","October","November","December"],ve=({month:a,year:t,type:r,onPrevMonth:i,onNextMonth:l,onToday:c,onTypeChange:h})=>e.jsxs("div",{className:"flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsxs("div",{className:"flex flex-wrap items-end gap-x-2.5 gap-y-1",children:[e.jsx(b,{as:"h1",variant:"display",weight:"bold",tracking:"tighter",className:"text-2xl leading-none sm:text-[2.15rem]",children:Ne[a-1]}),e.jsx(b,{as:"span",variant:"subheading",weight:"medium",tone:"secondary",tracking:"tight",className:"pb-0.5",children:t})]}),e.jsx(b,{as:"p",variant:"meta",weight:"medium",tone:"secondary",children:"Track note activity and reminders across the month"})]}),e.jsx("div",{className:"flex lg:justify-end",children:e.jsxs("div",{className:"surface-base inline-flex flex-wrap items-center gap-3 rounded-[16px] px-3.5 py-2.5",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ue,{className:"h-4 w-4 shrink-0 text-fg-tertiary"}),e.jsx(b,{id:"calendar-note-date-label",as:"span",variant:"label",weight:"medium",tone:"tertiary",children:"Note date"}),e.jsxs(ne,{value:r,"aria-labelledby":"calendar-note-date-label",onValueChange:g=>h(g),variant:"ghost",size:"sm",children:[e.jsx(Y,{value:"create",children:"Created"}),e.jsx(Y,{value:"update",children:"Updated"})]})]}),e.jsx("div",{className:"h-5 w-px bg-divider"}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(Z,{variant:"ghost",size:"sm",onClick:c,children:"Today"}),e.jsx(Z,{variant:"ghost",size:"icon-sm","aria-label":"Previous month",onClick:i,children:e.jsx(se,{width:18,height:18})}),e.jsx(Z,{variant:"ghost",size:"icon-sm","aria-label":"Next month",onClick:l,children:e.jsx(oe,{width:18,height:18})})]})]})})]}),De=`
2
- query NotesInDateRange($dateRange: DateRangeInput) {
3
- notesInDateRange(dateRange: $dateRange) {
4
- id
5
- title
6
- createdAt
7
- updatedAt
8
- }
9
- }
10
- `,Ae=`
11
- query RemindersInDateRange($dateRange: DateRangeInput) {
12
- remindersInDateRange(dateRange: $dateRange) {
13
- id
14
- noteId
15
- reminderDate
16
- completed
17
- priority
18
- content
19
- note {
20
- id
21
- title
22
- }
23
- }
24
- }
25
- `,Ce=async a=>{const t=await Q(De,{dateRange:a});if(t.type==="error")throw t;return t.notesInDateRange},He=async a=>{const t=await Q(Ae,{dateRange:a});if(t.type==="error")throw t;return t.remindersInDateRange},Re=({year:a,month:t})=>{const r=`${a}-${String(t).padStart(2,"0")}-01`,i=t===12?1:t+1,c=`${t===12?a+1:a}-${String(i).padStart(2,"0")}-01`,h={start:r,end:c},u=U({queryKey:P.calendar.notesInDateRange(a,t),queryFn:()=>Ce(h)}),g=U({queryKey:P.reminders.inDateRange(a,t),queryFn:()=>He(h)});return{notes:u.data??[],reminders:g.data??[],isLoading:u.isLoading||g.isLoading,isError:u.isError||g.isError}},we=["SUN","MON","TUE","WED","THU","FRI","SAT"],Ee=[],Se=[],z=ce(me);function Le(){const a=z.useNavigate(),{year:t,month:r,type:i}=z.useSearch(),l=s.useRef(null),c=s.useRef(!1),h=s.useRef(0),u=s.useRef(0),g=s.useCallback(n=>{c.current=!0,h.current=n.pageX-(l.current?.offsetLeft??0),u.current=l.current?.scrollLeft??0,l.current&&(l.current.style.cursor="grabbing",l.current.style.userSelect="none")},[]),M=s.useCallback(n=>{if(!c.current||!l.current)return;n.preventDefault();const m=(n.pageX-l.current.offsetLeft-h.current)*1.2;l.current.scrollLeft=u.current-m},[]),v=s.useCallback(()=>{c.current=!1,l.current&&(l.current.style.cursor="grab",l.current.style.userSelect="")},[]),{notes:N,reminders:x,isLoading:D,isError:R}=Re({year:t,month:r}),w=s.useMemo(()=>{const n=f(),d=`${n.year()}-${n.month()+1}-${n.date()}`,m=new Map;for(const o of N){const y=i==="create"?f(Number(o.createdAt)):f(Number(o.updatedAt)),p=`${y.year()}-${y.month()+1}-${y.date()}`,j=m.get(p)||[];j.push(o),m.set(p,j)}const V=new Map;for(const o of x){const y=f(Number(o.reminderDate)),p=`${y.year()}-${y.month()+1}-${y.date()}`,j=V.get(p)||[];j.push(o),V.set(p,j)}const W=new Date(t,r-1,1),X=new Date(t,r,0),I=W.getDay(),T=X.getDate(),C=[],O=r===1?12:r-1,F=r===1?t-1:t,J=new Date(F,O,0).getDate();for(let o=I-1;o>=0;o--)C.push({day:J-o,isCurrentMonth:!1,year:F,month:O});for(let o=1;o<=T;o++)C.push({day:o,isCurrentMonth:!0,year:t,month:r});const L=(I+T)%7,G=L===0?0:7-L,ee=r===12?1:r+1,te=r===12?t+1:t;for(let o=1;o<=G;o++)C.push({day:o,isCurrentMonth:!1,year:te,month:ee});return C.map((o,y)=>{const p=`${o.year}-${o.month}-${o.day}`,j=f(`${o.year}-${String(o.month).padStart(2,"0")}-${String(o.day).padStart(2,"0")}`);return{key:p,year:o.year,month:o.month,day:o.day,isCurrentMonth:o.isCurrentMonth,isSunday:y%7===0,isToday:p===d,isPast:j.isBefore(n,"day"),notes:m.get(p)||Ee,reminders:V.get(p)||Se}})},[t,r,N,x,i]),E=()=>{const n=r===1?12:r-1,d=r===1?t-1:t;a({search:m=>({...m,month:n,year:d})})},A=()=>{const n=r===12?1:r+1,d=r===12?t+1:t;a({search:m=>({...m,month:n,year:d})})},S=()=>{a({search:n=>({...n,month:f().month()+1,year:f().year()})})},$=n=>{n&&a({search:d=>({...d,type:n})})};return e.jsx(le,{title:"Calendar",variant:"none",children:R?e.jsx(ge,{children:"Failed to load calendar data. Please try again later."}):e.jsxs("div",{className:"surface-base",children:[e.jsx("div",{className:"border-b border-border-subtle/80 px-4 py-4 sm:px-5",children:e.jsx(ve,{month:r,year:t,type:i,onPrevMonth:E,onNextMonth:A,onToday:S,onTypeChange:$})}),e.jsx("div",{ref:l,className:"cursor-grab overflow-x-auto px-4 pb-4 pt-3 sm:px-5",onMouseDown:g,onMouseMove:M,onMouseUp:v,onMouseLeave:v,children:e.jsxs("div",{className:"min-w-[1260px]",children:[e.jsx("div",{className:"mb-2.5 grid grid-cols-7 gap-1.5",children:we.map((n,d)=>e.jsx(b,{as:"div",variant:"label",weight:"semibold",tracking:"wider",transform:"uppercase",className:`py-2 text-center ${d===0?"text-fg-weekend":"text-fg-tertiary"}`,children:n},n))}),D?e.jsx("div",{className:"grid grid-cols-7 gap-1.5",children:Array.from({length:35}).map((n,d)=>e.jsx(ie,{height:180},d))}):e.jsx("div",{className:"grid grid-cols-7 gap-1.5",children:w.map(n=>e.jsx(Me,{year:n.year,month:n.month,day:n.day,isCurrentMonth:n.isCurrentMonth,isSunday:n.isSunday,isToday:n.isToday,isPast:n.isPast,notes:n.notes,reminders:n.reminders,type:i},n.key))})]})})]})})}export{Le as default};