@de-otio/trellis 0.7.1 → 0.10.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 (1252) hide show
  1. package/LICENSE +661 -0
  2. package/dist/db.js +10 -18
  3. package/dist/db.js.map +1 -1
  4. package/dist/env.d.ts +66 -6
  5. package/dist/env.d.ts.map +1 -1
  6. package/dist/env.js +89 -70
  7. package/dist/env.js.map +1 -1
  8. package/dist/extensions.js +3 -8
  9. package/dist/extensions.js.map +1 -1
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +2 -9
  13. package/dist/index.js.map +1 -1
  14. package/dist/lambda/cleanup-cron.d.ts.map +1 -1
  15. package/dist/lambda/cleanup-cron.js +20 -24
  16. package/dist/lambda/cleanup-cron.js.map +1 -1
  17. package/dist/lambda/create-auth-challenge.d.ts.map +1 -1
  18. package/dist/lambda/create-auth-challenge.js +17 -19
  19. package/dist/lambda/create-auth-challenge.js.map +1 -1
  20. package/dist/lambda/custom-message.js +1 -5
  21. package/dist/lambda/custom-message.js.map +1 -1
  22. package/dist/lambda/define-auth-challenge.js +1 -5
  23. package/dist/lambda/define-auth-challenge.js.map +1 -1
  24. package/dist/lambda/delete-account-worker.d.ts.map +1 -1
  25. package/dist/lambda/delete-account-worker.js +25 -58
  26. package/dist/lambda/delete-account-worker.js.map +1 -1
  27. package/dist/lambda/diagnostics-proxy.d.ts.map +1 -1
  28. package/dist/lambda/diagnostics-proxy.js +14 -49
  29. package/dist/lambda/diagnostics-proxy.js.map +1 -1
  30. package/dist/lambda/e2e-sweeper.d.ts.map +1 -1
  31. package/dist/lambda/e2e-sweeper.js +30 -38
  32. package/dist/lambda/e2e-sweeper.js.map +1 -1
  33. package/dist/lambda/federation-outbox-worker.d.ts.map +1 -1
  34. package/dist/lambda/federation-outbox-worker.js +4 -6
  35. package/dist/lambda/federation-outbox-worker.js.map +1 -1
  36. package/dist/lambda/followers-events-worker.d.ts.map +1 -1
  37. package/dist/lambda/followers-events-worker.js +4 -6
  38. package/dist/lambda/followers-events-worker.js.map +1 -1
  39. package/dist/lambda/hourly-cron.d.ts.map +1 -1
  40. package/dist/lambda/hourly-cron.js +100 -32
  41. package/dist/lambda/hourly-cron.js.map +1 -1
  42. package/dist/lambda/link-check-worker.d.ts.map +1 -1
  43. package/dist/lambda/link-check-worker.js +4 -6
  44. package/dist/lambda/link-check-worker.js.map +1 -1
  45. package/dist/lambda/maintenance-cron.d.ts.map +1 -1
  46. package/dist/lambda/maintenance-cron.js +30 -63
  47. package/dist/lambda/maintenance-cron.js.map +1 -1
  48. package/dist/lambda/media-processing-worker.d.ts.map +1 -1
  49. package/dist/lambda/media-processing-worker.js +11 -46
  50. package/dist/lambda/media-processing-worker.js.map +1 -1
  51. package/dist/lambda/media-reconciliation-worker.d.ts.map +1 -1
  52. package/dist/lambda/media-reconciliation-worker.js +4 -6
  53. package/dist/lambda/media-reconciliation-worker.js.map +1 -1
  54. package/dist/lambda/nightly-cron.d.ts.map +1 -1
  55. package/dist/lambda/nightly-cron.js +67 -112
  56. package/dist/lambda/nightly-cron.js.map +1 -1
  57. package/dist/lambda/post-confirmation.d.ts.map +1 -1
  58. package/dist/lambda/post-confirmation.js +203 -47
  59. package/dist/lambda/post-confirmation.js.map +1 -1
  60. package/dist/lambda/pre-signup.js +7 -11
  61. package/dist/lambda/pre-signup.js.map +1 -1
  62. package/dist/lambda/pre-token-generation.d.ts.map +1 -1
  63. package/dist/lambda/pre-token-generation.js +27 -35
  64. package/dist/lambda/pre-token-generation.js.map +1 -1
  65. package/dist/lambda/tools/check-health.js +1 -5
  66. package/dist/lambda/tools/check-health.js.map +1 -1
  67. package/dist/lambda/tools/describe-services.js +4 -8
  68. package/dist/lambda/tools/describe-services.js.map +1 -1
  69. package/dist/lambda/tools/get-cost-report.js +4 -8
  70. package/dist/lambda/tools/get-cost-report.js.map +1 -1
  71. package/dist/lambda/tools/get-errors.js +5 -9
  72. package/dist/lambda/tools/get-errors.js.map +1 -1
  73. package/dist/lambda/tools/get-feature-flags.js +4 -8
  74. package/dist/lambda/tools/get-feature-flags.js.map +1 -1
  75. package/dist/lambda/tools/get-queue-status.js +5 -9
  76. package/dist/lambda/tools/get-queue-status.js.map +1 -1
  77. package/dist/lambda/tools/search-logs.js +5 -9
  78. package/dist/lambda/tools/search-logs.js.map +1 -1
  79. package/dist/lambda/tools/send-alert.js +4 -8
  80. package/dist/lambda/tools/send-alert.js.map +1 -1
  81. package/dist/lambda/verify-auth-challenge.d.ts.map +1 -1
  82. package/dist/lambda/verify-auth-challenge.js +10 -12
  83. package/dist/lambda/verify-auth-challenge.js.map +1 -1
  84. package/dist/lib/abuse-metrics.d.ts.map +1 -1
  85. package/dist/lib/abuse-metrics.js +10 -13
  86. package/dist/lib/abuse-metrics.js.map +1 -1
  87. package/dist/lib/activitypub/activity-processor.d.ts +1 -1
  88. package/dist/lib/activitypub/activity-processor.d.ts.map +1 -1
  89. package/dist/lib/activitypub/activity-processor.js +9 -43
  90. package/dist/lib/activitypub/activity-processor.js.map +1 -1
  91. package/dist/lib/activitypub/activity-service.js +1 -5
  92. package/dist/lib/activitypub/activity-service.js.map +1 -1
  93. package/dist/lib/activitypub/actor.d.ts +1 -1
  94. package/dist/lib/activitypub/actor.d.ts.map +1 -1
  95. package/dist/lib/activitypub/actor.js +1 -5
  96. package/dist/lib/activitypub/actor.js.map +1 -1
  97. package/dist/lib/activitypub/audience-service.d.ts +2 -2
  98. package/dist/lib/activitypub/audience-service.d.ts.map +1 -1
  99. package/dist/lib/activitypub/audience-service.js +8 -12
  100. package/dist/lib/activitypub/audience-service.js.map +1 -1
  101. package/dist/lib/activitypub/crypto.d.ts +1 -1
  102. package/dist/lib/activitypub/crypto.d.ts.map +1 -1
  103. package/dist/lib/activitypub/crypto.js +3 -41
  104. package/dist/lib/activitypub/crypto.js.map +1 -1
  105. package/dist/lib/activitypub/delivery-service.d.ts +5 -5
  106. package/dist/lib/activitypub/delivery-service.d.ts.map +1 -1
  107. package/dist/lib/activitypub/delivery-service.js +10 -47
  108. package/dist/lib/activitypub/delivery-service.js.map +1 -1
  109. package/dist/lib/activitypub/dispatchers/entity-actor.d.ts +3 -2
  110. package/dist/lib/activitypub/dispatchers/entity-actor.d.ts.map +1 -1
  111. package/dist/lib/activitypub/dispatchers/entity-actor.js +19 -23
  112. package/dist/lib/activitypub/dispatchers/entity-actor.js.map +1 -1
  113. package/dist/lib/activitypub/dispatchers/group-actor.d.ts +3 -2
  114. package/dist/lib/activitypub/dispatchers/group-actor.d.ts.map +1 -1
  115. package/dist/lib/activitypub/dispatchers/group-actor.js +19 -23
  116. package/dist/lib/activitypub/dispatchers/group-actor.js.map +1 -1
  117. package/dist/lib/activitypub/dispatchers/user-actor.d.ts +3 -2
  118. package/dist/lib/activitypub/dispatchers/user-actor.d.ts.map +1 -1
  119. package/dist/lib/activitypub/dispatchers/user-actor.js +16 -20
  120. package/dist/lib/activitypub/dispatchers/user-actor.js.map +1 -1
  121. package/dist/lib/activitypub/dm-service.js +1 -5
  122. package/dist/lib/activitypub/dm-service.js.map +1 -1
  123. package/dist/lib/activitypub/entity-profile-service.d.ts +1 -1
  124. package/dist/lib/activitypub/entity-profile-service.d.ts.map +1 -1
  125. package/dist/lib/activitypub/entity-profile-service.js +6 -10
  126. package/dist/lib/activitypub/entity-profile-service.js.map +1 -1
  127. package/dist/lib/activitypub/fedify/config.d.ts +3 -3
  128. package/dist/lib/activitypub/fedify/config.d.ts.map +1 -1
  129. package/dist/lib/activitypub/fedify/config.js +5 -8
  130. package/dist/lib/activitypub/fedify/config.js.map +1 -1
  131. package/dist/lib/activitypub/fedify/context.d.ts +1 -1
  132. package/dist/lib/activitypub/fedify/context.d.ts.map +1 -1
  133. package/dist/lib/activitypub/fedify/context.js +8 -12
  134. package/dist/lib/activitypub/fedify/context.js.map +1 -1
  135. package/dist/lib/activitypub/fedify/runtime.d.ts +1 -1
  136. package/dist/lib/activitypub/fedify/runtime.d.ts.map +1 -1
  137. package/dist/lib/activitypub/fedify/runtime.js +3 -6
  138. package/dist/lib/activitypub/fedify/runtime.js.map +1 -1
  139. package/dist/lib/activitypub/friendship-service.js +1 -5
  140. package/dist/lib/activitypub/friendship-service.js.map +1 -1
  141. package/dist/lib/activitypub/group-service.d.ts +1 -1
  142. package/dist/lib/activitypub/group-service.d.ts.map +1 -1
  143. package/dist/lib/activitypub/group-service.js +9 -46
  144. package/dist/lib/activitypub/group-service.js.map +1 -1
  145. package/dist/lib/activitypub/http-signatures.js +8 -45
  146. package/dist/lib/activitypub/http-signatures.js.map +1 -1
  147. package/dist/lib/activitypub/jsonld.d.ts +1 -1
  148. package/dist/lib/activitypub/jsonld.d.ts.map +1 -1
  149. package/dist/lib/activitypub/jsonld.js +1 -5
  150. package/dist/lib/activitypub/jsonld.js.map +1 -1
  151. package/dist/lib/activitypub/listeners/friends-collection.d.ts +1 -1
  152. package/dist/lib/activitypub/listeners/friends-collection.d.ts.map +1 -1
  153. package/dist/lib/activitypub/listeners/friends-collection.js +17 -20
  154. package/dist/lib/activitypub/listeners/friends-collection.js.map +1 -1
  155. package/dist/lib/activitypub/listeners/http-signatures.d.ts +1 -1
  156. package/dist/lib/activitypub/listeners/http-signatures.d.ts.map +1 -1
  157. package/dist/lib/activitypub/listeners/http-signatures.js +9 -46
  158. package/dist/lib/activitypub/listeners/http-signatures.js.map +1 -1
  159. package/dist/lib/activitypub/listeners/inbox.d.ts +2 -2
  160. package/dist/lib/activitypub/listeners/inbox.d.ts.map +1 -1
  161. package/dist/lib/activitypub/listeners/inbox.js +31 -35
  162. package/dist/lib/activitypub/listeners/inbox.js.map +1 -1
  163. package/dist/lib/activitypub/listeners/outbox.d.ts +1 -1
  164. package/dist/lib/activitypub/listeners/outbox.d.ts.map +1 -1
  165. package/dist/lib/activitypub/listeners/outbox.js +17 -20
  166. package/dist/lib/activitypub/listeners/outbox.js.map +1 -1
  167. package/dist/lib/activitypub/remote-fetch-service.d.ts +6 -6
  168. package/dist/lib/activitypub/remote-fetch-service.d.ts.map +1 -1
  169. package/dist/lib/activitypub/remote-fetch-service.js +6 -10
  170. package/dist/lib/activitypub/remote-fetch-service.js.map +1 -1
  171. package/dist/lib/activitypub/services/abuse-prevention.d.ts +1 -1
  172. package/dist/lib/activitypub/services/abuse-prevention.d.ts.map +1 -1
  173. package/dist/lib/activitypub/services/abuse-prevention.js +11 -17
  174. package/dist/lib/activitypub/services/abuse-prevention.js.map +1 -1
  175. package/dist/lib/activitypub/services/dm-service-fedify.d.ts +4 -4
  176. package/dist/lib/activitypub/services/dm-service-fedify.d.ts.map +1 -1
  177. package/dist/lib/activitypub/services/dm-service-fedify.js +24 -59
  178. package/dist/lib/activitypub/services/dm-service-fedify.js.map +1 -1
  179. package/dist/lib/activitypub/services/fedify-converters.d.ts +2 -2
  180. package/dist/lib/activitypub/services/fedify-converters.d.ts.map +1 -1
  181. package/dist/lib/activitypub/services/fedify-converters.js +3 -8
  182. package/dist/lib/activitypub/services/fedify-converters.js.map +1 -1
  183. package/dist/lib/activitypub/services/fedify-delivery.d.ts +2 -2
  184. package/dist/lib/activitypub/services/fedify-delivery.d.ts.map +1 -1
  185. package/dist/lib/activitypub/services/fedify-delivery.js +19 -56
  186. package/dist/lib/activitypub/services/fedify-delivery.js.map +1 -1
  187. package/dist/lib/activitypub/services/follow-activity-service.d.ts +2 -2
  188. package/dist/lib/activitypub/services/follow-activity-service.d.ts.map +1 -1
  189. package/dist/lib/activitypub/services/follow-activity-service.js +8 -12
  190. package/dist/lib/activitypub/services/follow-activity-service.js.map +1 -1
  191. package/dist/lib/activitypub/services/post-service-fedify.d.ts +2 -2
  192. package/dist/lib/activitypub/services/post-service-fedify.d.ts.map +1 -1
  193. package/dist/lib/activitypub/services/post-service-fedify.js +33 -65
  194. package/dist/lib/activitypub/services/post-service-fedify.js.map +1 -1
  195. package/dist/lib/activitypub/services/remote-activity-handler.d.ts +2 -2
  196. package/dist/lib/activitypub/services/remote-activity-handler.d.ts.map +1 -1
  197. package/dist/lib/activitypub/services/remote-activity-handler.js +25 -28
  198. package/dist/lib/activitypub/services/remote-activity-handler.js.map +1 -1
  199. package/dist/lib/activitypub/standalone-mode.d.ts +1 -1
  200. package/dist/lib/activitypub/standalone-mode.d.ts.map +1 -1
  201. package/dist/lib/activitypub/standalone-mode.js +13 -50
  202. package/dist/lib/activitypub/standalone-mode.js.map +1 -1
  203. package/dist/lib/activitypub/webfinger/server.d.ts +1 -1
  204. package/dist/lib/activitypub/webfinger/server.d.ts.map +1 -1
  205. package/dist/lib/activitypub/webfinger/server.js +18 -54
  206. package/dist/lib/activitypub/webfinger/server.js.map +1 -1
  207. package/dist/lib/age-gate-middleware.d.ts +4 -4
  208. package/dist/lib/age-gate-middleware.d.ts.map +1 -1
  209. package/dist/lib/age-gate-middleware.js +3 -6
  210. package/dist/lib/age-gate-middleware.js.map +1 -1
  211. package/dist/lib/age-gate.js +3 -8
  212. package/dist/lib/age-gate.js.map +1 -1
  213. package/dist/lib/age-tier-transition.d.ts +1 -1
  214. package/dist/lib/age-tier-transition.d.ts.map +1 -1
  215. package/dist/lib/age-tier-transition.js +7 -44
  216. package/dist/lib/age-tier-transition.js.map +1 -1
  217. package/dist/lib/app.d.ts +76 -0
  218. package/dist/lib/app.d.ts.map +1 -0
  219. package/dist/lib/app.js +400 -0
  220. package/dist/lib/app.js.map +1 -0
  221. package/dist/lib/audit/csv-export.js +6 -13
  222. package/dist/lib/audit/csv-export.js.map +1 -1
  223. package/dist/lib/audit/pii-filter.d.ts +9 -0
  224. package/dist/lib/audit/pii-filter.d.ts.map +1 -1
  225. package/dist/lib/audit/pii-filter.js +57 -7
  226. package/dist/lib/audit/pii-filter.js.map +1 -1
  227. package/dist/lib/audit-actions.d.ts +94 -0
  228. package/dist/lib/audit-actions.d.ts.map +1 -0
  229. package/dist/lib/audit-actions.js +107 -0
  230. package/dist/lib/audit-actions.js.map +1 -0
  231. package/dist/lib/audit-composer.d.ts +174 -0
  232. package/dist/lib/audit-composer.d.ts.map +1 -0
  233. package/dist/lib/audit-composer.js +421 -0
  234. package/dist/lib/audit-composer.js.map +1 -0
  235. package/dist/lib/auth/auth-context.d.ts +1 -1
  236. package/dist/lib/auth/auth-context.js +1 -2
  237. package/dist/lib/auth/auth-context.js.map +1 -1
  238. package/dist/lib/auth/auth-middleware.d.ts +16 -2
  239. package/dist/lib/auth/auth-middleware.d.ts.map +1 -1
  240. package/dist/lib/auth/auth-middleware.js +36 -45
  241. package/dist/lib/auth/auth-middleware.js.map +1 -1
  242. package/dist/lib/auth/capabilities.js +2 -5
  243. package/dist/lib/auth/capabilities.js.map +1 -1
  244. package/dist/lib/auth/claims-cache.d.ts +2 -2
  245. package/dist/lib/auth/claims-cache.js +19 -24
  246. package/dist/lib/auth/claims-cache.js.map +1 -1
  247. package/dist/lib/auth/cognito-jwt.d.ts +20 -2
  248. package/dist/lib/auth/cognito-jwt.d.ts.map +1 -1
  249. package/dist/lib/auth/cognito-jwt.js +83 -23
  250. package/dist/lib/auth/cognito-jwt.js.map +1 -1
  251. package/dist/lib/auth/idp-redirect-builder.d.ts +1 -1
  252. package/dist/lib/auth/idp-redirect-builder.d.ts.map +1 -1
  253. package/dist/lib/auth/idp-redirect-builder.js +4 -10
  254. package/dist/lib/auth/idp-redirect-builder.js.map +1 -1
  255. package/dist/lib/auth/require.d.ts +4 -4
  256. package/dist/lib/auth/require.d.ts.map +1 -1
  257. package/dist/lib/auth/require.js +11 -18
  258. package/dist/lib/auth/require.js.map +1 -1
  259. package/dist/lib/auth/role-grants.d.ts +1 -1
  260. package/dist/lib/auth/role-grants.d.ts.map +1 -1
  261. package/dist/lib/auth/role-grants.js +28 -31
  262. package/dist/lib/auth/role-grants.js.map +1 -1
  263. package/dist/lib/auth-context-manager.js +1 -5
  264. package/dist/lib/auth-context-manager.js.map +1 -1
  265. package/dist/lib/auth-handler.d.ts +5 -5
  266. package/dist/lib/auth-handler.d.ts.map +1 -1
  267. package/dist/lib/auth-handler.js +5 -9
  268. package/dist/lib/auth-handler.js.map +1 -1
  269. package/dist/lib/badge-handler.d.ts +1 -1
  270. package/dist/lib/badge-handler.d.ts.map +1 -1
  271. package/dist/lib/badge-handler.js +14 -52
  272. package/dist/lib/badge-handler.js.map +1 -1
  273. package/dist/lib/circle-handler.d.ts +10 -10
  274. package/dist/lib/circle-handler.d.ts.map +1 -1
  275. package/dist/lib/circle-handler.js +10 -47
  276. package/dist/lib/circle-handler.js.map +1 -1
  277. package/dist/lib/cognito/idp-sdk.js +11 -18
  278. package/dist/lib/cognito/idp-sdk.js.map +1 -1
  279. package/dist/lib/cognito/issuer-probe.js +9 -14
  280. package/dist/lib/cognito/issuer-probe.js.map +1 -1
  281. package/dist/lib/comment-handler.d.ts +10 -10
  282. package/dist/lib/comment-handler.d.ts.map +1 -1
  283. package/dist/lib/comment-handler.js +61 -97
  284. package/dist/lib/comment-handler.js.map +1 -1
  285. package/dist/lib/compliance/baseline.d.ts +2 -2
  286. package/dist/lib/compliance/baseline.d.ts.map +1 -1
  287. package/dist/lib/compliance/baseline.js +15 -18
  288. package/dist/lib/compliance/baseline.js.map +1 -1
  289. package/dist/lib/compliance/tenant-merge.d.ts +1 -1
  290. package/dist/lib/compliance/tenant-merge.d.ts.map +1 -1
  291. package/dist/lib/compliance/tenant-merge.js +1 -4
  292. package/dist/lib/compliance/tenant-merge.js.map +1 -1
  293. package/dist/lib/compliance/types.d.ts +1 -1
  294. package/dist/lib/compliance/types.js +2 -3
  295. package/dist/lib/compliance/types.js.map +1 -1
  296. package/dist/lib/connection-code-handler.d.ts +7 -7
  297. package/dist/lib/connection-code-handler.d.ts.map +1 -1
  298. package/dist/lib/connection-code-handler.js +13 -50
  299. package/dist/lib/connection-code-handler.js.map +1 -1
  300. package/dist/lib/content-discovery.d.ts +1 -1
  301. package/dist/lib/content-discovery.d.ts.map +1 -1
  302. package/dist/lib/content-discovery.js +15 -52
  303. package/dist/lib/content-discovery.js.map +1 -1
  304. package/dist/lib/context-aware-data-access.d.ts +1 -1
  305. package/dist/lib/context-aware-data-access.d.ts.map +1 -1
  306. package/dist/lib/context-aware-data-access.js +1 -5
  307. package/dist/lib/context-aware-data-access.js.map +1 -1
  308. package/dist/lib/cors-handler.d.ts +1 -1
  309. package/dist/lib/cors-handler.d.ts.map +1 -1
  310. package/dist/lib/cors-handler.js +13 -17
  311. package/dist/lib/cors-handler.js.map +1 -1
  312. package/dist/lib/cost-accumulator.d.ts.map +1 -1
  313. package/dist/lib/cost-accumulator.js +7 -11
  314. package/dist/lib/cost-accumulator.js.map +1 -1
  315. package/dist/lib/crypto/voting/elgamal-encryption.js +1 -5
  316. package/dist/lib/crypto/voting/elgamal-encryption.js.map +1 -1
  317. package/dist/lib/crypto/voting/encryption-scheme.js +1 -2
  318. package/dist/lib/crypto/voting/encryption-scheme.js.map +1 -1
  319. package/dist/lib/crypto/voting/hash-utils.js +6 -12
  320. package/dist/lib/crypto/voting/hash-utils.js.map +1 -1
  321. package/dist/lib/crypto/voting/hybrid-encryption.js +5 -9
  322. package/dist/lib/crypto/voting/hybrid-encryption.js.map +1 -1
  323. package/dist/lib/crypto/voting/index.js +4 -14
  324. package/dist/lib/crypto/voting/index.js.map +1 -1
  325. package/dist/lib/crypto/voting/post-quantum-encryption.js +1 -5
  326. package/dist/lib/crypto/voting/post-quantum-encryption.js.map +1 -1
  327. package/dist/lib/csrf.d.ts +2 -2
  328. package/dist/lib/csrf.d.ts.map +1 -1
  329. package/dist/lib/csrf.js +1 -5
  330. package/dist/lib/csrf.js.map +1 -1
  331. package/dist/lib/data-router.d.ts +5 -4
  332. package/dist/lib/data-router.d.ts.map +1 -1
  333. package/dist/lib/data-router.js +67 -90
  334. package/dist/lib/data-router.js.map +1 -1
  335. package/dist/lib/database-circuit-breaker.d.ts +61 -34
  336. package/dist/lib/database-circuit-breaker.d.ts.map +1 -1
  337. package/dist/lib/database-circuit-breaker.js +102 -109
  338. package/dist/lib/database-circuit-breaker.js.map +1 -1
  339. package/dist/lib/database-config.js +1 -4
  340. package/dist/lib/database-config.js.map +1 -1
  341. package/dist/lib/database-connection-manager.d.ts +42 -2
  342. package/dist/lib/database-connection-manager.d.ts.map +1 -1
  343. package/dist/lib/database-connection-manager.js +178 -74
  344. package/dist/lib/database-connection-manager.js.map +1 -1
  345. package/dist/lib/database-monitor.d.ts +1 -1
  346. package/dist/lib/database-monitor.d.ts.map +1 -1
  347. package/dist/lib/database-monitor.js +5 -9
  348. package/dist/lib/database-monitor.js.map +1 -1
  349. package/dist/lib/database-rate-limiter.d.ts +1 -1
  350. package/dist/lib/database-rate-limiter.d.ts.map +1 -1
  351. package/dist/lib/database-rate-limiter.js +3 -7
  352. package/dist/lib/database-rate-limiter.js.map +1 -1
  353. package/dist/lib/database-wrapper-helper.d.ts +2 -2
  354. package/dist/lib/database-wrapper-helper.d.ts.map +1 -1
  355. package/dist/lib/database-wrapper-helper.js +7 -11
  356. package/dist/lib/database-wrapper-helper.js.map +1 -1
  357. package/dist/lib/database-wrapper.d.ts +1 -1
  358. package/dist/lib/database-wrapper.d.ts.map +1 -1
  359. package/dist/lib/database-wrapper.js +5 -9
  360. package/dist/lib/database-wrapper.js.map +1 -1
  361. package/dist/lib/db-query-helper.d.ts +3 -3
  362. package/dist/lib/db-query-helper.d.ts.map +1 -1
  363. package/dist/lib/db-query-helper.js +4 -9
  364. package/dist/lib/db-query-helper.js.map +1 -1
  365. package/dist/lib/discovery-exposure.d.ts +42 -0
  366. package/dist/lib/discovery-exposure.d.ts.map +1 -0
  367. package/dist/lib/discovery-exposure.js +89 -0
  368. package/dist/lib/discovery-exposure.js.map +1 -0
  369. package/dist/lib/discovery-handler.d.ts +6 -6
  370. package/dist/lib/discovery-handler.d.ts.map +1 -1
  371. package/dist/lib/discovery-handler.js +10 -43
  372. package/dist/lib/discovery-handler.js.map +1 -1
  373. package/dist/lib/domain-reputation-service.d.ts +1 -1
  374. package/dist/lib/domain-reputation-service.d.ts.map +1 -1
  375. package/dist/lib/domain-reputation-service.js +12 -15
  376. package/dist/lib/domain-reputation-service.js.map +1 -1
  377. package/dist/lib/email-privacy.js +4 -8
  378. package/dist/lib/email-privacy.js.map +1 -1
  379. package/dist/lib/email-provider.d.ts +2 -2
  380. package/dist/lib/email-provider.d.ts.map +1 -1
  381. package/dist/lib/email-provider.js +8 -16
  382. package/dist/lib/email-provider.js.map +1 -1
  383. package/dist/lib/entity-handler.d.ts +5 -6
  384. package/dist/lib/entity-handler.d.ts.map +1 -1
  385. package/dist/lib/entity-handler.js +52 -81
  386. package/dist/lib/entity-handler.js.map +1 -1
  387. package/dist/lib/entity-relationship-handler.d.ts +9 -9
  388. package/dist/lib/entity-relationship-handler.d.ts.map +1 -1
  389. package/dist/lib/entity-relationship-handler.js +14 -51
  390. package/dist/lib/entity-relationship-handler.js.map +1 -1
  391. package/dist/lib/entity-tagging-errors.js +4 -11
  392. package/dist/lib/entity-tagging-errors.js.map +1 -1
  393. package/dist/lib/entity-tagging-validator.d.ts +3 -3
  394. package/dist/lib/entity-tagging-validator.d.ts.map +1 -1
  395. package/dist/lib/entity-tagging-validator.js +6 -11
  396. package/dist/lib/entity-tagging-validator.js.map +1 -1
  397. package/dist/lib/exif-stripper.js +1 -4
  398. package/dist/lib/exif-stripper.js.map +1 -1
  399. package/dist/lib/extension-context.d.ts +2 -2
  400. package/dist/lib/extension-context.d.ts.map +1 -1
  401. package/dist/lib/extension-context.js +1 -4
  402. package/dist/lib/extension-context.js.map +1 -1
  403. package/dist/lib/extension-route-wrapper.d.ts +1 -1
  404. package/dist/lib/extension-route-wrapper.d.ts.map +1 -1
  405. package/dist/lib/extension-route-wrapper.js +17 -55
  406. package/dist/lib/extension-route-wrapper.js.map +1 -1
  407. package/dist/lib/extension-validator.js +3 -6
  408. package/dist/lib/extension-validator.js.map +1 -1
  409. package/dist/lib/feature-flags.d.ts +5 -2
  410. package/dist/lib/feature-flags.d.ts.map +1 -1
  411. package/dist/lib/feature-flags.js +15 -48
  412. package/dist/lib/feature-flags.js.map +1 -1
  413. package/dist/lib/feature-toggle-global-client.d.ts +6 -0
  414. package/dist/lib/feature-toggle-global-client.d.ts.map +1 -0
  415. package/dist/lib/feature-toggle-global-client.js +73 -0
  416. package/dist/lib/feature-toggle-global-client.js.map +1 -0
  417. package/dist/lib/feature-toggle-service.d.ts +137 -27
  418. package/dist/lib/feature-toggle-service.d.ts.map +1 -1
  419. package/dist/lib/feature-toggle-service.js +302 -119
  420. package/dist/lib/feature-toggle-service.js.map +1 -1
  421. package/dist/lib/feed-handler.d.ts +8 -8
  422. package/dist/lib/feed-handler.d.ts.map +1 -1
  423. package/dist/lib/feed-handler.js +33 -62
  424. package/dist/lib/feed-handler.js.map +1 -1
  425. package/dist/lib/feed-pagination.d.ts +26 -0
  426. package/dist/lib/feed-pagination.d.ts.map +1 -1
  427. package/dist/lib/feed-pagination.js +31 -11
  428. package/dist/lib/feed-pagination.js.map +1 -1
  429. package/dist/lib/feed-personalization.d.ts +1 -1
  430. package/dist/lib/feed-personalization.d.ts.map +1 -1
  431. package/dist/lib/feed-personalization.js +6 -43
  432. package/dist/lib/feed-personalization.js.map +1 -1
  433. package/dist/lib/followers-events.js +8 -13
  434. package/dist/lib/followers-events.js.map +1 -1
  435. package/dist/lib/friends-handler.d.ts +2 -2
  436. package/dist/lib/friends-handler.d.ts.map +1 -1
  437. package/dist/lib/friends-handler.js +9 -46
  438. package/dist/lib/friends-handler.js.map +1 -1
  439. package/dist/lib/geo/entity-geo-repository.d.ts +67 -0
  440. package/dist/lib/geo/entity-geo-repository.d.ts.map +1 -0
  441. package/dist/lib/geo/entity-geo-repository.js +91 -0
  442. package/dist/lib/geo/entity-geo-repository.js.map +1 -0
  443. package/dist/lib/graph/errors.d.ts.map +1 -1
  444. package/dist/lib/graph/errors.js +13 -18
  445. package/dist/lib/graph/errors.js.map +1 -1
  446. package/dist/lib/graph/graph-factory.d.ts +12 -53
  447. package/dist/lib/graph/graph-factory.d.ts.map +1 -1
  448. package/dist/lib/graph/graph-factory.js +67 -162
  449. package/dist/lib/graph/graph-factory.js.map +1 -1
  450. package/dist/lib/graph/graph-service.d.ts +1 -1
  451. package/dist/lib/graph/graph-service.d.ts.map +1 -1
  452. package/dist/lib/graph/graph-service.js +1 -2
  453. package/dist/lib/graph/graph-service.js.map +1 -1
  454. package/dist/lib/graph/index.d.ts +10 -14
  455. package/dist/lib/graph/index.d.ts.map +1 -1
  456. package/dist/lib/graph/index.js +12 -46
  457. package/dist/lib/graph/index.js.map +1 -1
  458. package/dist/lib/graph/postgres/_shared.d.ts +18 -0
  459. package/dist/lib/graph/postgres/_shared.d.ts.map +1 -0
  460. package/dist/lib/graph/postgres/_shared.js +24 -0
  461. package/dist/lib/graph/postgres/_shared.js.map +1 -0
  462. package/dist/lib/graph/postgres/circles.d.ts +66 -0
  463. package/dist/lib/graph/postgres/circles.d.ts.map +1 -0
  464. package/dist/lib/graph/postgres/circles.js +513 -0
  465. package/dist/lib/graph/postgres/circles.js.map +1 -0
  466. package/dist/lib/graph/postgres/discovery.d.ts +165 -0
  467. package/dist/lib/graph/postgres/discovery.d.ts.map +1 -0
  468. package/dist/lib/graph/postgres/discovery.js +579 -0
  469. package/dist/lib/graph/postgres/discovery.js.map +1 -0
  470. package/dist/lib/graph/postgres/entity-relationships.d.ts +53 -0
  471. package/dist/lib/graph/postgres/entity-relationships.d.ts.map +1 -0
  472. package/dist/lib/graph/postgres/entity-relationships.js +304 -0
  473. package/dist/lib/graph/postgres/entity-relationships.js.map +1 -0
  474. package/dist/lib/graph/postgres/interaction-events.d.ts +106 -0
  475. package/dist/lib/graph/postgres/interaction-events.d.ts.map +1 -0
  476. package/dist/lib/graph/postgres/interaction-events.js +162 -0
  477. package/dist/lib/graph/postgres/interaction-events.js.map +1 -0
  478. package/dist/lib/graph/postgres/postgres-graph-service.d.ts +74 -0
  479. package/dist/lib/graph/postgres/postgres-graph-service.d.ts.map +1 -0
  480. package/dist/lib/graph/postgres/postgres-graph-service.js +167 -0
  481. package/dist/lib/graph/postgres/postgres-graph-service.js.map +1 -0
  482. package/dist/lib/graph/postgres/relationships.d.ts +58 -0
  483. package/dist/lib/graph/postgres/relationships.d.ts.map +1 -0
  484. package/dist/lib/graph/postgres/relationships.js +314 -0
  485. package/dist/lib/graph/postgres/relationships.js.map +1 -0
  486. package/dist/lib/graph/postgres/scoring.d.ts +74 -0
  487. package/dist/lib/graph/postgres/scoring.d.ts.map +1 -0
  488. package/dist/lib/graph/postgres/scoring.js +297 -0
  489. package/dist/lib/graph/postgres/scoring.js.map +1 -0
  490. package/dist/lib/graph/postgres/sync.d.ts +149 -0
  491. package/dist/lib/graph/postgres/sync.d.ts.map +1 -0
  492. package/dist/lib/graph/postgres/sync.js +269 -0
  493. package/dist/lib/graph/postgres/sync.js.map +1 -0
  494. package/dist/lib/graph/scoring-engine.d.ts +7 -1
  495. package/dist/lib/graph/scoring-engine.d.ts.map +1 -1
  496. package/dist/lib/graph/scoring-engine.js +29 -35
  497. package/dist/lib/graph/scoring-engine.js.map +1 -1
  498. package/dist/lib/graph/types.d.ts +18 -1
  499. package/dist/lib/graph/types.d.ts.map +1 -1
  500. package/dist/lib/graph/types.js +1 -2
  501. package/dist/lib/graph/types.js.map +1 -1
  502. package/dist/lib/hook-dispatcher.d.ts +1 -1
  503. package/dist/lib/hook-dispatcher.d.ts.map +1 -1
  504. package/dist/lib/hook-dispatcher.js +8 -12
  505. package/dist/lib/hook-dispatcher.js.map +1 -1
  506. package/dist/lib/input-sanitizer.js +1 -5
  507. package/dist/lib/input-sanitizer.js.map +1 -1
  508. package/dist/lib/internal-docs-handler.d.ts +2 -2
  509. package/dist/lib/internal-docs-handler.d.ts.map +1 -1
  510. package/dist/lib/internal-docs-handler.js +20 -28
  511. package/dist/lib/internal-docs-handler.js.map +1 -1
  512. package/dist/lib/internal-docs-navigation.js +2 -6
  513. package/dist/lib/internal-docs-navigation.js.map +1 -1
  514. package/dist/lib/invitation-handler.d.ts +2 -2
  515. package/dist/lib/invitation-handler.d.ts.map +1 -1
  516. package/dist/lib/invitation-handler.js +41 -82
  517. package/dist/lib/invitation-handler.js.map +1 -1
  518. package/dist/lib/ip-scrubber.js +3 -8
  519. package/dist/lib/ip-scrubber.js.map +1 -1
  520. package/dist/lib/link-security-handler.d.ts +3 -2
  521. package/dist/lib/link-security-handler.d.ts.map +1 -1
  522. package/dist/lib/link-security-handler.js +8 -44
  523. package/dist/lib/link-security-handler.js.map +1 -1
  524. package/dist/lib/logger.d.ts +31 -82
  525. package/dist/lib/logger.d.ts.map +1 -1
  526. package/dist/lib/logger.js +43 -185
  527. package/dist/lib/logger.js.map +1 -1
  528. package/dist/lib/media-cleanup-handler.d.ts +2 -2
  529. package/dist/lib/media-cleanup-handler.d.ts.map +1 -1
  530. package/dist/lib/media-cleanup-handler.js +7 -11
  531. package/dist/lib/media-cleanup-handler.js.map +1 -1
  532. package/dist/lib/media-handler.d.ts +1 -1
  533. package/dist/lib/media-handler.d.ts.map +1 -1
  534. package/dist/lib/media-handler.js +36 -73
  535. package/dist/lib/media-handler.js.map +1 -1
  536. package/dist/lib/media-metadata-extractor.d.ts +1 -1
  537. package/dist/lib/media-metadata-extractor.d.ts.map +1 -1
  538. package/dist/lib/media-metadata-extractor.js +3 -7
  539. package/dist/lib/media-metadata-extractor.js.map +1 -1
  540. package/dist/lib/media-metrics.d.ts +2 -2
  541. package/dist/lib/media-metrics.d.ts.map +1 -1
  542. package/dist/lib/media-metrics.js +3 -7
  543. package/dist/lib/media-metrics.js.map +1 -1
  544. package/dist/lib/metadata/index.d.ts +5 -5
  545. package/dist/lib/metadata/index.d.ts.map +1 -1
  546. package/dist/lib/metadata/index.js +5 -21
  547. package/dist/lib/metadata/index.js.map +1 -1
  548. package/dist/lib/metadata/metadata-config.js +2 -5
  549. package/dist/lib/metadata/metadata-config.js.map +1 -1
  550. package/dist/lib/metadata/metadata-errors.js +2 -7
  551. package/dist/lib/metadata/metadata-errors.js.map +1 -1
  552. package/dist/lib/metadata/metadata-extractor.d.ts +1 -1
  553. package/dist/lib/metadata/metadata-extractor.d.ts.map +1 -1
  554. package/dist/lib/metadata/metadata-extractor.js +42 -82
  555. package/dist/lib/metadata/metadata-extractor.js.map +1 -1
  556. package/dist/lib/metadata/metadata-sanitizer.js +17 -24
  557. package/dist/lib/metadata/metadata-sanitizer.js.map +1 -1
  558. package/dist/lib/metadata/metadata-schemas.d.ts +16 -100
  559. package/dist/lib/metadata/metadata-schemas.d.ts.map +1 -1
  560. package/dist/lib/metadata/metadata-schemas.js +31 -34
  561. package/dist/lib/metadata/metadata-schemas.js.map +1 -1
  562. package/dist/lib/mfa/mfa-handler.d.ts +1 -1
  563. package/dist/lib/mfa/mfa-handler.d.ts.map +1 -1
  564. package/dist/lib/mfa/mfa-handler.js +13 -17
  565. package/dist/lib/mfa/mfa-handler.js.map +1 -1
  566. package/dist/lib/mfa/totp-service.js +8 -18
  567. package/dist/lib/mfa/totp-service.js.map +1 -1
  568. package/dist/lib/middleware/comment-rate-limit.d.ts +1 -1
  569. package/dist/lib/middleware/comment-rate-limit.d.ts.map +1 -1
  570. package/dist/lib/middleware/comment-rate-limit.js +7 -10
  571. package/dist/lib/middleware/comment-rate-limit.js.map +1 -1
  572. package/dist/lib/middleware/feature-toggle-rate-limit.d.ts +1 -1
  573. package/dist/lib/middleware/feature-toggle-rate-limit.d.ts.map +1 -1
  574. package/dist/lib/middleware/feature-toggle-rate-limit.js +8 -13
  575. package/dist/lib/middleware/feature-toggle-rate-limit.js.map +1 -1
  576. package/dist/lib/middleware/idempotency-store.js +20 -26
  577. package/dist/lib/middleware/idempotency-store.js.map +1 -1
  578. package/dist/lib/middleware/idempotency.d.ts +2 -2
  579. package/dist/lib/middleware/idempotency.d.ts.map +1 -1
  580. package/dist/lib/middleware/idempotency.js +12 -50
  581. package/dist/lib/middleware/idempotency.js.map +1 -1
  582. package/dist/lib/middleware.d.ts +22 -9
  583. package/dist/lib/middleware.d.ts.map +1 -1
  584. package/dist/lib/middleware.js +72 -153
  585. package/dist/lib/middleware.js.map +1 -1
  586. package/dist/lib/moderation-handler.d.ts +1 -1
  587. package/dist/lib/moderation-handler.d.ts.map +1 -1
  588. package/dist/lib/moderation-handler.js +15 -54
  589. package/dist/lib/moderation-handler.js.map +1 -1
  590. package/dist/lib/net/trusted-client-ip.d.ts +8 -30
  591. package/dist/lib/net/trusted-client-ip.d.ts.map +1 -1
  592. package/dist/lib/net/trusted-client-ip.js +13 -94
  593. package/dist/lib/net/trusted-client-ip.js.map +1 -1
  594. package/dist/lib/notification-handler.d.ts +1 -1
  595. package/dist/lib/notification-handler.d.ts.map +1 -1
  596. package/dist/lib/notification-handler.js +10 -15
  597. package/dist/lib/notification-handler.js.map +1 -1
  598. package/dist/lib/notification-preferences-handler.d.ts +1 -1
  599. package/dist/lib/notification-preferences-handler.d.ts.map +1 -1
  600. package/dist/lib/notification-preferences-handler.js +7 -11
  601. package/dist/lib/notification-preferences-handler.js.map +1 -1
  602. package/dist/lib/oauth/cognito-issuer.d.ts +1 -1
  603. package/dist/lib/oauth/cognito-issuer.d.ts.map +1 -1
  604. package/dist/lib/oauth/cognito-issuer.js +5 -10
  605. package/dist/lib/oauth/cognito-issuer.js.map +1 -1
  606. package/dist/lib/oauth/device-authorization.d.ts +1 -1
  607. package/dist/lib/oauth/device-authorization.d.ts.map +1 -1
  608. package/dist/lib/oauth/device-authorization.js +62 -77
  609. package/dist/lib/oauth/device-authorization.js.map +1 -1
  610. package/dist/lib/oauth/envelope-crypto.d.ts +2 -2
  611. package/dist/lib/oauth/envelope-crypto.js +22 -34
  612. package/dist/lib/oauth/envelope-crypto.js.map +1 -1
  613. package/dist/lib/oauth/refresh-detection.js +42 -52
  614. package/dist/lib/oauth/refresh-detection.js.map +1 -1
  615. package/dist/lib/openai-budget.d.ts.map +1 -1
  616. package/dist/lib/openai-budget.js +7 -44
  617. package/dist/lib/openai-budget.js.map +1 -1
  618. package/dist/lib/openapi/generator.d.ts +1 -1
  619. package/dist/lib/openapi/generator.d.ts.map +1 -1
  620. package/dist/lib/openapi/generator.js +2 -6
  621. package/dist/lib/openapi/generator.js.map +1 -1
  622. package/dist/lib/orphaned-media-handler.d.ts +1 -1
  623. package/dist/lib/orphaned-media-handler.d.ts.map +1 -1
  624. package/dist/lib/orphaned-media-handler.js +9 -46
  625. package/dist/lib/orphaned-media-handler.js.map +1 -1
  626. package/dist/lib/parental-control-handler.d.ts +2 -2
  627. package/dist/lib/parental-control-handler.d.ts.map +1 -1
  628. package/dist/lib/parental-control-handler.js +18 -55
  629. package/dist/lib/parental-control-handler.js.map +1 -1
  630. package/dist/lib/parental-link-handler.d.ts +8 -8
  631. package/dist/lib/parental-link-handler.d.ts.map +1 -1
  632. package/dist/lib/parental-link-handler.js +10 -14
  633. package/dist/lib/parental-link-handler.js.map +1 -1
  634. package/dist/lib/performance-metrics.d.ts +1 -1
  635. package/dist/lib/performance-metrics.d.ts.map +1 -1
  636. package/dist/lib/performance-metrics.js +3 -6
  637. package/dist/lib/performance-metrics.js.map +1 -1
  638. package/dist/lib/post-handler.d.ts +9 -9
  639. package/dist/lib/post-handler.d.ts.map +1 -1
  640. package/dist/lib/post-handler.js +67 -101
  641. package/dist/lib/post-handler.js.map +1 -1
  642. package/dist/lib/privacy-defaults.js +3 -8
  643. package/dist/lib/privacy-defaults.js.map +1 -1
  644. package/dist/lib/privacy-handler.d.ts +2 -2
  645. package/dist/lib/privacy-handler.d.ts.map +1 -1
  646. package/dist/lib/privacy-handler.js +6 -10
  647. package/dist/lib/privacy-handler.js.map +1 -1
  648. package/dist/lib/pseudonym.d.ts +56 -0
  649. package/dist/lib/pseudonym.d.ts.map +1 -0
  650. package/dist/lib/pseudonym.js +85 -0
  651. package/dist/lib/pseudonym.js.map +1 -0
  652. package/dist/lib/queue-consumers/media-reconciliation-consumer.d.ts +2 -2
  653. package/dist/lib/queue-consumers/media-reconciliation-consumer.d.ts.map +1 -1
  654. package/dist/lib/queue-consumers/media-reconciliation-consumer.js +5 -8
  655. package/dist/lib/queue-consumers/media-reconciliation-consumer.js.map +1 -1
  656. package/dist/lib/quiet-hours.js +2 -6
  657. package/dist/lib/quiet-hours.js.map +1 -1
  658. package/dist/lib/rate-limit.d.ts +58 -47
  659. package/dist/lib/rate-limit.d.ts.map +1 -1
  660. package/dist/lib/rate-limit.js +168 -157
  661. package/dist/lib/rate-limit.js.map +1 -1
  662. package/dist/lib/reaction-handler.d.ts +10 -10
  663. package/dist/lib/reaction-handler.d.ts.map +1 -1
  664. package/dist/lib/reaction-handler.js +44 -80
  665. package/dist/lib/reaction-handler.js.map +1 -1
  666. package/dist/lib/recaptcha.js +6 -9
  667. package/dist/lib/recaptcha.js.map +1 -1
  668. package/dist/lib/redirect-resolver.d.ts +2 -2
  669. package/dist/lib/redirect-resolver.d.ts.map +1 -1
  670. package/dist/lib/redirect-resolver.js +5 -9
  671. package/dist/lib/redirect-resolver.js.map +1 -1
  672. package/dist/lib/region-config.d.ts +3 -3
  673. package/dist/lib/region-config.d.ts.map +1 -1
  674. package/dist/lib/region-config.js +15 -58
  675. package/dist/lib/region-config.js.map +1 -1
  676. package/dist/lib/region-detection.d.ts +55 -24
  677. package/dist/lib/region-detection.d.ts.map +1 -1
  678. package/dist/lib/region-detection.js +140 -199
  679. package/dist/lib/region-detection.js.map +1 -1
  680. package/dist/lib/region-registry.d.ts +49 -0
  681. package/dist/lib/region-registry.d.ts.map +1 -0
  682. package/dist/lib/region-registry.js +112 -0
  683. package/dist/lib/region-registry.js.map +1 -0
  684. package/dist/lib/relationship-handler.d.ts +9 -9
  685. package/dist/lib/relationship-handler.d.ts.map +1 -1
  686. package/dist/lib/relationship-handler.js +12 -49
  687. package/dist/lib/relationship-handler.js.map +1 -1
  688. package/dist/lib/request-context.d.ts +16 -16
  689. package/dist/lib/request-context.d.ts.map +1 -1
  690. package/dist/lib/request-context.js +14 -22
  691. package/dist/lib/request-context.js.map +1 -1
  692. package/dist/lib/route-helpers.d.ts +3 -4
  693. package/dist/lib/route-helpers.d.ts.map +1 -1
  694. package/dist/lib/route-helpers.js +20 -75
  695. package/dist/lib/route-helpers.js.map +1 -1
  696. package/dist/lib/routes/activitypub/actor.d.ts +1 -1
  697. package/dist/lib/routes/activitypub/actor.d.ts.map +1 -1
  698. package/dist/lib/routes/activitypub/actor.js +20 -23
  699. package/dist/lib/routes/activitypub/actor.js.map +1 -1
  700. package/dist/lib/routes/activitypub/audiences.d.ts +1 -1
  701. package/dist/lib/routes/activitypub/audiences.d.ts.map +1 -1
  702. package/dist/lib/routes/activitypub/audiences.js +76 -80
  703. package/dist/lib/routes/activitypub/audiences.js.map +1 -1
  704. package/dist/lib/routes/activitypub/collections.d.ts +1 -1
  705. package/dist/lib/routes/activitypub/collections.d.ts.map +1 -1
  706. package/dist/lib/routes/activitypub/collections.js +24 -26
  707. package/dist/lib/routes/activitypub/collections.js.map +1 -1
  708. package/dist/lib/routes/activitypub/entity-profile.d.ts +1 -1
  709. package/dist/lib/routes/activitypub/entity-profile.d.ts.map +1 -1
  710. package/dist/lib/routes/activitypub/entity-profile.js +36 -39
  711. package/dist/lib/routes/activitypub/entity-profile.js.map +1 -1
  712. package/dist/lib/routes/activitypub/friends.d.ts +1 -1
  713. package/dist/lib/routes/activitypub/friends.d.ts.map +1 -1
  714. package/dist/lib/routes/activitypub/friends.js +9 -12
  715. package/dist/lib/routes/activitypub/friends.js.map +1 -1
  716. package/dist/lib/routes/activitypub/group.d.ts +1 -1
  717. package/dist/lib/routes/activitypub/group.d.ts.map +1 -1
  718. package/dist/lib/routes/activitypub/group.js +91 -94
  719. package/dist/lib/routes/activitypub/group.js.map +1 -1
  720. package/dist/lib/routes/activitypub/inbox.d.ts +1 -1
  721. package/dist/lib/routes/activitypub/inbox.d.ts.map +1 -1
  722. package/dist/lib/routes/activitypub/inbox.js +30 -33
  723. package/dist/lib/routes/activitypub/inbox.js.map +1 -1
  724. package/dist/lib/routes/activitypub/messages.d.ts +1 -1
  725. package/dist/lib/routes/activitypub/messages.d.ts.map +1 -1
  726. package/dist/lib/routes/activitypub/messages.js +79 -83
  727. package/dist/lib/routes/activitypub/messages.js.map +1 -1
  728. package/dist/lib/routes/activitypub/outbox.d.ts +1 -1
  729. package/dist/lib/routes/activitypub/outbox.d.ts.map +1 -1
  730. package/dist/lib/routes/activitypub/outbox.js +9 -12
  731. package/dist/lib/routes/activitypub/outbox.js.map +1 -1
  732. package/dist/lib/routes/activitypub/post.d.ts +1 -1
  733. package/dist/lib/routes/activitypub/post.d.ts.map +1 -1
  734. package/dist/lib/routes/activitypub/post.js +32 -35
  735. package/dist/lib/routes/activitypub/post.js.map +1 -1
  736. package/dist/lib/routes/activitypub/webfinger.d.ts +1 -1
  737. package/dist/lib/routes/activitypub/webfinger.d.ts.map +1 -1
  738. package/dist/lib/routes/activitypub/webfinger.js +5 -8
  739. package/dist/lib/routes/activitypub/webfinger.js.map +1 -1
  740. package/dist/lib/routes/admin-costs.d.ts +1 -1
  741. package/dist/lib/routes/admin-costs.d.ts.map +1 -1
  742. package/dist/lib/routes/admin-costs.js +22 -26
  743. package/dist/lib/routes/admin-costs.js.map +1 -1
  744. package/dist/lib/routes/admin.d.ts +1 -1
  745. package/dist/lib/routes/admin.d.ts.map +1 -1
  746. package/dist/lib/routes/admin.js +290 -269
  747. package/dist/lib/routes/admin.js.map +1 -1
  748. package/dist/lib/routes/agent-authorize.d.ts +5 -5
  749. package/dist/lib/routes/agent-authorize.d.ts.map +1 -1
  750. package/dist/lib/routes/agent-authorize.js +68 -74
  751. package/dist/lib/routes/agent-authorize.js.map +1 -1
  752. package/dist/lib/routes/agent-sessions.d.ts +4 -4
  753. package/dist/lib/routes/agent-sessions.d.ts.map +1 -1
  754. package/dist/lib/routes/agent-sessions.js +30 -35
  755. package/dist/lib/routes/agent-sessions.js.map +1 -1
  756. package/dist/lib/routes/agent-surface.d.ts +2 -2
  757. package/dist/lib/routes/agent-surface.d.ts.map +1 -1
  758. package/dist/lib/routes/agent-surface.js +20 -24
  759. package/dist/lib/routes/agent-surface.js.map +1 -1
  760. package/dist/lib/routes/auth-discover.d.ts +1 -1
  761. package/dist/lib/routes/auth-discover.d.ts.map +1 -1
  762. package/dist/lib/routes/auth-discover.js +20 -56
  763. package/dist/lib/routes/auth-discover.js.map +1 -1
  764. package/dist/lib/routes/auth.d.ts +1 -1
  765. package/dist/lib/routes/auth.d.ts.map +1 -1
  766. package/dist/lib/routes/auth.js +13 -16
  767. package/dist/lib/routes/auth.js.map +1 -1
  768. package/dist/lib/routes/badges.d.ts +1 -1
  769. package/dist/lib/routes/badges.d.ts.map +1 -1
  770. package/dist/lib/routes/badges.js +20 -23
  771. package/dist/lib/routes/badges.js.map +1 -1
  772. package/dist/lib/routes/circles.d.ts +1 -1
  773. package/dist/lib/routes/circles.d.ts.map +1 -1
  774. package/dist/lib/routes/circles.js +40 -44
  775. package/dist/lib/routes/circles.js.map +1 -1
  776. package/dist/lib/routes/comments.d.ts +1 -1
  777. package/dist/lib/routes/comments.d.ts.map +1 -1
  778. package/dist/lib/routes/comments.js +67 -71
  779. package/dist/lib/routes/comments.js.map +1 -1
  780. package/dist/lib/routes/connection-codes.d.ts +1 -1
  781. package/dist/lib/routes/connection-codes.d.ts.map +1 -1
  782. package/dist/lib/routes/connection-codes.js +30 -34
  783. package/dist/lib/routes/connection-codes.js.map +1 -1
  784. package/dist/lib/routes/content-discovery.d.ts +1 -1
  785. package/dist/lib/routes/content-discovery.d.ts.map +1 -1
  786. package/dist/lib/routes/content-discovery.js +31 -34
  787. package/dist/lib/routes/content-discovery.js.map +1 -1
  788. package/dist/lib/routes/dashboard.d.ts +1 -1
  789. package/dist/lib/routes/dashboard.d.ts.map +1 -1
  790. package/dist/lib/routes/dashboard.js +251 -288
  791. package/dist/lib/routes/dashboard.js.map +1 -1
  792. package/dist/lib/routes/deletion.d.ts +1 -1
  793. package/dist/lib/routes/deletion.d.ts.map +1 -1
  794. package/dist/lib/routes/deletion.js +37 -74
  795. package/dist/lib/routes/deletion.js.map +1 -1
  796. package/dist/lib/routes/discovery.d.ts +1 -1
  797. package/dist/lib/routes/discovery.d.ts.map +1 -1
  798. package/dist/lib/routes/discovery.js +20 -24
  799. package/dist/lib/routes/discovery.js.map +1 -1
  800. package/dist/lib/routes/employees.d.ts +1 -1
  801. package/dist/lib/routes/employees.d.ts.map +1 -1
  802. package/dist/lib/routes/employees.js +15 -52
  803. package/dist/lib/routes/employees.js.map +1 -1
  804. package/dist/lib/routes/entities.d.ts +1 -1
  805. package/dist/lib/routes/entities.d.ts.map +1 -1
  806. package/dist/lib/routes/entities.js +133 -137
  807. package/dist/lib/routes/entities.js.map +1 -1
  808. package/dist/lib/routes/entity-relationships.d.ts +1 -1
  809. package/dist/lib/routes/entity-relationships.d.ts.map +1 -1
  810. package/dist/lib/routes/entity-relationships.js +35 -39
  811. package/dist/lib/routes/entity-relationships.js.map +1 -1
  812. package/dist/lib/routes/errors.d.ts +1 -1
  813. package/dist/lib/routes/errors.d.ts.map +1 -1
  814. package/dist/lib/routes/errors.js +4 -10
  815. package/dist/lib/routes/errors.js.map +1 -1
  816. package/dist/lib/routes/export.d.ts +1 -1
  817. package/dist/lib/routes/export.d.ts.map +1 -1
  818. package/dist/lib/routes/export.js +31 -35
  819. package/dist/lib/routes/export.js.map +1 -1
  820. package/dist/lib/routes/feature-flags.d.ts +1 -1
  821. package/dist/lib/routes/feature-flags.d.ts.map +1 -1
  822. package/dist/lib/routes/feature-flags.js +20 -23
  823. package/dist/lib/routes/feature-flags.js.map +1 -1
  824. package/dist/lib/routes/feeds.d.ts +1 -1
  825. package/dist/lib/routes/feeds.d.ts.map +1 -1
  826. package/dist/lib/routes/feeds.js +42 -46
  827. package/dist/lib/routes/feeds.js.map +1 -1
  828. package/dist/lib/routes/friends.d.ts +1 -1
  829. package/dist/lib/routes/friends.d.ts.map +1 -1
  830. package/dist/lib/routes/friends.js +35 -39
  831. package/dist/lib/routes/friends.js.map +1 -1
  832. package/dist/lib/routes/health.d.ts +1 -1
  833. package/dist/lib/routes/health.d.ts.map +1 -1
  834. package/dist/lib/routes/health.js +23 -27
  835. package/dist/lib/routes/health.js.map +1 -1
  836. package/dist/lib/routes/index.d.ts +2 -7
  837. package/dist/lib/routes/index.d.ts.map +1 -1
  838. package/dist/lib/routes/index.js +137 -158
  839. package/dist/lib/routes/index.js.map +1 -1
  840. package/dist/lib/routes/internal-docs.d.ts +1 -1
  841. package/dist/lib/routes/internal-docs.d.ts.map +1 -1
  842. package/dist/lib/routes/internal-docs.js +13 -16
  843. package/dist/lib/routes/internal-docs.js.map +1 -1
  844. package/dist/lib/routes/invitations.d.ts +1 -1
  845. package/dist/lib/routes/invitations.d.ts.map +1 -1
  846. package/dist/lib/routes/invitations.js +19 -22
  847. package/dist/lib/routes/invitations.js.map +1 -1
  848. package/dist/lib/routes/link-reports.d.ts +2 -2
  849. package/dist/lib/routes/link-reports.d.ts.map +1 -1
  850. package/dist/lib/routes/link-reports.js +86 -48
  851. package/dist/lib/routes/link-reports.js.map +1 -1
  852. package/dist/lib/routes/map.d.ts +1 -1
  853. package/dist/lib/routes/map.d.ts.map +1 -1
  854. package/dist/lib/routes/map.js +5 -8
  855. package/dist/lib/routes/map.js.map +1 -1
  856. package/dist/lib/routes/media-metadata-visibility.d.ts +1 -1
  857. package/dist/lib/routes/media-metadata-visibility.d.ts.map +1 -1
  858. package/dist/lib/routes/media-metadata-visibility.js +30 -67
  859. package/dist/lib/routes/media-metadata-visibility.js.map +1 -1
  860. package/dist/lib/routes/media.d.ts +1 -1
  861. package/dist/lib/routes/media.d.ts.map +1 -1
  862. package/dist/lib/routes/media.js +156 -193
  863. package/dist/lib/routes/media.js.map +1 -1
  864. package/dist/lib/routes/mfa.d.ts +1 -1
  865. package/dist/lib/routes/mfa.d.ts.map +1 -1
  866. package/dist/lib/routes/mfa.js +60 -64
  867. package/dist/lib/routes/mfa.js.map +1 -1
  868. package/dist/lib/routes/notifications.d.ts +1 -1
  869. package/dist/lib/routes/notifications.d.ts.map +1 -1
  870. package/dist/lib/routes/notifications.js +68 -72
  871. package/dist/lib/routes/notifications.js.map +1 -1
  872. package/dist/lib/routes/oauth.d.ts +1 -1
  873. package/dist/lib/routes/oauth.d.ts.map +1 -1
  874. package/dist/lib/routes/oauth.js +20 -23
  875. package/dist/lib/routes/oauth.js.map +1 -1
  876. package/dist/lib/routes/orphaned-media-health.d.ts +1 -1
  877. package/dist/lib/routes/orphaned-media-health.d.ts.map +1 -1
  878. package/dist/lib/routes/orphaned-media-health.js +10 -13
  879. package/dist/lib/routes/orphaned-media-health.js.map +1 -1
  880. package/dist/lib/routes/orphaned-media.d.ts +1 -1
  881. package/dist/lib/routes/orphaned-media.d.ts.map +1 -1
  882. package/dist/lib/routes/orphaned-media.js +20 -57
  883. package/dist/lib/routes/orphaned-media.js.map +1 -1
  884. package/dist/lib/routes/out.d.ts +1 -1
  885. package/dist/lib/routes/out.d.ts.map +1 -1
  886. package/dist/lib/routes/out.js +21 -24
  887. package/dist/lib/routes/out.js.map +1 -1
  888. package/dist/lib/routes/parental-controls.d.ts +1 -1
  889. package/dist/lib/routes/parental-controls.d.ts.map +1 -1
  890. package/dist/lib/routes/parental-controls.js +91 -95
  891. package/dist/lib/routes/parental-controls.js.map +1 -1
  892. package/dist/lib/routes/posts.d.ts +1 -1
  893. package/dist/lib/routes/posts.d.ts.map +1 -1
  894. package/dist/lib/routes/posts.js +101 -105
  895. package/dist/lib/routes/posts.js.map +1 -1
  896. package/dist/lib/routes/privacy.d.ts +1 -1
  897. package/dist/lib/routes/privacy.d.ts.map +1 -1
  898. package/dist/lib/routes/privacy.js +21 -25
  899. package/dist/lib/routes/privacy.js.map +1 -1
  900. package/dist/lib/routes/products.d.ts +1 -1
  901. package/dist/lib/routes/products.d.ts.map +1 -1
  902. package/dist/lib/routes/products.js +44 -48
  903. package/dist/lib/routes/products.js.map +1 -1
  904. package/dist/lib/routes/relationships.d.ts +1 -1
  905. package/dist/lib/routes/relationships.d.ts.map +1 -1
  906. package/dist/lib/routes/relationships.js +35 -39
  907. package/dist/lib/routes/relationships.js.map +1 -1
  908. package/dist/lib/routes/sentiments.d.ts +1 -1
  909. package/dist/lib/routes/sentiments.d.ts.map +1 -1
  910. package/dist/lib/routes/sentiments.js +71 -75
  911. package/dist/lib/routes/sentiments.js.map +1 -1
  912. package/dist/lib/routes/setup-status.d.ts +1 -1
  913. package/dist/lib/routes/setup-status.d.ts.map +1 -1
  914. package/dist/lib/routes/setup-status.js +17 -20
  915. package/dist/lib/routes/setup-status.js.map +1 -1
  916. package/dist/lib/routes/taxonomy-analytics.d.ts +1 -1
  917. package/dist/lib/routes/taxonomy-analytics.d.ts.map +1 -1
  918. package/dist/lib/routes/taxonomy-analytics.js +29 -33
  919. package/dist/lib/routes/taxonomy-analytics.js.map +1 -1
  920. package/dist/lib/routes/taxonomy.d.ts +1 -1
  921. package/dist/lib/routes/taxonomy.d.ts.map +1 -1
  922. package/dist/lib/routes/taxonomy.js +48 -51
  923. package/dist/lib/routes/taxonomy.js.map +1 -1
  924. package/dist/lib/routes/tenant-audit.d.ts +1 -1
  925. package/dist/lib/routes/tenant-audit.d.ts.map +1 -1
  926. package/dist/lib/routes/tenant-audit.js +35 -92
  927. package/dist/lib/routes/tenant-audit.js.map +1 -1
  928. package/dist/lib/routes/tenant-compliance.d.ts +1 -1
  929. package/dist/lib/routes/tenant-compliance.d.ts.map +1 -1
  930. package/dist/lib/routes/tenant-compliance.js +16 -52
  931. package/dist/lib/routes/tenant-compliance.js.map +1 -1
  932. package/dist/lib/routes/tenant-domains.d.ts +1 -1
  933. package/dist/lib/routes/tenant-domains.d.ts.map +1 -1
  934. package/dist/lib/routes/tenant-domains.js +27 -30
  935. package/dist/lib/routes/tenant-domains.js.map +1 -1
  936. package/dist/lib/routes/tenant-idp.d.ts +1 -1
  937. package/dist/lib/routes/tenant-idp.d.ts.map +1 -1
  938. package/dist/lib/routes/tenant-idp.js +27 -30
  939. package/dist/lib/routes/tenant-idp.js.map +1 -1
  940. package/dist/lib/routes/tenant-members.d.ts +1 -1
  941. package/dist/lib/routes/tenant-members.d.ts.map +1 -1
  942. package/dist/lib/routes/tenant-members.js +21 -24
  943. package/dist/lib/routes/tenant-members.js.map +1 -1
  944. package/dist/lib/routes/tenant-role-mappings.d.ts +1 -1
  945. package/dist/lib/routes/tenant-role-mappings.d.ts.map +1 -1
  946. package/dist/lib/routes/tenant-role-mappings.js +27 -30
  947. package/dist/lib/routes/tenant-role-mappings.js.map +1 -1
  948. package/dist/lib/routes/tenants.d.ts +1 -1
  949. package/dist/lib/routes/tenants.d.ts.map +1 -1
  950. package/dist/lib/routes/tenants.js +37 -40
  951. package/dist/lib/routes/tenants.js.map +1 -1
  952. package/dist/lib/routes/types.d.ts +10 -5
  953. package/dist/lib/routes/types.d.ts.map +1 -1
  954. package/dist/lib/routes/types.js +1 -2
  955. package/dist/lib/routes/types.js.map +1 -1
  956. package/dist/lib/routes/upload-sessions.d.ts +1 -1
  957. package/dist/lib/routes/upload-sessions.d.ts.map +1 -1
  958. package/dist/lib/routes/upload-sessions.js +57 -94
  959. package/dist/lib/routes/upload-sessions.js.map +1 -1
  960. package/dist/lib/routes/user.d.ts +1 -1
  961. package/dist/lib/routes/user.d.ts.map +1 -1
  962. package/dist/lib/routes/user.js +137 -85
  963. package/dist/lib/routes/user.js.map +1 -1
  964. package/dist/lib/routes.d.ts +2 -2
  965. package/dist/lib/routes.d.ts.map +1 -1
  966. package/dist/lib/routes.js +2 -7
  967. package/dist/lib/routes.js.map +1 -1
  968. package/dist/lib/scaling-health.d.ts.map +1 -1
  969. package/dist/lib/scaling-health.js +6 -9
  970. package/dist/lib/scaling-health.js.map +1 -1
  971. package/dist/lib/scheduled/media-stale-cleanup.js +5 -8
  972. package/dist/lib/scheduled/media-stale-cleanup.js.map +1 -1
  973. package/dist/lib/scheduled/orphaned-media-monitor.d.ts +1 -1
  974. package/dist/lib/scheduled/orphaned-media-monitor.d.ts.map +1 -1
  975. package/dist/lib/scheduled/orphaned-media-monitor.js +5 -42
  976. package/dist/lib/scheduled/orphaned-media-monitor.js.map +1 -1
  977. package/dist/lib/schemas.d.ts +85 -204
  978. package/dist/lib/schemas.d.ts.map +1 -1
  979. package/dist/lib/schemas.js +71 -74
  980. package/dist/lib/schemas.js.map +1 -1
  981. package/dist/lib/secrets/idp-secrets.d.ts +1 -1
  982. package/dist/lib/secrets/idp-secrets.js +13 -19
  983. package/dist/lib/secrets/idp-secrets.js.map +1 -1
  984. package/dist/lib/security-event-cleaner.js +1 -5
  985. package/dist/lib/security-event-cleaner.js.map +1 -1
  986. package/dist/lib/security-headers.js +1 -5
  987. package/dist/lib/security-headers.js.map +1 -1
  988. package/dist/lib/security-monitor.d.ts +4 -2
  989. package/dist/lib/security-monitor.d.ts.map +1 -1
  990. package/dist/lib/security-monitor.js +16 -18
  991. package/dist/lib/security-monitor.js.map +1 -1
  992. package/dist/lib/sentiment-digest.d.ts +1 -1
  993. package/dist/lib/sentiment-digest.d.ts.map +1 -1
  994. package/dist/lib/sentiment-digest.js +5 -8
  995. package/dist/lib/sentiment-digest.js.map +1 -1
  996. package/dist/lib/sentiment-display.js +3 -7
  997. package/dist/lib/sentiment-display.js.map +1 -1
  998. package/dist/lib/services/image-normalizer.js +1 -5
  999. package/dist/lib/services/image-normalizer.js.map +1 -1
  1000. package/dist/lib/services/media-reconciliation-service.d.ts +1 -1
  1001. package/dist/lib/services/media-reconciliation-service.d.ts.map +1 -1
  1002. package/dist/lib/services/media-reconciliation-service.js +7 -11
  1003. package/dist/lib/services/media-reconciliation-service.js.map +1 -1
  1004. package/dist/lib/services/media-upload-service.d.ts +1 -1
  1005. package/dist/lib/services/media-upload-service.d.ts.map +1 -1
  1006. package/dist/lib/services/media-upload-service.js +4 -8
  1007. package/dist/lib/services/media-upload-service.js.map +1 -1
  1008. package/dist/lib/services/user-data-deletion.d.ts +45 -2
  1009. package/dist/lib/services/user-data-deletion.d.ts.map +1 -1
  1010. package/dist/lib/services/user-data-deletion.js +87 -9
  1011. package/dist/lib/services/user-data-deletion.js.map +1 -1
  1012. package/dist/lib/session-awareness.js +2 -6
  1013. package/dist/lib/session-awareness.js.map +1 -1
  1014. package/dist/lib/session-config.js +8 -17
  1015. package/dist/lib/session-config.js.map +1 -1
  1016. package/dist/lib/{session-manager.d.ts → session-cookie.d.ts} +58 -15
  1017. package/dist/lib/session-cookie.d.ts.map +1 -0
  1018. package/dist/lib/session-cookie.js +0 -0
  1019. package/dist/lib/session-cookie.js.map +1 -0
  1020. package/dist/lib/signup-metadata.d.ts +129 -0
  1021. package/dist/lib/signup-metadata.d.ts.map +1 -0
  1022. package/dist/lib/signup-metadata.js +127 -0
  1023. package/dist/lib/signup-metadata.js.map +1 -0
  1024. package/dist/lib/sso-auth-handler.js +1 -5
  1025. package/dist/lib/sso-auth-handler.js.map +1 -1
  1026. package/dist/lib/tag-suggestions-handler.d.ts +1 -1
  1027. package/dist/lib/tag-suggestions-handler.d.ts.map +1 -1
  1028. package/dist/lib/tag-suggestions-handler.js +1 -5
  1029. package/dist/lib/tag-suggestions-handler.js.map +1 -1
  1030. package/dist/lib/taxonomy-handler-factory.d.ts +2 -2
  1031. package/dist/lib/taxonomy-handler-factory.d.ts.map +1 -1
  1032. package/dist/lib/taxonomy-handler-factory.js +7 -10
  1033. package/dist/lib/taxonomy-handler-factory.js.map +1 -1
  1034. package/dist/lib/taxonomy-handler.d.ts +2 -2
  1035. package/dist/lib/taxonomy-handler.d.ts.map +1 -1
  1036. package/dist/lib/taxonomy-handler.js +8 -8
  1037. package/dist/lib/taxonomy-handler.js.map +1 -1
  1038. package/dist/lib/taxonomy-metrics.js +5 -9
  1039. package/dist/lib/taxonomy-metrics.js.map +1 -1
  1040. package/dist/lib/taxonomy-search-metrics.d.ts +2 -2
  1041. package/dist/lib/taxonomy-search-metrics.d.ts.map +1 -1
  1042. package/dist/lib/taxonomy-search-metrics.js +3 -7
  1043. package/dist/lib/taxonomy-search-metrics.js.map +1 -1
  1044. package/dist/lib/tenant/audit-emit.d.ts +18 -8
  1045. package/dist/lib/tenant/audit-emit.d.ts.map +1 -1
  1046. package/dist/lib/tenant/audit-emit.js +50 -11
  1047. package/dist/lib/tenant/audit-emit.js.map +1 -1
  1048. package/dist/lib/tenant/derive-domain.js +1 -4
  1049. package/dist/lib/tenant/derive-domain.js.map +1 -1
  1050. package/dist/lib/tenant/domain-handler.d.ts +2 -2
  1051. package/dist/lib/tenant/domain-handler.d.ts.map +1 -1
  1052. package/dist/lib/tenant/domain-handler.js +50 -62
  1053. package/dist/lib/tenant/domain-handler.js.map +1 -1
  1054. package/dist/lib/tenant/domain-validator.d.ts +1 -1
  1055. package/dist/lib/tenant/domain-validator.js +10 -13
  1056. package/dist/lib/tenant/domain-validator.js.map +1 -1
  1057. package/dist/lib/tenant/domain-verifier.d.ts +3 -3
  1058. package/dist/lib/tenant/domain-verifier.js +8 -11
  1059. package/dist/lib/tenant/domain-verifier.js.map +1 -1
  1060. package/dist/lib/tenant/idp-handler.d.ts +4 -4
  1061. package/dist/lib/tenant/idp-handler.d.ts.map +1 -1
  1062. package/dist/lib/tenant/idp-handler.js +45 -82
  1063. package/dist/lib/tenant/idp-handler.js.map +1 -1
  1064. package/dist/lib/tenant/idp-name.js +1 -4
  1065. package/dist/lib/tenant/idp-name.js.map +1 -1
  1066. package/dist/lib/tenant/member-handler.d.ts +2 -2
  1067. package/dist/lib/tenant/member-handler.d.ts.map +1 -1
  1068. package/dist/lib/tenant/member-handler.js +30 -67
  1069. package/dist/lib/tenant/member-handler.js.map +1 -1
  1070. package/dist/lib/tenant/reserved-slugs.d.ts +1 -1
  1071. package/dist/lib/tenant/reserved-slugs.d.ts.map +1 -1
  1072. package/dist/lib/tenant/reserved-slugs.js +8 -14
  1073. package/dist/lib/tenant/reserved-slugs.js.map +1 -1
  1074. package/dist/lib/tenant/resolve-role.js +1 -4
  1075. package/dist/lib/tenant/resolve-role.js.map +1 -1
  1076. package/dist/lib/tenant/role-mapping-handler.d.ts +2 -2
  1077. package/dist/lib/tenant/role-mapping-handler.d.ts.map +1 -1
  1078. package/dist/lib/tenant/role-mapping-handler.js +24 -61
  1079. package/dist/lib/tenant/role-mapping-handler.js.map +1 -1
  1080. package/dist/lib/tenant/setup-status.d.ts +1 -1
  1081. package/dist/lib/tenant/setup-status.d.ts.map +1 -1
  1082. package/dist/lib/tenant/setup-status.js +3 -40
  1083. package/dist/lib/tenant/setup-status.js.map +1 -1
  1084. package/dist/lib/tenant/slug-validator.js +3 -6
  1085. package/dist/lib/tenant/slug-validator.js.map +1 -1
  1086. package/dist/lib/tenant/tenant-handler.d.ts +2 -2
  1087. package/dist/lib/tenant/tenant-handler.d.ts.map +1 -1
  1088. package/dist/lib/tenant/tenant-handler.js +31 -68
  1089. package/dist/lib/tenant/tenant-handler.js.map +1 -1
  1090. package/dist/lib/tenant/transfer-ownership.js +2 -6
  1091. package/dist/lib/tenant/transfer-ownership.js.map +1 -1
  1092. package/dist/lib/tenant-scope.d.ts +97 -0
  1093. package/dist/lib/tenant-scope.d.ts.map +1 -0
  1094. package/dist/lib/tenant-scope.js +270 -0
  1095. package/dist/lib/tenant-scope.js.map +1 -0
  1096. package/dist/lib/terminology.d.ts.map +1 -1
  1097. package/dist/lib/terminology.js +7 -9
  1098. package/dist/lib/terminology.js.map +1 -1
  1099. package/dist/lib/theme.js +2 -6
  1100. package/dist/lib/theme.js.map +1 -1
  1101. package/dist/lib/threat-intel-service.d.ts +2 -2
  1102. package/dist/lib/threat-intel-service.d.ts.map +1 -1
  1103. package/dist/lib/threat-intel-service.js +3 -7
  1104. package/dist/lib/threat-intel-service.js.map +1 -1
  1105. package/dist/lib/types/media-reconciliation.js +1 -2
  1106. package/dist/lib/types/media-reconciliation.js.map +1 -1
  1107. package/dist/lib/upload-session-handler.d.ts +1 -1
  1108. package/dist/lib/upload-session-handler.d.ts.map +1 -1
  1109. package/dist/lib/upload-session-handler.js +13 -50
  1110. package/dist/lib/upload-session-handler.js.map +1 -1
  1111. package/dist/lib/user/derive-handle.d.ts +22 -0
  1112. package/dist/lib/user/derive-handle.d.ts.map +1 -1
  1113. package/dist/lib/user/derive-handle.js +18 -6
  1114. package/dist/lib/user/derive-handle.js.map +1 -1
  1115. package/dist/lib/user-badge.js +6 -14
  1116. package/dist/lib/user-badge.js.map +1 -1
  1117. package/dist/lib/user-deletion-handler-enhanced.d.ts +2 -2
  1118. package/dist/lib/user-deletion-handler-enhanced.d.ts.map +1 -1
  1119. package/dist/lib/user-deletion-handler-enhanced.js +16 -53
  1120. package/dist/lib/user-deletion-handler-enhanced.js.map +1 -1
  1121. package/dist/lib/user-deprovisioning.d.ts +1 -1
  1122. package/dist/lib/user-deprovisioning.d.ts.map +1 -1
  1123. package/dist/lib/user-deprovisioning.js +16 -20
  1124. package/dist/lib/user-deprovisioning.js.map +1 -1
  1125. package/dist/lib/user-export-handler.d.ts +4 -4
  1126. package/dist/lib/user-export-handler.d.ts.map +1 -1
  1127. package/dist/lib/user-export-handler.js +11 -15
  1128. package/dist/lib/user-export-handler.js.map +1 -1
  1129. package/dist/lib/validate-request.js +8 -13
  1130. package/dist/lib/validate-request.js.map +1 -1
  1131. package/dist/lib/validation/feature-toggle-schemas.d.ts +130 -249
  1132. package/dist/lib/validation/feature-toggle-schemas.d.ts.map +1 -1
  1133. package/dist/lib/validation/feature-toggle-schemas.js +50 -59
  1134. package/dist/lib/validation/feature-toggle-schemas.js.map +1 -1
  1135. package/dist/lib/validation/validate-request.d.ts.map +1 -1
  1136. package/dist/lib/validation/validate-request.js +12 -23
  1137. package/dist/lib/validation/validate-request.js.map +1 -1
  1138. package/dist/lib/validation.js +1 -5
  1139. package/dist/lib/validation.js.map +1 -1
  1140. package/dist/lib/version.js +3 -8
  1141. package/dist/lib/version.js.map +1 -1
  1142. package/dist/server.d.ts +1 -1
  1143. package/dist/server.d.ts.map +1 -1
  1144. package/dist/server.js +29 -69
  1145. package/dist/server.js.map +1 -1
  1146. package/dist/types/cloudflare-compat.d.ts +3 -93
  1147. package/dist/types/cloudflare-compat.d.ts.map +1 -1
  1148. package/dist/types/cloudflare-compat.js +1 -2
  1149. package/dist/types/cloudflare-compat.js.map +1 -1
  1150. package/dist/worker.d.ts +6 -6
  1151. package/dist/worker.d.ts.map +1 -1
  1152. package/dist/worker.js +6 -13
  1153. package/dist/worker.js.map +1 -1
  1154. package/package.json +28 -15
  1155. package/prisma/migrations/20260602054730_add_entity_geo_and_pending_schema/migration.sql +113 -0
  1156. package/prisma/migrations/20260602162901_research_foundations/migration.sql +65 -0
  1157. package/prisma/migrations/20260604130000_surveillance_phase0_enablers/migration.sql +107 -0
  1158. package/prisma/migrations/20260604140000_fold_link_reports_into_reports/migration.sql +23 -0
  1159. package/prisma/migrations/20260604140000_fold_link_reports_into_reports/rollback.reference.sql +31 -0
  1160. package/prisma/migrations/20260606000000_handle_canonical_identity/migration.sql +18 -0
  1161. package/prisma/schema.prisma +426 -68
  1162. package/src/lambda/cleanup-cron.ts +10 -7
  1163. package/src/lambda/create-auth-challenge.ts +6 -3
  1164. package/src/lambda/delete-account-worker.ts +17 -12
  1165. package/src/lambda/diagnostics-proxy.ts +9 -6
  1166. package/src/lambda/e2e-sweeper.ts +17 -23
  1167. package/src/lambda/federation-outbox-worker.ts +4 -1
  1168. package/src/lambda/followers-events-worker.ts +4 -1
  1169. package/src/lambda/hourly-cron.ts +112 -20
  1170. package/src/lambda/link-check-worker.ts +4 -1
  1171. package/src/lambda/maintenance-cron.ts +24 -13
  1172. package/src/lambda/media-processing-worker.ts +5 -2
  1173. package/src/lambda/media-reconciliation-worker.ts +4 -1
  1174. package/src/lambda/nightly-cron.ts +53 -54
  1175. package/src/lambda/post-confirmation.ts +262 -76
  1176. package/src/lambda/pre-token-generation.ts +39 -44
  1177. package/src/lambda/verify-auth-challenge.ts +4 -1
  1178. package/dist/lib/audit/emit.d.ts +0 -56
  1179. package/dist/lib/audit/emit.d.ts.map +0 -1
  1180. package/dist/lib/audit/emit.js +0 -124
  1181. package/dist/lib/audit/emit.js.map +0 -1
  1182. package/dist/lib/audit/event-types.d.ts +0 -36
  1183. package/dist/lib/audit/event-types.d.ts.map +0 -1
  1184. package/dist/lib/audit/event-types.js +0 -69
  1185. package/dist/lib/audit/event-types.js.map +0 -1
  1186. package/dist/lib/audit-logger.d.ts +0 -142
  1187. package/dist/lib/audit-logger.d.ts.map +0 -1
  1188. package/dist/lib/audit-logger.js +0 -326
  1189. package/dist/lib/audit-logger.js.map +0 -1
  1190. package/dist/lib/circuit-breaker.d.ts +0 -27
  1191. package/dist/lib/circuit-breaker.d.ts.map +0 -1
  1192. package/dist/lib/circuit-breaker.js +0 -63
  1193. package/dist/lib/circuit-breaker.js.map +0 -1
  1194. package/dist/lib/graph/dual-write-service.d.ts +0 -116
  1195. package/dist/lib/graph/dual-write-service.d.ts.map +0 -1
  1196. package/dist/lib/graph/dual-write-service.js +0 -332
  1197. package/dist/lib/graph/dual-write-service.js.map +0 -1
  1198. package/dist/lib/graph/dual-write.d.ts +0 -396
  1199. package/dist/lib/graph/dual-write.d.ts.map +0 -1
  1200. package/dist/lib/graph/dual-write.js +0 -53
  1201. package/dist/lib/graph/dual-write.js.map +0 -1
  1202. package/dist/lib/graph/graph-schema-init.d.ts +0 -31
  1203. package/dist/lib/graph/graph-schema-init.d.ts.map +0 -1
  1204. package/dist/lib/graph/graph-schema-init.js +0 -105
  1205. package/dist/lib/graph/graph-schema-init.js.map +0 -1
  1206. package/dist/lib/graph/neo4j-graph-service.d.ts +0 -186
  1207. package/dist/lib/graph/neo4j-graph-service.d.ts.map +0 -1
  1208. package/dist/lib/graph/neo4j-graph-service.js +0 -1625
  1209. package/dist/lib/graph/neo4j-graph-service.js.map +0 -1
  1210. package/dist/lib/graph/reconciliation-service.d.ts +0 -113
  1211. package/dist/lib/graph/reconciliation-service.d.ts.map +0 -1
  1212. package/dist/lib/graph/reconciliation-service.js +0 -533
  1213. package/dist/lib/graph/reconciliation-service.js.map +0 -1
  1214. package/dist/lib/id-generator.d.ts +0 -29
  1215. package/dist/lib/id-generator.d.ts.map +0 -1
  1216. package/dist/lib/id-generator.js +0 -51
  1217. package/dist/lib/id-generator.js.map +0 -1
  1218. package/dist/lib/kv/dynamodb-kv.d.ts +0 -39
  1219. package/dist/lib/kv/dynamodb-kv.d.ts.map +0 -1
  1220. package/dist/lib/kv/dynamodb-kv.js +0 -239
  1221. package/dist/lib/kv/dynamodb-kv.js.map +0 -1
  1222. package/dist/lib/queue/sqs-queue.d.ts +0 -16
  1223. package/dist/lib/queue/sqs-queue.d.ts.map +0 -1
  1224. package/dist/lib/queue/sqs-queue.js +0 -39
  1225. package/dist/lib/queue/sqs-queue.js.map +0 -1
  1226. package/dist/lib/route-matcher.d.ts +0 -24
  1227. package/dist/lib/route-matcher.d.ts.map +0 -1
  1228. package/dist/lib/route-matcher.js +0 -96
  1229. package/dist/lib/route-matcher.js.map +0 -1
  1230. package/dist/lib/router.d.ts +0 -26
  1231. package/dist/lib/router.d.ts.map +0 -1
  1232. package/dist/lib/router.js +0 -90
  1233. package/dist/lib/router.js.map +0 -1
  1234. package/dist/lib/routes-all.d.ts +0 -9
  1235. package/dist/lib/routes-all.d.ts.map +0 -1
  1236. package/dist/lib/routes-all.js +0 -170
  1237. package/dist/lib/routes-all.js.map +0 -1
  1238. package/dist/lib/secret-resolver.d.ts +0 -88
  1239. package/dist/lib/secret-resolver.d.ts.map +0 -1
  1240. package/dist/lib/secret-resolver.js +0 -183
  1241. package/dist/lib/secret-resolver.js.map +0 -1
  1242. package/dist/lib/session-manager.d.ts.map +0 -1
  1243. package/dist/lib/session-manager.js +0 -492
  1244. package/dist/lib/session-manager.js.map +0 -1
  1245. package/dist/lib/storage/s3-storage.d.ts +0 -29
  1246. package/dist/lib/storage/s3-storage.d.ts.map +0 -1
  1247. package/dist/lib/storage/s3-storage.js +0 -135
  1248. package/dist/lib/storage/s3-storage.js.map +0 -1
  1249. package/dist/lib/tenant-context.d.ts +0 -35
  1250. package/dist/lib/tenant-context.d.ts.map +0 -1
  1251. package/dist/lib/tenant-context.js +0 -54
  1252. package/dist/lib/tenant-context.js.map +0 -1
