aimeat 1.25.0 → 1.26.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 (252) hide show
  1. package/README.md +8 -1
  2. package/dist/locales/en.json +144 -0
  3. package/dist/locales/fi.json +144 -0
  4. package/dist/public/components/ImageDeliverable.js +2 -1
  5. package/dist/public/components/Modal.js +3 -2
  6. package/dist/public/components/NotificationBell.js +2 -1
  7. package/dist/public/components/PresenceDot.js +53 -0
  8. package/dist/public/css/components/markdown.css +67 -0
  9. package/dist/public/css/theme.css +30 -0
  10. package/dist/public/css/views/notebook.css +195 -0
  11. package/dist/public/css/views/profile.css +15 -0
  12. package/dist/public/js/api.js +5 -3
  13. package/dist/public/js/components/auth-image.js +3 -2
  14. package/dist/public/js/components/tag-cloud.js +1 -1
  15. package/dist/public/js/components/tag-editor.js +1 -1
  16. package/dist/public/js/hooks.js +1 -2
  17. package/dist/public/js/presence-store.js +97 -0
  18. package/dist/public/js/services/admin.js +14 -5
  19. package/dist/public/js/services/boards.js +1 -1
  20. package/dist/public/js/services/ecosystem.js +1 -1
  21. package/dist/public/js/services/foundry-prompts-base.js +2 -2
  22. package/dist/public/js/services/foundry-smoke.js +2 -1
  23. package/dist/public/js/services/foundry-validate.js +6 -8
  24. package/dist/public/js/services/foundry.js +4 -3
  25. package/dist/public/js/services/generator-prompts-base.js +2 -2
  26. package/dist/public/js/services/generator-smoke.js +2 -1
  27. package/dist/public/js/services/generator-validate.js +5 -7
  28. package/dist/public/js/services/generator.js +2 -1
  29. package/dist/public/js/services/memory.js +13 -0
  30. package/dist/public/js/services/messages.js +2 -1
  31. package/dist/public/js/services/notebook.js +124 -0
  32. package/dist/public/js/services/packages.js +3 -2
  33. package/dist/public/js/services/presence.js +35 -0
  34. package/dist/public/js/style-testbed.js +6 -5
  35. package/dist/public/lib/minidenticons.min.js +1 -0
  36. package/dist/public/lib/yaml.mjs +1 -0
  37. package/dist/public/spa.html +90 -8
  38. package/dist/public/types/aimeat-globals.d.ts +52 -0
  39. package/dist/public/types/vendored-libs.d.ts +56 -0
  40. package/dist/public/views/_template.js +3 -1
  41. package/dist/public/views/admin/agent-integration-tab.js +4 -3
  42. package/dist/public/views/admin/agents-tab.js +3 -2
  43. package/dist/public/views/admin/config-tab.js +4 -3
  44. package/dist/public/views/admin/economy-tab.js +4 -3
  45. package/dist/public/views/admin/federation-tab.js +138 -1
  46. package/dist/public/views/admin/maintenance-tab.js +1 -1
  47. package/dist/public/views/admin/messages-tab.js +115 -0
  48. package/dist/public/views/admin/overview-tab.js +4 -3
  49. package/dist/public/views/admin/portal-tab.js +90 -2
  50. package/dist/public/views/admin/push-tab.js +8 -6
  51. package/dist/public/views/admin/security-tab.js +7 -7
  52. package/dist/public/views/admin.js +29 -9
  53. package/dist/public/views/doc-solo.js +3 -1
  54. package/dist/public/views/guides.js +8 -4
  55. package/dist/public/views/hobbies.js +4 -2
  56. package/dist/public/views/marketplace.js +10 -9
  57. package/dist/public/views/openclaw.js +1 -1
  58. package/dist/public/views/portal-dev.js +5 -2
  59. package/dist/public/views/portal.js +3 -2
  60. package/dist/public/views/profile/agents/shared-board.js +4 -2
  61. package/dist/public/views/profile/agents/tab-messages.js +13 -11
  62. package/dist/public/views/profile/agents-messages-subtab.js +2 -1
  63. package/dist/public/views/profile/apps-tab.js +2 -1
  64. package/dist/public/views/profile/boards-tab.js +3 -2
  65. package/dist/public/views/profile/calibrator-batch.js +3 -2
  66. package/dist/public/views/profile/data-wallet-tab.js +2 -1
  67. package/dist/public/views/profile/extensions-tab.js +4 -3
  68. package/dist/public/views/profile/federation-tab.js +4 -0
  69. package/dist/public/views/profile/foundry-dashboard/use-autopilot.js +3 -2
  70. package/dist/public/views/profile/foundry-detail.js +1 -1
  71. package/dist/public/views/profile/generator-detail.js +1 -1
  72. package/dist/public/views/profile/inbox-tab.js +7 -3
  73. package/dist/public/views/profile/inline-panels.js +3 -1
  74. package/dist/public/views/profile/knowledge-tab.js +2 -1
  75. package/dist/public/views/profile/landing-page.js +88 -0
  76. package/dist/public/views/profile/memory-tab.js +6 -5
  77. package/dist/public/views/profile/notebook-tab.js +500 -0
  78. package/dist/public/views/profile/organisms/activity-panel.js +135 -0
  79. package/dist/public/views/profile/organisms/agents.js +141 -0
  80. package/dist/public/views/profile/organisms/document.js +274 -0
  81. package/dist/public/views/profile/organisms/helpers.js +61 -0
  82. package/dist/public/views/profile/organisms/home.js +315 -0
  83. package/dist/public/views/profile/organisms/members.js +220 -0
  84. package/dist/public/views/profile/organisms/panels.js +173 -0
  85. package/dist/public/views/profile/organisms/participants-panel.js +160 -0
  86. package/dist/public/views/profile/organisms/schema-form.js +127 -0
  87. package/dist/public/views/profile/organisms/sources-panel.js +164 -0
  88. package/dist/public/views/profile/organisms/widgets.js +58 -0
  89. package/dist/public/views/profile/organisms/workspace-comments.js +99 -0
  90. package/dist/public/views/profile/organisms/workspace-list.js +268 -0
  91. package/dist/public/views/profile/organisms/workspace.js +1272 -0
  92. package/dist/public/views/profile/organisms-tab.js +456 -3819
  93. package/dist/public/views/profile/shared.js +64 -2
  94. package/dist/public/views/profile/workflows-form.js +1 -1
  95. package/dist/public/views/profile.js +16 -14
  96. package/dist/public/views/public-knowledge-viewer.js +3 -2
  97. package/dist/public/views/public-workspace-viewer.js +2 -1
  98. package/dist/scripts/check-importmap.d.ts +2 -0
  99. package/dist/scripts/check-importmap.d.ts.map +1 -0
  100. package/dist/scripts/check-importmap.js +102 -0
  101. package/dist/scripts/check-importmap.js.map +1 -0
  102. package/dist/src/cli/scaffold.d.ts +26 -3
  103. package/dist/src/cli/scaffold.d.ts.map +1 -1
  104. package/dist/src/cli/scaffold.js +33 -3
  105. package/dist/src/cli/scaffold.js.map +1 -1
  106. package/dist/src/config.d.ts +10 -0
  107. package/dist/src/config.d.ts.map +1 -1
  108. package/dist/src/config.js +5 -0
  109. package/dist/src/config.js.map +1 -1
  110. package/dist/src/generated/api-types.d.ts +927 -11
  111. package/dist/src/generated/api-types.d.ts.map +1 -1
  112. package/dist/src/generated/prisma-postgres/edge.js +32 -6
  113. package/dist/src/generated/prisma-postgres/index-browser.js +29 -3
  114. package/dist/src/generated/prisma-postgres/index.d.ts +1970 -160
  115. package/dist/src/generated/prisma-postgres/index.js +32 -6
  116. package/dist/src/generated/prisma-postgres/package.json +1 -1
  117. package/dist/src/generated/prisma-postgres/schema.prisma +45 -12
  118. package/dist/src/generated/prisma-postgres/wasm.js +32 -6
  119. package/dist/src/index.js +36 -4
  120. package/dist/src/index.js.map +1 -1
  121. package/dist/src/routes/admin-monitoring.d.ts.map +1 -1
  122. package/dist/src/routes/admin-monitoring.js +8 -0
  123. package/dist/src/routes/admin-monitoring.js.map +1 -1
  124. package/dist/src/routes/federation-peer.d.ts.map +1 -1
  125. package/dist/src/routes/federation-peer.js +327 -43
  126. package/dist/src/routes/federation-peer.js.map +1 -1
  127. package/dist/src/routes/federation-sync.d.ts +2 -0
  128. package/dist/src/routes/federation-sync.d.ts.map +1 -1
  129. package/dist/src/routes/federation-sync.js +20 -1
  130. package/dist/src/routes/federation-sync.js.map +1 -1
  131. package/dist/src/routes/librarian.d.ts +18 -0
  132. package/dist/src/routes/librarian.d.ts.map +1 -0
  133. package/dist/src/routes/librarian.js +88 -0
  134. package/dist/src/routes/librarian.js.map +1 -0
  135. package/dist/src/routes/messages.d.ts.map +1 -1
  136. package/dist/src/routes/messages.js +2 -1
  137. package/dist/src/routes/messages.js.map +1 -1
  138. package/dist/src/routes/portal.d.ts.map +1 -1
  139. package/dist/src/routes/portal.js +9 -1
  140. package/dist/src/routes/portal.js.map +1 -1
  141. package/dist/src/routes/presence.d.ts +23 -0
  142. package/dist/src/routes/presence.d.ts.map +1 -0
  143. package/dist/src/routes/presence.js +88 -0
  144. package/dist/src/routes/presence.js.map +1 -0
  145. package/dist/src/routes/site.d.ts +12 -0
  146. package/dist/src/routes/site.d.ts.map +1 -1
  147. package/dist/src/routes/site.js +45 -1
  148. package/dist/src/routes/site.js.map +1 -1
  149. package/dist/src/routes/sse.d.ts +2 -0
  150. package/dist/src/routes/sse.d.ts.map +1 -1
  151. package/dist/src/routes/sse.js +9 -0
  152. package/dist/src/routes/sse.js.map +1 -1
  153. package/dist/src/routes/wellknown.d.ts.map +1 -1
  154. package/dist/src/routes/wellknown.js +5 -0
  155. package/dist/src/routes/wellknown.js.map +1 -1
  156. package/dist/src/routes/work.d.ts.map +1 -1
  157. package/dist/src/routes/work.js +6 -0
  158. package/dist/src/routes/work.js.map +1 -1
  159. package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
  160. package/dist/src/server-bootstrap/routes-loader.js +13 -0
  161. package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
  162. package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
  163. package/dist/src/server-bootstrap/service-init.js +34 -0
  164. package/dist/src/server-bootstrap/service-init.js.map +1 -1
  165. package/dist/src/services/config-schema.d.ts.map +1 -1
  166. package/dist/src/services/config-schema.js +2 -0
  167. package/dist/src/services/config-schema.js.map +1 -1
  168. package/dist/src/services/federation-availability.d.ts +28 -0
  169. package/dist/src/services/federation-availability.d.ts.map +1 -0
  170. package/dist/src/services/federation-availability.js +58 -0
  171. package/dist/src/services/federation-availability.js.map +1 -0
  172. package/dist/src/services/federation-book.d.ts +70 -0
  173. package/dist/src/services/federation-book.d.ts.map +1 -0
  174. package/dist/src/services/federation-book.js +198 -0
  175. package/dist/src/services/federation-book.js.map +1 -0
  176. package/dist/src/services/federation-tiers.d.ts +45 -0
  177. package/dist/src/services/federation-tiers.d.ts.map +1 -0
  178. package/dist/src/services/federation-tiers.js +58 -0
  179. package/dist/src/services/federation-tiers.js.map +1 -0
  180. package/dist/src/services/federation.d.ts +15 -0
  181. package/dist/src/services/federation.d.ts.map +1 -1
  182. package/dist/src/services/federation.js +12 -0
  183. package/dist/src/services/federation.js.map +1 -1
  184. package/dist/src/services/librarian.d.ts +62 -0
  185. package/dist/src/services/librarian.d.ts.map +1 -0
  186. package/dist/src/services/librarian.js +135 -0
  187. package/dist/src/services/librarian.js.map +1 -0
  188. package/dist/src/services/message-delivery.d.ts +3 -1
  189. package/dist/src/services/message-delivery.d.ts.map +1 -1
  190. package/dist/src/services/message-delivery.js +23 -2
  191. package/dist/src/services/message-delivery.js.map +1 -1
  192. package/dist/src/services/network-policy.d.ts +88 -0
  193. package/dist/src/services/network-policy.d.ts.map +1 -0
  194. package/dist/src/services/network-policy.js +154 -0
  195. package/dist/src/services/network-policy.js.map +1 -0
  196. package/dist/src/services/notebook-classify-prompt.d.ts +15 -0
  197. package/dist/src/services/notebook-classify-prompt.d.ts.map +1 -0
  198. package/dist/src/services/notebook-classify-prompt.js +39 -0
  199. package/dist/src/services/notebook-classify-prompt.js.map +1 -0
  200. package/dist/src/services/notebook-classify.d.ts +80 -0
  201. package/dist/src/services/notebook-classify.d.ts.map +1 -0
  202. package/dist/src/services/notebook-classify.js +150 -0
  203. package/dist/src/services/notebook-classify.js.map +1 -0
  204. package/dist/src/services/presence.d.ts +108 -0
  205. package/dist/src/services/presence.d.ts.map +1 -0
  206. package/dist/src/services/presence.js +304 -0
  207. package/dist/src/services/presence.js.map +1 -0
  208. package/dist/src/services/prompt-defaults.d.ts.map +1 -1
  209. package/dist/src/services/prompt-defaults.js +13 -0
  210. package/dist/src/services/prompt-defaults.js.map +1 -1
  211. package/dist/src/services/site.d.ts +20 -0
  212. package/dist/src/services/site.d.ts.map +1 -1
  213. package/dist/src/services/site.js +70 -0
  214. package/dist/src/services/site.js.map +1 -1
  215. package/dist/src/storage/interface.d.ts +48 -0
  216. package/dist/src/storage/interface.d.ts.map +1 -1
  217. package/dist/src/storage/interface.js.map +1 -1
  218. package/dist/src/storage/providers/mongodb/index.d.ts +11 -1
  219. package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
  220. package/dist/src/storage/providers/mongodb/index.js +128 -2
  221. package/dist/src/storage/providers/mongodb/index.js.map +1 -1
  222. package/dist/src/storage/providers/sqlite/index.d.ts +7 -1
  223. package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
  224. package/dist/src/storage/providers/sqlite/index.js +27 -2
  225. package/dist/src/storage/providers/sqlite/index.js.map +1 -1
  226. package/dist/src/storage/providers/sqlite/repos/direct-message.d.ts +5 -1
  227. package/dist/src/storage/providers/sqlite/repos/direct-message.d.ts.map +1 -1
  228. package/dist/src/storage/providers/sqlite/repos/direct-message.js +48 -0
  229. package/dist/src/storage/providers/sqlite/repos/direct-message.js.map +1 -1
  230. package/dist/src/storage/providers/sqlite/repos/memory.d.ts +2 -0
  231. package/dist/src/storage/providers/sqlite/repos/memory.d.ts.map +1 -1
  232. package/dist/src/storage/providers/sqlite/repos/memory.js +55 -0
  233. package/dist/src/storage/providers/sqlite/repos/memory.js.map +1 -1
  234. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
  235. package/dist/src/storage/providers/sqlite/schema.js +61 -0
  236. package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
  237. package/dist/src/storage/repositories/direct-message.repository.d.ts +5 -1
  238. package/dist/src/storage/repositories/direct-message.repository.d.ts.map +1 -1
  239. package/dist/src/storage/repositories/memory.repository.d.ts +25 -0
  240. package/dist/src/storage/repositories/memory.repository.d.ts.map +1 -1
  241. package/dist/src/utils/node-descriptor.d.ts +34 -0
  242. package/dist/src/utils/node-descriptor.d.ts.map +1 -0
  243. package/dist/src/utils/node-descriptor.js +42 -0
  244. package/dist/src/utils/node-descriptor.js.map +1 -0
  245. package/dist/src/utils/version.d.ts +3 -0
  246. package/dist/src/utils/version.d.ts.map +1 -0
  247. package/dist/src/utils/version.js +40 -0
  248. package/dist/src/utils/version.js.map +1 -0
  249. package/dist/static/app-catalog.html +643 -4
  250. package/package.json +5 -2
  251. package/prisma/schema.postgres.prisma +51 -18
  252. package/prisma/schema.prisma +29 -0
