okengine 0.18.5 → 0.19.1

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 (512) hide show
  1. package/AGENTS.md +18 -10
  2. package/README.md +2 -2
  3. package/package.json +51 -50
  4. package/site/content/docs/ai/llms-txt.mdx +1 -1
  5. package/site/content/docs/ai/skills.mdx +4 -1
  6. package/site/content/docs/client/auth.mdx +208 -0
  7. package/site/content/docs/client/calling.mdx +451 -0
  8. package/site/content/docs/client/index.mdx +208 -0
  9. package/site/content/docs/client/live.mdx +234 -0
  10. package/site/content/docs/client/meta.json +5 -0
  11. package/site/content/docs/client/react.mdx +249 -0
  12. package/site/content/docs/elements/ai/agents.mdx +235 -0
  13. package/site/content/docs/elements/ai/index.mdx +342 -0
  14. package/site/content/docs/elements/ai/mcp.mdx +275 -0
  15. package/site/content/docs/elements/ai/meta.json +5 -0
  16. package/site/content/docs/elements/ai/models.mdx +283 -0
  17. package/site/content/docs/elements/ai/prompts.mdx +257 -0
  18. package/site/content/docs/elements/channel/email.mdx +269 -0
  19. package/site/content/docs/elements/channel/index.mdx +344 -0
  20. package/site/content/docs/elements/channel/meta.json +5 -0
  21. package/site/content/docs/elements/channel/push.mdx +218 -0
  22. package/site/content/docs/elements/channel/receipts.mdx +206 -0
  23. package/site/content/docs/elements/channel/sms.mdx +264 -0
  24. package/site/content/docs/elements/channel/whatsapp.mdx +220 -0
  25. package/site/content/docs/elements/clock/index.mdx +301 -0
  26. package/site/content/docs/elements/clock/meta.json +5 -0
  27. package/site/content/docs/elements/clock/schedules.mdx +508 -0
  28. package/site/content/docs/elements/clock/sleep.mdx +448 -0
  29. package/site/content/docs/elements/flow/consumers.mdx +707 -0
  30. package/site/content/docs/elements/flow/http.mdx +1080 -0
  31. package/site/content/docs/elements/flow/index.mdx +618 -0
  32. package/site/content/docs/elements/flow/meta.json +5 -0
  33. package/site/content/docs/elements/flow/routing.mdx +559 -0
  34. package/site/content/docs/elements/flow/workflows.mdx +640 -0
  35. package/site/content/docs/elements/gate/auth.mdx +371 -0
  36. package/site/content/docs/elements/gate/authorization.mdx +298 -0
  37. package/site/content/docs/elements/gate/index.mdx +418 -0
  38. package/site/content/docs/elements/gate/meta.json +5 -0
  39. package/site/content/docs/elements/gate/rate-limits.mdx +365 -0
  40. package/site/content/docs/elements/gate/rls.mdx +303 -0
  41. package/site/content/docs/elements/gate/tenancy.mdx +375 -0
  42. package/site/content/docs/elements/index.mdx +20 -10
  43. package/site/content/docs/elements/signal/broadcast.mdx +519 -0
  44. package/site/content/docs/elements/signal/index.mdx +352 -0
  45. package/site/content/docs/elements/signal/live.mdx +591 -0
  46. package/site/content/docs/elements/signal/meta.json +5 -0
  47. package/site/content/docs/elements/signal/once.mdx +597 -0
  48. package/site/content/docs/elements/store/files.mdx +667 -0
  49. package/site/content/docs/elements/store/index.mdx +313 -0
  50. package/site/content/docs/elements/store/kv.mdx +637 -0
  51. package/site/content/docs/elements/store/meta.json +5 -0
  52. package/site/content/docs/elements/store/search.mdx +950 -0
  53. package/site/content/docs/elements/store/sql.mdx +941 -0
  54. package/site/content/docs/elements/vault/config.mdx +259 -0
  55. package/site/content/docs/elements/vault/index.mdx +356 -0
  56. package/site/content/docs/elements/vault/meta.json +5 -0
  57. package/site/content/docs/elements/vault/rotation.mdx +276 -0
  58. package/site/content/docs/elements/vault/secrets.mdx +288 -0
  59. package/site/content/docs/index.mdx +52 -40
  60. package/site/content/docs/meta.json +8 -7
  61. package/site/content/docs/plugins/cors.mdx +2 -1
  62. package/site/content/docs/plugins/csrf.mdx +4 -1
  63. package/site/content/docs/plugins/headers.mdx +2 -1
  64. package/site/content/docs/plugins/ip-allowlist.mdx +2 -1
  65. package/site/content/docs/plugins/magic-link.mdx +6 -0
  66. package/site/content/docs/plugins/maintenance-mode.mdx +2 -1
  67. package/site/content/docs/plugins/oauth.mdx +1 -1
  68. package/site/content/docs/plugins/otp.mdx +12 -1
  69. package/site/content/docs/plugins/passkey.mdx +39 -15
  70. package/site/content/docs/plugins/two-factor.mdx +91 -34
  71. package/site/content/docs/plugins/username.mdx +1 -1
  72. package/site/content/docs/recipes/caddy.mdx +3 -3
  73. package/site/content/docs/recipes/index.mdx +18 -28
  74. package/site/content/docs/recipes/mailpit.mdx +1 -1
  75. package/site/content/docs/recipes/meilisearch.mdx +3 -3
  76. package/site/content/docs/recipes/meta.json +1 -4
  77. package/site/content/docs/recipes/nginx.mdx +2 -2
  78. package/site/content/docs/recipes/openrouter.mdx +283 -0
  79. package/site/content/docs/recipes/pgdog.mdx +3 -3
  80. package/site/content/docs/recipes/postgres.mdx +1 -2
  81. package/site/content/docs/recipes/rustfs.mdx +2 -2
  82. package/site/content/docs/recipes/traefik.mdx +3 -3
  83. package/site/content/docs/reference/cli.mdx +231 -0
  84. package/site/content/docs/reference/configuration.mdx +30 -10
  85. package/site/content/docs/reference/environment-variables.mdx +93 -20
  86. package/site/content/docs/reference/errors.mdx +132 -29
  87. package/site/content/docs/reference/fx.mdx +138 -73
  88. package/site/content/docs/reference/index.mdx +13 -21
  89. package/site/content/docs/reference/meta.json +4 -5
  90. package/site/content/docs/reference/okid.mdx +42 -17
  91. package/site/content/docs/reference/plugins.mdx +4 -3
  92. package/site/content/docs/reference/security.mdx +197 -0
  93. package/site/content/docs/understand/meta.json +5 -0
  94. package/site/content/docs/understand/the-architecture.mdx +264 -0
  95. package/site/content/docs/understand/try-it.mdx +58 -0
  96. package/src/auth/api-keys.ts +2 -1
  97. package/src/auth/bindings.ts +64 -16
  98. package/src/auth/gate-auth.test.ts +6 -1
  99. package/src/auth/identity.ts +152 -5
  100. package/src/auth/index.ts +29 -0
  101. package/src/auth/invites.ts +2 -1
  102. package/src/auth/method-context.ts +41 -0
  103. package/src/auth/oauth-as/crypto.ts +2 -1
  104. package/src/auth/oauth-as/stores.ts +2 -1
  105. package/src/auth/operator.ts +2 -1
  106. package/src/auth/sessions-jwt.test.ts +77 -0
  107. package/src/auth/sessions.ts +20 -4
  108. package/src/auth/tenants.ts +3 -2
  109. package/src/auth/two-factor-challenge.test.ts +61 -0
  110. package/src/auth/two-factor-challenge.ts +284 -0
  111. package/src/auth/verification.ts +5 -0
  112. package/src/bench/REPORT.md +80 -0
  113. package/src/bench/g03-signal-once.bench.ts +1 -1
  114. package/src/bench/g10-observability-contention.bench.ts +1 -1
  115. package/src/bench/g17-hybrid-search.bench.ts +572 -0
  116. package/src/bench/load-app.ts +2 -10
  117. package/src/cli/ai-setup/ai-setup.test.ts +331 -42
  118. package/src/cli/ai-setup/apply.ts +294 -52
  119. package/src/cli/ai-setup/catalog.ts +238 -1342
  120. package/src/cli/ai-setup/index.ts +14 -99
  121. package/src/cli/ai-setup/prompts.ts +60 -443
  122. package/src/cli/ask-seed.test.ts +96 -0
  123. package/src/cli/ask-seed.ts +82 -0
  124. package/src/cli/ask-vault-gaps.test.ts +84 -0
  125. package/src/cli/ask-vault-gaps.ts +146 -0
  126. package/src/cli/build.ts +2 -2
  127. package/src/cli/client-add.test.ts +26 -1
  128. package/src/cli/client-add.ts +106 -27
  129. package/src/cli/db-seed.ts +2 -0
  130. package/src/cli/db.ts +150 -11
  131. package/src/cli/dev.ts +119 -211
  132. package/src/cli/docker-clean.ts +2 -2
  133. package/src/cli/docker-cli.test.ts +1 -1
  134. package/src/cli/doctor-diff.ts +4 -2
  135. package/src/cli/doctor-pii.test.ts +1 -1
  136. package/src/cli/doctor.ts +14 -1
  137. package/src/cli/hero-meta.test.ts +4 -2
  138. package/src/cli/load-config.images.test.ts +8 -10
  139. package/src/cli/load-config.ts +1 -1
  140. package/src/cli/registry.ts +22 -10
  141. package/src/cli/replay.ts +3 -1
  142. package/src/cli/start.ts +1 -1
  143. package/src/cli/tui/keys.ts +2 -3
  144. package/src/client/auth/cookies.ts +74 -0
  145. package/src/client/auth/create-auth-client.ts +636 -0
  146. package/src/client/auth/denials.ts +99 -0
  147. package/src/client/auth/session.ts +283 -0
  148. package/src/client/auth.test.ts +251 -0
  149. package/src/client/auth.ts +39 -114
  150. package/src/client/create-with-session.ts +245 -0
  151. package/src/client/create.ts +51 -5
  152. package/src/client/index.ts +11 -1
  153. package/src/client/live.ts +11 -79
  154. package/src/client/notes-contract.test.ts +5 -10
  155. package/src/client/sse.ts +137 -0
  156. package/src/client/stream.ts +147 -0
  157. package/src/client/transport.test.ts +32 -0
  158. package/src/client/transport.ts +123 -26
  159. package/src/client/types.ts +118 -14
  160. package/src/client-react/index.ts +185 -24
  161. package/src/client-react/use-live-query.ts +13 -3
  162. package/src/compiler/aot.test.ts +7 -4
  163. package/src/compiler/effects-embed.test.ts +56 -0
  164. package/src/compiler/effects-fetch.test.ts +43 -0
  165. package/src/compiler/effects-infer.ts +58 -2
  166. package/src/compiler/extract.test.ts +257 -43
  167. package/src/compiler/extract.ts +566 -48
  168. package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -4
  169. package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +2 -8
  170. package/src/compiler/fixtures/skyport.expected.json +4 -4
  171. package/src/compiler/fixtures/triggers/five-triggers.ts +14 -10
  172. package/src/compiler/response.ts +2 -2
  173. package/src/compiler/search-writer-isolation.test.ts +40 -0
  174. package/src/config/index.ts +11 -0
  175. package/src/console/server/app.ts +17 -23
  176. package/src/console/server/bind.ts +4 -0
  177. package/src/console/server/console.test.ts +2 -2
  178. package/src/console/server/flows-invoke.test.ts +50 -34
  179. package/src/console/server/flows.ts +436 -255
  180. package/src/console/server/runs-ingest.test.ts +6 -3
  181. package/src/console/server/serve.ts +1 -1
  182. package/src/console/server/signals.test.ts +1 -5
  183. package/src/console/server/signals.ts +8 -6
  184. package/src/console/server/state.ts +6 -1
  185. package/src/console/server/store.ts +1 -1
  186. package/src/console/ui-next/dist/assets/FileExportIcon-Ck-5od4R.js +1 -0
  187. package/src/console/ui-next/dist/assets/MoreHorizontalCircle01Icon-gMNGsE37.js +1 -0
  188. package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +1 -0
  189. package/src/console/ui-next/dist/assets/UnavailableIcon-D9cvHVPr.js +1 -0
  190. package/src/console/ui-next/dist/assets/UserIcon-DaE2PB5_.js +1 -0
  191. package/src/console/ui-next/dist/assets/access-page-C_qLDhTq.js +4 -0
  192. package/src/console/ui-next/dist/assets/agent-disclosure-BHVqr3TN.js +1 -0
  193. package/src/console/ui-next/dist/assets/cache-glyph-CKe92lRQ.js +1 -0
  194. package/src/console/ui-next/dist/assets/call-pii-button-DEwTl8ZX.js +1 -0
  195. package/src/console/ui-next/dist/assets/collapsible-BCBtDrCt.js +1 -0
  196. package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +1 -0
  197. package/src/console/ui-next/dist/assets/dagre.esm-B1_XeuLP.js +1 -0
  198. package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +1 -0
  199. package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +1 -0
  200. package/src/console/ui-next/dist/assets/duration-tone-JroqeuCp.js +9 -0
  201. package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +1 -0
  202. package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +1 -0
  203. package/src/console/ui-next/dist/assets/flows-page-CVHa0RTt.js +1 -0
  204. package/src/console/ui-next/dist/assets/highlighted-json-DjJW6hqe.js +154 -0
  205. package/src/console/ui-next/dist/assets/http-method-DC5HBdLU.js +1 -0
  206. package/src/console/ui-next/dist/assets/index-CYjiZ3WO.js +63 -0
  207. package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +2 -0
  208. package/src/console/ui-next/dist/assets/observability-page-CAYMyKb3.js +4 -0
  209. package/src/console/ui-next/dist/assets/react-dom-Ddte4I-Q.js +9 -0
  210. package/src/console/ui-next/dist/assets/replica-lag-yAQYLv75.js +18 -0
  211. package/src/console/ui-next/dist/assets/request-meta-D0yusGxJ.js +1 -0
  212. package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +1 -0
  213. package/src/console/ui-next/dist/assets/{sql-BskegiFM.js → sql-BsFa4tDR.js} +1 -1
  214. package/src/console/ui-next/dist/assets/store-page-BTKJeJ02.js +41 -0
  215. package/src/console/ui-next/dist/assets/trace-detail-sheet-Bp-Yygs5.js +2 -0
  216. package/src/console/ui-next/dist/assets/tree-expand-toggle-DoaVDfAM.js +55 -0
  217. package/src/console/ui-next/dist/assets/units-page-BRz7xyYL.js +1 -0
  218. package/src/console/ui-next/dist/assets/{use-vault-list-uk4WVboC.js → use-vault-list-CT4-gajj.js} +1 -1
  219. package/src/console/ui-next/dist/assets/vault-page-3jQt-bOJ.js +2 -0
  220. package/src/console/ui-next/dist/assets/xyflow-CSyC6ryz.css +1 -0
  221. package/src/console/ui-next/dist/assets/xyflow-yApv7D4e.js +7 -0
  222. package/src/console/ui-next/dist/index.html +6 -13
  223. package/src/console/ui-next/seed-invoke-host.ts +21 -18
  224. package/src/console/ui-next/src/client.ts +7 -2
  225. package/src/console/ui-next/src/features/flows/graph/element-map.test.ts +1 -1
  226. package/src/console/ui-next/src/features/flows/graph/element-map.ts +5 -3
  227. package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +12 -2
  228. package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +4 -0
  229. package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +8 -0
  230. package/src/console/ui-next/src/features/flows/traces/trace-detail.test.ts +4 -5
  231. package/src/console/ui-next/src/features/flows/traces/trace-gates.ts +3 -6
  232. package/src/console/ui-next/src/features/flows/traces/waterfall-bars.ts +4 -0
  233. package/src/console/ui-next/src/features/flows/traces/waterfall-tooltip.ts +9 -3
  234. package/src/console/ui-next/src/features/store/detail/reveal-cell.tsx +7 -11
  235. package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +2 -2
  236. package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +2 -0
  237. package/src/console/ui-next/src/features/store/lib/grid-model.test.ts +25 -1
  238. package/src/console/ui-next/src/features/store/lib/grid-model.ts +36 -1
  239. package/src/console/ui-next/src/features/store/query/query-results.tsx +3 -3
  240. package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +2 -0
  241. package/src/console/ui-next/src/features/units/lib/call-read-safe.ts +3 -1
  242. package/src/console/ui-next/src/features/units/lib/fields-from-schema.ts +6 -0
  243. package/src/docker/ai-model-status.test.ts +1 -12
  244. package/src/docker/ai-model-status.ts +10 -38
  245. package/src/docker/compose-up.test.ts +100 -0
  246. package/src/docker/compose-up.ts +292 -0
  247. package/src/docker/compose.ts +4 -14
  248. package/src/docker/derive.ts +9 -34
  249. package/src/docker/docker.test.ts +16 -261
  250. package/src/docker/images-config.test.ts +13 -25
  251. package/src/docker/index.ts +1 -24
  252. package/src/docker/recipes/index.ts +0 -23
  253. package/src/docker/recipes/pgdog.ts +6 -4
  254. package/src/docker/stack-id.test.ts +2 -2
  255. package/src/docker/stack-id.ts +0 -1
  256. package/src/docker/types.ts +2 -2
  257. package/src/drivers/ai-anthropic.ts +10 -0
  258. package/src/drivers/ai-openai-compatible.ts +34 -7
  259. package/src/drivers/ai-providers.test.ts +0 -107
  260. package/src/drivers/ai-stream.test.ts +0 -34
  261. package/src/drivers/ai-types.ts +17 -8
  262. package/src/drivers/channel-fcm.ts +6 -1
  263. package/src/drivers/channel-msegat.ts +6 -1
  264. package/src/drivers/channel-resend.ts +5 -1
  265. package/src/drivers/channel-smtp.ts +5 -1
  266. package/src/drivers/channel-sndr.ts +10 -1
  267. package/src/drivers/channel-taqnyat-mail.ts +5 -1
  268. package/src/drivers/channel-taqnyat-whatsapp.ts +6 -1
  269. package/src/drivers/channel-taqnyat.ts +6 -1
  270. package/src/drivers/channel-types.ts +10 -0
  271. package/src/drivers/channel-unifonic.ts +6 -1
  272. package/src/drivers/channel-wa-cloud.ts +6 -1
  273. package/src/drivers/channel-webpush.ts +6 -1
  274. package/src/drivers/external.ts +33 -0
  275. package/src/drivers/index.ts +0 -10
  276. package/src/drivers/meilisearch.ts +6 -0
  277. package/src/drivers/oauth-types.ts +4 -0
  278. package/src/drivers/postgres.test.ts +74 -3
  279. package/src/drivers/postgres.ts +175 -6
  280. package/src/drivers/signal-types.ts +5 -5
  281. package/src/drivers/types.ts +7 -0
  282. package/src/drivers/vault-types.ts +5 -0
  283. package/src/elements/ai/declare.ts +17 -4
  284. package/src/elements/ai/eval.ts +1 -1
  285. package/src/elements/ai/mcp-http.ts +1 -1
  286. package/src/elements/ai/pii.ts +1 -1
  287. package/src/elements/ai/providers.test.ts +289 -0
  288. package/src/elements/ai/providers.ts +169 -0
  289. package/src/elements/ai/runtime.ts +68 -5
  290. package/src/elements/ai/schema.ts +2 -2
  291. package/src/elements/ai.test.ts +7 -7
  292. package/src/elements/ai.ts +17 -1
  293. package/src/elements/channel/runtime.ts +105 -12
  294. package/src/elements/clock/cron-fields.test.ts +144 -0
  295. package/src/elements/clock/cron-fields.ts +185 -0
  296. package/src/elements/clock/declare.ts +247 -3
  297. package/src/elements/clock.ts +21 -1
  298. package/src/elements/gate/declare.ts +1 -1
  299. package/src/elements/gate.ts +1 -1
  300. package/src/elements/index.ts +15 -0
  301. package/src/elements/signal/chaos-child.ts +1 -2
  302. package/src/elements/signal/declare.ts +65 -37
  303. package/src/elements/signal/delivery-modes.test.ts +11 -31
  304. package/src/elements/signal/dry-run-replay.test.ts +1 -7
  305. package/src/elements/signal/dry-run-write-isolation.test.ts +1 -7
  306. package/src/elements/signal/key-ordering.test.ts +6 -26
  307. package/src/elements/signal/lease-reclaim.test.ts +2 -6
  308. package/src/elements/signal/optional-emit.test.ts +6 -9
  309. package/src/elements/signal/order-lifecycle.test.ts +4 -17
  310. package/src/elements/signal/orphan-messages.test.ts +4 -15
  311. package/src/elements/signal/reconcile.test.ts +2 -2
  312. package/src/elements/signal/runtime.ts +1 -1
  313. package/src/elements/signal/schema-emit.test.ts +4 -8
  314. package/src/elements/signal.test.ts +24 -49
  315. package/src/elements/signal.ts +9 -2
  316. package/src/elements/store/domain-ddl.test.ts +1 -1
  317. package/src/elements/store/live-http.test.ts +9 -4
  318. package/src/elements/store/prepare-row.test.ts +123 -0
  319. package/src/elements/store/resource.ts +43 -12
  320. package/src/elements/store/schema-decl.ts +117 -0
  321. package/src/elements/store/search-backfill.ts +205 -0
  322. package/src/elements/store/search-bind.ts +66 -0
  323. package/src/elements/store/search-bm25.ts +78 -0
  324. package/src/elements/store/search-ddl.ts +156 -0
  325. package/src/elements/store/search-embed-flow.ts +141 -0
  326. package/src/elements/store/search-errors.ts +34 -0
  327. package/src/elements/store/search-fusion.ts +112 -0
  328. package/src/elements/store/search-lsh.ts +214 -0
  329. package/src/elements/store/search-runtime.pglite.test.ts +186 -0
  330. package/src/elements/store/search-runtime.ts +314 -0
  331. package/src/elements/store/search.test.ts +226 -0
  332. package/src/elements/store/sql-session.test.ts +1 -0
  333. package/src/elements/store/sql-session.ts +83 -3
  334. package/src/elements/store/table.ts +23 -2
  335. package/src/elements/store/upsert-app.test.ts +1 -3
  336. package/src/elements/store.ts +52 -0
  337. package/src/full.ts +4 -2
  338. package/src/http.ts +4 -1
  339. package/src/i18n/catalogs/ar.ts +14 -6
  340. package/src/i18n/catalogs/en.ts +14 -6
  341. package/src/index.ts +6 -1
  342. package/src/kernel/adopt-barrel-fresh.test.ts +7 -7
  343. package/src/kernel/adopt-routes.ts +9 -1
  344. package/src/kernel/app-auth.ts +5 -0
  345. package/src/kernel/app.ts +102 -9
  346. package/src/kernel/auto-cache.test.ts +6 -12
  347. package/src/kernel/auto-registry.test.ts +3 -3
  348. package/src/kernel/boot-bind/ai.test.ts +22 -19
  349. package/src/kernel/boot-bind/ai.ts +5 -43
  350. package/src/kernel/boot-bind/clock.ts +23 -5
  351. package/src/kernel/boot-bind/honor-config.test.ts +4 -4
  352. package/src/kernel/boot.test.ts +11 -6
  353. package/src/kernel/boot.ts +66 -16
  354. package/src/kernel/boundary-contract.ts +93 -0
  355. package/src/kernel/budget.test.ts +1 -1
  356. package/src/kernel/call.ts +89 -0
  357. package/src/kernel/capability.ts +6 -0
  358. package/src/kernel/client-descriptor.ts +123 -0
  359. package/src/kernel/clock-timezone.test.ts +80 -0
  360. package/src/kernel/correlation.test.ts +1 -1
  361. package/src/kernel/dry-run.ts +11 -8
  362. package/src/kernel/effects-stamping.test.ts +42 -9
  363. package/src/kernel/effects.test.ts +4 -2
  364. package/src/kernel/effects.ts +51 -9
  365. package/src/kernel/errors-channel.ts +17 -0
  366. package/src/kernel/errors-live-resume.ts +3 -2
  367. package/src/kernel/errors-tenant.ts +7 -4
  368. package/src/kernel/errors.registry-helpers.ts +96 -0
  369. package/src/kernel/errors.registry.test.ts +139 -25
  370. package/src/kernel/errors.ts +102 -23
  371. package/src/kernel/external-effects.test.ts +196 -0
  372. package/src/kernel/flow.test.ts +13 -4
  373. package/src/kernel/flow.ts +69 -71
  374. package/src/kernel/fx-ask-telemetry.test.ts +2 -2
  375. package/src/kernel/fx-dead-letters.test.ts +3 -3
  376. package/src/kernel/fx-fetch.ts +55 -0
  377. package/src/kernel/fx-live-stream.ts +2 -2
  378. package/src/kernel/fx-live.test.ts +8 -8
  379. package/src/kernel/fx.test.ts +17 -11
  380. package/src/kernel/fx.ts +180 -57
  381. package/src/kernel/horizontal-child.ts +1 -1
  382. package/src/kernel/http-query.test.ts +3 -6
  383. package/src/kernel/index.ts +13 -3
  384. package/src/kernel/instance-id.ts +1 -1
  385. package/src/kernel/instances.test.ts +40 -0
  386. package/src/kernel/instances.ts +47 -9
  387. package/src/kernel/live-http.test.ts +6 -7
  388. package/src/kernel/live-http.ts +6 -2
  389. package/src/kernel/live-resume.test.ts +1 -1
  390. package/src/kernel/mcp-tool.test.ts +3 -3
  391. package/src/kernel/on.ts +98 -4
  392. package/src/kernel/pipeline.test.ts +12 -15
  393. package/src/kernel/plugin-elements.test.ts +1 -1
  394. package/src/kernel/stamp-http.test.ts +3 -3
  395. package/src/kernel/triggers.ts +210 -95
  396. package/src/kernel-entry.ts +0 -1
  397. package/src/manifest/diff.ts +11 -1
  398. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  399. package/src/manifest/types.ts +46 -2
  400. package/src/mcp/docs-index.ts +3 -3
  401. package/src/mcp/docs-mcp.test.ts +2 -2
  402. package/src/mcp/docs-tools.ts +2 -1
  403. package/src/okid.test.ts +56 -0
  404. package/src/okid.ts +55 -11
  405. package/src/plugins/anonymous.ts +8 -4
  406. package/src/plugins/auth/shared.ts +27 -3
  407. package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
  408. package/src/plugins/auth-methods.security.test.ts +561 -23
  409. package/src/plugins/config-source.ts +1 -1
  410. package/src/plugins/csrf.test.ts +65 -0
  411. package/src/plugins/index.ts +2 -0
  412. package/src/plugins/magic-link.ts +36 -16
  413. package/src/plugins/oauth/shared.ts +3 -1
  414. package/src/plugins/oauth.ts +22 -14
  415. package/src/plugins/otp.ts +37 -21
  416. package/src/plugins/passkey-webauthn.ts +9 -6
  417. package/src/plugins/passkey.ts +98 -26
  418. package/src/plugins/pre-account-hijack.test.ts +223 -0
  419. package/src/plugins/two-factor.ts +466 -37
  420. package/src/plugins/username.ts +19 -7
  421. package/src/release/build-lib.ts +1 -0
  422. package/src/release/limits.ts +2 -2
  423. package/src/release/measure.ts +1 -1
  424. package/src/runs/collect.test.ts +0 -2
  425. package/src/runtime/json-code-block.test.ts +250 -20
  426. package/src/runtime/json-code-block.ts +1261 -41
  427. package/src/term.test.ts +1 -1
  428. package/src/test/create-test-app.test.ts +12 -12
  429. package/src/test/live-signals.test.ts +6 -6
  430. package/src/test/provisions.integration.test.ts +10 -14
  431. package/src/test/reset-element-registries.ts +1 -1
  432. package/src/test/tenant-isolation.test.ts +12 -6
  433. package/site/content/docs/deployment/docker-swarm.mdx +0 -164
  434. package/site/content/docs/deployment/docker.mdx +0 -227
  435. package/site/content/docs/deployment/index.mdx +0 -83
  436. package/site/content/docs/deployment/kubernetes.mdx +0 -176
  437. package/site/content/docs/deployment/meta.json +0 -5
  438. package/site/content/docs/deployment/reverse-proxy.mdx +0 -234
  439. package/site/content/docs/elements/ai.mdx +0 -385
  440. package/site/content/docs/elements/channel.mdx +0 -346
  441. package/site/content/docs/elements/clock.mdx +0 -244
  442. package/site/content/docs/elements/flow.mdx +0 -420
  443. package/site/content/docs/elements/gate.mdx +0 -436
  444. package/site/content/docs/elements/signal.mdx +0 -380
  445. package/site/content/docs/elements/store.mdx +0 -1099
  446. package/site/content/docs/elements/vault.mdx +0 -405
  447. package/site/content/docs/get-started/basic-usage.mdx +0 -173
  448. package/site/content/docs/get-started/index.mdx +0 -43
  449. package/site/content/docs/get-started/installation.mdx +0 -220
  450. package/site/content/docs/get-started/introduction.mdx +0 -144
  451. package/site/content/docs/get-started/meta.json +0 -13
  452. package/site/content/docs/get-started/project-structure.mdx +0 -925
  453. package/site/content/docs/get-started/testing.mdx +0 -328
  454. package/site/content/docs/get-started/why.mdx +0 -114
  455. package/site/content/docs/recipes/llama-cpp.mdx +0 -151
  456. package/site/content/docs/recipes/ollama.mdx +0 -142
  457. package/site/content/docs/recipes/sglang.mdx +0 -105
  458. package/site/content/docs/recipes/vllm.mdx +0 -106
  459. package/site/content/docs/reference/cli.md +0 -232
  460. package/site/content/docs/reference/client.mdx +0 -469
  461. package/site/content/docs/reference/security.md +0 -74
  462. package/src/cli/ai-setup/detect-ollama.ts +0 -213
  463. package/src/cli/ai-setup/recommend.test.ts +0 -225
  464. package/src/cli/ai-setup/recommend.ts +0 -225
  465. package/src/cli/dev-controls.test.ts +0 -122
  466. package/src/cli/dev-controls.ts +0 -164
  467. package/src/cli/tui/DevLive.tsx +0 -126
  468. package/src/console/ui-next/dist/assets/access-page-3-EFj-2G.js +0 -4
  469. package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +0 -1
  470. package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +0 -1
  471. package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +0 -1
  472. package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +0 -1
  473. package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +0 -1
  474. package/src/console/ui-next/dist/assets/dagre.esm-ZwcdTuZZ.js +0 -1
  475. package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +0 -1
  476. package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +0 -1
  477. package/src/console/ui-next/dist/assets/duration-tone-sC3lGABz.js +0 -9
  478. package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +0 -1
  479. package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +0 -1
  480. package/src/console/ui-next/dist/assets/flows-page-cVFnA4HH.js +0 -1
  481. package/src/console/ui-next/dist/assets/highlighted-json-Awq7gYdu.js +0 -154
  482. package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +0 -1
  483. package/src/console/ui-next/dist/assets/index-CMIgUbD0.js +0 -66
  484. package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
  485. package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
  486. package/src/console/ui-next/dist/assets/observability-page-CQ3p34ip.js +0 -4
  487. package/src/console/ui-next/dist/assets/preload-helper-oH4irX4C.js +0 -1
  488. package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +0 -1
  489. package/src/console/ui-next/dist/assets/react-dom-Bph1y7z7.js +0 -9
  490. package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +0 -18
  491. package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +0 -1
  492. package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +0 -1
  493. package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +0 -1
  494. package/src/console/ui-next/dist/assets/skeleton-D-czQJT6.js +0 -1
  495. package/src/console/ui-next/dist/assets/store-page-02xOiqIK.js +0 -41
  496. package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +0 -2
  497. package/src/console/ui-next/dist/assets/tree-expand-toggle-BtyhmWb4.js +0 -55
  498. package/src/console/ui-next/dist/assets/units-page-l8FeKfnP.js +0 -1
  499. package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +0 -1
  500. package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +0 -1
  501. package/src/console/ui-next/dist/assets/vault-page-CL-d_mLE.js +0 -2
  502. package/src/console/ui-next/dist/assets/xyflow-D7n4g6go.js +0 -7
  503. package/src/console/ui-next/dist/assets/xyflow-DZ0Ws1xk.css +0 -1
  504. package/src/docker/ollama-pull.ts +0 -232
  505. package/src/docker/recipes/llama-cpp.ts +0 -298
  506. package/src/docker/recipes/ollama.ts +0 -44
  507. package/src/docker/recipes/sglang.ts +0 -55
  508. package/src/docker/recipes/vllm.ts +0 -44
  509. package/src/drivers/ai-ollama-tools.integration.test.ts +0 -109
  510. package/src/drivers/ai-ollama.integration.test.ts +0 -184
  511. package/src/drivers/ai-ollama.ts +0 -389
  512. package/src/drivers/ollama.ts +0 -14
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Random-hyperplane LSH — K fixed planes generated once per field lifetime.
3
+ */
4
+
5
+ import { createHash } from "node:crypto";
6
+ import { LSH_DEFAULT_K } from "./search-errors.ts";
7
+
8
+ /**
9
+ * Stable seed string for a field's hyperplanes.
10
+ *
11
+ * @param table - SQL table
12
+ * @param column - SQL column
13
+ * @param dims - Embedding dimensionality
14
+ * @param k - Number of planes
15
+ */
16
+ export function hyperplaneSeed(table: string, column: string, dims: number, k: number): string {
17
+ return `${table}|${column}|${dims}|${k}`;
18
+ }
19
+
20
+ /**
21
+ * Generate K unit-ish random hyperplanes in `dims` dimensions from a seed.
22
+ * Deterministic across hosts for the same seed.
23
+ *
24
+ * @param seed - Stable seed string
25
+ * @param dims - Vector dimensionality
26
+ * @param k - Plane count (default {@link LSH_DEFAULT_K})
27
+ */
28
+ export function generateHyperplanes(
29
+ seed: string,
30
+ dims: number,
31
+ k: number = LSH_DEFAULT_K,
32
+ ): Float32Array[] {
33
+ const planes: Float32Array[] = [];
34
+ let counter = 0;
35
+ for (let i = 0; i < k; i++) {
36
+ const plane = new Float32Array(dims);
37
+ let filled = 0;
38
+ while (filled < dims) {
39
+ const h = createHash("sha256").update(`${seed}\0${counter++}`).digest();
40
+ for (let b = 0; b + 3 < h.length && filled < dims; b += 4) {
41
+ const u = h.readUInt32BE(b) / 0xffff_ffff;
42
+ plane[filled++] = u * 2 - 1;
43
+ }
44
+ }
45
+ // L2 normalize
46
+ let norm = 0;
47
+ for (let j = 0; j < dims; j++) norm += plane[j]! * plane[j]!;
48
+ norm = Math.sqrt(norm) || 1;
49
+ for (let j = 0; j < dims; j++) plane[j]! /= norm;
50
+ planes.push(plane);
51
+ }
52
+ return planes;
53
+ }
54
+
55
+ /**
56
+ * Pack LSH bucket bits into a bigint (K ≤ 64).
57
+ *
58
+ * @param vector - Embedding
59
+ * @param planes - Fixed hyperplanes
60
+ */
61
+ export function lshBucket(vector: readonly number[], planes: readonly Float32Array[]): bigint {
62
+ if (planes.length > 64) {
63
+ throw new Error(`lshBucket: K=${planes.length} exceeds bigint packing (max 64)`);
64
+ }
65
+ let bits = 0n;
66
+ for (let i = 0; i < planes.length; i++) {
67
+ const plane = planes[i]!;
68
+ if (vector.length !== plane.length) {
69
+ throw new Error(`lshBucket: vector length ${vector.length} !== plane dims ${plane.length}`);
70
+ }
71
+ let dot = 0;
72
+ for (let j = 0; j < plane.length; j++) {
73
+ dot += vector[j]! * plane[j]!;
74
+ }
75
+ if (dot >= 0) bits |= 1n << BigInt(i);
76
+ }
77
+ return bits;
78
+ }
79
+
80
+ /**
81
+ * Encode an LSH bucket for PostgreSQL `bigint` (signed int64).
82
+ * K=64 bit patterns with the high bit set exceed unsigned range when passed
83
+ * as a decimal string — reinterpret as two's-complement signed.
84
+ *
85
+ * @param bucket - Unsigned bit pack from {@link lshBucket}
86
+ */
87
+ export function lshBucketToSql(bucket: bigint): string {
88
+ const masked = bucket & 0xffff_ffff_ffff_ffffn;
89
+ if (masked >= 0x8000_0000_0000_0000n) {
90
+ return (masked - 0x1_0000_0000_0000_0000n).toString();
91
+ }
92
+ return masked.toString();
93
+ }
94
+
95
+ /**
96
+ * Decode a PostgreSQL `bigint` LSH value back to an unsigned bit pack.
97
+ *
98
+ * @param value - Driver value (string | number | bigint)
99
+ */
100
+ export function lshBucketFromSql(value: unknown): bigint {
101
+ const n = typeof value === "bigint" ? value : BigInt(String(value));
102
+ return n < 0n ? n + 0x1_0000_0000_0000_0000n : n;
103
+ }
104
+
105
+ /**
106
+ * Cosine similarity in [−1, 1].
107
+ *
108
+ * @param a - Vector a
109
+ * @param b - Vector b
110
+ */
111
+ export function cosineSimilarity(a: readonly number[], b: readonly number[]): number {
112
+ if (a.length !== b.length) {
113
+ throw new Error(`cosineSimilarity: length mismatch ${a.length} vs ${b.length}`);
114
+ }
115
+ let dot = 0;
116
+ let na = 0;
117
+ let nb = 0;
118
+ for (let i = 0; i < a.length; i++) {
119
+ dot += a[i]! * b[i]!;
120
+ na += a[i]! * a[i]!;
121
+ nb += b[i]! * b[i]!;
122
+ }
123
+ const denom = Math.sqrt(na) * Math.sqrt(nb);
124
+ return denom === 0 ? 0 : dot / denom;
125
+ }
126
+
127
+ /**
128
+ * Hamming distance between two K-bit LSH packs (K ≤ 64).
129
+ *
130
+ * Random-hyperplane (Charikar) SimHash ranks neighbors by this distance.
131
+ * Hamming-1 equality is not a viable candidate set at {@link LSH_DEFAULT_K}:
132
+ * true near-neighbors typically sit at distance ~5–16, not 0–1.
133
+ *
134
+ * @param a - Bucket a
135
+ * @param b - Bucket b
136
+ */
137
+ export function hammingDistance(a: bigint, b: bigint): number {
138
+ let x = (a ^ b) & 0xffff_ffff_ffff_ffffn;
139
+ let count = 0;
140
+ while (x) {
141
+ x &= x - 1n;
142
+ count++;
143
+ }
144
+ return count;
145
+ }
146
+
147
+ /**
148
+ * Candidate buckets: exact match plus Hamming distance 1 flips.
149
+ *
150
+ * Kept for tight-collision tests and callers that want a 65-wide equality
151
+ * probe. Query-time retrieval uses {@link lshHammingSql} ranking instead —
152
+ * Hamming-1 alone misses almost all true neighbors at K=64.
153
+ *
154
+ * @param bucket - Query bucket
155
+ * @param k - Bit width
156
+ */
157
+ export function neighborBuckets(bucket: bigint, k: number): bigint[] {
158
+ const out: bigint[] = [bucket];
159
+ for (let i = 0; i < k; i++) {
160
+ out.push(bucket ^ (1n << BigInt(i)));
161
+ }
162
+ return out;
163
+ }
164
+
165
+ /**
166
+ * Postgres 14+ Hamming distance between a stored signed-int64 LSH column
167
+ * and a bound query bucket (`?::bigint`). Used as `ORDER BY … LIMIT k`.
168
+ *
169
+ * @param columnSql - Quoted LSH column identifier
170
+ * @param bucketPlaceholder - Bound-parameter placeholder (`?` before `$n` rewrite)
171
+ */
172
+ export function lshHammingSql(columnSql: string, bucketPlaceholder: string = "?"): string {
173
+ return `bit_count((${columnSql} # ${bucketPlaceholder}::bigint)::bit(64))`;
174
+ }
175
+
176
+ /**
177
+ * Serialize planes for `oke_search_planes.planes` (Float32 little-endian).
178
+ *
179
+ * @param planes - Hyperplanes
180
+ */
181
+ export function serializePlanes(planes: readonly Float32Array[]): Buffer {
182
+ const dims = planes[0]?.length ?? 0;
183
+ const buf = Buffer.allocUnsafe(4 + planes.length * dims * 4);
184
+ buf.writeUInt32LE(dims, 0);
185
+ let offset = 4;
186
+ for (const plane of planes) {
187
+ for (let i = 0; i < dims; i++) {
188
+ buf.writeFloatLE(plane[i]!, offset);
189
+ offset += 4;
190
+ }
191
+ }
192
+ return buf;
193
+ }
194
+
195
+ /**
196
+ * Deserialize planes from storage.
197
+ *
198
+ * @param buf - Stored bytes
199
+ * @param k - Expected plane count
200
+ */
201
+ export function deserializePlanes(buf: Buffer, k: number): Float32Array[] {
202
+ const dims = buf.readUInt32LE(0);
203
+ const planes: Float32Array[] = [];
204
+ let offset = 4;
205
+ for (let i = 0; i < k; i++) {
206
+ const plane = new Float32Array(dims);
207
+ for (let j = 0; j < dims; j++) {
208
+ plane[j] = buf.readFloatLE(offset);
209
+ offset += 4;
210
+ }
211
+ planes.push(plane);
212
+ }
213
+ return planes;
214
+ }
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Hybrid search runtime — PGlite end-to-end for LSH candidate SQL.
3
+ *
4
+ * Captures the literal SQL `runSqlSearch` issues and checks K=64 Hamming-rank
5
+ * recovery on the same synthetic hash-bag G17 uses (40-row hand case).
6
+ */
7
+
8
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
9
+ import { createHash } from "node:crypto";
10
+ import type { DeclaredColumn } from "../../manifest/types.ts";
11
+ import { pgliteDriver } from "../../drivers/pglite.ts";
12
+ import type { SqlConnection } from "../../drivers/types.ts";
13
+ import {
14
+ embColumn,
15
+ ensureHyperplaneInserts,
16
+ lshColumn,
17
+ OKE_SEARCH_PLANES,
18
+ searchDdlForTable,
19
+ } from "./search-ddl.ts";
20
+ import { LSH_DEFAULT_K } from "./search-errors.ts";
21
+ import {
22
+ cosineSimilarity,
23
+ deserializePlanes,
24
+ lshBucket,
25
+ lshBucketFromSql,
26
+ lshBucketToSql,
27
+ } from "./search-lsh.ts";
28
+ import { runSqlSearch, type SearchColumnMeta } from "./search-runtime.ts";
29
+
30
+ const TABLE = "lsh_recall_docs";
31
+ const DIMS = 32;
32
+ const TOPICS = [
33
+ "refund policy shipping delay",
34
+ "password reset two factor auth",
35
+ "invoice payment stripe webhook",
36
+ "search ranking bm25 hybrid",
37
+ "postgres gin btree index plan",
38
+ "tenant isolation row level security",
39
+ "durable flow journal resume",
40
+ "live query fanout subscriber",
41
+ ] as const;
42
+
43
+ const COLS: Record<string, DeclaredColumn> = {
44
+ id: { type: "text", sqlName: "id", primaryKey: true },
45
+ title: { type: "text", sqlName: "title", searchable: { weight: 2 } },
46
+ body: {
47
+ type: "text",
48
+ sqlName: "body",
49
+ searchable: { weight: 1 },
50
+ embed: { dims: DIMS, model: "mock" },
51
+ },
52
+ };
53
+
54
+ const SEARCH_COLS: SearchColumnMeta[] = [
55
+ { key: "title", sqlName: "title", weight: 2 },
56
+ { key: "body", sqlName: "body", weight: 1, embed: { dims: DIMS, model: "mock" } },
57
+ ];
58
+
59
+ let conn: SqlConnection;
60
+
61
+ beforeAll(async () => {
62
+ conn = await pgliteDriver.connect({ url: "memory://lsh-recall-runtime", role: "primary" });
63
+ }, 20_000);
64
+
65
+ afterAll(async () => {
66
+ await conn.close();
67
+ });
68
+
69
+ /**
70
+ * G17 synthetic embedding — deterministic SHA-256 hash bag, L2-normalized.
71
+ *
72
+ * @param text - Source text
73
+ */
74
+ function synthEmbed(text: string): number[] {
75
+ const v = Array.from({ length: DIMS }, () => 0);
76
+ const tokens = text.toLowerCase().split(/\W+/).filter(Boolean);
77
+ for (const t of tokens) {
78
+ const h = createHash("sha256").update(t).digest();
79
+ for (let i = 0; i < DIMS; i++) {
80
+ v[i]! += (h[i % h.length]! / 255) * 2 - 1;
81
+ }
82
+ }
83
+ let norm = 0;
84
+ for (const x of v) norm += x * x;
85
+ norm = Math.sqrt(norm) || 1;
86
+ return v.map((x) => x / norm);
87
+ }
88
+
89
+ describe("runSqlSearch LSH candidate path (PGlite)", () => {
90
+ test("issued SQL ranks by bit_count Hamming, not Hamming-1 ANY(); recovers exact top-10", async () => {
91
+ await conn.exec(`DROP TABLE IF EXISTS ${TABLE} CASCADE`);
92
+ await conn.exec(`
93
+ CREATE TABLE ${TABLE} (
94
+ id text PRIMARY KEY,
95
+ title text NOT NULL,
96
+ body text NOT NULL
97
+ )
98
+ `);
99
+ for (const stmt of searchDdlForTable(TABLE, COLS)) {
100
+ await conn.exec(stmt);
101
+ }
102
+ for (const ins of ensureHyperplaneInserts(TABLE, COLS)) {
103
+ await conn.exec(ins.sql, ins.params);
104
+ }
105
+
106
+ const planesRow = await conn.query(
107
+ `SELECT k, planes FROM ${OKE_SEARCH_PLANES} WHERE table_name = ? AND column_name = ?`,
108
+ [TABLE, "body"],
109
+ );
110
+ const prow = planesRow[0]!;
111
+ const k = Number(prow["k"] ?? LSH_DEFAULT_K);
112
+ const planes = deserializePlanes(Buffer.from(prow["planes"] as Buffer), k);
113
+
114
+ const vectors: number[][] = [];
115
+ const n = 40;
116
+ for (let i = 0; i < n; i++) {
117
+ const topic = TOPICS[i % TOPICS.length]!;
118
+ const id = `d${String(i).padStart(8, "0")}`;
119
+ const title = `${topic} item ${i}`;
120
+ const body = `${topic}. Document ${i} discusses ${topic} with enough tokens for BM25.`;
121
+ const vec = synthEmbed(body);
122
+ const bucket = lshBucket(vec, planes);
123
+ vectors.push(vec);
124
+ await conn.exec(
125
+ `INSERT INTO ${TABLE} (id, title, body, ${embColumn("body")}, ${lshColumn("body")})
126
+ VALUES (?, ?, ?, ?, ?)`,
127
+ [id, title, body, `{${vec.join(",")}}`, lshBucketToSql(bucket)],
128
+ );
129
+ }
130
+
131
+ // Write/query identity for one stored row vs re-projection of the same body.
132
+ const stored = await conn.query(`SELECT ${lshColumn("body")} AS b FROM ${TABLE} WHERE id = ?`, [
133
+ "d00000000",
134
+ ]);
135
+ const body0 = `${TOPICS[0]}. Document 0 discusses ${TOPICS[0]} with enough tokens for BM25.`;
136
+ const queryBucket = lshBucket(synthEmbed(body0), planes);
137
+ expect(lshBucketFromSql(stored[0]?.["b"])).toBe(queryBucket);
138
+
139
+ const captured: Array<{ sql: string; params: readonly unknown[] }> = [];
140
+ const tapped: SqlConnection = {
141
+ driverId: conn.driverId,
142
+ role: conn.role,
143
+ query: async (sql, params = []) => {
144
+ captured.push({ sql, params });
145
+ return conn.query(sql, params);
146
+ },
147
+ exec: (sql, params) => conn.exec(sql, params),
148
+ close: () => conn.close(),
149
+ };
150
+
151
+ const qVec = synthEmbed(TOPICS[0]!);
152
+ const result = await runSqlSearch({
153
+ conn: tapped,
154
+ table: TABLE,
155
+ columns: SEARCH_COLS,
156
+ pkSqlName: "id",
157
+ options: { query: `zxqwv ${TOPICS[0]}`, limit: 10 },
158
+ embedQuery: async () => qVec,
159
+ });
160
+
161
+ const candidate = captured.find((c) => /UNION/i.test(c.sql) && /bit_count/i.test(c.sql));
162
+ expect(candidate).toBeDefined();
163
+ expect(candidate!.sql).toContain("bit_count");
164
+ expect(candidate!.sql).toContain("ORDER BY");
165
+ expect(candidate!.sql).not.toMatch(/=\s*ANY\s*\(/i);
166
+ // Bound query bucket is the signed int64 pack of the query vector.
167
+ expect(candidate!.params).toContain(lshBucketToSql(lshBucket(qVec, planes)));
168
+
169
+ const scored: Array<{ i: number; s: number }> = [];
170
+ for (let i = 0; i < vectors.length; i++) {
171
+ scored.push({ i, s: cosineSimilarity(qVec, vectors[i]!) });
172
+ }
173
+ scored.sort((a, b) => b.s - a.s);
174
+ const exact = new Set(scored.slice(0, 10).map((x) => `d${String(x.i).padStart(8, "0")}`));
175
+ const approx = result.data.map((r) => String(r["id"]));
176
+ let hits = 0;
177
+ for (const id of approx.slice(0, 10)) {
178
+ if (exact.has(id)) hits += 1;
179
+ }
180
+ // Hamming-1 equality recovered 0/10 on this corpus. Hamming-rank UNION
181
+ // plus in-process cosine/RRF must recover a real majority of exact neighbors.
182
+ expect(result.data).toHaveLength(10);
183
+ expect(hits / 10).toBeGreaterThanOrEqual(0.5);
184
+ expect(result.meta.engine).toContain("lsh");
185
+ }, 30_000);
186
+ });