ocean-brain 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +73 -41
- package/dist/mcp.js +587 -26
- package/package.json +6 -1
- package/scripts/postinstall-prisma.mjs +41 -0
- package/server/client/dist/assets/Calendar-DRv2aEl8.js +28 -0
- package/server/client/dist/assets/Callout-B2kPcDrq.js +1 -0
- package/server/client/dist/assets/Graph-DotbTrZR.js +1 -0
- package/server/client/dist/assets/Image-B5R7gF2P.js +1 -0
- package/server/client/dist/assets/Image.es-Dld9r9MJ.js +1 -0
- package/server/client/dist/assets/ModalActionRow-CES9L_Gy.js +1 -0
- package/server/client/dist/assets/Note-SK4hDhEM.css +1 -0
- package/server/client/dist/assets/Note-cIbXJc1v.js +1 -0
- package/server/client/dist/assets/Reminders-4LunlZRb.js +1 -0
- package/server/client/dist/assets/Search-Cp17DGR6.js +1 -0
- package/server/client/dist/assets/SurfaceCard-yzVU4Qkx.js +1 -0
- package/server/client/dist/assets/Tag-CwmuMPmo.js +1 -0
- package/server/client/dist/assets/TagNotes-gGroWMtT.js +1 -0
- package/server/client/dist/assets/Trash.es-B3KWD8_C.js +1 -0
- package/server/client/dist/assets/color-wpu7wT_s.js +1 -0
- package/server/client/dist/assets/graph-vendor-CUxe67Lr.js +46 -0
- package/server/client/dist/assets/image.api-DJgOBt8S.js +17 -0
- package/server/client/dist/assets/index-40Y2UsVr.js +205 -0
- package/server/client/dist/assets/index-BnxpTwtL.css +1 -0
- package/server/client/dist/assets/index-DYUg2N-6.js +1 -0
- package/server/client/dist/assets/manage-image-ByY1mRZx.js +1 -0
- package/server/client/dist/assets/manage-image-detail-BVaDZHRu.js +1 -0
- package/server/client/dist/assets/mcp-Jj3061aI.js +1 -0
- package/server/client/dist/assets/{note-core-DTIu0anW.js → note-core-BCgMq5QA.js} +7 -7
- package/server/client/dist/assets/note-vendor-BofYbzmZ.js +54 -0
- package/server/client/dist/assets/placeholder-4P_GK7fV.js +34 -0
- package/server/client/dist/assets/trash-CPBwY07S.js +1 -0
- package/server/client/dist/assets/useReminderMutate-1YVndM2T.js +82 -0
- package/server/client/dist/index.html +5 -4
- package/server/dist/app.js +97 -9
- package/server/dist/app.js.map +1 -1
- package/server/dist/main.js +16 -2
- package/server/dist/main.js.map +1 -1
- package/server/dist/modules/auth-guard.js +73 -0
- package/server/dist/modules/auth-guard.js.map +1 -0
- package/server/dist/modules/auth-mode.js +51 -0
- package/server/dist/modules/auth-mode.js.map +1 -0
- package/server/dist/modules/auth.js +9 -0
- package/server/dist/modules/auth.js.map +1 -1
- package/server/dist/modules/blocknote.js +7 -1
- package/server/dist/modules/blocknote.js.map +1 -1
- package/server/dist/modules/error-handler.js +41 -0
- package/server/dist/modules/error-handler.js.map +1 -0
- package/server/dist/modules/image-upload.js +114 -0
- package/server/dist/modules/image-upload.js.map +1 -0
- package/server/dist/modules/mcp-admin.js +88 -0
- package/server/dist/modules/mcp-admin.js.map +1 -0
- package/server/dist/modules/mcp-auth.js +71 -0
- package/server/dist/modules/mcp-auth.js.map +1 -0
- package/server/dist/modules/mcp-token.js +28 -0
- package/server/dist/modules/mcp-token.js.map +1 -0
- package/server/dist/modules/note-authoring.js +140 -0
- package/server/dist/modules/note-authoring.js.map +1 -0
- package/server/dist/modules/note-cleanup.js +207 -0
- package/server/dist/modules/note-cleanup.js.map +1 -0
- package/server/dist/modules/note-snapshot.js +223 -0
- package/server/dist/modules/note-snapshot.js.map +1 -0
- package/server/dist/modules/note-trash.js +262 -0
- package/server/dist/modules/note-trash.js.map +1 -0
- package/server/dist/modules/prisma-runtime.js +46 -0
- package/server/dist/modules/prisma-runtime.js.map +1 -0
- package/server/dist/modules/recovery-retention.js +26 -0
- package/server/dist/modules/recovery-retention.js.map +1 -0
- package/server/dist/modules/remote-image.js +176 -0
- package/server/dist/modules/remote-image.js.map +1 -0
- package/server/dist/modules/tag-organization.js +66 -0
- package/server/dist/modules/tag-organization.js.map +1 -0
- package/server/dist/modules/use-async.js +2 -4
- package/server/dist/modules/use-async.js.map +1 -1
- package/server/dist/schema/note/index.js +150 -6
- package/server/dist/schema/note/index.js.map +1 -1
- package/server/dist/start.js +11 -0
- package/server/dist/start.js.map +1 -0
- package/server/dist/types/index.js.map +1 -1
- package/server/dist/urls.js +3 -2
- package/server/dist/urls.js.map +1 -1
- package/server/dist/views/auth.js +305 -0
- package/server/dist/views/auth.js.map +1 -0
- package/server/dist/views/image.js +24 -81
- package/server/dist/views/image.js.map +1 -1
- package/server/dist/views/index.js +4 -0
- package/server/dist/views/index.js.map +1 -1
- package/server/dist/views/mcp-admin.js +42 -0
- package/server/dist/views/mcp-admin.js.map +1 -0
- package/server/dist/views/note.js +124 -0
- package/server/dist/views/note.js.map +1 -0
- package/server/dist/views/tag.js +23 -0
- package/server/dist/views/tag.js.map +1 -0
- package/server/prisma/migrations/20260331183000_0010_note_snapshot/migration.sql +13 -0
- package/server/prisma/migrations/20260331195000_0011_note_trash_entities/migration.sql +35 -0
- package/server/prisma/migrations/20260331213000_0012_image_hash_unique/migration.sql +49 -0
- package/server/prisma/migrations/20260404000000_0013_mcp_admin_control/migration.sql +9 -0
- package/server/prisma/schema.prisma +66 -1
- package/server/client/dist/assets/index-BJgBFWwL.css +0 -1
- package/server/client/dist/assets/index-DvNRv9YC.js +0 -391
- package/server/client/dist/assets/note-vendor-CUVHa9LU.js +0 -54
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { createAppError } from "../modules/error-handler.js";
|
|
2
|
+
import {
|
|
3
|
+
createNoteFromMarkdown,
|
|
4
|
+
InvalidNoteAuthoringInputError,
|
|
5
|
+
updateNoteFromMarkdown
|
|
6
|
+
} from "../modules/note-authoring.js";
|
|
7
|
+
import { deleteNoteById } from "../modules/note-cleanup.js";
|
|
8
|
+
import { MCP_SNAPSHOT_META } from "../modules/note-snapshot.js";
|
|
9
|
+
const NOTE_LAYOUTS = /* @__PURE__ */ new Set(["narrow", "wide", "full"]);
|
|
10
|
+
const resolveNoteLayout = (value) => {
|
|
11
|
+
if (value === void 0) {
|
|
12
|
+
return void 0;
|
|
13
|
+
}
|
|
14
|
+
if (typeof value === "string" && NOTE_LAYOUTS.has(value)) {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
};
|
|
19
|
+
const createMcpCreateNoteHandler = (createNote = createNoteFromMarkdown) => {
|
|
20
|
+
return async (req, res) => {
|
|
21
|
+
const { title, markdown, layout } = req.body ?? {};
|
|
22
|
+
const resolvedLayout = resolveNoteLayout(layout);
|
|
23
|
+
if (typeof title !== "string") {
|
|
24
|
+
throw createAppError(400, "INVALID_NOTE_TITLE", "A note title is required.");
|
|
25
|
+
}
|
|
26
|
+
if (markdown !== void 0 && typeof markdown !== "string") {
|
|
27
|
+
throw createAppError(400, "INVALID_NOTE_MARKDOWN", "Note markdown must be a string.");
|
|
28
|
+
}
|
|
29
|
+
if (layout !== void 0 && resolvedLayout === null) {
|
|
30
|
+
throw createAppError(400, "INVALID_NOTE_LAYOUT", "Note layout must be one of narrow, wide, or full.");
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const note = await createNote({
|
|
34
|
+
title,
|
|
35
|
+
...markdown !== void 0 ? { markdown } : {},
|
|
36
|
+
...resolvedLayout ? { layout: resolvedLayout } : {}
|
|
37
|
+
});
|
|
38
|
+
res.status(200).json({
|
|
39
|
+
created: true,
|
|
40
|
+
note
|
|
41
|
+
}).end();
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (error instanceof InvalidNoteAuthoringInputError) {
|
|
44
|
+
throw createAppError(400, "INVALID_NOTE_INPUT", error.message);
|
|
45
|
+
}
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
const createMcpUpdateNoteHandler = (updateNote = updateNoteFromMarkdown) => {
|
|
51
|
+
return async (req, res) => {
|
|
52
|
+
const {
|
|
53
|
+
id,
|
|
54
|
+
title,
|
|
55
|
+
markdown,
|
|
56
|
+
layout,
|
|
57
|
+
editSessionId
|
|
58
|
+
} = req.body ?? {};
|
|
59
|
+
const noteId = Number(id);
|
|
60
|
+
const resolvedLayout = resolveNoteLayout(layout);
|
|
61
|
+
if (!Number.isInteger(noteId) || noteId <= 0) {
|
|
62
|
+
throw createAppError(400, "INVALID_NOTE_ID", "A valid note id is required.");
|
|
63
|
+
}
|
|
64
|
+
if (title !== void 0 && typeof title !== "string") {
|
|
65
|
+
throw createAppError(400, "INVALID_NOTE_TITLE", "Note title must be a string.");
|
|
66
|
+
}
|
|
67
|
+
if (markdown !== void 0 && typeof markdown !== "string") {
|
|
68
|
+
throw createAppError(400, "INVALID_NOTE_MARKDOWN", "Note markdown must be a string.");
|
|
69
|
+
}
|
|
70
|
+
if (layout !== void 0 && resolvedLayout === null) {
|
|
71
|
+
throw createAppError(400, "INVALID_NOTE_LAYOUT", "Note layout must be one of narrow, wide, or full.");
|
|
72
|
+
}
|
|
73
|
+
if (editSessionId !== void 0 && typeof editSessionId !== "string") {
|
|
74
|
+
throw createAppError(400, "INVALID_EDIT_SESSION_ID", "Edit session id must be a string.");
|
|
75
|
+
}
|
|
76
|
+
if (title === void 0 && markdown === void 0 && layout === void 0) {
|
|
77
|
+
throw createAppError(400, "INVALID_NOTE_INPUT", "At least one note field must be provided for update.");
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const note = await updateNote({
|
|
81
|
+
id: noteId,
|
|
82
|
+
...title !== void 0 ? { title } : {},
|
|
83
|
+
...markdown !== void 0 ? { markdown } : {},
|
|
84
|
+
...resolvedLayout ? { layout: resolvedLayout } : {},
|
|
85
|
+
...editSessionId !== void 0 ? { editSessionId } : {},
|
|
86
|
+
snapshotMeta: MCP_SNAPSHOT_META
|
|
87
|
+
});
|
|
88
|
+
if (!note) {
|
|
89
|
+
throw createAppError(404, "NOTE_NOT_FOUND", "The requested note was not found.");
|
|
90
|
+
}
|
|
91
|
+
res.status(200).json({
|
|
92
|
+
updated: true,
|
|
93
|
+
note
|
|
94
|
+
}).end();
|
|
95
|
+
} catch (error) {
|
|
96
|
+
if (error instanceof InvalidNoteAuthoringInputError) {
|
|
97
|
+
throw createAppError(400, "INVALID_NOTE_INPUT", error.message);
|
|
98
|
+
}
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
const createMcpDeleteNoteHandler = (deleteNote = deleteNoteById) => {
|
|
104
|
+
return async (req, res) => {
|
|
105
|
+
const id = Number(req.body?.id);
|
|
106
|
+
if (!Number.isInteger(id) || id <= 0) {
|
|
107
|
+
throw createAppError(400, "INVALID_NOTE_ID", "A valid note id is required.");
|
|
108
|
+
}
|
|
109
|
+
const deletedNote = await deleteNote(id);
|
|
110
|
+
if (!deletedNote) {
|
|
111
|
+
throw createAppError(404, "NOTE_NOT_FOUND", "The requested note was not found.");
|
|
112
|
+
}
|
|
113
|
+
res.status(200).json({
|
|
114
|
+
deleted: true,
|
|
115
|
+
note: deletedNote
|
|
116
|
+
}).end();
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
export {
|
|
120
|
+
createMcpCreateNoteHandler,
|
|
121
|
+
createMcpDeleteNoteHandler,
|
|
122
|
+
createMcpUpdateNoteHandler
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=note.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/views/note.ts"],"sourcesContent":["import type { Controller } from '~/types/index.js';\nimport { createAppError } from '~/modules/error-handler.js';\nimport {\n createNoteFromMarkdown,\n InvalidNoteAuthoringInputError,\n updateNoteFromMarkdown\n} from '~/modules/note-authoring.js';\nimport { deleteNoteById } from '~/modules/note-cleanup.js';\nimport { MCP_SNAPSHOT_META } from '~/modules/note-snapshot.js';\nimport type { NoteLayout } from '~/models.js';\n\nconst NOTE_LAYOUTS = new Set<NoteLayout>(['narrow', 'wide', 'full']);\n\nconst resolveNoteLayout = (value: unknown): NoteLayout | null | undefined => {\n if (value === undefined) {\n return undefined;\n }\n\n if (typeof value === 'string' && NOTE_LAYOUTS.has(value as NoteLayout)) {\n return value as NoteLayout;\n }\n\n return null;\n};\n\nexport const createMcpCreateNoteHandler = (\n createNote = createNoteFromMarkdown\n): Controller => {\n return async (req, res) => {\n const { title, markdown, layout } = req.body ?? {};\n const resolvedLayout = resolveNoteLayout(layout);\n\n if (typeof title !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_TITLE', 'A note title is required.');\n }\n\n if (markdown !== undefined && typeof markdown !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_MARKDOWN', 'Note markdown must be a string.');\n }\n\n if (layout !== undefined && resolvedLayout === null) {\n throw createAppError(400, 'INVALID_NOTE_LAYOUT', 'Note layout must be one of narrow, wide, or full.');\n }\n\n try {\n const note = await createNote({\n title,\n ...(markdown !== undefined ? { markdown } : {}),\n ...(resolvedLayout ? { layout: resolvedLayout } : {})\n });\n\n res.status(200).json({\n created: true,\n note\n }).end();\n } catch (error) {\n if (error instanceof InvalidNoteAuthoringInputError) {\n throw createAppError(400, 'INVALID_NOTE_INPUT', error.message);\n }\n\n throw error;\n }\n };\n};\n\nexport const createMcpUpdateNoteHandler = (\n updateNote = updateNoteFromMarkdown\n): Controller => {\n return async (req, res) => {\n const {\n id, title, markdown, layout, editSessionId\n } = req.body ?? {};\n const noteId = Number(id);\n const resolvedLayout = resolveNoteLayout(layout);\n\n if (!Number.isInteger(noteId) || noteId <= 0) {\n throw createAppError(400, 'INVALID_NOTE_ID', 'A valid note id is required.');\n }\n\n if (title !== undefined && typeof title !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_TITLE', 'Note title must be a string.');\n }\n\n if (markdown !== undefined && typeof markdown !== 'string') {\n throw createAppError(400, 'INVALID_NOTE_MARKDOWN', 'Note markdown must be a string.');\n }\n\n if (layout !== undefined && resolvedLayout === null) {\n throw createAppError(400, 'INVALID_NOTE_LAYOUT', 'Note layout must be one of narrow, wide, or full.');\n }\n\n if (editSessionId !== undefined && typeof editSessionId !== 'string') {\n throw createAppError(400, 'INVALID_EDIT_SESSION_ID', 'Edit session id must be a string.');\n }\n\n if (\n title === undefined &&\n markdown === undefined &&\n layout === undefined\n ) {\n throw createAppError(400, 'INVALID_NOTE_INPUT', 'At least one note field must be provided for update.');\n }\n\n try {\n const note = await updateNote({\n id: noteId,\n ...(title !== undefined ? { title } : {}),\n ...(markdown !== undefined ? { markdown } : {}),\n ...(resolvedLayout ? { layout: resolvedLayout } : {}),\n ...(editSessionId !== undefined ? { editSessionId } : {}),\n snapshotMeta: MCP_SNAPSHOT_META\n });\n\n if (!note) {\n throw createAppError(404, 'NOTE_NOT_FOUND', 'The requested note was not found.');\n }\n\n res.status(200).json({\n updated: true,\n note\n }).end();\n } catch (error) {\n if (error instanceof InvalidNoteAuthoringInputError) {\n throw createAppError(400, 'INVALID_NOTE_INPUT', error.message);\n }\n\n throw error;\n }\n };\n};\n\nexport const createMcpDeleteNoteHandler = (\n deleteNote = deleteNoteById\n): Controller => {\n return async (req, res) => {\n const id = Number(req.body?.id);\n\n if (!Number.isInteger(id) || id <= 0) {\n throw createAppError(400, 'INVALID_NOTE_ID', 'A valid note id is required.');\n }\n\n const deletedNote = await deleteNote(id);\n\n if (!deletedNote) {\n throw createAppError(404, 'NOTE_NOT_FOUND', 'The requested note was not found.');\n }\n\n res.status(200).json({\n deleted: true,\n note: deletedNote\n }).end();\n };\n};\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createAppError } from "../modules/error-handler.js";
|
|
2
|
+
import { InvalidTagNameError, ensureTagByName } from "../modules/tag-organization.js";
|
|
3
|
+
const createMcpCreateTagHandler = (ensureTag = ensureTagByName) => {
|
|
4
|
+
return async (req, res) => {
|
|
5
|
+
const name = req.body?.name;
|
|
6
|
+
if (typeof name !== "string") {
|
|
7
|
+
throw createAppError(400, "INVALID_TAG_NAME", "A tag name is required.");
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
const result = await ensureTag(name);
|
|
11
|
+
res.status(200).json(result).end();
|
|
12
|
+
} catch (error) {
|
|
13
|
+
if (error instanceof InvalidTagNameError) {
|
|
14
|
+
throw createAppError(400, "INVALID_TAG_NAME", error.message);
|
|
15
|
+
}
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export {
|
|
21
|
+
createMcpCreateTagHandler
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=tag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/views/tag.ts"],"sourcesContent":["import type { Controller } from '~/types/index.js';\nimport { createAppError } from '~/modules/error-handler.js';\nimport { InvalidTagNameError, ensureTagByName } from '~/modules/tag-organization.js';\n\nexport const createMcpCreateTagHandler = (\n ensureTag = ensureTagByName\n): Controller => {\n return async (req, res) => {\n const name = req.body?.name;\n\n if (typeof name !== 'string') {\n throw createAppError(400, 'INVALID_TAG_NAME', 'A tag name is required.');\n }\n\n try {\n const result = await ensureTag(name);\n res.status(200).json(result).end();\n } catch (error) {\n if (error instanceof InvalidTagNameError) {\n throw createAppError(400, 'INVALID_TAG_NAME', error.message);\n }\n\n throw error;\n }\n };\n};\n"],"mappings":"AACA,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB,uBAAuB;AAE9C,MAAM,4BAA4B,CACrC,YAAY,oBACC;AACb,SAAO,OAAO,KAAK,QAAQ;AACvB,UAAM,OAAO,IAAI,MAAM;AAEvB,QAAI,OAAO,SAAS,UAAU;AAC1B,YAAM,eAAe,KAAK,oBAAoB,yBAAyB;AAAA,IAC3E;AAEA,QAAI;AACA,YAAM,SAAS,MAAM,UAAU,IAAI;AACnC,UAAI,OAAO,GAAG,EAAE,KAAK,MAAM,EAAE,IAAI;AAAA,IACrC,SAAS,OAAO;AACZ,UAAI,iBAAiB,qBAAqB;AACtC,cAAM,eAAe,KAAK,oBAAoB,MAAM,OAAO;AAAA,MAC/D;AAEA,YAAM;AAAA,IACV;AAAA,EACJ;AACJ;","names":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
CREATE TABLE "NoteSnapshot" (
|
|
2
|
+
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
3
|
+
"noteId" INTEGER NOT NULL,
|
|
4
|
+
"title" TEXT NOT NULL,
|
|
5
|
+
"payload" TEXT NOT NULL,
|
|
6
|
+
"editSessionId" TEXT,
|
|
7
|
+
"meta" TEXT,
|
|
8
|
+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
9
|
+
CONSTRAINT "NoteSnapshot_noteId_fkey" FOREIGN KEY ("noteId") REFERENCES "Note" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
CREATE INDEX "NoteSnapshot_noteId_createdAt_idx" ON "NoteSnapshot"("noteId", "createdAt");
|
|
13
|
+
CREATE UNIQUE INDEX "NoteSnapshot_noteId_editSessionId_key" ON "NoteSnapshot"("noteId", "editSessionId");
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
CREATE TABLE "DeletedNote" (
|
|
2
|
+
"id" INTEGER NOT NULL PRIMARY KEY,
|
|
3
|
+
"title" TEXT NOT NULL,
|
|
4
|
+
"content" TEXT NOT NULL,
|
|
5
|
+
"createdAt" DATETIME NOT NULL,
|
|
6
|
+
"updatedAt" DATETIME NOT NULL,
|
|
7
|
+
"deletedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
8
|
+
"pinned" BOOLEAN NOT NULL DEFAULT false,
|
|
9
|
+
"order" INTEGER NOT NULL DEFAULT 0,
|
|
10
|
+
"layout" TEXT NOT NULL DEFAULT 'wide'
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
CREATE TABLE "DeletedNoteTag" (
|
|
14
|
+
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
15
|
+
"deletedNoteId" INTEGER NOT NULL,
|
|
16
|
+
"name" TEXT NOT NULL,
|
|
17
|
+
CONSTRAINT "DeletedNoteTag_deletedNoteId_fkey" FOREIGN KEY ("deletedNoteId") REFERENCES "DeletedNote" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
CREATE TABLE "DeletedReminder" (
|
|
21
|
+
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
22
|
+
"deletedNoteId" INTEGER NOT NULL,
|
|
23
|
+
"originalId" INTEGER,
|
|
24
|
+
"reminderDate" DATETIME NOT NULL,
|
|
25
|
+
"completed" BOOLEAN NOT NULL DEFAULT false,
|
|
26
|
+
"priority" TEXT NOT NULL DEFAULT 'medium',
|
|
27
|
+
"content" TEXT,
|
|
28
|
+
"createdAt" DATETIME NOT NULL,
|
|
29
|
+
"updatedAt" DATETIME NOT NULL,
|
|
30
|
+
CONSTRAINT "DeletedReminder_deletedNoteId_fkey" FOREIGN KEY ("deletedNoteId") REFERENCES "DeletedNote" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
CREATE INDEX "DeletedNote_deletedAt_updatedAt_idx" ON "DeletedNote"("deletedAt", "updatedAt");
|
|
34
|
+
CREATE INDEX "DeletedNoteTag_deletedNoteId_idx" ON "DeletedNoteTag"("deletedNoteId");
|
|
35
|
+
CREATE INDEX "DeletedReminder_deletedNoteId_idx" ON "DeletedReminder"("deletedNoteId");
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
CREATE TEMP TABLE "_ImageDuplicateMap" AS
|
|
2
|
+
SELECT
|
|
3
|
+
duplicate."id" AS "duplicateId",
|
|
4
|
+
duplicate."url" AS "duplicateUrl",
|
|
5
|
+
canonical."id" AS "canonicalId",
|
|
6
|
+
canonical."url" AS "canonicalUrl",
|
|
7
|
+
ROW_NUMBER() OVER (ORDER BY duplicate."id") AS "position"
|
|
8
|
+
FROM "Image" AS duplicate
|
|
9
|
+
JOIN (
|
|
10
|
+
SELECT "hash", MIN("id") AS "canonicalId"
|
|
11
|
+
FROM "Image"
|
|
12
|
+
GROUP BY "hash"
|
|
13
|
+
) AS grouped
|
|
14
|
+
ON grouped."hash" = duplicate."hash"
|
|
15
|
+
JOIN "Image" AS canonical
|
|
16
|
+
ON canonical."id" = grouped."canonicalId"
|
|
17
|
+
WHERE duplicate."id" <> grouped."canonicalId";
|
|
18
|
+
|
|
19
|
+
WITH RECURSIVE "rewritten"("noteId", "position", "content") AS (
|
|
20
|
+
SELECT "id", 0, "content"
|
|
21
|
+
FROM "Note"
|
|
22
|
+
UNION ALL
|
|
23
|
+
SELECT
|
|
24
|
+
"rewritten"."noteId",
|
|
25
|
+
"_ImageDuplicateMap"."position",
|
|
26
|
+
replace("rewritten"."content", "_ImageDuplicateMap"."duplicateUrl", "_ImageDuplicateMap"."canonicalUrl")
|
|
27
|
+
FROM "rewritten"
|
|
28
|
+
JOIN "_ImageDuplicateMap"
|
|
29
|
+
ON "_ImageDuplicateMap"."position" = "rewritten"."position" + 1
|
|
30
|
+
)
|
|
31
|
+
UPDATE "Note"
|
|
32
|
+
SET "content" = (
|
|
33
|
+
SELECT "rewritten"."content"
|
|
34
|
+
FROM "rewritten"
|
|
35
|
+
WHERE "rewritten"."noteId" = "Note"."id"
|
|
36
|
+
ORDER BY "rewritten"."position" DESC
|
|
37
|
+
LIMIT 1
|
|
38
|
+
)
|
|
39
|
+
WHERE EXISTS (SELECT 1 FROM "_ImageDuplicateMap");
|
|
40
|
+
|
|
41
|
+
DELETE FROM "Image"
|
|
42
|
+
WHERE "id" IN (
|
|
43
|
+
SELECT "duplicateId"
|
|
44
|
+
FROM "_ImageDuplicateMap"
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
CREATE UNIQUE INDEX "Image_hash_key" ON "Image"("hash");
|
|
48
|
+
|
|
49
|
+
DROP TABLE "_ImageDuplicateMap";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
CREATE TABLE "McpToken" (
|
|
2
|
+
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
3
|
+
"tokenHash" TEXT NOT NULL,
|
|
4
|
+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
5
|
+
"lastUsedAt" DATETIME,
|
|
6
|
+
"revokedAt" DATETIME
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
CREATE INDEX "McpToken_revokedAt_createdAt_idx" ON "McpToken"("revokedAt", "createdAt");
|
|
@@ -15,6 +15,16 @@ model Cache {
|
|
|
15
15
|
updatedAt DateTime @updatedAt
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
model McpToken {
|
|
19
|
+
id Int @id @default(autoincrement())
|
|
20
|
+
tokenHash String
|
|
21
|
+
createdAt DateTime @default(now())
|
|
22
|
+
lastUsedAt DateTime?
|
|
23
|
+
revokedAt DateTime?
|
|
24
|
+
|
|
25
|
+
@@index([revokedAt, createdAt])
|
|
26
|
+
}
|
|
27
|
+
|
|
18
28
|
model Note {
|
|
19
29
|
id Int @id @default(autoincrement())
|
|
20
30
|
title String
|
|
@@ -26,12 +36,67 @@ model Note {
|
|
|
26
36
|
layout NoteLayout @default(wide)
|
|
27
37
|
tags Tag[] @relation("NoteToTag")
|
|
28
38
|
reminders Reminder[] @relation("NoteToReminder")
|
|
39
|
+
snapshots NoteSnapshot[]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
model NoteSnapshot {
|
|
43
|
+
id Int @id @default(autoincrement())
|
|
44
|
+
noteId Int
|
|
45
|
+
note Note @relation(fields: [noteId], references: [id], onDelete: Cascade)
|
|
46
|
+
title String
|
|
47
|
+
payload String
|
|
48
|
+
editSessionId String?
|
|
49
|
+
meta String?
|
|
50
|
+
createdAt DateTime @default(now())
|
|
51
|
+
|
|
52
|
+
@@index([noteId, createdAt])
|
|
53
|
+
@@unique([noteId, editSessionId])
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
model DeletedNote {
|
|
57
|
+
id Int @id
|
|
58
|
+
title String
|
|
59
|
+
content String
|
|
60
|
+
createdAt DateTime
|
|
61
|
+
updatedAt DateTime
|
|
62
|
+
deletedAt DateTime @default(now())
|
|
63
|
+
pinned Boolean @default(false)
|
|
64
|
+
order Int @default(0)
|
|
65
|
+
layout NoteLayout @default(wide)
|
|
66
|
+
tags DeletedNoteTag[]
|
|
67
|
+
reminders DeletedReminder[]
|
|
68
|
+
|
|
69
|
+
@@index([deletedAt, updatedAt])
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
model DeletedNoteTag {
|
|
73
|
+
id Int @id @default(autoincrement())
|
|
74
|
+
deletedNoteId Int
|
|
75
|
+
deletedNote DeletedNote @relation(fields: [deletedNoteId], references: [id], onDelete: Cascade)
|
|
76
|
+
name String
|
|
77
|
+
|
|
78
|
+
@@index([deletedNoteId])
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
model DeletedReminder {
|
|
82
|
+
id Int @id @default(autoincrement())
|
|
83
|
+
deletedNoteId Int
|
|
84
|
+
deletedNote DeletedNote @relation(fields: [deletedNoteId], references: [id], onDelete: Cascade)
|
|
85
|
+
originalId Int?
|
|
86
|
+
reminderDate DateTime
|
|
87
|
+
completed Boolean @default(false)
|
|
88
|
+
priority ReminderPriority @default(medium)
|
|
89
|
+
content String?
|
|
90
|
+
createdAt DateTime
|
|
91
|
+
updatedAt DateTime
|
|
92
|
+
|
|
93
|
+
@@index([deletedNoteId])
|
|
29
94
|
}
|
|
30
95
|
|
|
31
96
|
model Image {
|
|
32
97
|
id Int @id @default(autoincrement())
|
|
33
98
|
url String
|
|
34
|
-
hash String
|
|
99
|
+
hash String @unique
|
|
35
100
|
createdAt DateTime @default(now())
|
|
36
101
|
updatedAt DateTime @updatedAt
|
|
37
102
|
}
|