@@ -1,1625 +0,0 @@
1
- "use strict";
2
- /**
3
- * Neo4j GraphService Implementation
4
- *
5
- * Implements the GraphService interface using the Neo4j JavaScript driver.
6
- * Used for local development and the AuraDB production/dev instances —
7
- * same Cypher dialect.
8
- *
9
- * Connection management, schema initialization, and health checks are fully
10
- * implemented. Business methods are stubbed (Phase 2).
11
- *
12
- * SECURITY: All queries use parameterized queries ($paramName) — never
13
- * string concatenation.
14
- *
15
- * @see /analysis/redesign/07-graph-database/04-graph-schema.md
16
- */
17
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
- if (k2 === undefined) k2 = k;
19
- var desc = Object.getOwnPropertyDescriptor(m, k);
20
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
- desc = { enumerable: true, get: function() { return m[k]; } };
22
- }
23
- Object.defineProperty(o, k2, desc);
24
- }) : (function(o, m, k, k2) {
25
- if (k2 === undefined) k2 = k;
26
- o[k2] = m[k];
27
- }));
28
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
- Object.defineProperty(o, "default", { enumerable: true, value: v });
30
- }) : function(o, v) {
31
- o["default"] = v;
32
- });
33
- var __importStar = (this && this.__importStar) || (function () {
34
- var ownKeys = function(o) {
35
- ownKeys = Object.getOwnPropertyNames || function (o) {
36
- var ar = [];
37
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
- return ar;
39
- };
40
- return ownKeys(o);
41
- };
42
- return function (mod) {
43
- if (mod && mod.__esModule) return mod;
44
- var result = {};
45
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
- __setModuleDefault(result, mod);
47
- return result;
48
- };
49
- })();
50
- var __importDefault = (this && this.__importDefault) || function (mod) {
51
- return (mod && mod.__esModule) ? mod : { "default": mod };
52
- };
53
- Object.defineProperty(exports, "__esModule", { value: true });
54
- exports.Neo4jGraphService = void 0;
55
- const neo4j_driver_1 = __importDefault(require("neo4j-driver"));
56
- const errors_1 = require("./errors");
57
- const graph_schema_init_1 = require("./graph-schema-init");
58
- const scoring_engine_1 = require("./scoring-engine");
59
- // ---------------------------------------------------------------------------
60
- // Implementation
61
- // ---------------------------------------------------------------------------
62
- class Neo4jGraphService {
63
- driver = null;
64
- connected = false;
65
- schemaInitialized = false;
66
- // =========================================================================
67
- // Connection Management (GraphConnection)
68
- // =========================================================================
69
- async connect(config) {
70
- if (this.connected && this.driver) {
71
- return; // Idempotent
72
- }
73
- try {
74
- // Resolve authentication
75
- let auth;
76
- if (config.auth.type === "basic") {
77
- auth = neo4j_driver_1.default.auth.basic(config.auth.username, config.auth.password);
78
- }
79
- // "none" auth type: no auth object passed to driver
80
- // Create driver with pool configuration
81
- this.driver = neo4j_driver_1.default.driver(config.endpoint, auth, {
82
- maxConnectionPoolSize: config.pool?.maxConnectionPoolSize ?? 100,
83
- connectionAcquisitionTimeout: config.pool?.connectionAcquisitionTimeout ?? 60_000,
84
- maxConnectionLifetime: config.pool?.maxConnectionLifetime ?? 3_600_000,
85
- ...(config.pool?.connectionLivenessCheckTimeout !== undefined && {
86
- connectionLivenessCheckTimeout: config.pool.connectionLivenessCheckTimeout,
87
- }),
88
- disableLosslessIntegers: true, // Return native JS numbers instead of Neo4j Integer
89
- });
90
- // Verify connectivity
91
- await this.driver.verifyConnectivity();
92
- this.connected = true;
93
- // Initialize schema (constraints + indexes) on first connect
94
- if (!this.schemaInitialized) {
95
- await this.initializeSchema();
96
- }
97
- }
98
- catch (error) {
99
- this.connected = false;
100
- this.driver = null;
101
- throw new errors_1.GraphConnectionError(`Failed to connect to Neo4j at ${config.endpoint}: ${error instanceof Error ? error.message : String(error)}`, { cause: error instanceof Error ? error : undefined });
102
- }
103
- }
104
- async close() {
105
- if (this.driver) {
106
- await this.driver.close();
107
- this.driver = null;
108
- this.connected = false;
109
- }
110
- }
111
- isConnected() {
112
- return this.connected;
113
- }
114
- // =========================================================================
115
- // Health Check
116
- // =========================================================================
117
- async healthCheck() {
118
- if (!this.driver || !this.connected) {
119
- return {
120
- healthy: false,
121
- latencyMs: 0,
122
- error: "Not connected",
123
- backend: "neo4j",
124
- };
125
- }
126
- const session = this.driver.session();
127
- const start = Date.now();
128
- try {
129
- await session.run("RETURN 1 AS health");
130
- const latencyMs = Date.now() - start;
131
- return {
132
- healthy: true,
133
- latencyMs,
134
- backend: "neo4j",
135
- };
136
- }
137
- catch (error) {
138
- const latencyMs = Date.now() - start;
139
- this.connected = false;
140
- return {
141
- healthy: false,
142
- latencyMs,
143
- error: error instanceof Error ? error.message : String(error),
144
- backend: "neo4j",
145
- };
146
- }
147
- finally {
148
- await session.close();
149
- }
150
- }
151
- // =========================================================================
152
- // Relationships
153
- // =========================================================================
154
- async createRelationship(input) {
155
- const { userId, targetType, targetId, connectionMethod = "discovery" } = input;
156
- // Initial score by connection method (from scoring engine constants)
157
- const initialScore = scoring_engine_1.CONNECTION_BONUSES[connectionMethod] ?? 0.3;
158
- const tier = (0, scoring_engine_1.scoreToTier)(initialScore);
159
- const now = new Date().toISOString();
160
- // Target label is capitalized: "user" -> "User", "entity" -> "Entity"
161
- const targetLabel = targetType === "user" ? "User" : "Entity";
162
- // MERGE the relationship (idempotent on the edge; we want conflict detection so
163
- // we use MATCH first and fail if it already exists, then CREATE).
164
- // We verify the target node exists, then create the edge.
165
- const result = await this.executeQuery(`
166
- MATCH (src:User {id: $userId})
167
- MATCH (tgt:${targetLabel} {id: $targetId})
168
- MERGE (src)-[r:RELATES_TO]->(tgt)
169
- ON CREATE SET
170
- r.computedScore = $initialScore,
171
- r.manualScore = null,
172
- r.score = $initialScore,
173
- r.tier = $tier,
174
- r.interactionCount = 0,
175
- r.lastInteractionAt = null,
176
- r.connectionMethod = $connectionMethod,
177
- r.reciprocated = false,
178
- r.createdAt = $now
179
- ON MATCH SET
180
- r._alreadyExisted = true
181
- WITH src, tgt, r
182
- // Handle reciprocity for user->user edges
183
- OPTIONAL MATCH (tgt)-[rev:RELATES_TO]->(src)
184
- WITH r, rev, (tgt:User) AS isUserTarget
185
- SET r.reciprocated = (isUserTarget AND rev IS NOT NULL)
186
- WITH r, rev, isUserTarget
187
- // Mark the reverse edge as reciprocated if it exists
188
- FOREACH (_ IN CASE WHEN isUserTarget AND rev IS NOT NULL THEN [1] ELSE [] END |
189
- SET rev.reciprocated = true
190
- )
191
- RETURN r
192
- `, { userId, targetId, initialScore, tier, connectionMethod, now });
193
- if (result.records.length === 0) {
194
- throw new errors_1.GraphNotFoundError(`Source user ${userId} or target ${targetType} ${targetId} not found in graph`);
195
- }
196
- const rel = result.records[0].get("r").properties;
197
- return recordToRelationship(rel, userId, targetType, targetId);
198
- }
199
- async removeRelationship(userId, targetType, targetId) {
200
- const targetLabel = targetType === "user" ? "User" : "Entity";
201
- const result = await this.executeQuery(`
202
- OPTIONAL MATCH (src:User {id: $userId})-[r:RELATES_TO]->(tgt:${targetLabel} {id: $targetId})
203
- WITH r, src, tgt, (tgt:User) AS isUserTarget, (r IS NOT NULL) AS found
204
- // If reciprocated user-user edge, clear the reverse reciprocated flag
205
- OPTIONAL MATCH (tgt)-[rev:RELATES_TO]->(src)
206
- WITH r, rev, isUserTarget, found
207
- FOREACH (_ IN CASE WHEN isUserTarget AND rev IS NOT NULL THEN [1] ELSE [] END |
208
- SET rev.reciprocated = false
209
- )
210
- WITH r, found
211
- FOREACH (_ IN CASE WHEN r IS NOT NULL THEN [1] ELSE [] END | DELETE r)
212
- RETURN found
213
- `, { userId, targetId });
214
- // If no relationship was matched and deleted, throw not found
215
- const found = result.records[0]?.get("found") ?? false;
216
- if (!found) {
217
- throw new errors_1.GraphNotFoundError(`Relationship from user ${userId} to ${targetType} ${targetId} not found`, "relationship", `${userId}->${targetId}`);
218
- }
219
- }
220
- async updateRelationshipScore(input) {
221
- const { userId, targetType, targetId, manualScore } = input;
222
- const targetLabel = targetType === "user" ? "User" : "Entity";
223
- const result = await this.executeQuery(`
224
- MATCH (src:User {id: $userId})-[r:RELATES_TO]->(tgt:${targetLabel} {id: $targetId})
225
- SET r.manualScore = $manualScore,
226
- r.score = CASE WHEN $manualScore IS NOT NULL THEN $manualScore ELSE r.computedScore END
227
- RETURN r
228
- `, {
229
- userId,
230
- targetId,
231
- manualScore: manualScore ?? null,
232
- });
233
- if (result.records.length === 0) {
234
- throw new errors_1.GraphNotFoundError(`Relationship from user ${userId} to ${targetType} ${targetId} not found`, "relationship", `${userId}->${targetId}`);
235
- }
236
- // The query updates r.score in the DB; derive tier from the effective score.
237
- const rel = result.records[0].get("r").properties;
238
- const effectiveScore = typeof rel.score === "number" ? rel.score : 0;
239
- rel.tier = (0, scoring_engine_1.scoreToTier)(effectiveScore);
240
- return recordToRelationship(rel, userId, targetType, targetId);
241
- }
242
- async getRelationship(userId, targetType, targetId) {
243
- const targetLabel = targetType === "user" ? "User" : "Entity";
244
- const result = await this.executeQuery(`
245
- MATCH (src:User {id: $userId})-[r:RELATES_TO]->(tgt:${targetLabel} {id: $targetId})
246
- RETURN r
247
- `, { userId, targetId });
248
- if (result.records.length === 0) {
249
- return null;
250
- }
251
- const rel = result.records[0].get("r").properties;
252
- return recordToRelationship(rel, userId, targetType, targetId);
253
- }
254
- async getRelationships(userId, options) {
255
- const limit = options?.pagination?.limit ?? 50;
256
- const cursor = options?.pagination?.cursor ?? null;
257
- // Build tier filter
258
- const tierFilter = options?.tier !== undefined ? "AND r.tier = $tier" : "";
259
- // Build target label constraint
260
- let targetMatch = "(tgt)";
261
- if (options?.targetType === "user") {
262
- targetMatch = "(tgt:User)";
263
- }
264
- else if (options?.targetType === "entity") {
265
- targetMatch = "(tgt:Entity)";
266
- }
267
- // Cursor encodes the score of the last item (score-based cursor pagination)
268
- const cursorScore = cursor !== null ? decodeCursor(cursor) : null;
269
- const cursorFilter = cursorScore !== null ? "AND r.score < $cursorScore" : "";
270
- const result = await this.executeQuery(`
271
- MATCH (src:User {id: $userId})-[r:RELATES_TO]->${targetMatch}
272
- WHERE 1=1 ${tierFilter} ${cursorFilter}
273
- RETURN r, tgt.id AS targetId,
274
- CASE WHEN tgt:User THEN 'user' ELSE 'entity' END AS targetType
275
- ORDER BY r.score DESC
276
- LIMIT $fetchLimit
277
- `, {
278
- userId,
279
- tier: options?.tier ?? null,
280
- cursorScore: cursorScore ?? null,
281
- fetchLimit: limit + 1, // fetch one extra to detect hasMore
282
- });
283
- const records = result.records;
284
- const hasMore = records.length > limit;
285
- const items = (hasMore ? records.slice(0, limit) : records).map((rec) => {
286
- const rel = rec.get("r").properties;
287
- const tId = rec.get("targetId");
288
- const tType = rec.get("targetType");
289
- return recordToRelationship(rel, userId, tType, tId);
290
- });
291
- const lastItem = items[items.length - 1];
292
- const nextCursor = hasMore && lastItem ? encodeCursor(lastItem.score) : null;
293
- return { items, cursor: nextCursor, hasMore };
294
- }
295
- async getRelationshipGraph(userId) {
296
- const result = await this.executeQuery(`
297
- MATCH (viewer:User {id: $userId})-[r:RELATES_TO]->(tgt)
298
- RETURN tgt.id AS targetId,
299
- CASE WHEN tgt:User THEN 'user' ELSE 'entity' END AS targetType,
300
- tgt.name AS name,
301
- r.score AS score,
302
- r.tier AS tier
303
- ORDER BY r.score DESC
304
- `, { userId });
305
- const nodes = result.records.map((rec) => {
306
- const rawScore = rec.get("score");
307
- const tier = rec.get("tier");
308
- return {
309
- id: rec.get("targetId"),
310
- type: rec.get("targetType"),
311
- name: rec.get("name") ?? "",
312
- // Coarsen to nearest 10 (0-100), no raw score exposed
313
- closeness: Math.round(rawScore * 10) * 10,
314
- tier,
315
- };
316
- });
317
- // Build tier summaries
318
- const counts = { inner: 0, closeFriends: 0, community: 0, ambient: 0 };
319
- for (const node of nodes) {
320
- const tierName = tierToName(node.tier);
321
- counts[tierName]++;
322
- }
323
- // Use canonical thresholds from the scoring engine
324
- const thresholdFor = (tier) => scoring_engine_1.TIER_THRESHOLDS.find((t) => t.tier === tier)?.minScore ?? 0;
325
- const tiers = {
326
- inner: { threshold: thresholdFor(0), count: counts.inner },
327
- closeFriends: { threshold: thresholdFor(1), count: counts.closeFriends },
328
- community: { threshold: thresholdFor(2), count: counts.community },
329
- ambient: { threshold: thresholdFor(3), count: counts.ambient },
330
- };
331
- return { nodes, tiers };
332
- }
333
- // =========================================================================
334
- // Circles (Stubbed — Phase 2)
335
- // =========================================================================
336
- // --- Circle Resolution helpers (P2.2) ---
337
- /** Default circle config thresholds from circle-queries.md. */
338
- static CIRCLE_THRESHOLDS = {
339
- innerThreshold: 0.8,
340
- closeFriendThreshold: 0.5,
341
- communityThreshold: 0.2,
342
- };
343
- static TIER_NAMES = { 0: "inner", 1: "closeFriends", 2: "community", 3: "ambient" };
344
- /** Score threshold bounds for a tier (from circle-queries.md). */
345
- getCircleTierBounds(tier, thresholds = Neo4jGraphService.CIRCLE_THRESHOLDS) {
346
- switch (tier) {
347
- case 0: return { lower: thresholds.innerThreshold, upper: Infinity };
348
- case 1: return { lower: thresholds.closeFriendThreshold, upper: thresholds.innerThreshold };
349
- case 2: return { lower: thresholds.communityThreshold, upper: thresholds.closeFriendThreshold };
350
- case 3: return { lower: 0.001, upper: thresholds.communityThreshold };
351
- }
352
- }
353
- decodeCircleCursor(cursor) {
354
- if (!cursor)
355
- return null;
356
- try {
357
- const d = JSON.parse(Buffer.from(cursor, "base64").toString("utf8"));
358
- if (d.createdAt && d.postId)
359
- return d;
360
- return null;
361
- }
362
- catch {
363
- return null;
364
- }
365
- }
366
- encodeCircleCursor(createdAt, postId) {
367
- return Buffer.from(JSON.stringify({ createdAt, postId })).toString("base64");
368
- }
369
- // --- Circle Resolution methods (P2.2) ---
370
- async getCircleMembers(userId, tier) {
371
- const bounds = this.getCircleTierBounds(tier);
372
- const result = await this.executeQuery(`MATCH (viewer:User {id: $viewerId})-[r:RELATES_TO]->(target)
373
- WHERE r.score >= $lowerThreshold AND r.score < $upperThreshold
374
- RETURN target.id AS id, labels(target)[0] AS type, target.name AS name, r.score AS score
375
- ORDER BY r.score DESC`, { viewerId: userId, lowerThreshold: bounds.lower, upperThreshold: bounds.upper === Infinity ? 1e9 : bounds.upper });
376
- return result.records.map((rec) => ({
377
- id: rec.get("id"),
378
- type: rec.get("type").toLowerCase() === "entity" ? "entity" : "user",
379
- name: rec.get("name"),
380
- score: rec.get("score"),
381
- tier,
382
- }));
383
- }
384
- async getVisiblePostIds(userId, tier, since, pagination) {
385
- const bounds = this.getCircleTierBounds(tier);
386
- const t = Neo4jGraphService.CIRCLE_THRESHOLDS;
387
- const cursor = this.decodeCircleCursor(pagination.cursor ?? undefined);
388
- const cursorClause = cursor
389
- ? `AND (post.createdAt < datetime($cursorCreatedAt) OR (post.createdAt = datetime($cursorCreatedAt) AND post.id < $cursorPostId))`
390
- : "";
391
- const query = `
392
- MATCH (viewer:User {id: $viewerId})-[r:RELATES_TO]->(entity:Entity)
393
- WHERE r.score >= $lowerThreshold AND r.score < $upperThreshold
394
- WITH entity, r.score AS relScore
395
- MATCH (post:Post)-[:ABOUT]->(entity)
396
- WHERE post.createdAt > datetime($since) AND post.radiusInt >= $tierInt ${cursorClause}
397
- WITH post, MIN(CASE WHEN relScore >= $innerThreshold THEN 0 WHEN relScore >= $closeFriendThreshold THEN 1 WHEN relScore >= $communityThreshold THEN 2 ELSE 3 END) AS resolvedTier
398
- RETURN post.id AS postId, post.createdAt AS createdAt, resolvedTier
399
- UNION
400
- MATCH (viewer:User {id: $viewerId})-[r:RELATES_TO]->(author:User)
401
- WHERE r.score >= $lowerThreshold AND r.score < $upperThreshold
402
- WITH author, r.score AS relScore
403
- MATCH (post:Post)
404
- WHERE post.authorId = author.id AND post.createdAt > datetime($since) AND post.radiusInt >= $tierInt ${cursorClause}
405
- WITH post, MIN(CASE WHEN relScore >= $innerThreshold THEN 0 WHEN relScore >= $closeFriendThreshold THEN 1 WHEN relScore >= $communityThreshold THEN 2 ELSE 3 END) AS resolvedTier
406
- RETURN post.id AS postId, post.createdAt AS createdAt, resolvedTier
407
- ORDER BY createdAt DESC
408
- LIMIT $limit`;
409
- const params = {
410
- viewerId: userId, lowerThreshold: bounds.lower,
411
- upperThreshold: bounds.upper === Infinity ? 1e9 : bounds.upper,
412
- since: since.toISOString(), tierInt: tier,
413
- innerThreshold: t.innerThreshold, closeFriendThreshold: t.closeFriendThreshold,
414
- communityThreshold: t.communityThreshold, limit: pagination.limit + 1,
415
- };
416
- if (cursor) {
417
- params.cursorCreatedAt = cursor.createdAt;
418
- params.cursorPostId = cursor.postId;
419
- }
420
- const result = await this.executeQuery(query, params);
421
- const items = result.records.slice(0, pagination.limit).map((rec) => {
422
- const ca = rec.get("createdAt");
423
- return { postId: rec.get("postId"), createdAt: ca instanceof Date ? ca : new Date(String(ca)), resolvedTier: rec.get("resolvedTier") };
424
- });
425
- const hasMore = result.records.length > pagination.limit;
426
- const last = items[items.length - 1];
427
- const nextCursor = hasMore && last ? this.encodeCircleCursor(last.createdAt.toISOString(), last.postId) : null;
428
- return { items, cursor: nextCursor, hasMore };
429
- }
430
- async getGlanceItems(userId, tier, limit) {
431
- const bounds = this.getCircleTierBounds(tier);
432
- // Step 1: get tier members
433
- const membersResult = await this.executeQuery(`MATCH (viewer:User {id: $viewerId})-[r:RELATES_TO]->(target)
434
- WHERE r.score >= $lowerThreshold AND r.score < $upperThreshold
435
- RETURN target.id AS targetId, labels(target)[0] AS targetType, target.name AS targetName, r.score AS score
436
- ORDER BY r.score DESC`, { viewerId: userId, lowerThreshold: bounds.lower, upperThreshold: bounds.upper === Infinity ? 1e9 : bounds.upper });
437
- const entityIds = [];
438
- const userIds = [];
439
- const memberMap = new Map();
440
- for (const rec of membersResult.records) {
441
- const tid = rec.get("targetId");
442
- const rawType = rec.get("targetType").toLowerCase();
443
- const tt = rawType === "entity" ? "entity" : "user";
444
- memberMap.set(tid, { targetType: tt, targetName: rec.get("targetName") });
445
- if (tt === "entity")
446
- entityIds.push(tid);
447
- else
448
- userIds.push(tid);
449
- }
450
- const glanceItems = [];
451
- // Step 2a: entity posts
452
- if (entityIds.length > 0) {
453
- const er = await this.executeQuery(`UNWIND $entityIds AS entityId
454
- MATCH (entity:Entity {id: entityId})<-[:ABOUT]-(post:Post)
455
- WHERE post.radiusInt >= $tierInt
456
- WITH entityId, post ORDER BY post.createdAt DESC
457
- WITH entityId, COLLECT(post)[0] AS latestPost
458
- WHERE latestPost IS NOT NULL
459
- RETURN entityId AS targetId, latestPost.id AS postId, latestPost.createdAt AS postCreatedAt`, { entityIds, tierInt: tier });
460
- for (const rec of er.records) {
461
- const tid = rec.get("targetId");
462
- const m = memberMap.get(tid);
463
- if (!m)
464
- continue;
465
- const pca = rec.get("postCreatedAt");
466
- glanceItems.push({ targetId: tid, targetType: "entity", targetName: m.targetName, postId: rec.get("postId"), postCreatedAt: pca instanceof Date ? pca : new Date(String(pca)) });
467
- }
468
- }
469
- // Step 2b: user posts
470
- if (userIds.length > 0) {
471
- const ur = await this.executeQuery(`UNWIND $userIds AS uId
472
- MATCH (post:Post) WHERE post.authorId = uId AND post.radiusInt >= $tierInt
473
- WITH uId, post ORDER BY post.createdAt DESC
474
- With uId, COLLECT(post)[0] AS latestPost
475
- WHERE latestPost IS NOT NULL
476
- RETURN uId AS targetId, latestPost.id AS postId, latestPost.createdAt AS postCreatedAt`, { userIds, tierInt: tier });
477
- for (const rec of ur.records) {
478
- const tid = rec.get("targetId");
479
- const m = memberMap.get(tid);
480
- if (!m)
481
- continue;
482
- const pca = rec.get("postCreatedAt");
483
- glanceItems.push({ targetId: tid, targetType: "user", targetName: m.targetName, postId: rec.get("postId"), postCreatedAt: pca instanceof Date ? pca : new Date(String(pca)) });
484
- }
485
- }
486
- glanceItems.sort((a, b) => b.postCreatedAt.getTime() - a.postCreatedAt.getTime());
487
- return glanceItems.slice(0, limit);
488
- }
489
- async getDepthPostIds(userId, targetType, targetId, since, limit) {
490
- const t = Neo4jGraphService.CIRCLE_THRESHOLDS;
491
- const commonParams = {
492
- viewerId: userId, targetId, since: since.toISOString(),
493
- innerThreshold: t.innerThreshold, closeFriendThreshold: t.closeFriendThreshold,
494
- communityThreshold: t.communityThreshold, limit,
495
- };
496
- if (targetType === "entity") {
497
- const result = await this.executeQuery(`MATCH (viewer:User {id: $viewerId})-[r:RELATES_TO]->(entity:Entity {id: $targetId})
498
- MATCH (post:Post)-[:ABOUT]->(entity)
499
- WHERE post.createdAt > datetime($since)
500
- AND post.radiusInt >= CASE WHEN r.score >= $innerThreshold THEN 0 WHEN r.score >= $closeFriendThreshold THEN 1 WHEN r.score >= $communityThreshold THEN 2 ELSE 3 END
501
- RETURN post.id AS postId ORDER BY post.createdAt DESC LIMIT $limit`, commonParams);
502
- return result.records.map((r) => r.get("postId"));
503
- }
504
- const result = await this.executeQuery(`MATCH (viewer:User {id: $viewerId})-[r:RELATES_TO]->(author:User {id: $targetId})
505
- MATCH (post:Post)
506
- WHERE post.authorId = author.id AND post.createdAt > datetime($since)
507
- AND post.radiusInt >= CASE WHEN r.score >= $innerThreshold THEN 0 WHEN r.score >= $closeFriendThreshold THEN 1 WHEN r.score >= $communityThreshold THEN 2 ELSE 3 END
508
- RETURN post.id AS postId ORDER BY post.createdAt DESC LIMIT $limit`, commonParams);
509
- return result.records.map((r) => r.get("postId"));
510
- }
511
- /**
512
- * Get circle status for all tiers. Uses four parallel count queries
513
- * (recommended by circle-queries.md). lastReadTimestamps come from
514
- * Postgres CircleReadState.
515
- */
516
- async getCircleStatus(userId, lastReadTimestamps) {
517
- const thresholds = Neo4jGraphService.CIRCLE_THRESHOLDS;
518
- const defaultLR = new Date(0);
519
- const lr = {
520
- 0: lastReadTimestamps?.[0] ?? defaultLR, 1: lastReadTimestamps?.[1] ?? defaultLR,
521
- 2: lastReadTimestamps?.[2] ?? defaultLR, 3: lastReadTimestamps?.[3] ?? defaultLR,
522
- };
523
- const tiers = [0, 1, 2, 3];
524
- return Promise.all(tiers.map(async (tier) => {
525
- const bounds = this.getCircleTierBounds(tier, thresholds);
526
- const result = await this.executeQuery(`MATCH (viewer:User {id: $viewerId})-[r:RELATES_TO]->(target)
527
- WHERE r.score >= $lowerThreshold AND r.score < $upperThreshold
528
- MATCH (post:Post)
529
- WHERE ((target:Entity AND EXISTS { MATCH (post)-[:ABOUT]->(target) }) OR (target:User AND post.authorId = target.id))
530
- AND post.radiusInt >= $tierInt AND post.createdAt > datetime($lastReadAt)
531
- RETURN COUNT(DISTINCT post.id) AS unseenCount`, { viewerId: userId, lowerThreshold: bounds.lower, upperThreshold: bounds.upper === Infinity ? 1e9 : bounds.upper, tierInt: tier, lastReadAt: lr[tier].toISOString() });
532
- const unseenCount = result.records.length > 0 ? result.records[0].get("unseenCount") : 0;
533
- return { tier, name: Neo4jGraphService.TIER_NAMES[tier], caughtUp: unseenCount === 0, unseenCount, lastReadAt: lastReadTimestamps?.[tier] ?? null };
534
- }));
535
- }
536
- /**
537
- * Get per-entity unseen counts within a tier. Uses circle-queries.md Query 5.
538
- * lastReadAt comes from Postgres CircleReadState.
539
- */
540
- async getCircleEntityStatus(userId, tier, lastReadAt) {
541
- const bounds = this.getCircleTierBounds(tier);
542
- const effectiveLR = lastReadAt ?? new Date(0);
543
- const result = await this.executeQuery(`MATCH (viewer:User {id: $viewerId})-[r:RELATES_TO]->(entity:Entity)
544
- WHERE r.score >= $lowerThreshold AND r.score < $upperThreshold
545
- OPTIONAL MATCH (post:Post)-[:ABOUT]->(entity)
546
- WHERE post.radiusInt >= $tierInt AND post.createdAt > datetime($lastReadAt)
547
- WITH entity, COUNT(post) AS unseenCount, MAX(post.createdAt) AS latestPostAt
548
- RETURN entity.id AS entityId, entity.name AS entityName, unseenCount = 0 AS caughtUp, unseenCount, latestPostAt
549
- ORDER BY unseenCount DESC, latestPostAt DESC`, { viewerId: userId, lowerThreshold: bounds.lower, upperThreshold: bounds.upper === Infinity ? 1e9 : bounds.upper, tierInt: tier, lastReadAt: effectiveLR.toISOString() });
550
- return result.records.map((rec) => {
551
- const lpa = rec.get("latestPostAt");
552
- return {
553
- entityId: rec.get("entityId"), entityName: rec.get("entityName"),
554
- caughtUp: rec.get("caughtUp"), unseenCount: rec.get("unseenCount"),
555
- latestPostAt: lpa ? (lpa instanceof Date ? lpa : new Date(String(lpa))) : null,
556
- };
557
- });
558
- }
559
- /**
560
- * Mark a circle tier as read. The canonical read state lives in Postgres
561
- * (CircleReadState). This stores it on the User node as graph-side fallback.
562
- */
563
- async markCircleRead(userId, tier, readAt) {
564
- const timestamp = readAt ?? new Date();
565
- const prop = `lastReadTier${tier}`;
566
- await this.executeQuery(`MATCH (u:User {id: $userId}) SET u.${prop} = datetime($readAt)`, { userId, readAt: timestamp.toISOString() });
567
- }
568
- // =========================================================================
569
- // Entity Relationships
570
- // =========================================================================
571
- async createEntityRelationship(input) {
572
- const { entityId, relatedEntityId, type, proposedByUserId } = input;
573
- // 1. Verify proposing user owns the source entity
574
- const ownershipCheck = await this.executeQuery(`MATCH (u:User {id: $userId})-[o:OWNS]->(e:Entity {id: $entityId})
575
- RETURN o.role AS role`, { userId: proposedByUserId, entityId });
576
- if (ownershipCheck.records.length === 0) {
577
- const { GraphAuthorizationError } = await Promise.resolve().then(() => __importStar(require("./errors")));
578
- throw new GraphAuthorizationError(`User ${proposedByUserId} does not own entity ${entityId}`);
579
- }
580
- // 2. Verify both entity nodes exist
581
- const entityCheck = await this.executeQuery(`MATCH (a:Entity {id: $entityId})
582
- MATCH (b:Entity {id: $relatedEntityId})
583
- RETURN a.id AS aId, b.id AS bId`, { entityId, relatedEntityId });
584
- if (entityCheck.records.length === 0) {
585
- const { GraphNotFoundError } = await Promise.resolve().then(() => __importStar(require("./errors")));
586
- throw new GraphNotFoundError(`One or both entities not found: ${entityId}, ${relatedEntityId}`);
587
- }
588
- // 3. Check for existing relationship of this type
589
- const existingCheck = await this.executeQuery(`MATCH (a:Entity {id: $entityId})-[r:ENTITY_RELATES {type: $type}]->(b:Entity {id: $relatedEntityId})
590
- RETURN r.status AS status`, { entityId, relatedEntityId, type });
591
- if (existingCheck.records.length > 0) {
592
- const { GraphConflictError } = await Promise.resolve().then(() => __importStar(require("./errors")));
593
- throw new GraphConflictError(`Entity relationship of type ${type} already exists between ${entityId} and ${relatedEntityId}`);
594
- }
595
- // 4. Determine if auto-confirm applies.
596
- // PACK_MATE between entities where a single user holds PRIMARY_OWNER or CO_OWNER
597
- // on BOTH entities auto-confirms. CARETAKER is excluded per security rules.
598
- let status = "PENDING";
599
- if (type === "PACK_MATE") {
600
- const sharedOwnerCheck = await this.executeQuery(`MATCH (u:User)-[o1:OWNS]->(a:Entity {id: $entityId})
601
- MATCH (u)-[o2:OWNS]->(b:Entity {id: $relatedEntityId})
602
- WHERE o1.role IN ['PRIMARY_OWNER', 'CO_OWNER']
603
- AND o2.role IN ['PRIMARY_OWNER', 'CO_OWNER']
604
- RETURN u.id AS userId
605
- LIMIT 1`, { entityId, relatedEntityId });
606
- if (sharedOwnerCheck.records.length > 0) {
607
- status = "CONFIRMED";
608
- }
609
- }
610
- const now = new Date();
611
- const since = now.toISOString();
612
- if (status === "CONFIRMED") {
613
- // Auto-confirmed PACK_MATE: create bidirectional edges immediately
614
- await this.executeQuery(`MATCH (a:Entity {id: $entityId}), (b:Entity {id: $relatedEntityId})
615
- CREATE (a)-[:ENTITY_RELATES {
616
- type: $type,
617
- status: 'CONFIRMED',
618
- proposedByUserId: $proposedByUserId,
619
- since: $since
620
- }]->(b)
621
- CREATE (b)-[:ENTITY_RELATES {
622
- type: $type,
623
- status: 'CONFIRMED',
624
- proposedByUserId: $proposedByUserId,
625
- since: $since
626
- }]->(a)`, { entityId, relatedEntityId, type, proposedByUserId, since });
627
- }
628
- else {
629
- // Create single PENDING edge from source to target
630
- await this.executeQuery(`MATCH (a:Entity {id: $entityId}), (b:Entity {id: $relatedEntityId})
631
- CREATE (a)-[:ENTITY_RELATES {
632
- type: $type,
633
- status: 'PENDING',
634
- proposedByUserId: $proposedByUserId,
635
- since: $since
636
- }]->(b)`, { entityId, relatedEntityId, type, proposedByUserId, since });
637
- }
638
- return {
639
- entityId,
640
- relatedEntityId,
641
- type,
642
- status,
643
- proposedByUserId,
644
- since: now,
645
- };
646
- }
647
- async confirmEntityRelationship(entityId, relatedEntityId, confirmingUserId) {
648
- // 1. Verify confirming user owns the target (related) entity
649
- const ownershipCheck = await this.executeQuery(`MATCH (u:User {id: $userId})-[o:OWNS]->(e:Entity {id: $relatedEntityId})
650
- RETURN o.role AS role`, { userId: confirmingUserId, relatedEntityId });
651
- if (ownershipCheck.records.length === 0) {
652
- const { GraphAuthorizationError } = await Promise.resolve().then(() => __importStar(require("./errors")));
653
- throw new GraphAuthorizationError(`User ${confirmingUserId} does not own entity ${relatedEntityId}`);
654
- }
655
- // 2. Find the pending relationship
656
- const relCheck = await this.executeQuery(`MATCH (a:Entity {id: $entityId})-[r:ENTITY_RELATES]->(b:Entity {id: $relatedEntityId})
657
- RETURN r.type AS type, r.status AS status, r.proposedByUserId AS proposedByUserId, r.since AS since`, { entityId, relatedEntityId });
658
- if (relCheck.records.length === 0) {
659
- const { GraphNotFoundError } = await Promise.resolve().then(() => __importStar(require("./errors")));
660
- throw new GraphNotFoundError(`Entity relationship not found between ${entityId} and ${relatedEntityId}`);
661
- }
662
- const record = relCheck.records[0];
663
- const currentStatus = record.get("status");
664
- const relType = record.get("type");
665
- const proposedByUserId = record.get("proposedByUserId");
666
- const since = record.get("since");
667
- if (currentStatus !== "PENDING") {
668
- const { GraphConflictError } = await Promise.resolve().then(() => __importStar(require("./errors")));
669
- throw new GraphConflictError(`Entity relationship is already ${currentStatus}`);
670
- }
671
- // 3. Update the existing edge to CONFIRMED
672
- await this.executeQuery(`MATCH (a:Entity {id: $entityId})-[r:ENTITY_RELATES]->(b:Entity {id: $relatedEntityId})
673
- SET r.status = 'CONFIRMED'`, { entityId, relatedEntityId });
674
- // 4. Create or confirm reciprocal edge based on relationship symmetry
675
- const SYMMETRIC_TYPES = new Set(["PACK_MATE", "SIBLING", "PLAYMATE", "WALK_BUDDY"]);
676
- const ASYMMETRIC_PAIRS = {
677
- PARENT: "OFFSPRING",
678
- OFFSPRING: "PARENT",
679
- };
680
- if (SYMMETRIC_TYPES.has(relType)) {
681
- // Symmetric: B→A edge gets the same type
682
- const reverseCheck = await this.executeQuery(`MATCH (b:Entity {id: $relatedEntityId})-[r:ENTITY_RELATES {type: $type}]->(a:Entity {id: $entityId})
683
- RETURN r.status AS status`, { entityId, relatedEntityId, type: relType });
684
- if (reverseCheck.records.length === 0) {
685
- await this.executeQuery(`MATCH (a:Entity {id: $entityId}), (b:Entity {id: $relatedEntityId})
686
- CREATE (b)-[:ENTITY_RELATES {
687
- type: $type,
688
- status: 'CONFIRMED',
689
- proposedByUserId: $proposedByUserId,
690
- since: $since
691
- }]->(a)`, { entityId, relatedEntityId, type: relType, proposedByUserId, since });
692
- }
693
- else {
694
- await this.executeQuery(`MATCH (b:Entity {id: $relatedEntityId})-[r:ENTITY_RELATES {type: $type}]->(a:Entity {id: $entityId})
695
- SET r.status = 'CONFIRMED'`, { entityId, relatedEntityId, type: relType });
696
- }
697
- }
698
- else if (ASYMMETRIC_PAIRS[relType]) {
699
- // Asymmetric: B→A edge gets the complementary type (PARENT↔OFFSPRING)
700
- const inverseType = ASYMMETRIC_PAIRS[relType];
701
- const reverseCheck = await this.executeQuery(`MATCH (b:Entity {id: $relatedEntityId})-[r:ENTITY_RELATES {type: $inverseType}]->(a:Entity {id: $entityId})
702
- RETURN r.status AS status`, { entityId, relatedEntityId, inverseType });
703
- if (reverseCheck.records.length === 0) {
704
- await this.executeQuery(`MATCH (a:Entity {id: $entityId}), (b:Entity {id: $relatedEntityId})
705
- CREATE (b)-[:ENTITY_RELATES {
706
- type: $inverseType,
707
- status: 'CONFIRMED',
708
- proposedByUserId: $proposedByUserId,
709
- since: $since
710
- }]->(a)`, { entityId, relatedEntityId, inverseType, proposedByUserId, since });
711
- }
712
- else {
713
- await this.executeQuery(`MATCH (b:Entity {id: $relatedEntityId})-[r:ENTITY_RELATES {type: $inverseType}]->(a:Entity {id: $entityId})
714
- SET r.status = 'CONFIRMED'`, { entityId, relatedEntityId, inverseType });
715
- }
716
- }
717
- return {
718
- entityId,
719
- relatedEntityId,
720
- type: relType,
721
- status: "CONFIRMED",
722
- proposedByUserId,
723
- since: new Date(since),
724
- };
725
- }
726
- async rejectEntityRelationship(entityId, relatedEntityId, rejectingUserId) {
727
- // 1. Verify rejecting user owns the target (related) entity
728
- const ownershipCheck = await this.executeQuery(`MATCH (u:User {id: $userId})-[o:OWNS]->(e:Entity {id: $relatedEntityId})
729
- RETURN o.role AS role`, { userId: rejectingUserId, relatedEntityId });
730
- if (ownershipCheck.records.length === 0) {
731
- const { GraphAuthorizationError } = await Promise.resolve().then(() => __importStar(require("./errors")));
732
- throw new GraphAuthorizationError(`User ${rejectingUserId} does not own entity ${relatedEntityId}`);
733
- }
734
- // 2. Find the relationship
735
- const relCheck = await this.executeQuery(`MATCH (a:Entity {id: $entityId})-[r:ENTITY_RELATES]->(b:Entity {id: $relatedEntityId})
736
- RETURN r.status AS status`, { entityId, relatedEntityId });
737
- if (relCheck.records.length === 0) {
738
- const { GraphNotFoundError } = await Promise.resolve().then(() => __importStar(require("./errors")));
739
- throw new GraphNotFoundError(`Entity relationship not found between ${entityId} and ${relatedEntityId}`);
740
- }
741
- // 3. Set status to REJECTED
742
- await this.executeQuery(`MATCH (a:Entity {id: $entityId})-[r:ENTITY_RELATES]->(b:Entity {id: $relatedEntityId})
743
- SET r.status = 'REJECTED'`, { entityId, relatedEntityId });
744
- }
745
- async removeEntityRelationship(entityId, relatedEntityId, removingUserId) {
746
- // 1. Verify removing user owns either entity
747
- const ownershipCheck = await this.executeQuery(`MATCH (u:User {id: $userId})-[o:OWNS]->(e:Entity)
748
- WHERE e.id = $entityId OR e.id = $relatedEntityId
749
- RETURN e.id AS ownedEntityId
750
- LIMIT 1`, { userId: removingUserId, entityId, relatedEntityId });
751
- if (ownershipCheck.records.length === 0) {
752
- const { GraphAuthorizationError } = await Promise.resolve().then(() => __importStar(require("./errors")));
753
- throw new GraphAuthorizationError(`User ${removingUserId} does not own either entity ${entityId} or ${relatedEntityId}`);
754
- }
755
- // 2. Check relationship exists (in the A→B direction)
756
- const relCheck = await this.executeQuery(`MATCH (a:Entity {id: $entityId})-[r:ENTITY_RELATES]->(b:Entity {id: $relatedEntityId})
757
- RETURN r.type AS type`, { entityId, relatedEntityId });
758
- if (relCheck.records.length === 0) {
759
- const { GraphNotFoundError } = await Promise.resolve().then(() => __importStar(require("./errors")));
760
- throw new GraphNotFoundError(`Entity relationship not found between ${entityId} and ${relatedEntityId}`);
761
- }
762
- // 3. Delete A→B edge and reciprocal B→A edge if it exists
763
- await this.executeQuery(`MATCH (a:Entity {id: $entityId})-[r:ENTITY_RELATES]->(b:Entity {id: $relatedEntityId})
764
- DELETE r`, { entityId, relatedEntityId });
765
- await this.executeQuery(`OPTIONAL MATCH (b:Entity {id: $relatedEntityId})-[r:ENTITY_RELATES]->(a:Entity {id: $entityId})
766
- DELETE r`, { entityId, relatedEntityId });
767
- }
768
- async getEntityRelationships(entityId, options) {
769
- let query = `MATCH (a:Entity {id: $entityId})-[r:ENTITY_RELATES]->(b:Entity)
770
- WHERE 1=1`;
771
- const params = { entityId };
772
- if (options?.type) {
773
- query += ` AND r.type = $type`;
774
- params.type = options.type;
775
- }
776
- if (options?.status) {
777
- query += ` AND r.status = $status`;
778
- params.status = options.status;
779
- }
780
- query += ` RETURN b.id AS relatedEntityId, r.type AS type, r.status AS status,
781
- r.proposedByUserId AS proposedByUserId, r.since AS since
782
- ORDER BY r.since DESC`;
783
- const result = await this.executeQuery(query, params);
784
- return result.records.map((record) => ({
785
- entityId,
786
- relatedEntityId: record.get("relatedEntityId"),
787
- type: record.get("type"),
788
- status: record.get("status"),
789
- proposedByUserId: record.get("proposedByUserId"),
790
- since: new Date(record.get("since")),
791
- }));
792
- }
793
- async getPendingEntityRelationships(userId) {
794
- // Return relationships where the user owns the TARGET entity and the edge is PENDING.
795
- // The relationship direction is A→B (source→target), and user owns B.
796
- const result = await this.executeQuery(`MATCH (u:User {id: $userId})-[:OWNS]->(b:Entity)
797
- MATCH (a:Entity)-[r:ENTITY_RELATES {status: 'PENDING'}]->(b)
798
- RETURN a.id AS entityId, b.id AS relatedEntityId, r.type AS type,
799
- r.proposedByUserId AS proposedByUserId, r.since AS since
800
- ORDER BY r.since DESC`, { userId });
801
- return result.records.map((record) => ({
802
- entityId: record.get("entityId"),
803
- relatedEntityId: record.get("relatedEntityId"),
804
- type: record.get("type"),
805
- status: "PENDING",
806
- proposedByUserId: record.get("proposedByUserId"),
807
- since: new Date(record.get("since")),
808
- }));
809
- }
810
- // =========================================================================
811
- // Discovery
812
- //
813
- // RATE LIMITING NOTE: All discovery endpoints should be rate-limited at
814
- // 5 requests/minute/user. Enforcement is at the handler/route layer.
815
- // Hop count is hard-capped at 2 in discoverByGraph.
816
- // =========================================================================
817
- /**
818
- * Discover entities through multi-hop entity-to-entity relationship traversal.
819
- *
820
- * Traverses PLAYMATE|PACK_MATE|SIBLING|PARENT|OFFSPRING|WALK_BUDDY edges
821
- * starting from the user's owned entities. Returns only entities the user
822
- * does NOT already have a relationship with, and where discoverable != false.
823
- *
824
- * SECURITY: Hops are hard-capped at 2 regardless of input. 3-hop traversals
825
- * can visit 100^3 nodes on popular entities (graph DoS vector). All query
826
- * values are parameterized — the hop range is a safe numeric literal derived
827
- * from server-side clamped input, never user-supplied string data.
828
- */
829
- async discoverByGraph(userId, hops, filters) {
830
- // Hard-cap at 2 regardless of what the caller passes
831
- const safeHops = hops <= 1 ? 1 : 2;
832
- const limit = filters?.limit ?? 20;
833
- const filterClauses = [
834
- "NOT EXISTS { MATCH (me)-[:RELATES_TO]->(discovered) }",
835
- "(discovered.discoverable IS NULL OR discovered.discoverable = true)",
836
- ];
837
- if (filters?.entityType)
838
- filterClauses.push("discovered.entityType = $entityType");
839
- if (filters?.breed)
840
- filterClauses.push("discovered.breed = $breed");
841
- if (filters?.lifeStage)
842
- filterClauses.push("discovered.lifeStage = $lifeStage");
843
- const whereClause = filterClauses.join("\n AND ");
844
- // safeHops is 1 or 2 — a numeric literal in the template, not user input.
845
- const hopRange = safeHops === 1 ? "1" : "1..2";
846
- const query = `
847
- MATCH (me:User {id: $userId})-[:OWNS]->(myEntity:Entity),
848
- (myEntity)-[:PLAYMATE|PACK_MATE|SIBLING|PARENT|OFFSPRING|WALK_BUDDY*${hopRange}]-(discovered:Entity)
849
- WHERE ${whereClause}
850
- RETURN DISTINCT
851
- discovered.id AS entityId,
852
- discovered.name AS name,
853
- discovered.entityType AS entityType,
854
- discovered.breed AS breed,
855
- ${safeHops} AS hops
856
- ORDER BY discovered.name ASC
857
- LIMIT $limit
858
- `;
859
- const params = { userId, limit };
860
- if (filters?.entityType)
861
- params.entityType = filters.entityType;
862
- if (filters?.breed)
863
- params.breed = filters.breed;
864
- if (filters?.lifeStage)
865
- params.lifeStage = filters.lifeStage;
866
- const result = await this.executeQuery(query, params);
867
- return result.records.map((record) => {
868
- const entityId = record.get("entityId");
869
- const name = record.get("name");
870
- const entityType = record.get("entityType");
871
- const breed = record.get("breed");
872
- const hopCount = record.get("hops");
873
- const discovery = { entityId, name, entityType, hops: hopCount };
874
- if (breed)
875
- discovery.breed = breed;
876
- return discovery;
877
- });
878
- }
879
- /**
880
- * Discover entities by geographic proximity using point.distance().
881
- *
882
- * Only returns entities where discoverable is not false, and entities the
883
- * user does NOT already have a relationship with.
884
- *
885
- * SECURITY: Exact distances are withheld for all results — only a coarse
886
- * distance band is returned to prevent location triangulation (security
887
- * review Finding 15). Coordinates are pre-coarsened to ~1km precision at
888
- * sync time for additional protection. Entities with existing relationships
889
- * are excluded so exact distance is never needed here.
890
- */
891
- async discoverNearby(userId, lat, lng, radiusMeters, filters) {
892
- const limit = filters?.limit ?? 20;
893
- // These clauses are safe because the filter values come from $params
894
- const entityTypeFilter = filters?.entityType ? "AND entity.entityType = $entityType" : "";
895
- const breedFilter = filters?.breed ? "AND entity.breed = $breed" : "";
896
- const query = `
897
- MATCH (entity:Entity)
898
- WHERE (entity.discoverable IS NULL OR entity.discoverable = true)
899
- AND entity.lat IS NOT NULL
900
- AND entity.lng IS NOT NULL
901
- ${entityTypeFilter}
902
- ${breedFilter}
903
- AND point.distance(
904
- point({latitude: entity.lat, longitude: entity.lng}),
905
- point({latitude: $lat, longitude: $lng})
906
- ) < $radiusMeters
907
- WITH entity,
908
- point.distance(
909
- point({latitude: entity.lat, longitude: entity.lng}),
910
- point({latitude: $lat, longitude: $lng})
911
- ) AS distanceMeters
912
- OPTIONAL MATCH (me:User {id: $userId})-[rel:RELATES_TO]->(entity)
913
- WITH entity, distanceMeters, rel
914
- WHERE rel IS NULL
915
- RETURN entity.id AS entityId,
916
- entity.name AS name,
917
- entity.entityType AS entityType,
918
- entity.breed AS breed,
919
- distanceMeters
920
- ORDER BY distanceMeters ASC
921
- LIMIT $limit
922
- `;
923
- const params = { userId, lat, lng, radiusMeters, limit };
924
- if (filters?.entityType)
925
- params.entityType = filters.entityType;
926
- if (filters?.breed)
927
- params.breed = filters.breed;
928
- const result = await this.executeQuery(query, params);
929
- return result.records.map((record) => {
930
- const entityId = record.get("entityId");
931
- const name = record.get("name");
932
- const entityType = record.get("entityType");
933
- const breed = record.get("breed");
934
- const distMeters = record.get("distanceMeters");
935
- const discovery = {
936
- entityId,
937
- name,
938
- entityType,
939
- // SECURITY: Coarse band only — never exact distance for unrelated entities
940
- distanceBand: Neo4jGraphService.toDistanceBand(distMeters),
941
- };
942
- if (breed)
943
- discovery.breed = breed;
944
- return discovery;
945
- });
946
- }
947
- /**
948
- * Get entity recommendations based on shared connections, breed similarity,
949
- * and geographic proximity.
950
- *
951
- * Runs three parallel queries (signals) and merges results, deduplicated by
952
- * entity ID, keeping the highest-scoring reason per entity.
953
- *
954
- * SECURITY: `owner_proximity` is never exposed as a RecommendationReason.
955
- * Exposing it would allow the viewer to infer a close relationship with the
956
- * entity's owner from a visible recommendation, leaking graph topology.
957
- * Owner proximity is used internally to boost shared-connection scoring but
958
- * always surfaced as "shared_connections" in the response.
959
- */
960
- async getRecommendations(userId, limit) {
961
- const params = { userId, limit };
962
- // Signal 1: Shared connections (also folds in owner proximity internally)
963
- const sharedConnectionsQuery = `
964
- MATCH (me:User {id: $userId})-[:OWNS|RELATES_TO]->(myEntity:Entity)
965
- -[:PLAYMATE|PACK_MATE|SIBLING|PARENT|OFFSPRING|WALK_BUDDY*1..2]-(candidate:Entity)
966
- WHERE NOT EXISTS { MATCH (me)-[:RELATES_TO]->(candidate) }
967
- AND NOT EXISTS { MATCH (me)-[:OWNS]->(candidate) }
968
- AND (candidate.discoverable IS NULL OR candidate.discoverable = true)
969
- AND candidate.id <> myEntity.id
970
- WITH candidate, count(DISTINCT myEntity) AS sharedCount
971
- RETURN candidate.id AS entityId,
972
- candidate.name AS name,
973
- candidate.entityType AS entityType,
974
- toFloat(sharedCount) / 10.0 AS score,
975
- 'shared_connections' AS reason
976
- ORDER BY score DESC
977
- LIMIT $limit
978
- `;
979
- // Signal 2: Same breed as user's owned entities
980
- const sameBreedQuery = `
981
- MATCH (me:User {id: $userId})-[:OWNS]->(myDog:Entity)
982
- WHERE myDog.breed IS NOT NULL
983
- WITH me, collect(DISTINCT myDog.breed) AS myBreeds
984
- MATCH (candidate:Entity)
985
- WHERE candidate.breed IN myBreeds
986
- AND NOT EXISTS { MATCH (me)-[:RELATES_TO]->(candidate) }
987
- AND NOT EXISTS { MATCH (me)-[:OWNS]->(candidate) }
988
- AND (candidate.discoverable IS NULL OR candidate.discoverable = true)
989
- RETURN candidate.id AS entityId,
990
- candidate.name AS name,
991
- candidate.entityType AS entityType,
992
- 0.6 AS score,
993
- 'same_breed' AS reason
994
- LIMIT $limit
995
- `;
996
- // Signal 3: Geographic proximity to user's owned entities
997
- const nearbyQuery = `
998
- MATCH (me:User {id: $userId})-[:OWNS]->(myEntity:Entity)
999
- WHERE myEntity.lat IS NOT NULL AND myEntity.lng IS NOT NULL
1000
- WITH me, collect(myEntity) AS myEntities
1001
- MATCH (candidate:Entity)
1002
- WHERE candidate.lat IS NOT NULL
1003
- AND candidate.lng IS NOT NULL
1004
- AND NOT EXISTS { MATCH (me)-[:RELATES_TO]->(candidate) }
1005
- AND NOT EXISTS { MATCH (me)-[:OWNS]->(candidate) }
1006
- AND (candidate.discoverable IS NULL OR candidate.discoverable = true)
1007
- WITH candidate, myEntities,
1008
- reduce(minD = 999999999.0, e IN myEntities |
1009
- CASE
1010
- WHEN point.distance(
1011
- point({latitude: candidate.lat, longitude: candidate.lng}),
1012
- point({latitude: e.lat, longitude: e.lng})
1013
- ) < minD
1014
- THEN point.distance(
1015
- point({latitude: candidate.lat, longitude: candidate.lng}),
1016
- point({latitude: e.lat, longitude: e.lng})
1017
- )
1018
- ELSE minD
1019
- END
1020
- ) AS minDist
1021
- WHERE minDist < 5000
1022
- RETURN candidate.id AS entityId,
1023
- candidate.name AS name,
1024
- candidate.entityType AS entityType,
1025
- (1.0 - (minDist / 10000.0)) * 0.5 AS score,
1026
- 'nearby' AS reason
1027
- ORDER BY minDist ASC
1028
- LIMIT $limit
1029
- `;
1030
- const [sharedResult, breedResult, nearbyResult] = await Promise.all([
1031
- this.executeQuery(sharedConnectionsQuery, params),
1032
- this.executeQuery(sameBreedQuery, params),
1033
- this.executeQuery(nearbyQuery, params),
1034
- ]);
1035
- // Merge and deduplicate: keep highest-scoring entry per entity
1036
- const candidateMap = new Map();
1037
- for (const queryResult of [sharedResult, breedResult, nearbyResult]) {
1038
- for (const record of queryResult.records) {
1039
- const entityId = record.get("entityId");
1040
- const existing = candidateMap.get(entityId);
1041
- const score = record.get("score");
1042
- if (!existing || score > existing.score) {
1043
- candidateMap.set(entityId, {
1044
- entityId,
1045
- name: record.get("name"),
1046
- entityType: record.get("entityType"),
1047
- score,
1048
- reason: record.get("reason"),
1049
- });
1050
- }
1051
- }
1052
- }
1053
- return Array.from(candidateMap.values())
1054
- .sort((a, b) => b.score - a.score)
1055
- .slice(0, limit)
1056
- .map((c) => ({
1057
- entityId: c.entityId,
1058
- name: c.name,
1059
- entityType: c.entityType,
1060
- reason: c.reason,
1061
- confidence: Math.min(1.0, Math.max(0.0, c.score)),
1062
- }));
1063
- }
1064
- // =========================================================================
1065
- // Private Static Helpers
1066
- // =========================================================================
1067
- /**
1068
- * Convert an exact distance in meters to a coarse distance band string.
1069
- *
1070
- * SECURITY: Used by discoverNearby() to prevent location triangulation.
1071
- * Values match the DiscoveryResult.distanceBand union type exactly.
1072
- */
1073
- static toDistanceBand(meters) {
1074
- if (meters < 500)
1075
- return "< 500m";
1076
- if (meters < 1000)
1077
- return "500m-1km";
1078
- if (meters < 2000)
1079
- return "1-2km";
1080
- if (meters < 5000)
1081
- return "2-5km";
1082
- return "> 5km";
1083
- }
1084
- // =========================================================================
1085
- // Scoring (Phase 2 — P2.4)
1086
- // =========================================================================
1087
- /**
1088
- * Record a user interaction on a RELATES_TO edge.
1089
- *
1090
- * Updates interaction count, last interaction timestamp, and per-type
1091
- * interaction counters. No-op if the relationship does not exist.
1092
- *
1093
- * SECURITY: All queries parameterized.
1094
- */
1095
- async recordInteraction(input) {
1096
- const targetLabel = input.targetType === "user" ? "User" : "Entity";
1097
- // Increment total count, set lastInteractionAt, and increment per-type counter.
1098
- // The per-type counter property is named i_{type} (e.g., i_view, i_comment).
1099
- // Note: property name is safe — interactionType comes from the InteractionType union.
1100
- const counterProperty = `i_${input.interactionType}`;
1101
- await this.executeQuery(`
1102
- MATCH (u:User {id: $userId})-[r:RELATES_TO]->(t:${targetLabel} {id: $targetId})
1103
- SET r.interactionCount = coalesce(r.interactionCount, 0) + 1,
1104
- r.lastInteractionAt = datetime($now),
1105
- r.${counterProperty} = coalesce(r.${counterProperty}, 0) + 1
1106
- `, {
1107
- userId: input.userId,
1108
- targetId: input.targetId,
1109
- now: new Date().toISOString(),
1110
- });
1111
- }
1112
- /**
1113
- * Recompute scores for ALL relationships of a user.
1114
- *
1115
- * Batch-processes all RELATES_TO edges in a single query pass per target type,
1116
- * avoiding N+1 patterns. Returns only relationships where the tier changed.
1117
- *
1118
- * SECURITY: All queries parameterized.
1119
- */
1120
- async recomputeScores(userId) {
1121
- const { computeScore, scoreToTier } = await Promise.resolve().then(() => __importStar(require("./scoring-engine")));
1122
- const tierChanges = [];
1123
- const now = new Date();
1124
- // --- User targets ---
1125
- // Batch fetch all user relationships with their reciprocity status
1126
- const userRels = await this.executeQuery(`
1127
- MATCH (u:User {id: $userId})-[r:RELATES_TO]->(t:User)
1128
- OPTIONAL MATCH (t)-[rev:RELATES_TO]->(u)
1129
- RETURN t.id AS targetId,
1130
- r.computedScore AS oldScore,
1131
- r.tier AS oldTier,
1132
- r.connectionMethod AS connectionMethod,
1133
- r.interactionCount AS interactionCount,
1134
- r.lastInteractionAt AS lastInteractionAt,
1135
- r.createdAt AS createdAt,
1136
- r.manualScore AS manualScore,
1137
- coalesce(r.i_view, 0) AS i_view,
1138
- coalesce(r.i_react, 0) AS i_react,
1139
- coalesce(r.i_comment, 0) AS i_comment,
1140
- coalesce(r.i_share, 0) AS i_share,
1141
- coalesce(r.i_depth_mode, 0) AS i_depth_mode,
1142
- coalesce(r.i_profile_visit, 0) AS i_profile_visit,
1143
- coalesce(r.i_content_creation, 0) AS i_content_creation,
1144
- rev IS NOT NULL AS reciprocated
1145
- `, { userId });
1146
- // Compute new scores and collect updates
1147
- const userUpdates = [];
1148
- for (const record of userRels.records) {
1149
- const targetId = record.get("targetId");
1150
- const oldScore = record.get("oldScore") ?? 0;
1151
- const oldTier = record.get("oldTier") ?? 3;
1152
- const lastInteractionRaw = record.get("lastInteractionAt");
1153
- const createdAtRaw = record.get("createdAt");
1154
- const newComputedScore = computeScore({
1155
- targetType: "user",
1156
- connectionMethod: record.get("connectionMethod") ?? "discovery",
1157
- interactionCount: record.get("interactionCount") ?? 0,
1158
- interactionsByType: {
1159
- view: record.get("i_view"),
1160
- react: record.get("i_react"),
1161
- comment: record.get("i_comment"),
1162
- share: record.get("i_share"),
1163
- depth_mode: record.get("i_depth_mode"),
1164
- profile_visit: record.get("i_profile_visit"),
1165
- content_creation: record.get("i_content_creation"),
1166
- },
1167
- lastInteractionAt: lastInteractionRaw
1168
- ? new Date(lastInteractionRaw)
1169
- : null,
1170
- reciprocated: record.get("reciprocated"),
1171
- createdAt: createdAtRaw ? new Date(createdAtRaw) : now,
1172
- manualScore: record.get("manualScore") ?? null,
1173
- isOwned: false,
1174
- ownerScore: null,
1175
- now,
1176
- });
1177
- const manualScore = record.get("manualScore") ?? null;
1178
- const effectiveNewScore = manualScore ?? newComputedScore;
1179
- const newTier = scoreToTier(effectiveNewScore);
1180
- userUpdates.push({
1181
- targetId,
1182
- newScore: newComputedScore,
1183
- newTier,
1184
- });
1185
- if (newTier !== oldTier) {
1186
- tierChanges.push({
1187
- userId,
1188
- targetType: "user",
1189
- targetId,
1190
- previousScore: oldScore,
1191
- newScore: newComputedScore,
1192
- previousTier: oldTier,
1193
- newTier,
1194
- });
1195
- }
1196
- }
1197
- // Batch-write user relationship scores
1198
- if (userUpdates.length > 0) {
1199
- await this.executeQuery(`
1200
- UNWIND $updates AS upd
1201
- MATCH (u:User {id: $userId})-[r:RELATES_TO]->(t:User {id: upd.targetId})
1202
- SET r.computedScore = upd.newScore,
1203
- r.tier = upd.newTier
1204
- `, { userId, updates: userUpdates });
1205
- }
1206
- // --- Entity targets ---
1207
- // Batch fetch all entity relationships with ownership and owner scores
1208
- const entityRels = await this.executeQuery(`
1209
- MATCH (u:User {id: $userId})-[r:RELATES_TO]->(t:Entity)
1210
- OPTIONAL MATCH (u)-[:OWNS]->(t)
1211
- WITH u, r, t, EXISTS((u)-[:OWNS]->(t)) AS isOwned
1212
- OPTIONAL MATCH (owner:User)-[:OWNS]->(t)
1213
- WHERE owner.id <> $userId
1214
- OPTIONAL MATCH (u)-[ownerRel:RELATES_TO]->(owner)
1215
- WITH u, r, t, isOwned,
1216
- collect(ownerRel.computedScore) AS ownerScores
1217
- RETURN t.id AS targetId,
1218
- r.computedScore AS oldScore,
1219
- r.tier AS oldTier,
1220
- r.connectionMethod AS connectionMethod,
1221
- r.interactionCount AS interactionCount,
1222
- r.lastInteractionAt AS lastInteractionAt,
1223
- r.createdAt AS createdAt,
1224
- r.manualScore AS manualScore,
1225
- coalesce(r.i_view, 0) AS i_view,
1226
- coalesce(r.i_react, 0) AS i_react,
1227
- coalesce(r.i_comment, 0) AS i_comment,
1228
- coalesce(r.i_share, 0) AS i_share,
1229
- coalesce(r.i_depth_mode, 0) AS i_depth_mode,
1230
- coalesce(r.i_profile_visit, 0) AS i_profile_visit,
1231
- coalesce(r.i_content_creation, 0) AS i_content_creation,
1232
- isOwned,
1233
- ownerScores
1234
- `, { userId });
1235
- const entityUpdates = [];
1236
- for (const record of entityRels.records) {
1237
- const targetId = record.get("targetId");
1238
- const oldScore = record.get("oldScore") ?? 0;
1239
- const oldTier = record.get("oldTier") ?? 3;
1240
- const isOwned = record.get("isOwned");
1241
- const lastInteractionRaw = record.get("lastInteractionAt");
1242
- const createdAtRaw = record.get("createdAt");
1243
- // Average the owner scores for the owner proximity signal
1244
- const ownerScores = record.get("ownerScores") ?? [];
1245
- const validOwnerScores = ownerScores.filter((s) => s !== null && s !== undefined);
1246
- const avgOwnerScore = validOwnerScores.length > 0
1247
- ? validOwnerScores.reduce((a, b) => a + b, 0) /
1248
- validOwnerScores.length
1249
- : null;
1250
- const newComputedScore = computeScore({
1251
- targetType: "entity",
1252
- connectionMethod: record.get("connectionMethod") ?? "discovery",
1253
- interactionCount: record.get("interactionCount") ?? 0,
1254
- interactionsByType: {
1255
- view: record.get("i_view"),
1256
- react: record.get("i_react"),
1257
- comment: record.get("i_comment"),
1258
- share: record.get("i_share"),
1259
- depth_mode: record.get("i_depth_mode"),
1260
- profile_visit: record.get("i_profile_visit"),
1261
- content_creation: record.get("i_content_creation"),
1262
- },
1263
- lastInteractionAt: lastInteractionRaw
1264
- ? new Date(lastInteractionRaw)
1265
- : null,
1266
- reciprocated: false, // Not applicable for entities
1267
- createdAt: createdAtRaw ? new Date(createdAtRaw) : now,
1268
- manualScore: record.get("manualScore") ?? null,
1269
- isOwned,
1270
- ownerScore: avgOwnerScore,
1271
- now,
1272
- });
1273
- const manualScore = record.get("manualScore") ?? null;
1274
- const effectiveNewScore = isOwned
1275
- ? 1.0
1276
- : (manualScore ?? newComputedScore);
1277
- const newTier = scoreToTier(effectiveNewScore);
1278
- entityUpdates.push({
1279
- targetId,
1280
- newScore: newComputedScore,
1281
- newTier,
1282
- });
1283
- if (newTier !== oldTier) {
1284
- tierChanges.push({
1285
- userId,
1286
- targetType: "entity",
1287
- targetId,
1288
- previousScore: oldScore,
1289
- newScore: newComputedScore,
1290
- previousTier: oldTier,
1291
- newTier,
1292
- });
1293
- }
1294
- }
1295
- // Batch-write entity relationship scores
1296
- if (entityUpdates.length > 0) {
1297
- await this.executeQuery(`
1298
- UNWIND $updates AS upd
1299
- MATCH (u:User {id: $userId})-[r:RELATES_TO]->(t:Entity {id: upd.targetId})
1300
- SET r.computedScore = upd.newScore,
1301
- r.tier = upd.newTier
1302
- `, { userId, updates: entityUpdates });
1303
- }
1304
- return tierChanges;
1305
- }
1306
- /**
1307
- * Apply time-based decay to all of a user's relationship scores.
1308
- *
1309
- * - User->User: 50% decay after 60 days of no interaction
1310
- * - User->Entity: 50% decay after 120 days of no interaction
1311
- * - Owned entities (:OWNS edge) are exempt — always pinned at 1.0
1312
- *
1313
- * SECURITY: All queries parameterized.
1314
- */
1315
- async applyDecay(userId) {
1316
- const { computeDecay, scoreToTier, USER_DECAY_HALF_LIFE_DAYS, ENTITY_DECAY_HALF_LIFE_DAYS, } = await Promise.resolve().then(() => __importStar(require("./scoring-engine")));
1317
- const tierChanges = [];
1318
- const now = new Date();
1319
- // --- User targets: apply decay ---
1320
- const userRels = await this.executeQuery(`
1321
- MATCH (u:User {id: $userId})-[r:RELATES_TO]->(t:User)
1322
- WHERE r.lastInteractionAt IS NOT NULL
1323
- RETURN t.id AS targetId,
1324
- r.computedScore AS currentScore,
1325
- r.tier AS currentTier,
1326
- r.manualScore AS manualScore,
1327
- r.lastInteractionAt AS lastInteractionAt
1328
- `, { userId });
1329
- const userDecayUpdates = [];
1330
- for (const record of userRels.records) {
1331
- const targetId = record.get("targetId");
1332
- const currentScore = record.get("currentScore") ?? 0;
1333
- const currentTier = record.get("currentTier") ?? 3;
1334
- const manualScore = record.get("manualScore") ?? null;
1335
- const lastInteractionAt = new Date(record.get("lastInteractionAt"));
1336
- const decayFactor = computeDecay(lastInteractionAt, now, USER_DECAY_HALF_LIFE_DAYS);
1337
- // Apply multiplicative decay: score * (1 - decayFactor)
1338
- const decayedScore = Math.max(0, currentScore * (1 - decayFactor));
1339
- const effective = manualScore ?? decayedScore;
1340
- const newTier = scoreToTier(effective);
1341
- userDecayUpdates.push({
1342
- targetId,
1343
- newScore: decayedScore,
1344
- newTier,
1345
- });
1346
- if (newTier !== currentTier) {
1347
- tierChanges.push({
1348
- userId,
1349
- targetType: "user",
1350
- targetId,
1351
- previousScore: currentScore,
1352
- newScore: decayedScore,
1353
- previousTier: currentTier,
1354
- newTier,
1355
- });
1356
- }
1357
- }
1358
- if (userDecayUpdates.length > 0) {
1359
- await this.executeQuery(`
1360
- UNWIND $updates AS upd
1361
- MATCH (u:User {id: $userId})-[r:RELATES_TO]->(t:User {id: upd.targetId})
1362
- SET r.computedScore = upd.newScore,
1363
- r.tier = upd.newTier
1364
- `, { userId, updates: userDecayUpdates });
1365
- }
1366
- // --- Entity targets: apply decay (skip owned) ---
1367
- const entityRels = await this.executeQuery(`
1368
- MATCH (u:User {id: $userId})-[r:RELATES_TO]->(t:Entity)
1369
- WHERE r.lastInteractionAt IS NOT NULL
1370
- AND NOT EXISTS((u)-[:OWNS]->(t))
1371
- RETURN t.id AS targetId,
1372
- r.computedScore AS currentScore,
1373
- r.tier AS currentTier,
1374
- r.manualScore AS manualScore,
1375
- r.lastInteractionAt AS lastInteractionAt
1376
- `, { userId });
1377
- const entityDecayUpdates = [];
1378
- for (const record of entityRels.records) {
1379
- const targetId = record.get("targetId");
1380
- const currentScore = record.get("currentScore") ?? 0;
1381
- const currentTier = record.get("currentTier") ?? 3;
1382
- const manualScore = record.get("manualScore") ?? null;
1383
- const lastInteractionAt = new Date(record.get("lastInteractionAt"));
1384
- const decayFactor = computeDecay(lastInteractionAt, now, ENTITY_DECAY_HALF_LIFE_DAYS);
1385
- const decayedScore = Math.max(0, currentScore * (1 - decayFactor));
1386
- const effective = manualScore ?? decayedScore;
1387
- const newTier = scoreToTier(effective);
1388
- entityDecayUpdates.push({
1389
- targetId,
1390
- newScore: decayedScore,
1391
- newTier,
1392
- });
1393
- if (newTier !== currentTier) {
1394
- tierChanges.push({
1395
- userId,
1396
- targetType: "entity",
1397
- targetId,
1398
- previousScore: currentScore,
1399
- newScore: decayedScore,
1400
- previousTier: currentTier,
1401
- newTier,
1402
- });
1403
- }
1404
- }
1405
- if (entityDecayUpdates.length > 0) {
1406
- await this.executeQuery(`
1407
- UNWIND $updates AS upd
1408
- MATCH (u:User {id: $userId})-[r:RELATES_TO]->(t:Entity {id: upd.targetId})
1409
- SET r.computedScore = upd.newScore,
1410
- r.tier = upd.newTier
1411
- `, { userId, updates: entityDecayUpdates });
1412
- }
1413
- return tierChanges;
1414
- }
1415
- // =========================================================================
1416
- // Sync — Dual-Write from Postgres
1417
- // =========================================================================
1418
- async syncUser(input) {
1419
- await this.executeQuery(`
1420
- MERGE (u:User {id: $id})
1421
- ON CREATE SET u.role = $role
1422
- ON MATCH SET u.role = $role
1423
- `, { id: input.id, role: input.role });
1424
- }
1425
- async removeUser(userId) {
1426
- await this.executeQuery(`MATCH (u:User {id: $id}) DETACH DELETE u`, { id: userId });
1427
- }
1428
- async syncEntity(input) {
1429
- await this.executeQuery(`
1430
- MERGE (e:Entity {id: $id})
1431
- ON CREATE SET
1432
- e.entityType = $entityType,
1433
- e.name = $name,
1434
- e.breed = $breed,
1435
- e.lifeStage = $lifeStage,
1436
- e.lat = $lat,
1437
- e.lng = $lng
1438
- ON MATCH SET
1439
- e.entityType = $entityType,
1440
- e.name = $name,
1441
- e.breed = $breed,
1442
- e.lifeStage = $lifeStage,
1443
- e.lat = $lat,
1444
- e.lng = $lng
1445
- `, {
1446
- id: input.id,
1447
- entityType: input.entityType,
1448
- name: input.name,
1449
- breed: input.breed ?? null,
1450
- lifeStage: input.lifeStage ?? null,
1451
- lat: input.lat ?? null,
1452
- lng: input.lng ?? null,
1453
- });
1454
- }
1455
- async removeEntity(entityId) {
1456
- await this.executeQuery(`MATCH (e:Entity {id: $id}) DETACH DELETE e`, { id: entityId });
1457
- }
1458
- async syncPost(input) {
1459
- await this.executeQuery(`
1460
- MERGE (u:User {id: $authorId})
1461
- MERGE (p:Post {id: $id})
1462
- ON CREATE SET
1463
- p.radius = $radius,
1464
- p.createdAt = $createdAt
1465
- ON MATCH SET
1466
- p.radius = $radius,
1467
- p.createdAt = $createdAt
1468
- MERGE (u)-[:AUTHORED]->(p)
1469
- `, {
1470
- id: input.id,
1471
- authorId: input.authorId,
1472
- radius: input.radius,
1473
- createdAt: input.createdAt.toISOString(),
1474
- });
1475
- }
1476
- async removePost(postId) {
1477
- await this.executeQuery(`MATCH (p:Post {id: $id}) DETACH DELETE p`, { id: postId });
1478
- }
1479
- async syncPostSubjects(input) {
1480
- // Delete all existing ABOUT edges from the post, then recreate
1481
- await this.executeQuery(`
1482
- MATCH (p:Post {id: $postId})
1483
- OPTIONAL MATCH (p)-[r:ABOUT]->()
1484
- DELETE r
1485
- WITH p
1486
- UNWIND $entityIds AS eId
1487
- MATCH (e:Entity {id: eId})
1488
- MERGE (p)-[rel:ABOUT]->(e)
1489
- SET rel.isPrimary = (eId = $primaryEntityId)
1490
- `, {
1491
- postId: input.postId,
1492
- entityIds: input.entityIds,
1493
- primaryEntityId: input.primaryEntityId ?? null,
1494
- });
1495
- }
1496
- async syncOwnership(input) {
1497
- await this.executeQuery(`
1498
- MATCH (u:User {id: $userId})
1499
- MATCH (e:Entity {id: $entityId})
1500
- MERGE (u)-[r:OWNS]->(e)
1501
- ON CREATE SET r.role = $role
1502
- ON MATCH SET r.role = $role
1503
- `, {
1504
- userId: input.userId,
1505
- entityId: input.entityId,
1506
- role: input.role,
1507
- });
1508
- }
1509
- async removeOwnership(entityId, userId) {
1510
- await this.executeQuery(`
1511
- MATCH (u:User {id: $userId})-[r:OWNS]->(e:Entity {id: $entityId})
1512
- DELETE r
1513
- `, { userId, entityId });
1514
- }
1515
- // =========================================================================
1516
- // Internal Helpers
1517
- // =========================================================================
1518
- /**
1519
- * Get a new session from the driver. Throws if not connected.
1520
- * Callers are responsible for closing the session.
1521
- */
1522
- getSession() {
1523
- if (!this.driver || !this.connected) {
1524
- throw new errors_1.GraphConnectionError("Not connected to Neo4j");
1525
- }
1526
- return this.driver.session();
1527
- }
1528
- /**
1529
- * Execute a parameterized Cypher query and return the result.
1530
- * Sessions are opened and closed automatically.
1531
- *
1532
- * SECURITY: Always use parameters — never interpolate values into the query.
1533
- */
1534
- async executeQuery(query, parameters) {
1535
- const session = this.getSession();
1536
- try {
1537
- return await session.run(query, parameters);
1538
- }
1539
- catch (error) {
1540
- throw new errors_1.GraphQueryError(`Query failed: ${error instanceof Error ? error.message : String(error)}`, query, { cause: error instanceof Error ? error : undefined });
1541
- }
1542
- finally {
1543
- await session.close();
1544
- }
1545
- }
1546
- /**
1547
- * Initialize the graph schema (constraints and indexes).
1548
- * Called once on first connect.
1549
- */
1550
- async initializeSchema() {
1551
- const session = this.getSession();
1552
- try {
1553
- await (0, graph_schema_init_1.initGraphSchema)(session);
1554
- this.schemaInitialized = true;
1555
- }
1556
- catch (error) {
1557
- throw new errors_1.GraphConnectionError(`Schema initialization failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error instanceof Error ? error : undefined });
1558
- }
1559
- finally {
1560
- await session.close();
1561
- }
1562
- }
1563
- }
1564
- exports.Neo4jGraphService = Neo4jGraphService;
1565
- // ---------------------------------------------------------------------------
1566
- // Internal helpers (module-private)
1567
- // ---------------------------------------------------------------------------
1568
- /** Map a tier number to its TierSummary key. */
1569
- function tierToName(tier) {
1570
- switch (tier) {
1571
- case 0: return "inner";
1572
- case 1: return "closeFriends";
1573
- case 2: return "community";
1574
- default: return "ambient";
1575
- }
1576
- }
1577
- /**
1578
- * Encode a score-based pagination cursor.
1579
- * The cursor is a base64-encoded JSON object with the score.
1580
- */
1581
- function encodeCursor(score) {
1582
- return Buffer.from(JSON.stringify({ score })).toString("base64");
1583
- }
1584
- /**
1585
- * Decode a score-based pagination cursor.
1586
- * Returns null if the cursor is invalid.
1587
- */
1588
- function decodeCursor(cursor) {
1589
- try {
1590
- const parsed = JSON.parse(Buffer.from(cursor, "base64").toString("utf8"));
1591
- if (parsed && typeof parsed === "object" && "score" in parsed) {
1592
- const score = parsed.score;
1593
- if (typeof score === "number")
1594
- return score;
1595
- }
1596
- return null;
1597
- }
1598
- catch {
1599
- return null;
1600
- }
1601
- }
1602
- /**
1603
- * Map a raw Neo4j relationship property map to a Relationship object.
1604
- * All edge properties are stored as-is (numbers, strings, null).
1605
- */
1606
- function recordToRelationship(rel, userId, targetType, targetId) {
1607
- const computedScore = typeof rel.computedScore === "number" ? rel.computedScore : 0;
1608
- const manualScore = typeof rel.manualScore === "number" ? rel.manualScore : null;
1609
- const score = typeof rel.score === "number" ? rel.score : computedScore;
1610
- return {
1611
- userId,
1612
- targetType,
1613
- targetId,
1614
- score,
1615
- computedScore,
1616
- manualScore,
1617
- tier: (0, scoring_engine_1.scoreToTier)(score),
1618
- interactionCount: typeof rel.interactionCount === "number" ? rel.interactionCount : 0,
1619
- lastInteractionAt: rel.lastInteractionAt != null ? new Date(rel.lastInteractionAt) : null,
1620
- connectionMethod: (rel.connectionMethod ?? "discovery"),
1621
- reciprocated: rel.reciprocated === true,
1622
- createdAt: rel.createdAt != null ? new Date(rel.createdAt) : new Date(),
1623
- };
1624
- }
1625
- //# sourceMappingURL=neo4j-graph-service.js.map