@@ -507,6 +507,7 @@ export class PrismaStorage {
507
507
  version: record.version,
508
508
  flagCount: record.flagCount ?? 0,
509
509
  allowedOrigins: record.allowedOrigins ?? [],
510
+ searchBlob: this.buildSearchBlob(record),
510
511
  createdAt: new Date(record.createdAt),
511
512
  updatedAt: new Date(record.updatedAt),
512
513
  },
@@ -519,6 +520,7 @@ export class PrismaStorage {
519
520
  version: record.version,
520
521
  flagCount: record.flagCount ?? 0,
521
522
  allowedOrigins: record.allowedOrigins ?? [],
523
+ searchBlob: this.buildSearchBlob(record),
522
524
  updatedAt: new Date(record.updatedAt),
523
525
  },
524
526
  });
@@ -542,6 +544,7 @@ export class PrismaStorage {
542
544
  version: record.version,
543
545
  flagCount: record.flagCount ?? 0,
544
546
  allowedOrigins: record.allowedOrigins ?? [],
547
+ searchBlob: this.buildSearchBlob(record),
545
548
  updatedAt: new Date(record.updatedAt),
546
549
  },
547
550
  });
@@ -670,6 +673,57 @@ export class PrismaStorage {
670
673
  return true;
671
674
  });
