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.
- package/package.json +76 -10
- package/site/content/docs/deployment/docker-swarm.mdx +48 -111
- package/site/content/docs/deployment/docker.mdx +43 -36
- package/site/content/docs/deployment/index.mdx +9 -9
- package/site/content/docs/deployment/kubernetes.mdx +4 -4
- package/site/content/docs/elements/ai.mdx +7 -7
- package/site/content/docs/elements/channel.mdx +9 -7
- package/site/content/docs/elements/clock.mdx +8 -8
- package/site/content/docs/elements/flow.mdx +46 -47
- package/site/content/docs/elements/gate.mdx +6 -5
- package/site/content/docs/elements/signal.mdx +2 -2
- package/site/content/docs/elements/store.mdx +71 -78
- package/site/content/docs/elements/vault.mdx +89 -70
- package/site/content/docs/get-started/basic-usage.mdx +8 -8
- package/site/content/docs/get-started/installation.mdx +36 -36
- package/site/content/docs/get-started/introduction.mdx +11 -0
- package/site/content/docs/get-started/why.mdx +2 -2
- package/site/content/docs/plugins/anonymous.mdx +1 -1
- package/site/content/docs/plugins/magic-link.mdx +11 -11
- package/site/content/docs/plugins/otp.mdx +2 -2
- package/site/content/docs/plugins/passkey.mdx +1 -1
- package/site/content/docs/plugins/two-factor.mdx +1 -1
- package/site/content/docs/plugins/username.mdx +1 -1
- package/site/content/docs/recipes/caddy.mdx +1 -1
- package/site/content/docs/recipes/cockroachdb.mdx +2 -2
- package/site/content/docs/recipes/dragonfly.mdx +1 -1
- package/site/content/docs/recipes/index.mdx +1 -2
- package/site/content/docs/recipes/llama-cpp.mdx +21 -23
- package/site/content/docs/recipes/mailpit.mdx +11 -11
- package/site/content/docs/recipes/meilisearch.mdx +10 -10
- package/site/content/docs/recipes/meta.json +0 -1
- package/site/content/docs/recipes/ollama.mdx +1 -1
- package/site/content/docs/recipes/pgdog.mdx +12 -9
- package/site/content/docs/recipes/postgres.mdx +3 -3
- package/site/content/docs/recipes/redis.mdx +2 -2
- package/site/content/docs/recipes/rustfs.mdx +10 -7
- package/site/content/docs/recipes/sglang.mdx +1 -1
- package/site/content/docs/recipes/supabase-docker.mdx +1 -1
- package/site/content/docs/recipes/timescale.mdx +2 -2
- package/site/content/docs/recipes/valkey.mdx +1 -1
- package/site/content/docs/recipes/vllm.mdx +1 -1
- package/site/content/docs/recipes/yugabytedb.mdx +2 -2
- package/site/content/docs/reference/cli.md +61 -38
- package/site/content/docs/reference/configuration.mdx +145 -70
- package/site/content/docs/reference/environment-variables.mdx +36 -28
- package/site/content/docs/reference/errors.mdx +28 -29
- package/site/content/docs/reference/fx.mdx +11 -4
- package/site/content/docs/reference/i18n.mdx +17 -6
- package/site/content/docs/reference/index.mdx +5 -0
- package/site/content/docs/reference/meta.json +1 -0
- package/site/content/docs/reference/migrating-environments.mdx +158 -0
- package/site/content/docs/reference/plugins.mdx +2 -2
- package/src/auth/gate-auth.test.ts +12 -10
- package/src/cli/ai-setup/ai-setup.test.ts +27 -15
- package/src/cli/ai-setup/apply.ts +111 -15
- package/src/cli/ai-setup/catalog.ts +3 -3
- package/src/cli/ai-setup/index.ts +1 -1
- package/src/cli/ai-setup/prompts.ts +1 -1
- package/src/cli/ai-setup/recommend.test.ts +1 -1
- package/src/cli/ask-seed.test.ts +3 -3
- package/src/cli/build.ts +1 -1
- package/src/cli/db-auto-push.test.ts +6 -3
- package/src/cli/db-auto-push.ts +7 -5
- package/src/cli/db-seed.ts +7 -8
- package/src/cli/db.test.ts +70 -71
- package/src/cli/db.ts +86 -12
- package/src/cli/dev-controller.test.ts +35 -0
- package/src/cli/dev-controller.ts +298 -0
- package/src/cli/dev-controls.ts +11 -65
- package/src/cli/dev-db-push.test.ts +47 -15
- package/src/cli/dev-schema-sync.test.ts +11 -11
- package/src/cli/dev-schema-sync.ts +10 -10
- package/src/cli/dev-session-lock.test.ts +106 -0
- package/src/cli/dev-session-lock.ts +209 -0
- package/src/cli/dev.test.ts +166 -121
- package/src/cli/dev.ts +138 -192
- package/src/cli/doc-staleness.test.ts +3 -6
- package/src/cli/docker-clean.test.ts +33 -1
- package/src/cli/docker-clean.ts +28 -33
- package/src/cli/docker-cli.test.ts +12 -11
- package/src/cli/docker.ts +95 -20
- package/src/cli/doctor.test.ts +40 -0
- package/src/cli/doctor.ts +55 -15
- package/src/cli/drizzle-env.test.ts +11 -13
- package/src/cli/drizzle-env.ts +18 -11
- package/src/cli/ensure-drizzle-config.ts +11 -14
- package/src/cli/hero-meta.test.ts +15 -15
- package/src/cli/hero-meta.ts +10 -9
- package/src/cli/index.ts +36 -6
- package/src/cli/load-config.images.test.ts +16 -12
- package/src/cli/load-config.source.test.ts +50 -0
- package/src/cli/load-config.ts +34 -28
- package/src/cli/meilisearch-local.ts +1 -2
- package/src/cli/mode.ts +7 -58
- package/src/cli/registry.ts +175 -19
- package/src/cli/resolve-dev-sql-env.test.ts +8 -16
- package/src/cli/resolve-dev-sql-env.ts +13 -15
- package/src/cli/safe-defaults.test.ts +28 -10
- package/src/cli/schema.ts +65 -16
- package/src/cli/test.ts +58 -0
- package/src/cli/tui/App.tsx +252 -0
- package/src/cli/tui/DevLive.tsx +116 -0
- package/src/cli/tui/components/ConfirmDialog.tsx +48 -0
- package/src/cli/tui/components/HeaderBar.tsx +67 -0
- package/src/cli/tui/components/LogStream.tsx +47 -0
- package/src/cli/tui/components/PanelCard.tsx +39 -0
- package/src/cli/tui/components/SelectRow.tsx +37 -0
- package/src/cli/tui/components/SlashPalette.tsx +172 -0
- package/src/cli/tui/components/Spinner.tsx +32 -0
- package/src/cli/tui/components/StatusBar.tsx +51 -0
- package/src/cli/tui/components/StatusDot.tsx +37 -0
- package/src/cli/tui/components/TabBar.tsx +49 -0
- package/src/cli/tui/components/Wordmark.tsx +43 -0
- package/src/cli/tui/format.ts +38 -0
- package/src/cli/tui/keys.test.ts +18 -0
- package/src/cli/tui/keys.ts +26 -0
- package/src/cli/tui/launch.test.ts +18 -0
- package/src/cli/tui/launch.ts +57 -0
- package/src/cli/tui/panels/Dashboard.tsx +201 -0
- package/src/cli/tui/panels/Database.tsx +198 -0
- package/src/cli/tui/panels/Dev.tsx +257 -0
- package/src/cli/tui/panels/Docker.tsx +357 -0
- package/src/cli/tui/panels/Navigator.test.ts +22 -0
- package/src/cli/tui/panels/Navigator.tsx +213 -0
- package/src/cli/tui/slash-catalog.test.ts +31 -0
- package/src/cli/tui/slash-catalog.ts +184 -0
- package/src/cli/tui/slash-run.ts +54 -0
- package/src/cli/tui/state/ports.ts +95 -0
- package/src/cli/tui/theme.ts +24 -0
- package/src/cli/vault-cmd.test.ts +402 -0
- package/src/cli/vault-cmd.ts +727 -69
- package/src/cli/vault-secure-input.test.ts +56 -0
- package/src/cli/vault-secure-input.ts +124 -0
- package/src/compiler/effects-infer.ts +7 -0
- package/src/compiler/fixtures/skyport/oke.config.ts +3 -3
- package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -1
- package/src/compiler/fixtures/skyport.expected.json +1 -1
- package/src/compiler-entry.ts +7 -0
- package/src/config/define-config.test.ts +111 -47
- package/src/config/driver-defaults.test.ts +16 -23
- package/src/config/driver-defaults.ts +33 -63
- package/src/config/index.ts +169 -144
- package/src/config/resolve-driver.test.ts +14 -19
- package/src/console/server/app.ts +4 -2
- package/src/console/server/console.test.ts +58 -1
- package/src/console/server/flows.ts +22 -2
- package/src/console/server/index.ts +3 -0
- package/src/console/server/operator-db.test.ts +55 -13
- package/src/console/server/operator-db.ts +305 -263
- package/src/console/server/serve.ts +16 -7
- package/src/console/server/state.ts +31 -9
- package/src/console/server/vault.test.ts +120 -5
- package/src/console/server/vault.ts +208 -12
- package/src/console/ui/dist/assets/{index-D-9KFce5.js → index--Y0Uaz-m.js} +2 -2
- package/src/console/ui/dist/assets/panel-vault-BkZdJPX8.js +1 -0
- package/src/console/ui/dist/assets/style-C3L349iZ.css +3 -0
- package/src/console/ui/dist/index.html +2 -2
- package/src/console/ui/shell/client.ts +16 -0
- package/src/console/ui/shell/panels/vault/VaultPanel.tsx +54 -1
- package/src/console/ui/vault/VaultA11yView.tsx +33 -1
- package/src/console/ui/vault/backend.test.ts +75 -0
- package/src/console/ui/vault/backend.ts +117 -0
- package/src/console/ui/vault/fixture.ts +21 -2
- package/src/console/ui/vault/index.ts +11 -1
- package/src/console/ui/vault/types.ts +26 -0
- package/src/docker/compose.ts +164 -61
- package/src/docker/derive.ts +106 -12
- package/src/docker/docker.test.ts +156 -110
- package/src/docker/helpers.ts +98 -0
- package/src/docker/images-config.test.ts +3 -8
- package/src/docker/index.ts +30 -5
- package/src/docker/recipes/index.ts +0 -3
- package/src/docker/recipes/llama-cpp.ts +4 -4
- package/src/docker/recipes/pgdog.ts +9 -2
- package/src/docker/resources.test.ts +71 -0
- package/src/docker/resources.ts +176 -0
- package/src/docker/stack-id.test.ts +11 -4
- package/src/docker/stack-id.ts +42 -32
- package/src/docker/stack.integration.test.ts +4 -15
- package/src/docker/types.ts +35 -3
- package/src/drivers/ai-ollama.integration.test.ts +2 -2
- package/src/drivers/conformance.test.ts +11 -12
- package/src/drivers/drizzle-dialect.test.ts +0 -4
- package/src/drivers/drizzle-dialect.ts +7 -13
- package/src/drivers/index.ts +24 -7
- package/src/drivers/journal-postgres.test.ts +3 -1
- package/src/drivers/journal-postgres.ts +4 -2
- package/src/drivers/meilisearch.ts +1 -1
- package/src/drivers/pglite.ts +28 -5
- package/src/drivers/types.ts +9 -11
- package/src/drivers/vault-aws-secrets-manager.test.ts +159 -0
- package/src/drivers/vault-aws-secrets-manager.ts +333 -0
- package/src/drivers/vault-builtin.test.ts +110 -0
- package/src/drivers/vault-builtin.ts +184 -0
- package/src/drivers/vault-driver-removal.test.ts +13 -0
- package/src/drivers/vault-managed.test.ts +95 -0
- package/src/drivers/vault-managed.ts +101 -25
- package/src/drivers/vault-types.ts +25 -5
- package/src/elements/ai/runtime.ts +1 -1
- package/src/elements/clock/chaos.test.ts +4 -1
- package/src/elements/clock/durable.ts +57 -4
- package/src/elements/clock.test.ts +13 -14
- package/src/elements/gate/constants.ts +18 -0
- package/src/elements/gate.test.ts +1 -1
- package/src/elements/gate.ts +2 -2
- package/src/elements/store/domain-ddl.test.ts +5 -12
- package/src/elements/store/emit-drizzle.ts +44 -19
- package/src/elements/store/index-boot.test.ts +15 -116
- package/src/elements/store/load-plugin-tables.ts +1 -1
- package/src/elements/store/resource-list-docs.fixture.ts +12 -6
- package/src/elements/store/resource-list-docs.test.ts +64 -44
- package/src/elements/store/resource.test.ts +17 -10
- package/src/elements/store/runtime.ts +9 -12
- package/src/elements/store/schema-decl.test.ts +16 -32
- package/src/elements/store/seed.test.ts +1 -2
- package/src/elements/store/seed.ts +7 -8
- package/src/elements/store/sql-condition.test.ts +2 -2
- package/src/elements/store/sql-session.test.ts +8 -10
- package/src/elements/store/sql-session.ts +10 -2
- package/src/elements/store.test.ts +13 -13
- package/src/elements/vault/audit.ts +233 -0
- package/src/elements/vault/boot-chain.test.ts +78 -0
- package/src/elements/vault/boot-chain.ts +43 -39
- package/src/elements/vault/builtin-adapter.test.ts +479 -0
- package/src/elements/vault/builtin-adapter.ts +1184 -0
- package/src/elements/vault/crypto.test.ts +237 -0
- package/src/elements/vault/crypto.ts +431 -0
- package/src/elements/vault/declare.ts +164 -3
- package/src/elements/vault/errors.ts +56 -0
- package/src/elements/vault/kms-unseal.test.ts +76 -0
- package/src/elements/vault/kms-unseal.ts +181 -0
- package/src/elements/vault/path.ts +90 -0
- package/src/elements/vault/resilience.test.ts +102 -0
- package/src/elements/vault/resilience.ts +107 -0
- package/src/elements/vault/runtime.ts +36 -4
- package/src/elements/vault/security-checklist.test.ts +130 -0
- package/src/elements/vault/storage.ts +448 -0
- package/src/elements/vault/types.ts +288 -0
- package/src/elements/vault/unseal.ts +150 -0
- package/src/elements/vault.test.ts +72 -4
- package/src/elements/vault.ts +91 -2
- package/src/full.ts +248 -0
- package/src/http.ts +41 -0
- package/src/i18n/interpolate-simple.ts +37 -0
- package/src/i18n/messages.ts +51 -4
- package/src/i18n-entry.ts +7 -0
- package/src/index.ts +35 -145
- package/src/journal-entry.ts +20 -0
- package/src/kernel/adopt-barrel-fresh.test.ts +25 -10
- package/src/kernel/app.ts +40 -42
- package/src/kernel/auto-registry.test.ts +2 -2
- package/src/kernel/boot-bind/ai.test.ts +5 -5
- package/src/kernel/boot-bind/ai.ts +2 -1
- package/src/kernel/boot-bind/channel.test.ts +6 -6
- package/src/kernel/boot-bind/channel.ts +3 -10
- package/src/kernel/boot-bind/clock.ts +2 -2
- package/src/kernel/boot-bind/gate.ts +5 -9
- package/src/kernel/boot-bind/honor-config.test.ts +42 -42
- package/src/kernel/boot-bind/journal.ts +2 -2
- package/src/kernel/boot-bind/store.test.ts +43 -44
- package/src/kernel/boot-bind/store.ts +16 -41
- package/src/kernel/boot-bind/vault.ts +16 -1
- package/src/kernel/boot.test.ts +12 -4
- package/src/kernel/boot.ts +31 -19
- package/src/kernel/budget-entry.ts +1 -1
- package/src/kernel/compensate.test.ts +288 -1
- package/src/kernel/compensate.ts +126 -0
- package/src/kernel/concurrency.test.ts +10 -9
- package/src/kernel/effects-stamping.test.ts +27 -2
- package/src/kernel/element-registries.ts +5 -3
- package/src/kernel/flow.ts +4 -2
- package/src/kernel/fx.test.ts +119 -3
- package/src/kernel/fx.ts +215 -40
- package/src/kernel/index.ts +14 -0
- package/src/kernel/journal.ts +130 -7
- package/src/kernel/pipeline.test.ts +20 -6
- package/src/kernel/redacted.test.ts +35 -0
- package/src/kernel/redacted.ts +24 -2
- package/src/kernel/router/create-default.ts +16 -0
- package/src/kernel/router/create-edge.ts +18 -0
- package/src/kernel/router/create.ts +23 -0
- package/src/kernel/router/index.ts +23 -0
- package/src/kernel/router/linear.ts +88 -0
- package/src/kernel/router/regexp.ts +188 -0
- package/src/kernel/router/smart.ts +120 -0
- package/src/kernel/router/trie.ts +108 -0
- package/src/kernel/router/types.ts +56 -0
- package/src/kernel/router.ts +18 -532
- package/src/kernel-entry.ts +43 -0
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/fixtures/skyport.manifest.json +1 -1
- package/src/plugins/config-source.test.ts +7 -7
- package/src/release/build-lib.ts +58 -0
- package/src/release/exports.test.ts +4 -2
- package/src/release/exports.ts +30 -4
- package/src/release/measure.ts +101 -22
- package/src/runs/duckdb.ts +7 -2
- package/src/shared/optional-peer.ts +41 -0
- package/src/term.test.ts +3 -44
- package/src/test/create-test-app.ts +12 -0
- package/src/test/provisions.integration.test.ts +1 -1
- package/src/test/reset-element-registries.ts +2 -0
- package/src/upgrade/codemods.test.ts +7 -20
- package/src/upgrade/codemods.ts +93 -60
- package/site/content/docs/recipes/openbao.mdx +0 -141
- package/src/cli/ask-dev-mode.ts +0 -40
- package/src/cli/dev-mode.test.ts +0 -45
- package/src/cli/dev-mode.ts +0 -78
- package/src/cli/openbao-bootstrap.test.ts +0 -150
- package/src/cli/openbao-bootstrap.ts +0 -321
- package/src/cli/openbao-restart.integration.test.ts +0 -145
- package/src/console/ui/dist/assets/panel-vault-Za1GyJfM.js +0 -1
- package/src/console/ui/dist/assets/style-C8MxEWPd.css +0 -3
- package/src/docker/recipes/openbao.ts +0 -47
- package/src/drivers/libsql.ts +0 -179
- package/src/drivers/sqlite.ts +0 -44
- package/src/drivers/vault-openbao.test.ts +0 -97
- package/src/drivers/vault-openbao.ts +0 -143
|
@@ -24,18 +24,24 @@ import {
|
|
|
24
24
|
type SchemaTableDecl,
|
|
25
25
|
} from "./schema-decl.ts";
|
|
26
26
|
|
|
27
|
-
/** Supported Drizzle dialects for domain schema emit. */
|
|
28
|
-
export type SqlDialect = "
|
|
27
|
+
/** Supported Drizzle dialects for domain schema emit (Postgres-family only). */
|
|
28
|
+
export type SqlDialect = "postgres";
|
|
29
29
|
|
|
30
30
|
/** Header written at the top of generated files. */
|
|
31
31
|
export const GENERATED_SCHEMA_HEADER = "// generated by oke — do not edit";
|
|
32
32
|
|
|
33
33
|
/** Default output path (relative to project root). */
|
|
34
|
-
export const DEFAULT_GENERATED_SCHEMA_REL = "src/db/schema.
|
|
34
|
+
export const DEFAULT_GENERATED_SCHEMA_REL = "src/db/schema.drizzle.ts";
|
|
35
35
|
|
|
36
36
|
/** Default declaration module path (relative to project root). */
|
|
37
37
|
export const DEFAULT_DECLARE_SCHEMA_REL = "src/db/schema.decl.ts";
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Prior `src/db/` emit filename — still resolved when present and the new
|
|
41
|
+
* default does not exist yet.
|
|
42
|
+
*/
|
|
43
|
+
export const PREV_GENERATED_SCHEMA_REL = "src/db/schema.generated.ts";
|
|
44
|
+
|
|
39
45
|
/** Legacy paths kept so pre-layout projects keep resolving. */
|
|
40
46
|
export const LEGACY_GENERATED_SCHEMA_REL = "src/schema.generated.ts";
|
|
41
47
|
|
|
@@ -45,11 +51,15 @@ export const LEGACY_DECLARE_SCHEMA_REL = "src/schema.decl.ts";
|
|
|
45
51
|
/**
|
|
46
52
|
* Map a store.sql driver id to an emit dialect.
|
|
47
53
|
*
|
|
48
|
-
* @param driverId - Protocol driver id (`
|
|
54
|
+
* @param driverId - Protocol driver id (`postgres` · `pglite` · …)
|
|
49
55
|
*/
|
|
50
56
|
export function dialectFromDriverId(driverId: string | undefined): SqlDialect {
|
|
51
|
-
if (driverId === "postgres"
|
|
52
|
-
|
|
57
|
+
if (driverId === undefined || driverId === "postgres" || driverId === "pglite") {
|
|
58
|
+
return "postgres";
|
|
59
|
+
}
|
|
60
|
+
throw new Error(
|
|
61
|
+
`oke schema emit: store.sql driver "${driverId}" is not supported (postgres | pglite)`,
|
|
62
|
+
);
|
|
53
63
|
}
|
|
54
64
|
|
|
55
65
|
/**
|
|
@@ -58,9 +68,14 @@ export function dialectFromDriverId(driverId: string | undefined): SqlDialect {
|
|
|
58
68
|
* @param col - Column decl
|
|
59
69
|
* @param dialect - Target dialect (affects import names only at file level)
|
|
60
70
|
*/
|
|
61
|
-
export function emitColumnSource(col: SchemaColumnDecl, _dialect: SqlDialect): string {
|
|
62
|
-
|
|
63
|
-
|
|
71
|
+
export function emitColumnSource(col: SchemaColumnDecl, _dialect: SqlDialect = "postgres"): string {
|
|
72
|
+
// Postgres INTEGER is 32-bit; abstract `integer` (often ms clocks) → bigint.
|
|
73
|
+
// drizzle-orm's `bigint()` requires `{ mode }` — omitting it throws on
|
|
74
|
+
// `config.mode` when the generated schema is loaded by drizzle-kit push.
|
|
75
|
+
let expr =
|
|
76
|
+
col.sqlType === "integer"
|
|
77
|
+
? `bigint(${JSON.stringify(col.sqlName)}, { mode: "number" })`
|
|
78
|
+
: `text(${JSON.stringify(col.sqlName)})`;
|
|
64
79
|
if (col.primaryKey) expr += ".primaryKey()";
|
|
65
80
|
else if (col.notNull) expr += ".notNull()";
|
|
66
81
|
if (col.unique) expr += ".unique()";
|
|
@@ -157,19 +172,20 @@ export interface EmitDrizzleSourceOptions {
|
|
|
157
172
|
* Emit a full Drizzle schema module from abstract table decls.
|
|
158
173
|
*
|
|
159
174
|
* @param tables - App + plugin tables (already merged)
|
|
160
|
-
* @param dialect -
|
|
175
|
+
* @param dialect - Always `postgres` (`pgTable`); retained for call-site clarity
|
|
161
176
|
* @param options - Optional relations to emit as `defineRelations`
|
|
162
177
|
*/
|
|
163
178
|
export function emitDrizzleSource(
|
|
164
179
|
tables: readonly SchemaTableDecl[],
|
|
165
|
-
dialect: SqlDialect,
|
|
180
|
+
dialect: SqlDialect = "postgres",
|
|
166
181
|
options: EmitDrizzleSourceOptions = {},
|
|
167
182
|
): string {
|
|
168
|
-
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
183
|
+
void dialect;
|
|
184
|
+
const needsInteger = tables.some((t) =>
|
|
185
|
+
Object.values(t.columns).some((c) => c.sqlType === "integer"),
|
|
186
|
+
);
|
|
187
|
+
const pgIntImport = needsInteger ? "bigint" : null;
|
|
188
|
+
const coreImport = `import { pgTable, text${pgIntImport ? `, ${pgIntImport}` : ""} } from "drizzle-orm/pg-core";`;
|
|
173
189
|
|
|
174
190
|
const needsId = tables.some((t) =>
|
|
175
191
|
Object.values(t.columns).some((c) => c.defaultFnKind === "id"),
|
|
@@ -191,7 +207,7 @@ export function emitDrizzleSource(
|
|
|
191
207
|
const lines = Object.values(table.columns).map(
|
|
192
208
|
(col) => ` ${col.key}: ${emitColumnSource(col, dialect)},`,
|
|
193
209
|
);
|
|
194
|
-
return `export const ${exportNameForTable(table.name)} =
|
|
210
|
+
return `export const ${exportNameForTable(table.name)} = pgTable(${JSON.stringify(table.name)}, {\n${lines.join("\n")}\n});`;
|
|
195
211
|
});
|
|
196
212
|
|
|
197
213
|
const relationsBlock = emitRelationsSource(relations);
|
|
@@ -380,11 +396,20 @@ export function resolveEmitPaths(
|
|
|
380
396
|
|
|
381
397
|
let outRel = db?.generated;
|
|
382
398
|
if (!outRel) {
|
|
383
|
-
const
|
|
399
|
+
const preferSrcLegacy =
|
|
384
400
|
declareRel === LEGACY_DECLARE_SCHEMA_REL ||
|
|
385
401
|
(!existsSync(join(cwd, DEFAULT_DECLARE_SCHEMA_REL)) &&
|
|
386
402
|
existsSync(join(cwd, LEGACY_GENERATED_SCHEMA_REL)));
|
|
387
|
-
|
|
403
|
+
if (preferSrcLegacy) {
|
|
404
|
+
outRel = LEGACY_GENERATED_SCHEMA_REL;
|
|
405
|
+
} else if (
|
|
406
|
+
!existsSync(join(cwd, DEFAULT_GENERATED_SCHEMA_REL)) &&
|
|
407
|
+
existsSync(join(cwd, PREV_GENERATED_SCHEMA_REL))
|
|
408
|
+
) {
|
|
409
|
+
outRel = PREV_GENERATED_SCHEMA_REL;
|
|
410
|
+
} else {
|
|
411
|
+
outRel = DEFAULT_GENERATED_SCHEMA_REL;
|
|
412
|
+
}
|
|
388
413
|
}
|
|
389
414
|
|
|
390
415
|
return {
|
|
@@ -1,43 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* End-to-end `store.index()` boot wiring — the CONFIGURED driver resolves at
|
|
3
|
-
* real boot for every backend (memory /
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* real boot for every backend (memory / pgvector over pglite / pgvector over
|
|
4
|
+
* real Postgres), SQL-backed indexes share store.sql's already-open connection
|
|
5
|
+
* (never a second, redundant one), and search runs through each engine's
|
|
6
|
+
* native ANN index — no JS-side full scan survives.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { afterEach, describe, expect, test } from "bun:test";
|
|
10
|
-
import {
|
|
11
|
-
connectLibsql,
|
|
12
|
-
libsqlDriver,
|
|
13
|
-
libsqlIndexDriver,
|
|
14
|
-
openLibsqlIndex,
|
|
15
|
-
} from "../../drivers/libsql.ts";
|
|
16
10
|
import { connectPglite } from "../../drivers/pglite.ts";
|
|
17
11
|
import { openPgvectorIndex } from "../../drivers/pgvector.ts";
|
|
18
12
|
import { connectPostgres } from "../../drivers/postgres.ts";
|
|
19
|
-
import type { SqlConnection
|
|
13
|
+
import type { SqlConnection } from "../../drivers/types.ts";
|
|
20
14
|
import { bindStore } from "../../kernel/boot-bind/store.ts";
|
|
21
|
-
import {
|
|
22
|
-
createStoreRuntime,
|
|
23
|
-
index as declareIndex,
|
|
24
|
-
sql as declareSql,
|
|
25
|
-
type SqlStoreHandle,
|
|
26
|
-
type VectorIndexStoreFxHandle,
|
|
27
|
-
} from "../store.ts";
|
|
15
|
+
import { index as declareIndex, type VectorIndexStoreFxHandle } from "../store.ts";
|
|
28
16
|
|
|
29
17
|
const WRITE_CTX = (name: string) => ({
|
|
30
18
|
effects: { reads: [`index:${name}` as const], writes: [`index:${name}` as const] },
|
|
31
19
|
});
|
|
32
20
|
|
|
33
21
|
const prev = {
|
|
34
|
-
libsql: process.env.OKE_LIBSQL_URL,
|
|
35
22
|
pglite: process.env.OKE_PGLITE_URL,
|
|
36
23
|
};
|
|
37
24
|
|
|
38
25
|
afterEach(() => {
|
|
39
|
-
if (prev.libsql === undefined) delete process.env.OKE_LIBSQL_URL;
|
|
40
|
-
else process.env.OKE_LIBSQL_URL = prev.libsql;
|
|
41
26
|
if (prev.pglite === undefined) delete process.env.OKE_PGLITE_URL;
|
|
42
27
|
else process.env.OKE_PGLITE_URL = prev.pglite;
|
|
43
28
|
});
|
|
@@ -66,7 +51,7 @@ function recordingConn(conn: SqlConnection): { conn: SqlConnection; statements:
|
|
|
66
51
|
describe("store.index boot wiring — memory", () => {
|
|
67
52
|
test("boot with no configured index driver resolves memory end to end", async () => {
|
|
68
53
|
const kb = declareIndex("kb", { dims: 3 });
|
|
69
|
-
const runtime = bindStore({ stores: [kb] }, "
|
|
54
|
+
const runtime = bindStore({ stores: [kb] }, "test", () => Date.now());
|
|
70
55
|
const handle = (await runtime.open(kb, WRITE_CTX("kb"))) as VectorIndexStoreFxHandle;
|
|
71
56
|
expect(handle.driverId).toBe("memory");
|
|
72
57
|
await handle.upsert("near", [1, 0, 0]);
|
|
@@ -77,88 +62,16 @@ describe("store.index boot wiring — memory", () => {
|
|
|
77
62
|
});
|
|
78
63
|
});
|
|
79
64
|
|
|
80
|
-
describe("store.index boot wiring — libsql", () => {
|
|
81
|
-
test("boot: sql=libsql + index=libsql resolves native ANN end to end", async () => {
|
|
82
|
-
process.env.OKE_LIBSQL_URL = ":memory:";
|
|
83
|
-
const kb = declareIndex("kb", { dims: 3 });
|
|
84
|
-
const runtime = bindStore(
|
|
85
|
-
{
|
|
86
|
-
config: { drivers: { store: { sql: { local: "libsql" }, index: { local: "libsql" } } } },
|
|
87
|
-
stores: [kb],
|
|
88
|
-
},
|
|
89
|
-
"local",
|
|
90
|
-
() => Date.now(),
|
|
91
|
-
);
|
|
92
|
-
const handle = (await runtime.open(kb, WRITE_CTX("kb"))) as VectorIndexStoreFxHandle;
|
|
93
|
-
expect(handle.driverId).toBe("libsql");
|
|
94
|
-
|
|
95
|
-
await handle.upsert("near", [1, 0.1, 0], { label: "near" });
|
|
96
|
-
await handle.upsert("far", [0, 1, 0]);
|
|
97
|
-
await handle.upsert("farther", [-1, 0, 0]);
|
|
98
|
-
const hits = await handle.search([1, 0, 0], 3);
|
|
99
|
-
expect(hits.map((h: { id: string }) => h.id)).toEqual(["near", "far", "farther"]);
|
|
100
|
-
expect(hits[0]!.score).toBeGreaterThan(hits[1]!.score);
|
|
101
|
-
expect(hits[0]!.meta).toEqual({ label: "near" });
|
|
102
|
-
expect(await handle.delete("farther")).toBe(true);
|
|
103
|
-
await runtime.close();
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test("sql and index facets share one already-open libsql connection", async () => {
|
|
107
|
-
let connects = 0;
|
|
108
|
-
const countingLibsql: SqlDriver = {
|
|
109
|
-
...libsqlDriver,
|
|
110
|
-
connect: async (opts) => {
|
|
111
|
-
connects++;
|
|
112
|
-
return libsqlDriver.connect(opts);
|
|
113
|
-
},
|
|
114
|
-
};
|
|
115
|
-
const docs = declareSql("docs");
|
|
116
|
-
const kb = declareIndex("kb", { dims: 3 });
|
|
117
|
-
const runtime = createStoreRuntime({
|
|
118
|
-
drivers: { sql: countingLibsql, index: libsqlIndexDriver },
|
|
119
|
-
sql: { docs: { name: "docs", primary: { url: ":memory:" } } },
|
|
120
|
-
index: { kb: { url: ":memory:" } },
|
|
121
|
-
});
|
|
122
|
-
// Index first: it must open the connection the sql facet then reuses.
|
|
123
|
-
const idxHandle = (await runtime.open(kb, WRITE_CTX("kb"))) as VectorIndexStoreFxHandle;
|
|
124
|
-
await idxHandle.upsert("a", [1, 0, 0]);
|
|
125
|
-
const sqlHandle = (await runtime.open(docs, {
|
|
126
|
-
effects: { reads: ["sql:docs"], writes: ["sql:docs"] },
|
|
127
|
-
})) as SqlStoreHandle;
|
|
128
|
-
await sqlHandle.raw("CREATE TABLE IF NOT EXISTS t_share (id TEXT)", []);
|
|
129
|
-
expect(connects).toBe(1);
|
|
130
|
-
await runtime.close();
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test("libsql index searches through vector_top_k — real ANN, not a scan", async () => {
|
|
134
|
-
const real = await connectLibsql({ url: ":memory:" });
|
|
135
|
-
const { conn, statements } = recordingConn(real);
|
|
136
|
-
const idx = await openLibsqlIndex({ name: "ann", dims: 3, sql: conn });
|
|
137
|
-
await idx.upsert("x", [1, 0, 0]);
|
|
138
|
-
await idx.upsert("y", [0, 1, 0]);
|
|
139
|
-
const hits = await idx.search([1, 0, 0], 1);
|
|
140
|
-
expect(hits[0]?.id).toBe("x");
|
|
141
|
-
expect(statements.some((s) => s.includes("libsql_vector_idx"))).toBe(true);
|
|
142
|
-
expect(statements.some((s) => s.includes("vector_top_k"))).toBe(true);
|
|
143
|
-
const plan = await real.query(
|
|
144
|
-
`EXPLAIN QUERY PLAN SELECT * FROM vector_top_k('oke_idx_ann_vec', vector32('[1,0,0]'), 1)`,
|
|
145
|
-
);
|
|
146
|
-
expect(JSON.stringify(plan)).toContain("vector_top_k");
|
|
147
|
-
await idx.close();
|
|
148
|
-
await real.close();
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
|
|
152
65
|
describe("store.index boot wiring — pglite + pgvector", () => {
|
|
153
66
|
test("boot: sql=pglite + index=pgvector resolves end to end", async () => {
|
|
154
67
|
process.env.OKE_PGLITE_URL = "memory://";
|
|
155
68
|
const kb = declareIndex("kb", { dims: 3 });
|
|
156
69
|
const runtime = bindStore(
|
|
157
70
|
{
|
|
158
|
-
config: { drivers: { store: { sql: {
|
|
71
|
+
config: { drivers: { store: { sql: { test: "pglite" }, index: { test: "pgvector" } } } },
|
|
159
72
|
stores: [kb],
|
|
160
73
|
},
|
|
161
|
-
"
|
|
74
|
+
"test",
|
|
162
75
|
() => Date.now(),
|
|
163
76
|
);
|
|
164
77
|
const handle = (await runtime.open(kb, WRITE_CTX("kb"))) as VectorIndexStoreFxHandle;
|
|
@@ -202,24 +115,10 @@ describe("store.index boot wiring — fail loud", () => {
|
|
|
202
115
|
const kb = declareIndex("kb", { dims: 3 });
|
|
203
116
|
const runtime = bindStore(
|
|
204
117
|
{
|
|
205
|
-
config: { drivers: { store: { sql: {
|
|
206
|
-
stores: [kb],
|
|
207
|
-
},
|
|
208
|
-
"local",
|
|
209
|
-
() => Date.now(),
|
|
210
|
-
);
|
|
211
|
-
await expect(runtime.open(kb, WRITE_CTX("kb"))).rejects.toThrow(/cannot share sql driver/);
|
|
212
|
-
await runtime.close();
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
test("libsql index with sqlite sql driver throws", async () => {
|
|
216
|
-
const kb = declareIndex("kb", { dims: 3 });
|
|
217
|
-
const runtime = bindStore(
|
|
218
|
-
{
|
|
219
|
-
config: { drivers: { store: { sql: { local: "sqlite" }, index: { local: "libsql" } } } },
|
|
118
|
+
config: { drivers: { store: { sql: { test: "memory" }, index: { test: "pgvector" } } } },
|
|
220
119
|
stores: [kb],
|
|
221
120
|
},
|
|
222
|
-
"
|
|
121
|
+
"test",
|
|
223
122
|
() => Date.now(),
|
|
224
123
|
);
|
|
225
124
|
await expect(runtime.open(kb, WRITE_CTX("kb"))).rejects.toThrow(/cannot share sql driver/);
|
|
@@ -233,8 +132,8 @@ describe("store.index boot wiring — fail loud", () => {
|
|
|
233
132
|
const kb = declareIndex("kb");
|
|
234
133
|
expect(() =>
|
|
235
134
|
bindStore(
|
|
236
|
-
{ config: { drivers: { store: { index: {
|
|
237
|
-
"
|
|
135
|
+
{ config: { drivers: { store: { index: { test: "meilisearch" } } } }, stores: [kb] },
|
|
136
|
+
"test",
|
|
238
137
|
() => Date.now(),
|
|
239
138
|
),
|
|
240
139
|
).toThrow(/OKE_STORE_INDEX_URL/);
|
|
@@ -252,8 +151,8 @@ describe("store.index boot wiring — fail loud", () => {
|
|
|
252
151
|
try {
|
|
253
152
|
const kb = declareIndex("kb");
|
|
254
153
|
const runtime = bindStore(
|
|
255
|
-
{ config: { drivers: { store: { index: {
|
|
256
|
-
"
|
|
154
|
+
{ config: { drivers: { store: { index: { test: "meilisearch" } } } }, stores: [kb] },
|
|
155
|
+
"test",
|
|
257
156
|
() => Date.now(),
|
|
258
157
|
);
|
|
259
158
|
// No live server in unit tests: opening must fail loud (unreachable),
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Load plugin table contributions from a live `oke()` app entry.
|
|
3
3
|
*
|
|
4
4
|
* Used by `oke db` emit so `.plug()`-registered `field.*` tables merge into
|
|
5
|
-
* `schema.
|
|
5
|
+
* `schema.drizzle.ts` — not only at unit-test merge call sites.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { resolve } from "node:path";
|
|
@@ -11,16 +11,22 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { z } from "zod";
|
|
14
|
-
import { field, id,
|
|
14
|
+
import { field, id, store } from "../store.ts";
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
/** Unique table name — avoids colliding with other suites' `docs_items` DDL. */
|
|
17
|
+
const docsItems = store.schema.table("docs_list_items", {
|
|
17
18
|
id: field.text().primaryKey().defaultFn(id),
|
|
18
19
|
title: field.text().notNull(),
|
|
19
20
|
secret: field.text().notNull(),
|
|
20
|
-
|
|
21
|
+
// Small default — docs fixtures only need a stable integer clock column.
|
|
22
|
+
// (ms `now()` exceeds Postgres INTEGER; ensure DDL maps to BIGINT for apps.)
|
|
23
|
+
createdAt: field.integer().notNull().default(1),
|
|
21
24
|
});
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
/** Shared SQL store — tests must pass this to `oke({ stores })` after registry consume. */
|
|
27
|
+
export const docsListItemsStore = store.sql("docs-list-items", {
|
|
28
|
+
schema: { docs_list_items: docsItems },
|
|
29
|
+
});
|
|
24
30
|
|
|
25
31
|
const inSchema = z.object({ title: z.string().min(1), secret: z.string().min(1) });
|
|
26
32
|
const outSchema = z.object({
|
|
@@ -35,7 +41,7 @@ const outSchema = z.object({
|
|
|
35
41
|
* `count: "exact"` (offset default) and point to `count: "none"` as the escape
|
|
36
42
|
* hatch when COUNT(*) is too expensive.
|
|
37
43
|
*/
|
|
38
|
-
export const docsAdminTableResource = store.resource(
|
|
44
|
+
export const docsAdminTableResource = store.resource(docsListItemsStore, docsItems, {
|
|
39
45
|
in: inSchema,
|
|
40
46
|
out: outSchema,
|
|
41
47
|
list: { mode: "offset", count: "exact", limit: 20 },
|
|
@@ -47,7 +53,7 @@ export const docsAdminTableResource = store.resource(db, docsItems, {
|
|
|
47
53
|
* Public restricted endpoint — filters off entirely. Any `?col=op.value`
|
|
48
54
|
* query key that is not a reserved list param fails validation (422).
|
|
49
55
|
*/
|
|
50
|
-
export const docsRestrictedResource = store.resource(
|
|
56
|
+
export const docsRestrictedResource = store.resource(docsListItemsStore, docsItems, {
|
|
51
57
|
in: inSchema,
|
|
52
58
|
out: outSchema,
|
|
53
59
|
list: { mode: "offset", filter: "none", limit: 20 },
|
|
@@ -15,7 +15,11 @@ import { resetFlowSeq } from "../../kernel/flow.ts";
|
|
|
15
15
|
import { on, resetBindings } from "../../kernel/on.ts";
|
|
16
16
|
import { http } from "../../kernel/triggers.ts";
|
|
17
17
|
import { createTestApp } from "../../test/create-test-app.ts";
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
docsAdminTableResource,
|
|
20
|
+
docsListItemsStore,
|
|
21
|
+
docsRestrictedResource,
|
|
22
|
+
} from "./resource-list-docs.fixture.ts";
|
|
19
23
|
|
|
20
24
|
afterEach(() => {
|
|
21
25
|
resetBindings();
|
|
@@ -23,57 +27,73 @@ afterEach(() => {
|
|
|
23
27
|
});
|
|
24
28
|
|
|
25
29
|
describe("resource-list-docs fixtures — documented behaviors stay real", () => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
// PGLite first-boot under full-suite load can exceed the default 5s.
|
|
31
|
+
test(
|
|
32
|
+
"filter: \"none\" — forbidden filter key → 422 ValidationError 'unknown list param'",
|
|
33
|
+
async () => {
|
|
34
|
+
resetBindings();
|
|
35
|
+
resetFlowSeq();
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
37
|
+
const mounted = on(http.resource("/docs-restricted", docsRestrictedResource.all()));
|
|
38
|
+
const app = oke({ name: "docs-restricted-test" }).adopt({ docs: mounted });
|
|
39
|
+
// Explicit stores — module-level `store.sql` is drained by the first `oke()`
|
|
40
|
+
// (and cleared by the global afterEach registry reset).
|
|
41
|
+
Object.assign(app.$options, { env: "test", stores: [docsListItemsStore] });
|
|
33
42
|
|
|
34
|
-
|
|
43
|
+
const t = await createTestApp(app);
|
|
35
44
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
const bad = await app.fetch(new Request("http://localhost/docs-restricted?secret=eq.x"));
|
|
46
|
+
expect(bad.status).toBe(422);
|
|
47
|
+
const badBody = (await bad.json()) as {
|
|
48
|
+
data: null;
|
|
49
|
+
error: { code: string; data: { issues: Array<{ message: string; path: string[] }> } };
|
|
50
|
+
};
|
|
51
|
+
expect(badBody.error.code).toBe("ValidationError");
|
|
52
|
+
expect(badBody.error.data.issues[0]!.message).toBe('unknown list param "secret"');
|
|
53
|
+
expect(badBody.error.data.issues[0]!.path).toEqual(["secret"]);
|
|
45
54
|
|
|
46
|
-
|
|
47
|
-
|
|
55
|
+
const ok = await app.fetch(new Request("http://localhost/docs-restricted?limit=20"));
|
|
56
|
+
expect(ok.status).toBe(200);
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
|
|
58
|
+
await t.close();
|
|
59
|
+
},
|
|
60
|
+
{ timeout: 30_000 },
|
|
61
|
+
);
|
|
51
62
|
|
|
52
|
-
test(
|
|
53
|
-
|
|
54
|
-
|
|
63
|
+
test(
|
|
64
|
+
'offset + count: "exact" answers meta.total; "none" drops it',
|
|
65
|
+
async () => {
|
|
66
|
+
resetBindings();
|
|
67
|
+
resetFlowSeq();
|
|
55
68
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
69
|
+
const exactMounted = on(http.resource("/docs-admin", docsAdminTableResource.all()));
|
|
70
|
+
const app = oke({ name: "docs-admin-test" }).adopt({ docs: exactMounted });
|
|
71
|
+
Object.assign(app.$options, { env: "test", stores: [docsListItemsStore] });
|
|
59
72
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
73
|
+
const t = await createTestApp(app);
|
|
74
|
+
const created = await app.fetch(
|
|
75
|
+
new Request("http://localhost/docs-admin", {
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers: { "content-type": "application/json" },
|
|
78
|
+
body: JSON.stringify({ title: "one", secret: "s" }),
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
expect(created.status).toBe(201);
|
|
68
82
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
83
|
+
const exact = await app.fetch(new Request("http://localhost/docs-admin?limit=20"));
|
|
84
|
+
expect(exact.status).toBe(200);
|
|
85
|
+
const exactBody = (await exact.json()) as {
|
|
86
|
+
data: Array<{ title?: string }>;
|
|
87
|
+
meta: Record<string, unknown>;
|
|
88
|
+
};
|
|
89
|
+
// `count: "exact"` must answer meta.total (COUNT(*)); offset mode keeps meta.offset.
|
|
90
|
+
expect(typeof exactBody.meta.total).toBe("number");
|
|
91
|
+
expect(exactBody.meta.total).toBeGreaterThanOrEqual(1);
|
|
92
|
+
expect(exactBody.meta.offset).toBe(0);
|
|
93
|
+
expect(exactBody.data.some((row) => row.title === "one")).toBe(true);
|
|
76
94
|
|
|
77
|
-
|
|
78
|
-
|
|
95
|
+
await t.close();
|
|
96
|
+
},
|
|
97
|
+
{ timeout: 30_000 },
|
|
98
|
+
);
|
|
79
99
|
});
|
|
@@ -6,11 +6,10 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { afterEach, describe, expect, test } from "bun:test";
|
|
9
|
-
import {
|
|
10
|
-
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
|
9
|
+
import { integer, pgTable, text } from "drizzle-orm/pg-core";
|
|
11
10
|
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
|
12
11
|
import { z } from "zod";
|
|
13
|
-
import {
|
|
12
|
+
import { pgliteDriver } from "../../drivers/pglite.ts";
|
|
14
13
|
import { oke } from "../../kernel/app.ts";
|
|
15
14
|
import { resetFlowSeq } from "../../kernel/flow.ts";
|
|
16
15
|
import { on, resetBindings } from "../../kernel/on.ts";
|
|
@@ -26,7 +25,7 @@ afterEach(() => {
|
|
|
26
25
|
});
|
|
27
26
|
|
|
28
27
|
describe("mapRowToJs — declared keys only", () => {
|
|
29
|
-
const posts =
|
|
28
|
+
const posts = pgTable("posts", {
|
|
30
29
|
id: text("id").primaryKey(),
|
|
31
30
|
createdAt: integer("created_at").notNull(),
|
|
32
31
|
});
|
|
@@ -48,15 +47,15 @@ describe("mapRowToJs — declared keys only", () => {
|
|
|
48
47
|
});
|
|
49
48
|
|
|
50
49
|
describe("SqlStoreHandle exit — list/get/create return JS keys only", () => {
|
|
51
|
-
const posts =
|
|
50
|
+
const posts = pgTable("posts", {
|
|
52
51
|
id: text("id").primaryKey(),
|
|
53
52
|
title: text("title").notNull(),
|
|
54
53
|
createdAt: integer("created_at").notNull(),
|
|
55
54
|
});
|
|
56
55
|
|
|
57
56
|
test("select / findById / insert.returning never emit created_at", async () => {
|
|
58
|
-
const conn = await
|
|
59
|
-
|
|
57
|
+
const conn = await pgliteDriver.connect({
|
|
58
|
+
url: "memory://",
|
|
60
59
|
role: "primary",
|
|
61
60
|
});
|
|
62
61
|
const handle = createSqlStoreHandle("sql:app", {
|
|
@@ -87,7 +86,7 @@ describe("SqlStoreHandle exit — list/get/create return JS keys only", () => {
|
|
|
87
86
|
|
|
88
87
|
describe("resource HTTP — exact keys + PII with differing TS/SQL names", () => {
|
|
89
88
|
// TS `email` ↔ SQL `email_addr`; TS `createdAt` ↔ SQL `created_at`.
|
|
90
|
-
const contacts =
|
|
89
|
+
const contacts = pgTable("contacts", {
|
|
91
90
|
id: text("id").primaryKey().$defaultFn(id),
|
|
92
91
|
email: text("email_addr").notNull(),
|
|
93
92
|
createdAt: integer("created_at").notNull().$defaultFn(now),
|
|
@@ -122,7 +121,11 @@ describe("resource HTTP — exact keys + PII with differing TS/SQL names", () =>
|
|
|
122
121
|
|
|
123
122
|
const mounted = on(http.resource("/contacts", contactsR.all()));
|
|
124
123
|
const app = oke({ name: "contacts-resource-test" }).adopt({ contacts: mounted });
|
|
125
|
-
Object.assign(app.$options, {
|
|
124
|
+
Object.assign(app.$options, {
|
|
125
|
+
env: "test",
|
|
126
|
+
stores: [db],
|
|
127
|
+
config: { drivers: { store: { sql: { test: "pglite" } } } },
|
|
128
|
+
});
|
|
126
129
|
return app;
|
|
127
130
|
}
|
|
128
131
|
|
|
@@ -229,7 +232,11 @@ describe("resource HTTP — exact keys + PII with differing TS/SQL names", () =>
|
|
|
229
232
|
|
|
230
233
|
const mounted = on(http.resource("/people", peopleR.all()));
|
|
231
234
|
const app = oke({ name: "people-pii-test" }).adopt({ people: mounted });
|
|
232
|
-
Object.assign(app.$options, {
|
|
235
|
+
Object.assign(app.$options, {
|
|
236
|
+
env: "test",
|
|
237
|
+
stores: [db],
|
|
238
|
+
config: { drivers: { store: { sql: { test: "pglite" } } } },
|
|
239
|
+
});
|
|
233
240
|
|
|
234
241
|
const t = await createTestApp(app);
|
|
235
242
|
const created = await app.fetch(
|
|
@@ -158,7 +158,7 @@ export interface FilesStoreFxHandle {
|
|
|
158
158
|
/** Vector index handle on `fx.store`. */
|
|
159
159
|
export interface VectorIndexStoreFxHandle {
|
|
160
160
|
readonly ref: `index:${string}`;
|
|
161
|
-
readonly driverId: "memory" | "pgvector"
|
|
161
|
+
readonly driverId: "memory" | "pgvector";
|
|
162
162
|
upsert(id: string, vector: readonly number[], meta?: Record<string, unknown>): Promise<void>;
|
|
163
163
|
search(
|
|
164
164
|
vector: readonly number[],
|
|
@@ -290,7 +290,10 @@ export function createStoreRuntime(options: CreateStoreRuntimeOptions): StoreRun
|
|
|
290
290
|
async function openSql(decl: SqlStoreDecl, ctx: StoreInvokeContext): Promise<SqlStoreHandle> {
|
|
291
291
|
const binding = options.sql?.[decl.name] ?? {
|
|
292
292
|
name: decl.name,
|
|
293
|
-
|
|
293
|
+
// PGlite / postgres-shaped drivers persist under `.oke/`; the in-process
|
|
294
|
+
// `memory` SQL driver ignores `url`. Never use SQLite's `:memory:` here —
|
|
295
|
+
// PGlite treats that string as a filesystem path and creates `./:memory:`.
|
|
296
|
+
primary: { url: ".oke/pgdata" },
|
|
294
297
|
};
|
|
295
298
|
const target = resolveSqlTarget(binding, ctx.effects);
|
|
296
299
|
const driver = options.drivers.sql;
|
|
@@ -327,7 +330,7 @@ export function createStoreRuntime(options: CreateStoreRuntimeOptions): StoreRun
|
|
|
327
330
|
|
|
328
331
|
/** SQL-backed index drivers borrow the sql facet's connection. */
|
|
329
332
|
async function sqlConnForIndex(
|
|
330
|
-
driver: VectorIndexDriver & { id: "pgvector"
|
|
333
|
+
driver: VectorIndexDriver & { id: "pgvector" },
|
|
331
334
|
url: string | undefined,
|
|
332
335
|
): Promise<SqlConnection> {
|
|
333
336
|
const sqlDriver = options.drivers.sql;
|
|
@@ -336,16 +339,10 @@ export function createStoreRuntime(options: CreateStoreRuntimeOptions): StoreRun
|
|
|
336
339
|
`oke store: index driver "${driver.id}" needs a configured sql driver to share its connection`,
|
|
337
340
|
);
|
|
338
341
|
}
|
|
339
|
-
|
|
340
|
-
driver.id === "pgvector"
|
|
341
|
-
? sqlDriver.id === "postgres" || sqlDriver.id === "pglite"
|
|
342
|
-
: sqlDriver.id === "libsql";
|
|
343
|
-
if (!compatible) {
|
|
342
|
+
if (sqlDriver.id !== "postgres" && sqlDriver.id !== "pglite") {
|
|
344
343
|
throw new Error(
|
|
345
|
-
`oke store: index driver "
|
|
346
|
-
|
|
347
|
-
? `pgvector needs store.sql on "postgres" or "pglite"`
|
|
348
|
-
: `libsql index needs store.sql on "libsql"`),
|
|
344
|
+
`oke store: index driver "pgvector" cannot share sql driver "${sqlDriver.id}" — ` +
|
|
345
|
+
`pgvector needs store.sql on "postgres" or "pglite"`,
|
|
349
346
|
);
|
|
350
347
|
}
|
|
351
348
|
return sharedSqlConn(sqlDriver, "primary", { url });
|