mcpscraper-memory-db 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +40 -0
  2. package/dist/db/chat-link.d.ts +7 -0
  3. package/dist/db/chat-link.js +50 -0
  4. package/dist/db/chat-link.js.map +1 -0
  5. package/dist/db/facts.d.ts +60 -0
  6. package/dist/db/facts.js +186 -0
  7. package/dist/db/facts.js.map +1 -0
  8. package/dist/db/interlink-state.d.ts +34 -0
  9. package/dist/db/interlink-state.js +42 -0
  10. package/dist/db/interlink-state.js.map +1 -0
  11. package/dist/db/keys.d.ts +44 -0
  12. package/dist/db/keys.js +118 -0
  13. package/dist/db/keys.js.map +1 -0
  14. package/dist/db/messages.d.ts +77 -0
  15. package/dist/db/messages.js +198 -0
  16. package/dist/db/messages.js.map +1 -0
  17. package/dist/db/notes.d.ts +109 -0
  18. package/dist/db/notes.js +249 -0
  19. package/dist/db/notes.js.map +1 -0
  20. package/dist/db/pool.d.ts +7 -0
  21. package/dist/db/pool.js +37 -0
  22. package/dist/db/pool.js.map +1 -0
  23. package/dist/db/presence.d.ts +4 -0
  24. package/dist/db/presence.js +25 -0
  25. package/dist/db/presence.js.map +1 -0
  26. package/dist/db/props-snapshots.d.ts +18 -0
  27. package/dist/db/props-snapshots.js +37 -0
  28. package/dist/db/props-snapshots.js.map +1 -0
  29. package/dist/db/provenance.d.ts +26 -0
  30. package/dist/db/provenance.js +43 -0
  31. package/dist/db/provenance.js.map +1 -0
  32. package/dist/db/schedule-entitlements.d.ts +24 -0
  33. package/dist/db/schedule-entitlements.js +70 -0
  34. package/dist/db/schedule-entitlements.js.map +1 -0
  35. package/dist/db/schedule-link.d.ts +7 -0
  36. package/dist/db/schedule-link.js +50 -0
  37. package/dist/db/schedule-link.js.map +1 -0
  38. package/dist/db/scheduled-actions.d.ts +58 -0
  39. package/dist/db/scheduled-actions.js +139 -0
  40. package/dist/db/scheduled-actions.js.map +1 -0
  41. package/dist/db/schema.d.ts +3 -0
  42. package/dist/db/schema.js +340 -0
  43. package/dist/db/schema.js.map +1 -0
  44. package/dist/db/secure-notes.d.ts +26 -0
  45. package/dist/db/secure-notes.js +59 -0
  46. package/dist/db/secure-notes.js.map +1 -0
  47. package/dist/db/shares.d.ts +45 -0
  48. package/dist/db/shares.js +141 -0
  49. package/dist/db/shares.js.map +1 -0
  50. package/dist/db/tables.d.ts +50 -0
  51. package/dist/db/tables.js +226 -0
  52. package/dist/db/tables.js.map +1 -0
  53. package/dist/db/trust.d.ts +10 -0
  54. package/dist/db/trust.js +88 -0
  55. package/dist/db/trust.js.map +1 -0
  56. package/dist/db/usage.d.ts +30 -0
  57. package/dist/db/usage.js +106 -0
  58. package/dist/db/usage.js.map +1 -0
  59. package/dist/db/vaults.d.ts +98 -0
  60. package/dist/db/vaults.js +316 -0
  61. package/dist/db/vaults.js.map +1 -0
  62. package/dist/db/video-runs.d.ts +70 -0
  63. package/dist/db/video-runs.js +176 -0
  64. package/dist/db/video-runs.js.map +1 -0
  65. package/dist/db/webhooks.d.ts +20 -0
  66. package/dist/db/webhooks.js +43 -0
  67. package/dist/db/webhooks.js.map +1 -0
  68. package/dist/lib/auth.d.ts +75 -0
  69. package/dist/lib/auth.js +248 -0
  70. package/dist/lib/auth.js.map +1 -0
  71. package/dist/lib/cost-rates.d.ts +19 -0
  72. package/dist/lib/cost-rates.js +36 -0
  73. package/dist/lib/cost-rates.js.map +1 -0
  74. package/dist/lib/credit-debit.d.ts +15 -0
  75. package/dist/lib/credit-debit.js +21 -0
  76. package/dist/lib/credit-debit.js.map +1 -0
  77. package/dist/lib/operator.d.ts +5 -0
  78. package/dist/lib/operator.js +14 -0
  79. package/dist/lib/operator.js.map +1 -0
  80. package/dist/lib/schedule-cadence.d.ts +6 -0
  81. package/dist/lib/schedule-cadence.js +66 -0
  82. package/dist/lib/schedule-cadence.js.map +1 -0
  83. package/dist/lib/secret-crypto.d.ts +4 -0
  84. package/dist/lib/secret-crypto.js +28 -0
  85. package/dist/lib/secret-crypto.js.map +1 -0
  86. package/dist/lib/vault-contracts.d.ts +18 -0
  87. package/dist/lib/vault-contracts.js +248 -0
  88. package/dist/lib/vault-contracts.js.map +1 -0
  89. package/dist/lib/video-reaper.d.ts +13 -0
  90. package/dist/lib/video-reaper.js +19 -0
  91. package/dist/lib/video-reaper.js.map +1 -0
  92. package/dist/rag/embedder.d.ts +6 -0
  93. package/dist/rag/embedder.js +93 -0
  94. package/dist/rag/embedder.js.map +1 -0
  95. package/dist/rag/index-pipeline.d.ts +22 -0
  96. package/dist/rag/index-pipeline.js +62 -0
  97. package/dist/rag/index-pipeline.js.map +1 -0
  98. package/dist/rag/query-tool.d.ts +47 -0
  99. package/dist/rag/query-tool.js +47 -0
  100. package/dist/rag/query-tool.js.map +1 -0
  101. package/dist/rag/vector-store.d.ts +7 -0
  102. package/dist/rag/vector-store.js +25 -0
  103. package/dist/rag/vector-store.js.map +1 -0
  104. package/package.json +47 -0