672
675
  }
676
+ /** Flatten a record into searchable text: key + string/number leaves of value + tags. Indexed
677
+ * by the `searchBlob` `$text` index (created in init). Mirrors what SQLite FTS5 indexes. */
678
+ buildSearchBlob(record) {
679
+ const parts = [record.key, ...(record.tags ?? [])];
680
+ const collect = (v, depth) => {
681
+ if (depth > 6 || v == null)
682
+ return;
683
+ if (typeof v === 'string') {
684
+ if (v.trim())
685
+ parts.push(v);
686
+ }
687
+ else if (typeof v === 'number' || typeof v === 'boolean')
688
+ parts.push(String(v));
689
+ else if (Array.isArray(v))
690
+ for (const x of v)
691
+ collect(x, depth + 1);
692
+ else if (typeof v === 'object')
693
+ for (const x of Object.values(v))
694
+ collect(x, depth + 1);
695
+ };
696
+ collect(record.value, 0);
697
+ return parts.join(' \n ');
698
+ }
699
+ async searchText(query, opts) {
700
+ this.ensureReady();
701
+ const tokens = query.toLowerCase().match(/[\p{L}\p{N}]+/gu);
702
+ if (!tokens || tokens.length === 0)
703
+ return [];
704
+ const where = { OR: tokens.map(tok => ({ searchBlob: { contains: tok, mode: 'insensitive' } })) };
705
+ if (opts?.ownerGaiis?.length)
706
+ where.ownerGaii = { in: opts.ownerGaiis };
707
+ if (opts?.visibility)
708
+ where.visibility = opts.visibility;
709
+ if (opts?.keyPrefix)
710
+ where.key = { startsWith: opts.keyPrefix };
711
+ const limit = opts?.limit ?? 50;
712
+ const rows = await this.prisma.memory.findMany({ where, take: limit * 4 });
713
+ // Rank: more distinct tokens matched first, then most-recently updated. (No bm25 here; the
714
+ // librarian's value is finding the right records, and an AI rerank can follow — design §4.)
715
+ return rows
716
+ .filter(r => !r.ttlHours || Date.now() <= new Date(r.createdAt).getTime() + r.ttlHours * 3600_000)
717
+ .filter(r => opts?.maxFlags === undefined || (r.flagCount ?? 0) <= opts.maxFlags)
718
+ .map(r => {
719
+ const blob = String(r.searchBlob ?? '').toLowerCase();
720
+ const score = tokens.reduce((n, t) => n + (blob.includes(t) ? 1 : 0), 0);
721
+ return { record: this.toMemoryRecord(r), score, updatedAt: r.updatedAt };
722
+ })
723
+ .sort((a, b) => (b.score - a.score) || (b.updatedAt.getTime() - a.updatedAt.getTime()))
724
+ .slice(0, limit)
725
+ .map(({ record, score }) => ({ record, score }));
726
+ }
673
727
  // ── Actions ─────────────────────────────────────────────────
