okengine 0.10.3 → 0.11.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 (318) hide show
  1. package/package.json +76 -10
  2. package/site/content/docs/deployment/docker-swarm.mdx +48 -111
  3. package/site/content/docs/deployment/docker.mdx +43 -36
  4. package/site/content/docs/deployment/index.mdx +9 -9
  5. package/site/content/docs/deployment/kubernetes.mdx +4 -4
  6. package/site/content/docs/elements/ai.mdx +7 -7
  7. package/site/content/docs/elements/channel.mdx +9 -7
  8. package/site/content/docs/elements/clock.mdx +8 -8
  9. package/site/content/docs/elements/flow.mdx +46 -47
  10. package/site/content/docs/elements/gate.mdx +6 -5
  11. package/site/content/docs/elements/signal.mdx +2 -2
  12. package/site/content/docs/elements/store.mdx +71 -78
  13. package/site/content/docs/elements/vault.mdx +89 -70
  14. package/site/content/docs/get-started/basic-usage.mdx +8 -8
  15. package/site/content/docs/get-started/installation.mdx +36 -36
  16. package/site/content/docs/get-started/introduction.mdx +11 -0
  17. package/site/content/docs/get-started/why.mdx +2 -2
  18. package/site/content/docs/plugins/anonymous.mdx +1 -1
  19. package/site/content/docs/plugins/magic-link.mdx +11 -11
  20. package/site/content/docs/plugins/otp.mdx +2 -2
  21. package/site/content/docs/plugins/passkey.mdx +1 -1
  22. package/site/content/docs/plugins/two-factor.mdx +1 -1
  23. package/site/content/docs/plugins/username.mdx +1 -1
  24. package/site/content/docs/recipes/caddy.mdx +1 -1
  25. package/site/content/docs/recipes/cockroachdb.mdx +2 -2
  26. package/site/content/docs/recipes/dragonfly.mdx +1 -1
  27. package/site/content/docs/recipes/index.mdx +1 -2
  28. package/site/content/docs/recipes/llama-cpp.mdx +21 -23
  29. package/site/content/docs/recipes/mailpit.mdx +11 -11
  30. package/site/content/docs/recipes/meilisearch.mdx +10 -10
  31. package/site/content/docs/recipes/meta.json +0 -1
  32. package/site/content/docs/recipes/ollama.mdx +1 -1
  33. package/site/content/docs/recipes/pgdog.mdx +12 -9
  34. package/site/content/docs/recipes/postgres.mdx +3 -3
  35. package/site/content/docs/recipes/redis.mdx +2 -2
  36. package/site/content/docs/recipes/rustfs.mdx +10 -7
  37. package/site/content/docs/recipes/sglang.mdx +1 -1
  38. package/site/content/docs/recipes/supabase-docker.mdx +1 -1
  39. package/site/content/docs/recipes/timescale.mdx +2 -2
  40. package/site/content/docs/recipes/valkey.mdx +1 -1
  41. package/site/content/docs/recipes/vllm.mdx +1 -1
  42. package/site/content/docs/recipes/yugabytedb.mdx +2 -2
  43. package/site/content/docs/reference/cli.md +61 -38
  44. package/site/content/docs/reference/configuration.mdx +145 -70
  45. package/site/content/docs/reference/environment-variables.mdx +36 -28
  46. package/site/content/docs/reference/errors.mdx +28 -29
  47. package/site/content/docs/reference/fx.mdx +11 -4
  48. package/site/content/docs/reference/i18n.mdx +17 -6
  49. package/site/content/docs/reference/index.mdx +5 -0
  50. package/site/content/docs/reference/meta.json +1 -0
  51. package/site/content/docs/reference/migrating-environments.mdx +158 -0
  52. package/site/content/docs/reference/plugins.mdx +2 -2
  53. package/src/auth/gate-auth.test.ts +12 -10
  54. package/src/cli/ai-setup/ai-setup.test.ts +27 -15
  55. package/src/cli/ai-setup/apply.ts +111 -15
  56. package/src/cli/ai-setup/catalog.ts +3 -3
  57. package/src/cli/ai-setup/index.ts +1 -1
  58. package/src/cli/ai-setup/prompts.ts +1 -1
  59. package/src/cli/ai-setup/recommend.test.ts +1 -1
  60. package/src/cli/ask-seed.test.ts +3 -3
  61. package/src/cli/build.ts +1 -1
  62. package/src/cli/db-auto-push.test.ts +6 -3
  63. package/src/cli/db-auto-push.ts +7 -5
  64. package/src/cli/db-seed.ts +7 -8
  65. package/src/cli/db.test.ts +70 -71
  66. package/src/cli/db.ts +86 -12
  67. package/src/cli/dev-controller.test.ts +35 -0
  68. package/src/cli/dev-controller.ts +298 -0
  69. package/src/cli/dev-controls.ts +11 -65
  70. package/src/cli/dev-db-push.test.ts +47 -15
  71. package/src/cli/dev-schema-sync.test.ts +11 -11
  72. package/src/cli/dev-schema-sync.ts +10 -10
  73. package/src/cli/dev-session-lock.test.ts +106 -0
  74. package/src/cli/dev-session-lock.ts +209 -0
  75. package/src/cli/dev.test.ts +166 -121
  76. package/src/cli/dev.ts +138 -192
  77. package/src/cli/doc-staleness.test.ts +3 -6
  78. package/src/cli/docker-clean.test.ts +33 -1
  79. package/src/cli/docker-clean.ts +28 -33
  80. package/src/cli/docker-cli.test.ts +12 -11
  81. package/src/cli/docker.ts +95 -20
  82. package/src/cli/doctor.test.ts +40 -0
  83. package/src/cli/doctor.ts +55 -15
  84. package/src/cli/drizzle-env.test.ts +11 -13
  85. package/src/cli/drizzle-env.ts +18 -11
  86. package/src/cli/ensure-drizzle-config.ts +11 -14
  87. package/src/cli/hero-meta.test.ts +15 -15
  88. package/src/cli/hero-meta.ts +10 -9
  89. package/src/cli/index.ts +36 -6
  90. package/src/cli/load-config.images.test.ts +16 -12
  91. package/src/cli/load-config.source.test.ts +50 -0
  92. package/src/cli/load-config.ts +34 -28
  93. package/src/cli/meilisearch-local.ts +1 -2
  94. package/src/cli/mode.ts +7 -58
  95. package/src/cli/registry.ts +175 -19
  96. package/src/cli/resolve-dev-sql-env.test.ts +8 -16
  97. package/src/cli/resolve-dev-sql-env.ts +13 -15
  98. package/src/cli/safe-defaults.test.ts +28 -10
  99. package/src/cli/schema.ts +65 -16
  100. package/src/cli/test.ts +58 -0
  101. package/src/cli/tui/App.tsx +252 -0
  102. package/src/cli/tui/DevLive.tsx +116 -0
  103. package/src/cli/tui/components/ConfirmDialog.tsx +48 -0
  104. package/src/cli/tui/components/HeaderBar.tsx +67 -0
  105. package/src/cli/tui/components/LogStream.tsx +47 -0
  106. package/src/cli/tui/components/PanelCard.tsx +39 -0
  107. package/src/cli/tui/components/SelectRow.tsx +37 -0
  108. package/src/cli/tui/components/SlashPalette.tsx +172 -0
  109. package/src/cli/tui/components/Spinner.tsx +32 -0
  110. package/src/cli/tui/components/StatusBar.tsx +51 -0
  111. package/src/cli/tui/components/StatusDot.tsx +37 -0
  112. package/src/cli/tui/components/TabBar.tsx +49 -0
  113. package/src/cli/tui/components/Wordmark.tsx +43 -0
  114. package/src/cli/tui/format.ts +38 -0
  115. package/src/cli/tui/keys.test.ts +18 -0
  116. package/src/cli/tui/keys.ts +26 -0
  117. package/src/cli/tui/launch.test.ts +18 -0
  118. package/src/cli/tui/launch.ts +57 -0
  119. package/src/cli/tui/panels/Dashboard.tsx +201 -0
  120. package/src/cli/tui/panels/Database.tsx +198 -0
  121. package/src/cli/tui/panels/Dev.tsx +257 -0
  122. package/src/cli/tui/panels/Docker.tsx +357 -0
  123. package/src/cli/tui/panels/Navigator.test.ts +22 -0
  124. package/src/cli/tui/panels/Navigator.tsx +213 -0
  125. package/src/cli/tui/slash-catalog.test.ts +31 -0
  126. package/src/cli/tui/slash-catalog.ts +184 -0
  127. package/src/cli/tui/slash-run.ts +54 -0
  128. package/src/cli/tui/state/ports.ts +95 -0
  129. package/src/cli/tui/theme.ts +24 -0
  130. package/src/cli/vault-cmd.test.ts +402 -0
  131. package/src/cli/vault-cmd.ts +727 -69
  132. package/src/cli/vault-secure-input.test.ts +56 -0
  133. package/src/cli/vault-secure-input.ts +124 -0
  134. package/src/compiler/effects-infer.ts +7 -0
  135. package/src/compiler/fixtures/skyport/oke.config.ts +3 -3
  136. package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -1
  137. package/src/compiler/fixtures/skyport.expected.json +1 -1
  138. package/src/compiler-entry.ts +7 -0
  139. package/src/config/define-config.test.ts +111 -47
  140. package/src/config/driver-defaults.test.ts +16 -23
  141. package/src/config/driver-defaults.ts +33 -63
  142. package/src/config/index.ts +169 -144
  143. package/src/config/resolve-driver.test.ts +14 -19
  144. package/src/console/server/app.ts +4 -2
  145. package/src/console/server/console.test.ts +58 -1
  146. package/src/console/server/flows.ts +22 -2
  147. package/src/console/server/index.ts +3 -0
  148. package/src/console/server/operator-db.test.ts +55 -13
  149. package/src/console/server/operator-db.ts +305 -263
  150. package/src/console/server/serve.ts +16 -7
  151. package/src/console/server/state.ts +31 -9
  152. package/src/console/server/vault.test.ts +120 -5
  153. package/src/console/server/vault.ts +208 -12
  154. package/src/console/ui/dist/assets/{index-D-9KFce5.js → index--Y0Uaz-m.js} +2 -2
  155. package/src/console/ui/dist/assets/panel-vault-BkZdJPX8.js +1 -0
  156. package/src/console/ui/dist/assets/style-C3L349iZ.css +3 -0
  157. package/src/console/ui/dist/index.html +2 -2
  158. package/src/console/ui/shell/client.ts +16 -0
  159. package/src/console/ui/shell/panels/vault/VaultPanel.tsx +54 -1
  160. package/src/console/ui/vault/VaultA11yView.tsx +33 -1
  161. package/src/console/ui/vault/backend.test.ts +75 -0
  162. package/src/console/ui/vault/backend.ts +117 -0
  163. package/src/console/ui/vault/fixture.ts +21 -2
  164. package/src/console/ui/vault/index.ts +11 -1
  165. package/src/console/ui/vault/types.ts +26 -0
  166. package/src/docker/compose.ts +164 -61
  167. package/src/docker/derive.ts +106 -12
  168. package/src/docker/docker.test.ts +156 -110
  169. package/src/docker/helpers.ts +98 -0
  170. package/src/docker/images-config.test.ts +3 -8
  171. package/src/docker/index.ts +30 -5
  172. package/src/docker/recipes/index.ts +0 -3
  173. package/src/docker/recipes/llama-cpp.ts +4 -4
  174. package/src/docker/recipes/pgdog.ts +9 -2
  175. package/src/docker/resources.test.ts +71 -0
  176. package/src/docker/resources.ts +176 -0
  177. package/src/docker/stack-id.test.ts +11 -4
  178. package/src/docker/stack-id.ts +42 -32
  179. package/src/docker/stack.integration.test.ts +4 -15
  180. package/src/docker/types.ts +35 -3
  181. package/src/drivers/ai-ollama.integration.test.ts +2 -2
  182. package/src/drivers/conformance.test.ts +11 -12
  183. package/src/drivers/drizzle-dialect.test.ts +0 -4
  184. package/src/drivers/drizzle-dialect.ts +7 -13
  185. package/src/drivers/index.ts +24 -7
  186. package/src/drivers/journal-postgres.test.ts +3 -1
  187. package/src/drivers/journal-postgres.ts +4 -2
  188. package/src/drivers/meilisearch.ts +1 -1
  189. package/src/drivers/pglite.ts +28 -5
  190. package/src/drivers/types.ts +9 -11
  191. package/src/drivers/vault-aws-secrets-manager.test.ts +159 -0
  192. package/src/drivers/vault-aws-secrets-manager.ts +333 -0
  193. package/src/drivers/vault-builtin.test.ts +110 -0
  194. package/src/drivers/vault-builtin.ts +184 -0
  195. package/src/drivers/vault-driver-removal.test.ts +13 -0
  196. package/src/drivers/vault-managed.test.ts +95 -0
  197. package/src/drivers/vault-managed.ts +101 -25
  198. package/src/drivers/vault-types.ts +25 -5
  199. package/src/elements/ai/runtime.ts +1 -1
  200. package/src/elements/clock/chaos.test.ts +4 -1
  201. package/src/elements/clock/durable.ts +57 -4
  202. package/src/elements/clock.test.ts +13 -14
  203. package/src/elements/gate/constants.ts +18 -0
  204. package/src/elements/gate.test.ts +1 -1
  205. package/src/elements/gate.ts +2 -2
  206. package/src/elements/store/domain-ddl.test.ts +5 -12
  207. package/src/elements/store/emit-drizzle.ts +44 -19
  208. package/src/elements/store/index-boot.test.ts +15 -116
  209. package/src/elements/store/load-plugin-tables.ts +1 -1
  210. package/src/elements/store/resource-list-docs.fixture.ts +12 -6
  211. package/src/elements/store/resource-list-docs.test.ts +64 -44
  212. package/src/elements/store/resource.test.ts +17 -10
  213. package/src/elements/store/runtime.ts +9 -12
  214. package/src/elements/store/schema-decl.test.ts +16 -32
  215. package/src/elements/store/seed.test.ts +1 -2
  216. package/src/elements/store/seed.ts +7 -8
  217. package/src/elements/store/sql-condition.test.ts +2 -2
  218. package/src/elements/store/sql-session.test.ts +8 -10
  219. package/src/elements/store/sql-session.ts +10 -2
  220. package/src/elements/store.test.ts +13 -13
  221. package/src/elements/vault/audit.ts +233 -0
  222. package/src/elements/vault/boot-chain.test.ts +78 -0
  223. package/src/elements/vault/boot-chain.ts +43 -39
  224. package/src/elements/vault/builtin-adapter.test.ts +479 -0
  225. package/src/elements/vault/builtin-adapter.ts +1184 -0
  226. package/src/elements/vault/crypto.test.ts +237 -0
  227. package/src/elements/vault/crypto.ts +431 -0
  228. package/src/elements/vault/declare.ts +164 -3
  229. package/src/elements/vault/errors.ts +56 -0
  230. package/src/elements/vault/kms-unseal.test.ts +76 -0
  231. package/src/elements/vault/kms-unseal.ts +181 -0
  232. package/src/elements/vault/path.ts +90 -0
  233. package/src/elements/vault/resilience.test.ts +102 -0
  234. package/src/elements/vault/resilience.ts +107 -0
  235. package/src/elements/vault/runtime.ts +36 -4
  236. package/src/elements/vault/security-checklist.test.ts +130 -0
  237. package/src/elements/vault/storage.ts +448 -0
  238. package/src/elements/vault/types.ts +288 -0
  239. package/src/elements/vault/unseal.ts +150 -0
  240. package/src/elements/vault.test.ts +72 -4
  241. package/src/elements/vault.ts +91 -2
  242. package/src/full.ts +248 -0
  243. package/src/http.ts +41 -0
  244. package/src/i18n/interpolate-simple.ts +37 -0
  245. package/src/i18n/messages.ts +51 -4
  246. package/src/i18n-entry.ts +7 -0
  247. package/src/index.ts +35 -145
  248. package/src/journal-entry.ts +20 -0
  249. package/src/kernel/adopt-barrel-fresh.test.ts +25 -10
  250. package/src/kernel/app.ts +40 -42
  251. package/src/kernel/auto-registry.test.ts +2 -2
  252. package/src/kernel/boot-bind/ai.test.ts +5 -5
  253. package/src/kernel/boot-bind/ai.ts +2 -1
  254. package/src/kernel/boot-bind/channel.test.ts +6 -6
  255. package/src/kernel/boot-bind/channel.ts +3 -10
  256. package/src/kernel/boot-bind/clock.ts +2 -2
  257. package/src/kernel/boot-bind/gate.ts +5 -9
  258. package/src/kernel/boot-bind/honor-config.test.ts +42 -42
  259. package/src/kernel/boot-bind/journal.ts +2 -2
  260. package/src/kernel/boot-bind/store.test.ts +43 -44
  261. package/src/kernel/boot-bind/store.ts +16 -41
  262. package/src/kernel/boot-bind/vault.ts +16 -1
  263. package/src/kernel/boot.test.ts +12 -4
  264. package/src/kernel/boot.ts +31 -19
  265. package/src/kernel/budget-entry.ts +1 -1
  266. package/src/kernel/compensate.test.ts +288 -1
  267. package/src/kernel/compensate.ts +126 -0
  268. package/src/kernel/concurrency.test.ts +10 -9
  269. package/src/kernel/effects-stamping.test.ts +27 -2
  270. package/src/kernel/element-registries.ts +5 -3
  271. package/src/kernel/flow.ts +4 -2
  272. package/src/kernel/fx.test.ts +119 -3
  273. package/src/kernel/fx.ts +215 -40
  274. package/src/kernel/index.ts +14 -0
  275. package/src/kernel/journal.ts +130 -7
  276. package/src/kernel/pipeline.test.ts +20 -6
  277. package/src/kernel/redacted.test.ts +35 -0
  278. package/src/kernel/redacted.ts +24 -2
  279. package/src/kernel/router/create-default.ts +16 -0
  280. package/src/kernel/router/create-edge.ts +18 -0
  281. package/src/kernel/router/create.ts +23 -0
  282. package/src/kernel/router/index.ts +23 -0
  283. package/src/kernel/router/linear.ts +88 -0
  284. package/src/kernel/router/regexp.ts +188 -0
  285. package/src/kernel/router/smart.ts +120 -0
  286. package/src/kernel/router/trie.ts +108 -0
  287. package/src/kernel/router/types.ts +56 -0
  288. package/src/kernel/router.ts +18 -532
  289. package/src/kernel-entry.ts +43 -0
  290. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  291. package/src/manifest/fixtures/skyport.manifest.json +1 -1
  292. package/src/plugins/config-source.test.ts +7 -7
  293. package/src/release/build-lib.ts +58 -0
  294. package/src/release/exports.test.ts +4 -2
  295. package/src/release/exports.ts +30 -4
  296. package/src/release/measure.ts +101 -22
  297. package/src/runs/duckdb.ts +7 -2
  298. package/src/shared/optional-peer.ts +41 -0
  299. package/src/term.test.ts +3 -44
  300. package/src/test/create-test-app.ts +12 -0
  301. package/src/test/provisions.integration.test.ts +1 -1
  302. package/src/test/reset-element-registries.ts +2 -0
  303. package/src/upgrade/codemods.test.ts +7 -20
  304. package/src/upgrade/codemods.ts +93 -60
  305. package/site/content/docs/recipes/openbao.mdx +0 -141
  306. package/src/cli/ask-dev-mode.ts +0 -40
  307. package/src/cli/dev-mode.test.ts +0 -45
  308. package/src/cli/dev-mode.ts +0 -78
  309. package/src/cli/openbao-bootstrap.test.ts +0 -150
  310. package/src/cli/openbao-bootstrap.ts +0 -321
  311. package/src/cli/openbao-restart.integration.test.ts +0 -145
  312. package/src/console/ui/dist/assets/panel-vault-Za1GyJfM.js +0 -1
  313. package/src/console/ui/dist/assets/style-C8MxEWPd.css +0 -3
  314. package/src/docker/recipes/openbao.ts +0 -47
  315. package/src/drivers/libsql.ts +0 -179
  316. package/src/drivers/sqlite.ts +0 -44
  317. package/src/drivers/vault-openbao.test.ts +0 -97
  318. package/src/drivers/vault-openbao.ts +0 -143