@@ -0,0 +1,77 @@
1
+ import { NoteRecord } from './notes.js';
2
+ export { noteId as messageNoteId } from './notes.js';
3
+
4
+ interface AttachedNoteRef {
5
+ noteId: string;
6
+ srcVault: string;
7
+ srcPath: string;
8
+ title: string;
9
+ ownerIdentity: string;
10
+ }
11
+ declare function postMessageRow(args: {
12
+ vault: string;
13
+ content: string;
14
+ authorIdentity: string;
15
+ attachedNote?: AttachedNoteRef;
16
+ }): Promise<NoteRecord>;
17
+ declare function replyMessageRow(args: {
18
+ vault: string;
19
+ parentMessageId: string;
20
+ content: string;
21
+ authorIdentity: string;
22
+ attachedNote?: AttachedNoteRef;
23
+ }): Promise<NoteRecord>;
24
+ interface ThreadSummary {
25
+ replyCount: number;
26
+ lastReplyAt: string | null;
27
+ }
28
+ declare function listTopLevelMessages(vault: string): Promise<NoteRecord[]>;
29
+ declare function listThreadReplies(vault: string, parentMessageId: string): Promise<NoteRecord[]>;
30
+ declare function threadSummaries(vault: string): Promise<Map<string, ThreadSummary>>;
31
+ declare function markRead(messageId: string, identity: string): Promise<void>;
32
+ interface ReadReceipt {
33
+ identity: string;
34
+ readAt: string;
35
+ }
36
+ declare function readReceiptsFor(messageIds: string[]): Promise<Map<string, ReadReceipt[]>>;
37
+ declare function recordMentions(args: {
38
+ messageId: string;
39
+ ownerIdentity: string;
40
+ vault: string;
41
+ mentions: string[];
42
+ }): Promise<void>;
43
+ interface MentionRow {
44
+ messageId: string;
45
+ ownerIdentity: string;
46
+ vault: string;
47
+ createdAt: string;
48
+ }
49
+ declare function mentionsFor(identity: string, limit: number): Promise<MentionRow[]>;
50
+ declare function toggleReaction(args: {
51
+ messageId: string;
52
+ identity: string;
53
+ emoji: string;
54
+ remove?: boolean;
55
+ }): Promise<void>;
56
+ interface Reaction {
57
+ identity: string;
58
+ emoji: string;
59
+ }
60
+ declare function reactionsFor(messageIds: string[]): Promise<Map<string, Reaction[]>>;
61
+ declare function getCursor(identity: string, vault: string): Promise<string>;
62
+ declare function advanceCursor(identity: string, vault: string): Promise<string>;
63
+ declare function topLevelMessagesSince(vault: string, since: string): Promise<NoteRecord[]>;
64
+ interface ReplySince {
65
+ note: NoteRecord;
66
+ parentMessageId: string;
67
+ }
68
+ declare function repliesSince(vault: string, since: string): Promise<ReplySince[]>;
69
+ interface ReactionSince {
70
+ messageId: string;
71
+ identity: string;
72
+ emoji: string;
73
+ createdAt: string;
74
+ }
75
+ declare function reactionsSince(vault: string, since: string): Promise<ReactionSince[]>;
76
+
77
+ export { type AttachedNoteRef, type MentionRow, type Reaction, type ReactionSince, type ReadReceipt, type ReplySince, type ThreadSummary, advanceCursor, getCursor, listThreadReplies, listTopLevelMessages, markRead, mentionsFor, postMessageRow, reactionsFor, reactionsSince, readReceiptsFor, recordMentions, repliesSince, replyMessageRow, threadSummaries, toggleReaction, topLevelMessagesSince };
@@ -0,0 +1,198 @@
1
+ import { ensureSchema, query } from "./pool";
2
+ import { putNoteRow, noteId, mapNote, NOTE_COLUMNS } from "./notes";
3
+ function messagePath() {
4
+ return `msg/${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
5
+ }
6
+ async function postMessageRow(args) {
7
+ return putNoteRow({
8
+ vault: args.vault,
9
+ path: messagePath(),
10
+ content: args.content,
11
+ kind: "message",
12
+ source: "message",
13
+ props: args.attachedNote ? { attachedNote: args.attachedNote } : void 0,
14
+ updatedBy: args.authorIdentity
15
+ });
16
+ }
17
+ async function replyMessageRow(args) {
18
+ return putNoteRow({
19
+ vault: args.vault,
20
+ path: messagePath(),
21
+ content: args.content,
22
+ kind: "message",
23
+ source: "message",
24
+ props: { parentMessageId: args.parentMessageId, ...args.attachedNote ? { attachedNote: args.attachedNote } : {} },
25
+ updatedBy: args.authorIdentity
26
+ });
27
+ }
28
+ async function listTopLevelMessages(vault) {
29
+ await ensureSchema();
30
+ const res = await query(
31
+ `SELECT ${NOTE_COLUMNS}
32
+ FROM mem_notes WHERE vault = $1 AND kind = 'message' AND (props->>'parentMessageId') IS NULL
33
+ ORDER BY captured_at ASC`,
34
+ [vault]
35
+ );
36
+ return res.rows.map(mapNote);
37
+ }
38
+ async function listThreadReplies(vault, parentMessageId) {
39
+ await ensureSchema();
40
+ const res = await query(
41
+ `SELECT ${NOTE_COLUMNS}
42
+ FROM mem_notes WHERE vault = $1 AND kind = 'message' AND props->>'parentMessageId' = $2
43
+ ORDER BY captured_at ASC`,
44
+ [vault, parentMessageId]
45
+ );
46
+ return res.rows.map(mapNote);
47
+ }
48
+ async function threadSummaries(vault) {
49
+ await ensureSchema();
50
+ const res = await query(
51
+ `SELECT props->>'parentMessageId' AS parent, COUNT(*)::int AS reply_count, MAX(captured_at) AS last_reply_at
52
+ FROM mem_notes WHERE vault = $1 AND kind = 'message' AND props->>'parentMessageId' IS NOT NULL
53
+ GROUP BY props->>'parentMessageId'`,
54
+ [vault]
55
+ );
56
+ const out = /* @__PURE__ */ new Map();
57
+ for (const r of res.rows) out.set(r.parent, { replyCount: Number(r.reply_count), lastReplyAt: r.last_reply_at });
58
+ return out;
59
+ }
60
+ async function markRead(messageId, identity) {
61
+ await ensureSchema();
62
+ await query(
63
+ `INSERT INTO mem_message_reads (message_id, identity, read_at) VALUES ($1, $2, now())
64
+ ON CONFLICT (message_id, identity) DO NOTHING`,
65
+ [messageId, identity]
66
+ );
67
+ }
68
+ async function readReceiptsFor(messageIds) {
69
+ await ensureSchema();
70
+ if (messageIds.length === 0) return /* @__PURE__ */ new Map();
71
+ const res = await query(
72
+ `SELECT message_id, identity, read_at FROM mem_message_reads WHERE message_id = ANY($1) ORDER BY read_at ASC`,
73
+ [messageIds]
74
+ );
75
+ const out = /* @__PURE__ */ new Map();
76
+ for (const r of res.rows) {
77
+ const list = out.get(r.message_id) ?? [];
78
+ list.push({ identity: r.identity, readAt: r.read_at });
79
+ out.set(r.message_id, list);
80
+ }
81
+ return out;
82
+ }
83
+ async function recordMentions(args) {
84
+ if (args.mentions.length === 0) return;
85
+ await ensureSchema();
86
+ await Promise.all(
87
+ args.mentions.map(
88
+ (mentioned) => query(
89
+ `INSERT INTO mem_mentions (message_id, owner_identity, vault, mentioned) VALUES ($1, $2, $3, $4)`,
90
+ [args.messageId, args.ownerIdentity, args.vault, mentioned]
91
+ )
92
+ )
93
+ );
94
+ }
95
+ async function mentionsFor(identity, limit) {
96
+ await ensureSchema();
97
+ const res = await query(
98
+ `SELECT message_id, owner_identity, vault, created_at FROM mem_mentions WHERE mentioned = $1 ORDER BY created_at DESC LIMIT $2`,
99
+ [identity, limit]
100
+ );
101
+ return res.rows.map((r) => ({ messageId: r.message_id, ownerIdentity: r.owner_identity, vault: r.vault, createdAt: r.created_at }));
102
+ }
103
+ async function toggleReaction(args) {
104
+ await ensureSchema();
105
+ if (args.remove) {
106
+ await query(`DELETE FROM mem_message_reactions WHERE message_id = $1 AND identity = $2 AND emoji = $3`, [args.messageId, args.identity, args.emoji]);
107
+ } else {
108
+ await query(
109
+ `INSERT INTO mem_message_reactions (message_id, identity, emoji) VALUES ($1, $2, $3) ON CONFLICT (message_id, identity, emoji) DO NOTHING`,
110
+ [args.messageId, args.identity, args.emoji]
111
+ );
112
+ }
113
+ }
114
+ async function reactionsFor(messageIds) {
115
+ await ensureSchema();
116
+ if (messageIds.length === 0) return /* @__PURE__ */ new Map();
117
+ const res = await query(
118
+ `SELECT message_id, identity, emoji FROM mem_message_reactions WHERE message_id = ANY($1) ORDER BY created_at ASC`,
119
+ [messageIds]
120
+ );
121
+ const out = /* @__PURE__ */ new Map();
122
+ for (const r of res.rows) {
123
+ const list = out.get(r.message_id) ?? [];
124
+ list.push({ identity: r.identity, emoji: r.emoji });
125
+ out.set(r.message_id, list);
126
+ }
127
+ return out;
128
+ }
129
+ const EPOCH = "1970-01-01T00:00:00.000Z";
130
+ async function getCursor(identity, vault) {
131
+ await ensureSchema();
132
+ const res = await query(
133
+ `SELECT last_polled_at FROM mem_channel_cursor WHERE identity = $1 AND vault = $2 LIMIT 1`,
134
+ [identity, vault]
135
+ );
136
+ return res.rows[0]?.last_polled_at ?? EPOCH;
137
+ }
138
+ async function advanceCursor(identity, vault) {
139
+ await ensureSchema();
140
+ const res = await query(
141
+ `INSERT INTO mem_channel_cursor (identity, vault, last_polled_at) VALUES ($1, $2, now())
142
+ ON CONFLICT (identity, vault) DO UPDATE SET last_polled_at = now()
143
+ RETURNING last_polled_at`,
144
+ [identity, vault]
145
+ );
146
+ return res.rows[0].last_polled_at;
147
+ }
148
+ async function topLevelMessagesSince(vault, since) {
149
+ await ensureSchema();
150
+ const res = await query(
151
+ `SELECT ${NOTE_COLUMNS}
152
+ FROM mem_notes WHERE vault = $1 AND kind = 'message' AND (props->>'parentMessageId') IS NULL AND captured_at > $2::timestamptz
153
+ ORDER BY captured_at ASC`,
154
+ [vault, since]
155
+ );
156
+ return res.rows.map(mapNote);
157
+ }
158
+ async function repliesSince(vault, since) {
159
+ await ensureSchema();
160
+ const res = await query(
161
+ `SELECT ${NOTE_COLUMNS}
162
+ FROM mem_notes WHERE vault = $1 AND kind = 'message' AND (props->>'parentMessageId') IS NOT NULL AND captured_at > $2::timestamptz
163
+ ORDER BY captured_at ASC`,
164
+ [vault, since]
165
+ );
166
+ return res.rows.map((r) => ({ note: mapNote(r), parentMessageId: String(r.props?.parentMessageId ?? "") }));
167
+ }
168
+ async function reactionsSince(vault, since) {
169
+ await ensureSchema();
170
+ const res = await query(
171
+ `SELECT n.path, r.identity, r.emoji, r.created_at
172
+ FROM mem_message_reactions r JOIN mem_notes n ON n.id = r.message_id
173
+ WHERE n.vault = $1 AND r.created_at > $2::timestamptz
174
+ ORDER BY r.created_at ASC`,
175
+ [vault, since]
176
+ );
177
+ return res.rows.map((r) => ({ messageId: r.path, identity: r.identity, emoji: r.emoji, createdAt: r.created_at }));
178
+ }
179
+ export {
180
+ advanceCursor,
181
+ getCursor,
182
+ listThreadReplies,
183
+ listTopLevelMessages,
184
+ markRead,
185
+ mentionsFor,
186
+ noteId as messageNoteId,
187
+ postMessageRow,
188
+ reactionsFor,
189
+ reactionsSince,
190
+ readReceiptsFor,
191
+ recordMentions,
192
+ repliesSince,
193
+ replyMessageRow,
194
+ threadSummaries,
195
+ toggleReaction,
196
+ topLevelMessagesSince
197
+ };
198
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/db/messages.ts"],"sourcesContent":["import { ensureSchema, query } from './pool'\nimport { putNoteRow, noteId, mapNote, NOTE_COLUMNS, type NoteRecord, type RawNoteRow } from './notes'\n\nfunction messagePath(): string {\n return `msg/${new Date().toISOString().replace(/[:.]/g, '-')}`\n}\n\nexport interface AttachedNoteRef {\n noteId: string\n srcVault: string\n srcPath: string\n title: string\n ownerIdentity: string\n}\n\nexport async function postMessageRow(args: {\n vault: string\n content: string\n authorIdentity: string\n attachedNote?: AttachedNoteRef\n}): Promise<NoteRecord> {\n return putNoteRow({\n vault: args.vault,\n path: messagePath(),\n content: args.content,\n kind: 'message',\n source: 'message',\n props: args.attachedNote ? { attachedNote: args.attachedNote } : undefined,\n updatedBy: args.authorIdentity,\n })\n}\n\nexport async function replyMessageRow(args: {\n vault: string\n parentMessageId: string\n content: string\n authorIdentity: string\n attachedNote?: AttachedNoteRef\n}): Promise<NoteRecord> {\n return putNoteRow({\n vault: args.vault,\n path: messagePath(),\n content: args.content,\n kind: 'message',\n source: 'message',\n props: { parentMessageId: args.parentMessageId, ...(args.attachedNote ? { attachedNote: args.attachedNote } : {}) },\n updatedBy: args.authorIdentity,\n })\n}\n\nexport interface ThreadSummary {\n replyCount: number\n lastReplyAt: string | null\n}\n\nexport async function listTopLevelMessages(vault: string): Promise<NoteRecord[]> {\n await ensureSchema()\n const res = await query<RawNoteRow>(\n `SELECT ${NOTE_COLUMNS}\n FROM mem_notes WHERE vault = $1 AND kind = 'message' AND (props->>'parentMessageId') IS NULL\n ORDER BY captured_at ASC`,\n [vault],\n )\n return res.rows.map(mapNote)\n}\n\nexport async function listThreadReplies(vault: string, parentMessageId: string): Promise<NoteRecord[]> {\n await ensureSchema()\n const res = await query<RawNoteRow>(\n `SELECT ${NOTE_COLUMNS}\n FROM mem_notes WHERE vault = $1 AND kind = 'message' AND props->>'parentMessageId' = $2\n ORDER BY captured_at ASC`,\n [vault, parentMessageId],\n )\n return res.rows.map(mapNote)\n}\n\nexport async function threadSummaries(vault: string): Promise<Map<string, ThreadSummary>> {\n await ensureSchema()\n const res = await query<{ parent: string; reply_count: string; last_reply_at: string }>(\n `SELECT props->>'parentMessageId' AS parent, COUNT(*)::int AS reply_count, MAX(captured_at) AS last_reply_at\n FROM mem_notes WHERE vault = $1 AND kind = 'message' AND props->>'parentMessageId' IS NOT NULL\n GROUP BY props->>'parentMessageId'`,\n [vault],\n )\n const out = new Map<string, ThreadSummary>()\n for (const r of res.rows) out.set(r.parent, { replyCount: Number(r.reply_count), lastReplyAt: r.last_reply_at })\n return out\n}\n\nexport async function markRead(messageId: string, identity: string): Promise<void> {\n await ensureSchema()\n await query(\n `INSERT INTO mem_message_reads (message_id, identity, read_at) VALUES ($1, $2, now())\n ON CONFLICT (message_id, identity) DO NOTHING`,\n [messageId, identity],\n )\n}\n\nexport interface ReadReceipt {\n identity: string\n readAt: string\n}\n\nexport async function readReceiptsFor(messageIds: string[]): Promise<Map<string, ReadReceipt[]>> {\n await ensureSchema()\n if (messageIds.length === 0) return new Map()\n const res = await query<{ message_id: string; identity: string; read_at: string }>(\n `SELECT message_id, identity, read_at FROM mem_message_reads WHERE message_id = ANY($1) ORDER BY read_at ASC`,\n [messageIds],\n )\n const out = new Map<string, ReadReceipt[]>()\n for (const r of res.rows) {\n const list = out.get(r.message_id) ?? []\n list.push({ identity: r.identity, readAt: r.read_at })\n out.set(r.message_id, list)\n }\n return out\n}\n\nexport async function recordMentions(args: { messageId: string; ownerIdentity: string; vault: string; mentions: string[] }): Promise<void> {\n if (args.mentions.length === 0) return\n await ensureSchema()\n await Promise.all(\n args.mentions.map(mentioned =>\n query(\n `INSERT INTO mem_mentions (message_id, owner_identity, vault, mentioned) VALUES ($1, $2, $3, $4)`,\n [args.messageId, args.ownerIdentity, args.vault, mentioned],\n ),\n ),\n )\n}\n\nexport interface MentionRow {\n messageId: string\n ownerIdentity: string\n vault: string\n createdAt: string\n}\n\nexport async function mentionsFor(identity: string, limit: number): Promise<MentionRow[]> {\n await ensureSchema()\n const res = await query<{ message_id: string; owner_identity: string; vault: string; created_at: string }>(\n `SELECT message_id, owner_identity, vault, created_at FROM mem_mentions WHERE mentioned = $1 ORDER BY created_at DESC LIMIT $2`,\n [identity, limit],\n )\n return res.rows.map(r => ({ messageId: r.message_id, ownerIdentity: r.owner_identity, vault: r.vault, createdAt: r.created_at }))\n}\n\nexport async function toggleReaction(args: { messageId: string; identity: string; emoji: string; remove?: boolean }): Promise<void> {\n await ensureSchema()\n if (args.remove) {\n await query(`DELETE FROM mem_message_reactions WHERE message_id = $1 AND identity = $2 AND emoji = $3`, [args.messageId, args.identity, args.emoji])\n } else {\n await query(\n `INSERT INTO mem_message_reactions (message_id, identity, emoji) VALUES ($1, $2, $3) ON CONFLICT (message_id, identity, emoji) DO NOTHING`,\n [args.messageId, args.identity, args.emoji],\n )\n }\n}\n\nexport interface Reaction {\n identity: string\n emoji: string\n}\n\nexport async function reactionsFor(messageIds: string[]): Promise<Map<string, Reaction[]>> {\n await ensureSchema()\n if (messageIds.length === 0) return new Map()\n const res = await query<{ message_id: string; identity: string; emoji: string }>(\n `SELECT message_id, identity, emoji FROM mem_message_reactions WHERE message_id = ANY($1) ORDER BY created_at ASC`,\n [messageIds],\n )\n const out = new Map<string, Reaction[]>()\n for (const r of res.rows) {\n const list = out.get(r.message_id) ?? []\n list.push({ identity: r.identity, emoji: r.emoji })\n out.set(r.message_id, list)\n }\n return out\n}\n\nconst EPOCH = '1970-01-01T00:00:00.000Z'\n\nexport async function getCursor(identity: string, vault: string): Promise<string> {\n await ensureSchema()\n const res = await query<{ last_polled_at: string }>(\n `SELECT last_polled_at FROM mem_channel_cursor WHERE identity = $1 AND vault = $2 LIMIT 1`,\n [identity, vault],\n )\n return res.rows[0]?.last_polled_at ?? EPOCH\n}\n\nexport async function advanceCursor(identity: string, vault: string): Promise<string> {\n await ensureSchema()\n const res = await query<{ last_polled_at: string }>(\n `INSERT INTO mem_channel_cursor (identity, vault, last_polled_at) VALUES ($1, $2, now())\n ON CONFLICT (identity, vault) DO UPDATE SET last_polled_at = now()\n RETURNING last_polled_at`,\n [identity, vault],\n )\n return res.rows[0].last_polled_at\n}\n\nexport async function topLevelMessagesSince(vault: string, since: string): Promise<NoteRecord[]> {\n await ensureSchema()\n const res = await query<RawNoteRow>(\n `SELECT ${NOTE_COLUMNS}\n FROM mem_notes WHERE vault = $1 AND kind = 'message' AND (props->>'parentMessageId') IS NULL AND captured_at > $2::timestamptz\n ORDER BY captured_at ASC`,\n [vault, since],\n )\n return res.rows.map(mapNote)\n}\n\nexport interface ReplySince {\n note: NoteRecord\n parentMessageId: string\n}\n\nexport async function repliesSince(vault: string, since: string): Promise<ReplySince[]> {\n await ensureSchema()\n const res = await query<RawNoteRow>(\n `SELECT ${NOTE_COLUMNS}\n FROM mem_notes WHERE vault = $1 AND kind = 'message' AND (props->>'parentMessageId') IS NOT NULL AND captured_at > $2::timestamptz\n ORDER BY captured_at ASC`,\n [vault, since],\n )\n return res.rows.map(r => ({ note: mapNote(r), parentMessageId: String((r.props as Record<string, unknown> | null)?.parentMessageId ?? '') }))\n}\n\nexport interface ReactionSince {\n messageId: string\n identity: string\n emoji: string\n createdAt: string\n}\n\nexport async function reactionsSince(vault: string, since: string): Promise<ReactionSince[]> {\n await ensureSchema()\n const res = await query<{ path: string; identity: string; emoji: string; created_at: string }>(\n `SELECT n.path, r.identity, r.emoji, r.created_at\n FROM mem_message_reactions r JOIN mem_notes n ON n.id = r.message_id\n WHERE n.vault = $1 AND r.created_at > $2::timestamptz\n ORDER BY r.created_at ASC`,\n [vault, since],\n )\n return res.rows.map(r => ({ messageId: r.path, identity: r.identity, emoji: r.emoji, createdAt: r.created_at }))\n}\n\nexport { noteId as messageNoteId }\n"],"mappings":"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","names":[]}
@@ -0,0 +1,109 @@
1
+ type NoteKind = 'note' | 'library' | 'capture' | 'decision' | 'message';
2
+ type NoteProps = Record<string, unknown>;
3
+ interface NoteRecord {
4
+ id: string;
5
+ vault: string;
6
+ path: string;
7
+ title: string;
8
+ content: string;
9
+ kind: NoteKind;
10
+ source: string;
11
+ props: NoteProps;
12
+ capturedAt: string;
13
+ createdAt: string;
14
+ updatedAt: string;
15
+ revision: number;
16
+ updatedBy: string | null;
17
+ }
18
+ interface RawNoteRow {
19
+ id: string;
20
+ vault: string;
21
+ path: string;
22
+ title: string;
23
+ content: string;
24
+ kind: string;
25
+ source: string;
26
+ props: unknown;
27
+ captured_at: string;
28
+ created_at: string;
29
+ updated_at: string;
30
+ revision: number;
31
+ updated_by: string | null;
32
+ }
33
+ declare function noteId(vault: string, path: string): string;
34
+ declare function mapNote(r: RawNoteRow): NoteRecord;
35
+ declare const NOTE_COLUMNS = "id, vault, path, title, content, kind, source, props, captured_at, created_at, updated_at, revision, updated_by";
36
+ interface PutNoteArgs {
37
+ vault: string;
38
+ path: string;
39
+ title?: string;
40
+ content: string;
41
+ kind?: NoteKind;
42
+ source?: string;
43
+ props?: NoteProps;
44
+ capturedAt?: string;
45
+ updatedBy?: string;
46
+ }
47
+ declare function putNoteRow(args: PutNoteArgs): Promise<NoteRecord>;
48
+ type PutNoteCheckedResult = {
49
+ ok: true;
50
+ note: NoteRecord;
51
+ } | {
52
+ ok: false;
53
+ conflict: true;
54
+ current: NoteRecord;
55
+ };
56
+ declare function putNoteRowChecked(args: PutNoteArgs & {
57
+ baseRevision: number;
58
+ }): Promise<PutNoteCheckedResult>;
59
+ declare function getNoteRow(vault: string, path: string): Promise<NoteRecord | null>;
60
+ declare function getNoteById(id: string): Promise<NoteRecord | null>;
61
+ declare function listNoteRows(vault: string, kind?: NoteKind, tags?: string[]): Promise<NoteRecord[]>;
62
+ declare function listAllNoteRows(): Promise<NoteRecord[]>;
63
+ declare function resolveNoteRefs(vault: string, refs: string[]): Promise<Map<string, NoteRecord>>;
64
+ declare function exportVaultRows(vault: string): Promise<NoteRecord[]>;
65
+ declare function captureRow(args: {
66
+ vault: string;
67
+ content: string;
68
+ source: string;
69
+ capturedAt?: string;
70
+ title?: string;
71
+ folder?: string;
72
+ props?: NoteProps;
73
+ }): Promise<NoteRecord>;
74
+ declare function deleteNoteRow(vault: string, path: string): Promise<{
75
+ deleted: boolean;
76
+ }>;
77
+ type DeleteNoteCheckedResult = {
78
+ ok: true;
79
+ deleted: boolean;
80
+ } | {
81
+ ok: false;
82
+ conflict: true;
83
+ current: NoteRecord;
84
+ };
85
+ declare function deleteNoteRowChecked(vault: string, path: string, baseRevision: number): Promise<DeleteNoteCheckedResult>;
86
+ declare function deleteNotesForVault(vault: string): Promise<number>;
87
+ interface VaultStorageResult {
88
+ perVault: {
89
+ vault: string;
90
+ bytes: number;
91
+ notes: number;
92
+ }[];
93
+ totalBytes: number;
94
+ }
95
+ declare function vaultStorage(vaults?: string[]): Promise<VaultStorageResult>;
96
+ declare function listCapturesInRange(args: {
97
+ vault: string;
98
+ from: string;
99
+ to: string;
100
+ }): Promise<NoteRecord[]>;
101
+ interface SuggestHit {
102
+ vault: string;
103
+ path: string;
104
+ title: string;
105
+ kind: NoteKind;
106
+ }
107
+ declare function suggestNotesAcrossVaults(vaults: string[], prefix: string, limit: number): Promise<SuggestHit[]>;
108
+
109
+ export { type DeleteNoteCheckedResult, NOTE_COLUMNS, type NoteKind, type NoteProps, type NoteRecord, type PutNoteArgs, type PutNoteCheckedResult, type RawNoteRow, type SuggestHit, type VaultStorageResult, captureRow, deleteNoteRow, deleteNoteRowChecked, deleteNotesForVault, exportVaultRows, getNoteById, getNoteRow, listAllNoteRows, listCapturesInRange, listNoteRows, mapNote, noteId, putNoteRow, putNoteRowChecked, resolveNoteRefs, suggestNotesAcrossVaults, vaultStorage };
@@ -0,0 +1,249 @@
1
+ import { ensureSchema, query } from "./pool";
2
+ import { removeDocument } from "../rag/index-pipeline";
3
+ import { EMBED_DIM } from "../rag/embedder";
4
+ import { INDEX_NAME } from "../rag/vector-store";
5
+ const EMBED_BYTES_PER_CHUNK = EMBED_DIM * 4;
6
+ function noteId(vault, path) {
7
+ return `${vault}::${path}`;
8
+ }
9
+ function mapNote(r) {
10
+ return {
11
+ id: r.id,
12
+ vault: r.vault,
13
+ path: r.path,
14
+ title: r.title,
15
+ content: r.content,
16
+ kind: r.kind,
17
+ source: r.source,
18
+ props: r.props && typeof r.props === "object" ? r.props : {},
19
+ capturedAt: r.captured_at,
20
+ createdAt: r.created_at,
21
+ updatedAt: r.updated_at,
22
+ revision: r.revision,
23
+ updatedBy: r.updated_by
24
+ };
25
+ }
26
+ const NOTE_COLUMNS = "id, vault, path, title, content, kind, source, props, captured_at, created_at, updated_at, revision, updated_by";
27
+ async function putNoteRow(args) {
28
+ await ensureSchema();
29
+ const id = noteId(args.vault, args.path);
30
+ const res = await query(
31
+ `INSERT INTO mem_notes (id, vault, path, title, content, kind, source, props, captured_at, updated_at, revision, updated_by)
32
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, COALESCE($9::timestamptz, now()), now(), 1, $10)
33
+ ON CONFLICT (vault, path) DO UPDATE SET
34
+ title = EXCLUDED.title, content = EXCLUDED.content, kind = EXCLUDED.kind,
35
+ source = EXCLUDED.source, props = EXCLUDED.props, captured_at = EXCLUDED.captured_at,
36
+ updated_at = now(), revision = mem_notes.revision + 1, updated_by = EXCLUDED.updated_by
37
+ RETURNING ${NOTE_COLUMNS}`,
38
+ [id, args.vault, args.path, args.title ?? args.path, args.content, args.kind ?? "note", args.source ?? "", JSON.stringify(args.props ?? {}), args.capturedAt ?? null, args.updatedBy ?? null]
39
+ );
40
+ return mapNote(res.rows[0]);
41
+ }
42
+ async function putNoteRowChecked(args) {
43
+ await ensureSchema();
44
+ const id = noteId(args.vault, args.path);
45
+ const res = await query(
46
+ `INSERT INTO mem_notes (id, vault, path, title, content, kind, source, props, captured_at, updated_at, revision, updated_by)
47
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, COALESCE($9::timestamptz, now()), now(), 1, $10)
48
+ ON CONFLICT (vault, path) DO UPDATE SET
49
+ title = EXCLUDED.title, content = EXCLUDED.content, kind = EXCLUDED.kind,
50
+ source = EXCLUDED.source, props = EXCLUDED.props, captured_at = EXCLUDED.captured_at,
51
+ updated_at = now(), revision = mem_notes.revision + 1, updated_by = EXCLUDED.updated_by
52
+ WHERE mem_notes.revision = $11
53
+ RETURNING ${NOTE_COLUMNS}`,
54
+ [id, args.vault, args.path, args.title ?? args.path, args.content, args.kind ?? "note", args.source ?? "", JSON.stringify(args.props ?? {}), args.capturedAt ?? null, args.updatedBy ?? null, args.baseRevision]
55
+ );
56
+ if (res.rows[0]) return { ok: true, note: mapNote(res.rows[0]) };
57
+ const current = await getNoteRow(args.vault, args.path);
58
+ if (!current) return { ok: true, note: await putNoteRow(args) };
59
+ return { ok: false, conflict: true, current };
60
+ }
61
+ async function getNoteRow(vault, path) {
62
+ await ensureSchema();
63
+ const res = await query(
64
+ `SELECT ${NOTE_COLUMNS} FROM mem_notes WHERE vault = $1 AND path = $2 LIMIT 1`,
65
+ [vault, path]
66
+ );
67
+ return res.rows[0] ? mapNote(res.rows[0]) : null;
68
+ }
69
+ async function getNoteById(id) {
70
+ await ensureSchema();
71
+ const res = await query(`SELECT ${NOTE_COLUMNS} FROM mem_notes WHERE id = $1 LIMIT 1`, [id]);
72
+ return res.rows[0] ? mapNote(res.rows[0]) : null;
73
+ }
74
+ async function listNoteRows(vault, kind, tags) {
75
+ await ensureSchema();
76
+ const params = [vault];
77
+ let where = "vault = $1";
78
+ if (kind) {
79
+ params.push(kind);
80
+ where += ` AND kind = $${params.length}`;
81
+ }
82
+ if (tags && tags.length > 0) {
83
+ params.push(JSON.stringify(tags));
84
+ where += ` AND (props->'tags')::jsonb ?| ARRAY(SELECT jsonb_array_elements_text($${params.length}::jsonb))`;
85
+ }
86
+ const res = await query(
87
+ `SELECT ${NOTE_COLUMNS}
88
+ FROM mem_notes WHERE ${where} ORDER BY updated_at DESC`,
89
+ params
90
+ );
91
+ return res.rows.map(mapNote);
92
+ }
93
+ async function listAllNoteRows() {
94
+ await ensureSchema();
95
+ const res = await query(
96
+ `SELECT ${NOTE_COLUMNS} FROM mem_notes ORDER BY vault ASC, updated_at DESC`
97
+ );
98
+ return res.rows.map(mapNote);
99
+ }
100
+ async function resolveNoteRefs(vault, refs) {
101
+ const notes = await listNoteRows(vault);
102
+ const byPath = new Map(notes.map((n) => [n.path, n]));
103
+ const byTitle = new Map(notes.map((n) => [n.title.toLowerCase(), n]));
104
+ const resolved = /* @__PURE__ */ new Map();
105
+ for (const ref of refs) {
106
+ const note = byPath.get(ref) ?? byTitle.get(ref.toLowerCase());
107
+ if (note) resolved.set(ref, note);
108
+ }
109
+ return resolved;
110
+ }
111
+ async function exportVaultRows(vault) {
112
+ return listNoteRows(vault);
113
+ }
114
+ async function captureRow(args) {
115
+ const stamp = args.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
116
+ const base = `captures/${stamp.replace(/[:.]/g, "-")}`;
117
+ const path = args.folder ? `${args.folder}/${base}` : base;
118
+ return putNoteRow({
119
+ vault: args.vault,
120
+ path,
121
+ title: args.title ?? `Capture ${stamp}`,
122
+ content: args.content,
123
+ kind: "capture",
124
+ source: args.source,
125
+ props: args.props,
126
+ capturedAt: stamp
127
+ });
128
+ }
129
+ async function deleteNoteRow(vault, path) {
130
+ await ensureSchema();
131
+ const res = await query(`DELETE FROM mem_notes WHERE vault = $1 AND path = $2`, [vault, path]);
132
+ const deleted = (res.rowCount ?? 0) > 0;
133
+ if (deleted) {
134
+ try {
135
+ await removeDocument({ vault, id: noteId(vault, path) });
136
+ } catch {
137
+ }
138
+ }
139
+ return { deleted };
140
+ }
141
+ async function deleteNoteRowChecked(vault, path, baseRevision) {
142
+ await ensureSchema();
143
+ const res = await query(`DELETE FROM mem_notes WHERE vault = $1 AND path = $2 AND revision = $3`, [vault, path, baseRevision]);
144
+ if ((res.rowCount ?? 0) > 0) {
145
+ try {
146
+ await removeDocument({ vault, id: noteId(vault, path) });
147
+ } catch {
148
+ }
149
+ return { ok: true, deleted: true };
150
+ }
151
+ const current = await getNoteRow(vault, path);
152
+ if (!current) return { ok: true, deleted: false };
153
+ return { ok: false, conflict: true, current };
154
+ }
155
+ async function deleteNotesForVault(vault) {
156
+ await ensureSchema();
157
+ const res = await query(`DELETE FROM mem_notes WHERE vault = $1`, [vault]);
158
+ return res.rowCount ?? 0;
159
+ }
160
+ async function vaultStorage(vaults) {
161
+ if (vaults && vaults.length === 0) return { perVault: [], totalBytes: 0 };
162
+ await ensureSchema();
163
+ const params = [];
164
+ let where = "";
165
+ if (vaults && vaults.length > 0) {
166
+ params.push(vaults);
167
+ where = `WHERE vault = ANY($1)`;
168
+ }
169
+ const res = await query(
170
+ `SELECT vault, COUNT(*)::int AS notes, COALESCE(SUM(octet_length(content)), 0)::bigint AS bytes
171
+ FROM mem_notes ${where} GROUP BY vault ORDER BY vault ASC`,
172
+ params
173
+ );
174
+ const embedChunks = await embedChunksByVault(vaults);
175
+ const perVault = res.rows.map((r) => {
176
+ const contentBytes = Number(r.bytes);
177
+ const embedBytes = (embedChunks.get(r.vault) ?? 0) * EMBED_BYTES_PER_CHUNK;
178
+ return { vault: r.vault, bytes: contentBytes + embedBytes, notes: Number(r.notes) };
179
+ });
180
+ const totalBytes = perVault.reduce((sum, v) => sum + v.bytes, 0);
181
+ return { perVault, totalBytes };
182
+ }
183
+ async function embedChunksByVault(vaults) {
184
+ const out = /* @__PURE__ */ new Map();
185
+ if (vaults && vaults.length === 0) return out;
186
+ const params = [];
187
+ let where = "";
188
+ if (vaults && vaults.length > 0) {
189
+ params.push(vaults);
190
+ where = `WHERE metadata->>'vault' = ANY($1)`;
191
+ }
192
+ try {
193
+ const res = await query(
194
+ `SELECT metadata->>'vault' AS vault, COUNT(*)::bigint AS chunks
195
+ FROM "${INDEX_NAME}" ${where} GROUP BY 1`,
196
+ params
197
+ );
198
+ for (const r of res.rows) if (r.vault) out.set(r.vault, Number(r.chunks));
199
+ } catch {
200
+ return out;
201
+ }
202
+ return out;
203
+ }
204
+ async function listCapturesInRange(args) {
205
+ await ensureSchema();
206
+ const res = await query(
207
+ `SELECT ${NOTE_COLUMNS}
208
+ FROM mem_notes
209
+ WHERE vault = $1 AND captured_at >= $2::timestamptz AND captured_at <= $3::timestamptz
210
+ ORDER BY captured_at DESC`,
211
+ [args.vault, args.from, args.to]
212
+ );
213
+ return res.rows.map(mapNote);
214
+ }
215
+ async function suggestNotesAcrossVaults(vaults, prefix, limit) {
216
+ await ensureSchema();
217
+ if (vaults.length === 0 || !prefix.trim()) return [];
218
+ const res = await query(
219
+ `SELECT vault, path, title, kind,
220
+ CASE WHEN title ILIKE $2 || '%' THEN 0 ELSE 1 END AS rank
221
+ FROM mem_notes
222
+ WHERE vault = ANY($1) AND kind != 'message' AND title ILIKE '%' || $2 || '%'
223
+ ORDER BY rank ASC, updated_at DESC
224
+ LIMIT $3`,
225
+ [vaults, prefix.trim(), limit]
226
+ );
227
+ return res.rows.map((r) => ({ vault: r.vault, path: r.path, title: r.title, kind: r.kind }));
228
+ }
229
+ export {
230
+ NOTE_COLUMNS,
231
+ captureRow,
232
+ deleteNoteRow,
233
+ deleteNoteRowChecked,
234
+ deleteNotesForVault,
235
+ exportVaultRows,
236
+ getNoteById,
237
+ getNoteRow,
238
+ listAllNoteRows,
239
+ listCapturesInRange,
240
+ listNoteRows,
241
+ mapNote,
242
+ noteId,
243
+ putNoteRow,
244
+ putNoteRowChecked,
245
+ resolveNoteRefs,
246
+ suggestNotesAcrossVaults,
247
+ vaultStorage
248
+ };
249
+ //# sourceMappingURL=notes.js.map