674
728
  async createAction(action) {
675
729
  this.ensureReady();
@@ -4570,8 +4624,8 @@ export class PrismaStorage {
4570
4624
  this.ensureReady();
4571
4625
  await this.prisma.federationPeer.upsert({
4572
4626
  where: { nodeId: peer.nodeId },
4573
- create: { nodeId: peer.nodeId, url: peer.url, publicKey: peer.publicKey, status: peer.status, addedAt: new Date(peer.addedAt), lastSeen: new Date(peer.lastSeen), shareCatalogue: peer.shareCatalogue, replicateMemory: peer.replicateMemory, allowRouting: peer.allowRouting, peerMode: peer.peerMode || 'federation', allowFederatedAuth: peer.allowFederatedAuth ?? false, federationAuthScopes: peer.federationAuthScopes ?? [] },
4574
- update: { url: peer.url, publicKey: peer.publicKey, status: peer.status, lastSeen: new Date(peer.lastSeen), shareCatalogue: peer.shareCatalogue, replicateMemory: peer.replicateMemory, allowRouting: peer.allowRouting, peerMode: peer.peerMode || 'federation', allowFederatedAuth: peer.allowFederatedAuth ?? false, federationAuthScopes: peer.federationAuthScopes ?? [] },
4627
+ create: { nodeId: peer.nodeId, url: peer.url, publicKey: peer.publicKey, status: peer.status, addedAt: new Date(peer.addedAt), lastSeen: new Date(peer.lastSeen), shareCatalogue: peer.shareCatalogue, replicateMemory: peer.replicateMemory, allowRouting: peer.allowRouting, peerMode: peer.peerMode || 'federation', allowFederatedAuth: peer.allowFederatedAuth ?? false, federationAuthScopes: peer.federationAuthScopes ?? [], tier: peer.tier ?? 'member', availability: peer.availability ?? null, expiresAt: peer.expiresAt ? new Date(peer.expiresAt) : null, heartbeatOk: peer.heartbeatOk ?? 0, heartbeatTotal: peer.heartbeatTotal ?? 0, availabilityWindow: peer.availabilityWindow ?? null, availabilityPct: peer.availabilityPct ?? null, softwareVersion: peer.softwareVersion ?? null, nodeCardHash: peer.nodeCardHash ?? null },
4628
+ update: { url: peer.url, publicKey: peer.publicKey, status: peer.status, lastSeen: new Date(peer.lastSeen), shareCatalogue: peer.shareCatalogue, replicateMemory: peer.replicateMemory, allowRouting: peer.allowRouting, peerMode: peer.peerMode || 'federation', allowFederatedAuth: peer.allowFederatedAuth ?? false, federationAuthScopes: peer.federationAuthScopes ?? [], tier: peer.tier ?? 'member', availability: peer.availability ?? null, expiresAt: peer.expiresAt ? new Date(peer.expiresAt) : null, heartbeatOk: peer.heartbeatOk ?? 0, heartbeatTotal: peer.heartbeatTotal ?? 0, availabilityWindow: peer.availabilityWindow ?? null, availabilityPct: peer.availabilityPct ?? null, softwareVersion: peer.softwareVersion ?? null, nodeCardHash: peer.nodeCardHash ?? null },
4575
4629
  });
4576
4630
  }
4577
4631
  async listFederationPeers() {
@@ -4590,6 +4644,15 @@ export class PrismaStorage {
4590
4644
  peerMode: r.peerMode || 'federation',
4591
4645
  allowFederatedAuth: r.allowFederatedAuth ?? false,
4592
4646
  federationAuthScopes: r.federationAuthScopes ?? [],
4647
+ tier: r.tier ?? 'member',
4648
+ availability: r.availability ?? null,
4649
+ expiresAt: r.expiresAt instanceof Date ? r.expiresAt.toISOString() : (r.expiresAt ?? null),
4650
+ heartbeatOk: r.heartbeatOk ?? 0,
4651
+ heartbeatTotal: r.heartbeatTotal ?? 0,
4652
+ availabilityWindow: r.availabilityWindow ?? null,
4653
+ availabilityPct: r.availabilityPct ?? null,
4654
+ softwareVersion: r.softwareVersion ?? null,
4655
+ nodeCardHash: r.nodeCardHash ?? null,
4593
4656
  }));