@@ -1,179 +0,0 @@
1
- /**
2
- * `libsql` driver — binds `@libsql/client` (optional peer, dynamic import).
3
- *
4
- * Protocol-named: libSQL speaks the sqlite wire dialect plus native ANN
5
- * vectors (`F32_BLOB` + `libsql_vector_idx` + `vector_top_k`). Classic libSQL
6
- * only — never the Turso Rust rewrite (`@tursodatabase/database`).
7
- *
8
- * Serves both the `sql` facet (same `?` placeholder convention as `sqlite`)
9
- * and the `index` facet (native ANN, no JS-side distance math).
10
- *
11
- * Latency note: local file / `:memory:` opens are in-process like sqlite.
12
- */
13
-
14
- import { customType, sqliteTable, text } from "drizzle-orm/sqlite-core";
15
- import type {
16
- IndexHit,
17
- IndexOpenOptions,
18
- SqlConnectOptions,
19
- SqlConnection,
20
- SqlDriver,
21
- SqlRow,
22
- VectorIndexDriver,
23
- VectorIndexStore,
24
- } from "./types.ts";
25
-
26
- /** `@libsql/client` is an optional peer — loaded only when this driver runs. */
27
- type LibsqlModule = typeof import("@libsql/client");
28
-
29
- async function loadLibsql(): Promise<LibsqlModule> {
30
- try {
31
- return await import("@libsql/client");
32
- } catch {
33
- throw new Error(
34
- "libsql driver: install optional peer `@libsql/client` (bun add @libsql/client)",
35
- );
36
- }
37
- }
38
-
39
- /** Bare file paths become `file:` URLs; `:memory:` / scheme URLs pass through. */
40
- function normalizeLibsqlUrl(url: string): string {
41
- if (url === ":memory:" || url.includes("://") || url.startsWith("file:")) return url;
42
- return `file:${url}`;
43
- }
44
-
45
- /**
46
- * Open a libSQL connection implementing {@link SqlConnection}.
47
- *
48
- * @param options - URL (`:memory:` / `file:…` / `libsql://…`) / role
49
- */
50
- export async function connectLibsql(options: SqlConnectOptions = {}): Promise<SqlConnection> {
51
- const role = options.role ?? "primary";
52
- const { createClient } = await loadLibsql();
53
- const client = createClient({ url: normalizeLibsqlUrl(options.url ?? ":memory:") });
54
- return {
55
- driverId: "libsql",
56
- role,
57
- async query(sql, params = []) {
58
- const rs = await client.execute({ sql, args: params as never });
59
- return rs.rows as unknown as SqlRow[];
60
- },
61
- async exec(sql, params = []) {
62
- const rs = await client.execute({ sql, args: params as never });
63
- return { changes: rs.rowsAffected };
64
- },
65
- async close() {
66
- client.close();
67
- },
68
- };
69
- }
70
-
71
- /** Protocol-named libsql sql driver. */
72
- export const libsqlDriver: SqlDriver = {
73
- id: "libsql",
74
- facet: "sql",
75
- connect: connectLibsql,
76
- };
77
-
78
- /** libSQL native vector column: `F32_BLOB(dims)` (float32, validated by the engine). */
79
- const f32Blob = customType<{
80
- data: readonly number[];
81
- driverData: string;
82
- config: { dimensions: number };
83
- }>({
84
- dataType(config) {
85
- return `F32_BLOB(${config?.dimensions ?? 0})`;
86
- },
87
- toDriver(value) {
88
- return JSON.stringify(value);
89
- },
90
- });
91
-
92
- /**
93
- * Open a libSQL-backed index with native ANN.
94
- *
95
- * DDL: `F32_BLOB(dims)` column + `libsql_vector_idx` ANN index (validated
96
- * against `@libsql/client@0.17`). Queries run `vector_top_k` joined back to
97
- * the base table — approximate nearest neighbours, never a full scan. Score
98
- * is cosine similarity (`1 - vector_distance_cos`), matching the memory
99
- * driver's higher-is-better convention.
100
- *
101
- * @param options - Name / dims / shared SQL connection
102
- */
103
- export async function openLibsqlIndex(options: IndexOpenOptions): Promise<VectorIndexStore> {
104
- const ownsSql = !options.sql;
105
- const sql = options.sql ?? (await connectLibsql({ url: options.url }));
106
- if (sql.driverId !== "libsql") {
107
- if (ownsSql) await sql.close();
108
- throw new Error(
109
- `libsql index: needs a libsql SQL connection, got "${sql.driverId}" — ` +
110
- `set store.sql to "libsql" so the index shares its connection`,
111
- );
112
- }
113
-
114
- const tableName = `oke_idx_${options.name.replace(/[^a-zA-Z0-9_]/g, "_")}`;
115
- const indexName = `${tableName}_vec`;
116
- const table = sqliteTable(tableName, {
117
- id: text("id").primaryKey(),
118
- embedding: f32Blob("embedding", { dimensions: options.dims }).notNull(),
119
- meta: text("meta"),
120
- });
121
-
122
- await sql.exec(
123
- `CREATE TABLE IF NOT EXISTS "${tableName}" (id TEXT PRIMARY KEY, embedding ${table.embedding.getSQLType()} NOT NULL, meta TEXT)`,
124
- );
125
- // ANN index — fails loud on engines without vector support (never falls back).
126
- await sql.exec(
127
- `CREATE INDEX IF NOT EXISTS "${indexName}" ON "${tableName}" (libsql_vector_idx(embedding))`,
128
- );
129
-
130
- return {
131
- driverId: "libsql",
132
- async upsert(id, vector, meta) {
133
- if (vector.length !== options.dims) {
134
- throw new Error(`vector dims ${vector.length} !== index dims ${options.dims}`);
135
- }
136
- await sql.exec(
137
- `INSERT INTO "${tableName}" (id, embedding, meta) VALUES (?, vector32(?), ?) ` +
138
- `ON CONFLICT (id) DO UPDATE SET embedding = excluded.embedding, meta = excluded.meta`,
139
- [id, JSON.stringify(vector), meta ? JSON.stringify(meta) : null],
140
- );
141
- },
142
- async search(vector, topK = 10): Promise<IndexHit[]> {
143
- const k = Math.max(1, Math.floor(topK));
144
- const rows = await sql.query(
145
- `SELECT t.id AS id, t.meta AS meta, ` +
146
- `vector_distance_cos(t.embedding, vector32(?)) AS distance ` +
147
- `FROM vector_top_k('${indexName}', vector32(?), ${k}) AS i ` +
148
- `JOIN "${tableName}" AS t ON t.rowid = i.id ` +
149
- `ORDER BY distance ASC`,
150
- [JSON.stringify(vector), JSON.stringify(vector)],
151
- );
152
- return rows.map((row) => {
153
- const metaRaw = row.meta;
154
- return {
155
- id: String(row.id),
156
- score: 1 - Number(row.distance),
157
- meta:
158
- typeof metaRaw === "string"
159
- ? (JSON.parse(metaRaw) as Record<string, unknown>)
160
- : undefined,
161
- };
162
- });
163
- },
164
- async delete(id) {
165
- const result = await sql.exec(`DELETE FROM "${tableName}" WHERE id = ?`, [id]);
166
- return result.changes > 0;
167
- },
168
- async close() {
169
- if (ownsSql) await sql.close();
170
- },
171
- };
172
- }
173
-
174
- /** Protocol-named libsql index driver. */
175
- export const libsqlIndexDriver: VectorIndexDriver = {
176
- id: "libsql",
177
- facet: "index",
178
- open: openLibsqlIndex,
179
- };
@@ -1,44 +0,0 @@
1
- /**
2
- * `sqlite` driver — binds `bun:sqlite` (never better-sqlite3).
3
- */
4
-
5
- import { Database, type SQLQueryBindings } from "bun:sqlite";
6
- import type { SqlConnectOptions, SqlConnection, SqlDriver, SqlRow } from "./types.ts";
7
-
8
- /**
9
- * Open a bun:sqlite connection implementing {@link SqlConnection}.
10
- *
11
- * @param options - URL (`:memory:` / path) or injected Database
12
- */
13
- export async function connectSqlite(options: SqlConnectOptions = {}): Promise<SqlConnection> {
14
- const role = options.role ?? "primary";
15
- const db =
16
- options.client instanceof Database ? options.client : new Database(options.url ?? ":memory:");
17
-
18
- function asBindings(params: readonly unknown[]): SQLQueryBindings[] {
19
- return params as SQLQueryBindings[];
20
- }
21
-
22
- return {
23
- driverId: "sqlite",
24
- role,
25
- async query(sql, params = []) {
26
- const stmt = db.query(sql);
27
- return stmt.all(...(asBindings(params) as never[])) as SqlRow[];
28
- },
29
- async exec(sql, params = []) {
30
- const result = db.run(sql, ...(asBindings(params) as never[]));
31
- return { changes: result.changes };
32
- },
33
- async close() {
34
- db.close();
35
- },
36
- };
37
- }
38
-
39
- /** Protocol-named sqlite driver. */
40
- export const sqliteDriver: SqlDriver = {
41
- id: "sqlite",
42
- facet: "sql",
43
- connect: connectSqlite,
44
- };
@@ -1,97 +0,0 @@
1
- /**
2
- * OpenBao vault driver — KV v2 read + write/delete + fail-loud semantics.
3
- */
4
-
5
- import { describe, expect, test } from "bun:test";
6
- import { OpenBaoUnavailableError, openbaoVaultDriver } from "./vault-openbao.ts";
7
-
8
- /** Scripted fetch: LIST + per-key GET, then capture writes/deletes. */
9
- function fakeKv(
10
- seed: Record<string, string>,
11
- calls: { method: string; path: string; body?: string }[],
12
- ) {
13
- return (async (input: string | URL | Request, init?: RequestInit) => {
14
- const url = new URL(String(input));
15
- const method = init?.method ?? "GET";
16
- calls.push({
17
- method,
18
- path: url.pathname + url.search,
19
- body: typeof init?.body === "string" ? init.body : undefined,
20
- });
21
- const mount = "/v1/secret";
22
- if (method === "GET" && url.pathname === `${mount}/metadata`) {
23
- return Response.json({ data: { keys: Object.keys(seed) } });
24
- }
25
- if (method === "GET" && url.pathname.startsWith(`${mount}/data/`)) {
26
- const name = decodeURIComponent(url.pathname.slice(`${mount}/data/`.length));
27
- if (!(name in seed)) return new Response("{}", { status: 404 });
28
- return Response.json({ data: { data: { value: seed[name] } } });
29
- }
30
- if (method === "POST" && url.pathname.startsWith(`${mount}/data/`)) {
31
- return new Response(null, { status: 204 });
32
- }
33
- if (method === "DELETE" && url.pathname.startsWith(`${mount}/data/`)) {
34
- return new Response(null, { status: 204 });
35
- }
36
- return new Response("{}", { status: 404 });
37
- }) as typeof globalThis.fetch;
38
- }
39
-
40
- describe("openbao vault driver", () => {
41
- test("LIST + GET loads all keys", async () => {
42
- const calls: { method: string; path: string; body?: string }[] = [];
43
- const bag = await openbaoVaultDriver.open({
44
- url: "http://127.0.0.1:8200",
45
- token: "app-tok",
46
- fetch: fakeKv({ STRIPE_KEY: "sk_live", DATABASE_URL: "postgres://x" }, calls),
47
- });
48
- expect(bag.get("STRIPE_KEY")).toBe("sk_live");
49
- expect([...bag.names()].sort()).toEqual(["DATABASE_URL", "STRIPE_KEY"]);
50
- });
51
-
52
- test("set POSTs KV v2 data payload", async () => {
53
- const calls: { method: string; path: string; body?: string }[] = [];
54
- const bag = await openbaoVaultDriver.open({
55
- url: "http://127.0.0.1:8200",
56
- token: "app-tok",
57
- fetch: fakeKv({ STRIPE_KEY: "sk_live" }, calls),
58
- });
59
- bag.set?.("STRIPE_KEY", "sk_rotated");
60
- await Bun.sleep(0);
61
- const writeCall = calls.find((c) => c.method === "POST");
62
- expect(writeCall?.path).toBe("/v1/secret/data/STRIPE_KEY");
63
- expect(writeCall?.body).toBe(JSON.stringify({ data: { value: "sk_rotated" } }));
64
- expect(bag.get("STRIPE_KEY")).toBe("sk_rotated");
65
- });
66
-
67
- test("unreachable remote fails loud (no soft-empty bag)", async () => {
68
- let failed: unknown;
69
- try {
70
- await openbaoVaultDriver.open({
71
- url: "http://127.0.0.1:9",
72
- token: "app-tok",
73
- fetch: (async () => {
74
- throw new Error("connect ECONNREFUSED");
75
- }) as unknown as typeof globalThis.fetch,
76
- });
77
- } catch (err) {
78
- failed = err;
79
- }
80
- expect(failed).toBeInstanceOf(OpenBaoUnavailableError);
81
- });
82
-
83
- test("sealed / 5xx on GET fails loud", async () => {
84
- const fetchFn = (async (input: string | URL | Request) => {
85
- const url = String(input);
86
- if (url.includes("metadata")) return Response.json({ data: { keys: ["STRIPE_KEY"] } });
87
- return new Response("sealed", { status: 503 });
88
- }) as typeof globalThis.fetch;
89
- let failed: unknown;
90
- try {
91
- await openbaoVaultDriver.open({ url: "http://127.0.0.1:8200", token: "t", fetch: fetchFn });
92
- } catch (err) {
93
- failed = err;
94
- }
95
- expect(failed).toBeInstanceOf(OpenBaoUnavailableError);
96
- });
97
- });
@@ -1,143 +0,0 @@
1
- /**
2
- * `openbao` vault driver — OpenBao (Vault-compatible) KV v2 HTTP API.
3
- *
4
- * Protocol-named; image/vendor choice lives in `images`.
5
- */
6
-
7
- import type { VaultBag, VaultDriver, VaultOpenOptions } from "./vault-types.ts";
8
-
9
- /** Error thrown when the remote OpenBao is unreachable / sealed / errors. */
10
- export class OpenBaoUnavailableError extends Error {
11
- constructor(message: string) {
12
- super(message);
13
- this.name = "OpenBaoUnavailableError";
14
- }
15
- }
16
-
17
- /**
18
- * OpenBao KV-v2 bag. Reads are loaded at open when `url` + `token` resolve;
19
- * writes (`set` / `delete`) hit the HTTP API directly.
20
- *
21
- * When `url` and `token` are provided, an unreachable, sealed, or erroring
22
- * OpenBao is **fatal** (fail-loud) — the bag never silently degrades to an
23
- * empty / seed-only view.
24
- *
25
- * For boot validation the runtime passes declared names; this driver loads
26
- * all keys under `mount` when the LIST API is available, else falls back to
27
- * GETs for the seed names.
28
- */
29
- export const openbaoVaultDriver: VaultDriver = {
30
- id: "openbao",
31
- async open(options: VaultOpenOptions = {}): Promise<VaultBag> {
32
- const url = options.url?.replace(/\/$/, "");
33
- const token = options.token;
34
- const mount = options.mount ?? "secret";
35
- const fetchFn = options.fetch ?? globalThis.fetch;
36
- const map = new Map<string, string>(
37
- Object.entries(options.secrets ?? {}).filter(
38
- (e): e is [string, string] => typeof e[1] === "string",
39
- ),
40
- );
41
-
42
- const remote = url !== undefined && token !== undefined;
43
- let mutableRemote = false;
44
-
45
- if (remote && url !== undefined && token !== undefined) {
46
- const headers = { "X-Vault-Token": token };
47
- const base = `${url}/v1/${mount}`;
48
-
49
- async function listNames(): Promise<string[]> {
50
- const res = await fetchFn(`${base}/metadata?list=true`, { headers });
51
- if (!res.ok) return [];
52
- const body = (await res.json()) as { data?: { keys?: string[] } };
53
- return (body.data?.keys ?? []).map((k) => k.replace(/\/$/, ""));
54
- }
55
-
56
- async function readName(name: string): Promise<boolean> {
57
- const res = await fetchFn(`${base}/data/${encodeURIComponent(name)}`, { headers });
58
- if (res.status === 404) return false;
59
- if (!res.ok) {
60
- throw new OpenBaoUnavailableError(
61
- `openbao vault: GET ${name} failed (${res.status}) — sealed or unauthorized?`,
62
- );
63
- }
64
- const body = (await res.json()) as { data?: { data?: Record<string, unknown> } };
65
- const data = body.data?.data ?? {};
66
- const value =
67
- typeof data.value === "string"
68
- ? data.value
69
- : typeof data[name] === "string"
70
- ? (data[name] as string)
71
- : JSON.stringify(data);
72
- map.set(name, value);
73
- return true;
74
- }
75
-
76
- // LIST when the token has metadata list; otherwise only fetch the
77
- // seed/declared names so a least-privilege token still works. A
78
- // connection-level failure here must never degrade to an empty bag.
79
- let names: string[] = [];
80
- try {
81
- names = await listNames();
82
- } catch (err) {
83
- if (map.size === 0) {
84
- throw new OpenBaoUnavailableError(
85
- `openbao vault: unreachable at ${url} — ${err instanceof Error ? err.message : String(err)}`,
86
- );
87
- }
88
- // Fall through: LIST denied but we still have declared names to GET.
89
- }
90
- if (names.length > 0) {
91
- for (const key of names) await readName(key);
92
- mutableRemote = true;
93
- } else if (map.size > 0) {
94
- for (const name of map.keys()) await readName(name);
95
- mutableRemote = true;
96
- }
97
- }
98
-
99
- return {
100
- driverId: "openbao",
101
- get(name) {
102
- return map.get(name);
103
- },
104
- names() {
105
- return [...map.keys()];
106
- },
107
- ...(mutableRemote && url !== undefined && token !== undefined
108
- ? {
109
- set(name: string, value: string) {
110
- void (async () => {
111
- const res = await fetchFn(`${url}/v1/${mount}/data/${encodeURIComponent(name)}`, {
112
- method: "POST",
113
- headers: { "X-Vault-Token": token, "content-type": "application/json" },
114
- body: JSON.stringify({ data: { value } }),
115
- });
116
- if (!res.ok) {
117
- throw new OpenBaoUnavailableError(
118
- `openbao vault: write ${name} failed (${res.status})`,
119
- );
120
- }
121
- map.set(name, value);
122
- })();
123
- },
124
- delete(name: string) {
125
- const had = map.delete(name);
126
- void (async () => {
127
- const res = await fetchFn(`${url}/v1/${mount}/data/${encodeURIComponent(name)}`, {
128
- method: "DELETE",
129
- headers: { "X-Vault-Token": token },
130
- });
131
- if (!res.ok && res.status !== 404) {
132
- throw new OpenBaoUnavailableError(
133
- `openbao vault: delete ${name} failed (${res.status})`,
134
- );
135
- }
136
- })();
137
- return had;
138
- },
139
- }
140
- : {}),
141
- };
142
- },
143
- };