4594
4657
  }
4595
4658
  async deleteFederationPeer(nodeId) {
@@ -6996,6 +7059,69 @@ export class PrismaStorage {
6996
7059
  return false;
6997
7060
  }
6998
7061
  }
7062
+ async appendMessageDeliveryLog(log) {
7063
+ this.ensureReady();
7064
+ await this.prisma.messageDeliveryLog.create({
7065
+ data: {
7066
+ id: log.id, messageId: log.messageId, origin: log.origin, targetNodeId: log.targetNodeId,
7067
+ status: log.status, httpStatus: log.httpStatus ?? null, errorMessage: log.errorMessage ?? null,
7068
+ latencyMs: log.latencyMs, createdAt: new Date(log.createdAt),
7069
+ },
7070
+ });
7071
+ }
7072
+ toMessageDeliveryLog(row) {
7073
+ const rec = {
7074
+ id: row.id, messageId: row.messageId, origin: row.origin, targetNodeId: row.targetNodeId,
7075
+ status: row.status, latencyMs: row.latencyMs ?? 0,
7076
+ createdAt: row.createdAt instanceof Date ? row.createdAt.toISOString() : row.createdAt,
7077
+ };
7078
+ if (row.httpStatus != null)
7079
+ rec.httpStatus = row.httpStatus;
7080
+ if (row.errorMessage)
7081
+ rec.errorMessage = row.errorMessage;
7082
+ return rec;
7083
+ }
7084
+ async listMessageDeliveryLogs(limit = 100) {
7085
+ this.ensureReady();
7086
+ const rows = await this.prisma.messageDeliveryLog.findMany({ orderBy: { createdAt: 'desc' }, take: limit });
7087
+ return rows.map((r) => this.toMessageDeliveryLog(r));
7088
+ }
7089
+ async getMessageDeliveryStats() {
7090
+ this.ensureReady();
7091
+ const since = new Date(Date.now() - 24 * 3600_000);
7092
+ const [all, recent] = await Promise.all([
7093
+ this.prisma.messageDeliveryLog.groupBy({ by: ['status'], _count: { _all: true } }),
7094
+ this.prisma.messageDeliveryLog.groupBy({ by: ['status'], where: { createdAt: { gte: since } }, _count: { _all: true } }),
7095
+ ]);
7096
+ const byStatus = {};
7097
+ const byStatus24h = {};
7098
+ let total = 0, total24h = 0;
7099
+ for (const r of all) {
7100
+ byStatus[r.status] = r._count._all;
7101
+ total += r._count._all;
7102
+ }
7103
+ for (const r of recent) {
7104
+ byStatus24h[r.status] = r._count._all;
7105
+ total24h += r._count._all;
7106
+ }
7107
+ const nodes = await this.prisma.messageDeliveryLog.groupBy({ by: ['targetNodeId'], _count: { _all: true } });
7108
+ const topTargetNodes = await Promise.all(nodes.sort((a, b) => b._count._all - a._count._all).slice(0, 10).map(async (n) => ({
7109
+ nodeId: n.targetNodeId,
7110
+ total: n._count._all,
7111
+ failed: await this.prisma.messageDeliveryLog.count({ where: { targetNodeId: n.targetNodeId, status: { in: ['failed', 'undeliverable'] } } }),
7112
+ })));
7113
+ return { total, total24h, byStatus, byStatus24h, topTargetNodes };
7114
+ }
7115
+ async pruneMessageDeliveryLogs(keep = 10000) {
7116
+ this.ensureReady();
7117
+ const cutoff = await this.prisma.messageDeliveryLog.findMany({
7118
+ orderBy: { createdAt: 'desc' }, skip: keep, take: 1, select: { createdAt: true },
7119
+ });
7120
+ if (cutoff.length === 0)
7121
+ return 0;
7122
+ const res = await this.prisma.messageDeliveryLog.deleteMany({ where: { createdAt: { lt: cutoff[0].createdAt } } });
7123
+ return res.count;
7124
+ }
6999
7125
  async getContact(ownerGhii, contactId) {
7000
7126
  this.ensureReady();
7001
7127
  const row = await this.prisma.contactConsent.findUnique({ where: { id: this.contactDocId(ownerGhii, contactId) } });