okengine 0.10.2 → 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/ai/mcp.mdx +0 -1
- 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 -13
- package/site/content/docs/elements/channel.mdx +9 -13
- package/site/content/docs/elements/clock.mdx +8 -14
- package/site/content/docs/elements/flow.mdx +46 -54
- package/site/content/docs/elements/gate.mdx +6 -11
- package/site/content/docs/elements/signal.mdx +2 -8
- package/site/content/docs/elements/store.mdx +79 -93
- package/site/content/docs/elements/vault.mdx +89 -76
- package/site/content/docs/get-started/basic-usage.mdx +8 -14
- 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 +3 -4
- package/site/content/docs/index.mdx +0 -1
- package/site/content/docs/meta.json +0 -1
- 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 +14 -7
- 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 +30 -16
- 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 +8 -9
- 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 +246 -114
- package/src/cli/dev.ts +153 -205
- 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 +142 -9
- 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 +44 -10
- package/src/cli/load-config.source.test.ts +50 -0
- package/src/cli/load-config.ts +35 -29
- 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 +29 -11
- 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/extract.ts +12 -0
- package/src/compiler/fixtures/skyport/oke.config.ts +7 -5
- package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -1
- package/src/compiler/fixtures/skyport.expected.json +1 -1
- package/src/compiler/generate-adopt.ts +27 -1
- package/src/compiler-entry.ts +7 -0
- package/src/config/define-config.test.ts +111 -47
- package/src/config/driver-defaults.test.ts +115 -0
- package/src/config/driver-defaults.ts +156 -0
- package/src/config/index.ts +246 -131
- 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 +163 -0
- 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 +5 -4
- package/src/kernel/boot-bind/clock.ts +5 -5
- package/src/kernel/boot-bind/gate.ts +6 -7
- package/src/kernel/boot-bind/honor-config.test.ts +42 -42
- package/src/kernel/boot-bind/journal.ts +5 -5
- package/src/kernel/boot-bind/signal.ts +3 -1
- package/src/kernel/boot-bind/store.test.ts +55 -37
- package/src/kernel/boot-bind/store.ts +24 -34
- package/src/kernel/boot-bind/vault.ts +19 -4
- 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/console/access.mdx +0 -29
- package/site/content/docs/console/ai.mdx +0 -35
- package/site/content/docs/console/architecture.mdx +0 -35
- package/site/content/docs/console/channels.mdx +0 -37
- package/site/content/docs/console/clock.mdx +0 -51
- package/site/content/docs/console/flows.mdx +0 -31
- package/site/content/docs/console/gates.mdx +0 -73
- package/site/content/docs/console/index.mdx +0 -54
- package/site/content/docs/console/manifest-diff.mdx +0 -34
- package/site/content/docs/console/meta.json +0 -24
- package/site/content/docs/console/overview.mdx +0 -40
- package/site/content/docs/console/plugins.mdx +0 -41
- package/site/content/docs/console/privacy.mdx +0 -32
- package/site/content/docs/console/runs.mdx +0 -50
- package/site/content/docs/console/signals.mdx +0 -40
- package/site/content/docs/console/store.mdx +0 -32
- package/site/content/docs/console/tenancy.mdx +0 -32
- package/site/content/docs/console/traces.mdx +0 -38
- package/site/content/docs/console/vault.mdx +0 -41
- 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
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for hidden / stdin master-key helpers.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import { EventEmitter } from "node:events";
|
|
7
|
+
import { promptHidden, readStdinSecure } from "./vault-secure-input.ts";
|
|
8
|
+
|
|
9
|
+
describe("readStdinSecure", () => {
|
|
10
|
+
test("trims a full stdin payload", async () => {
|
|
11
|
+
const stdin = new EventEmitter() as EventEmitter & {
|
|
12
|
+
setEncoding?: (encoding: BufferEncoding) => void;
|
|
13
|
+
};
|
|
14
|
+
stdin.setEncoding = () => undefined;
|
|
15
|
+
const pending = readStdinSecure(stdin);
|
|
16
|
+
stdin.emit("data", " abc123\n");
|
|
17
|
+
stdin.emit("end");
|
|
18
|
+
expect(await pending).toBe("abc123");
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe("promptHidden", () => {
|
|
23
|
+
test("masks characters and resolves on Enter", async () => {
|
|
24
|
+
const stdin = new EventEmitter() as EventEmitter & {
|
|
25
|
+
setRawMode?: (mode: boolean) => void;
|
|
26
|
+
off?: (event: string, listener: (...args: unknown[]) => void) => void;
|
|
27
|
+
};
|
|
28
|
+
let raw = false;
|
|
29
|
+
stdin.setRawMode = (mode) => {
|
|
30
|
+
raw = mode;
|
|
31
|
+
};
|
|
32
|
+
stdin.off = (event: string | symbol, listener: (...args: unknown[]) => void) => {
|
|
33
|
+
stdin.removeListener(event, listener);
|
|
34
|
+
return stdin;
|
|
35
|
+
};
|
|
36
|
+
let written = "";
|
|
37
|
+
const pending = promptHidden("key: ", {
|
|
38
|
+
stdin,
|
|
39
|
+
write: (t) => {
|
|
40
|
+
written += t;
|
|
41
|
+
},
|
|
42
|
+
exit: () => {
|
|
43
|
+
throw new Error("exit should not run");
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
// Allow the listener to attach.
|
|
47
|
+
await Promise.resolve();
|
|
48
|
+
stdin.emit("data", "ab");
|
|
49
|
+
stdin.emit("data", "\r");
|
|
50
|
+
expect(await pending).toBe("ab");
|
|
51
|
+
expect(written).toContain("key: ");
|
|
52
|
+
expect(written).toContain("**");
|
|
53
|
+
expect(written).not.toContain("ab");
|
|
54
|
+
expect(raw).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure master-key input for `oke vault` — avoid shell history.
|
|
3
|
+
*
|
|
4
|
+
* Prefer `--key -` (stdin) or an interactive hidden prompt over putting
|
|
5
|
+
* base64 keys on the argv in shared environments.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Minimal readable stream used by {@link readStdinSecure}. */
|
|
9
|
+
export interface SecureStdin {
|
|
10
|
+
setEncoding?(encoding: BufferEncoding): void;
|
|
11
|
+
on(event: "data", listener: (chunk: string | Buffer) => void): unknown;
|
|
12
|
+
on(event: "end", listener: () => void): unknown;
|
|
13
|
+
on(event: "error", listener: (error: Error) => void): unknown;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Minimal TTY-ish stdin used by {@link promptHidden}. */
|
|
17
|
+
export interface SecurePromptStdin {
|
|
18
|
+
setRawMode?(mode: boolean): void;
|
|
19
|
+
on(event: "data", listener: (chunk: string | Buffer) => void): unknown;
|
|
20
|
+
removeListener?(event: "data", listener: (chunk: string | Buffer) => void): unknown;
|
|
21
|
+
off?(event: "data", listener: (chunk: string | Buffer) => void): unknown;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** IO sinks for {@link promptHidden}. */
|
|
25
|
+
export interface PromptHiddenOptions {
|
|
26
|
+
/** Prompt destination. Defaults to `process.stdout.write`. */
|
|
27
|
+
readonly write?: (text: string) => void;
|
|
28
|
+
/** Character stream (TTY). Defaults to `process.stdin`. */
|
|
29
|
+
readonly stdin?: SecurePromptStdin;
|
|
30
|
+
/** Exit handler for Ctrl+C. Defaults to `process.exit`. */
|
|
31
|
+
readonly exit?: (code: number) => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Read a trimmed secret from stdin (for `--key -` / `--new-key -`).
|
|
36
|
+
*
|
|
37
|
+
* @param stdin - Readable stream; defaults to `process.stdin`
|
|
38
|
+
*/
|
|
39
|
+
export async function readStdinSecure(stdin: SecureStdin = process.stdin): Promise<string> {
|
|
40
|
+
stdin.setEncoding?.("utf8");
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
let data = "";
|
|
43
|
+
stdin.on("data", (chunk) => {
|
|
44
|
+
data += typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
45
|
+
});
|
|
46
|
+
stdin.on("end", () => resolve(data.trim()));
|
|
47
|
+
stdin.on("error", reject);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Prompt for a secret on a TTY without echoing the cleartext.
|
|
53
|
+
*
|
|
54
|
+
* Characters are masked with `*`. Backspace edits; Enter submits; Ctrl+C
|
|
55
|
+
* exits the process (or the injected `exit` handler).
|
|
56
|
+
*
|
|
57
|
+
* @param question - Prompt text written before input
|
|
58
|
+
* @param options - Injectable IO for tests
|
|
59
|
+
*/
|
|
60
|
+
export async function promptHidden(
|
|
61
|
+
question: string,
|
|
62
|
+
options: PromptHiddenOptions = {},
|
|
63
|
+
): Promise<string> {
|
|
64
|
+
const write = options.write ?? ((t: string) => process.stdout.write(t));
|
|
65
|
+
const stdin = options.stdin ?? process.stdin;
|
|
66
|
+
const exit = options.exit ?? ((code: number) => process.exit(code));
|
|
67
|
+
|
|
68
|
+
write(question);
|
|
69
|
+
stdin.setRawMode?.(true);
|
|
70
|
+
|
|
71
|
+
return new Promise((resolve) => {
|
|
72
|
+
let input = "";
|
|
73
|
+
const onData = (char: string | Buffer): void => {
|
|
74
|
+
const text = typeof char === "string" ? char : char.toString("utf8");
|
|
75
|
+
for (const ch of text) {
|
|
76
|
+
if (ch === "\n" || ch === "\r" || ch === "\u0004") {
|
|
77
|
+
stdin.setRawMode?.(false);
|
|
78
|
+
write("\n");
|
|
79
|
+
removeDataListener(stdin, onData);
|
|
80
|
+
resolve(input);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (ch === "\u0003") {
|
|
84
|
+
stdin.setRawMode?.(false);
|
|
85
|
+
write("\n");
|
|
86
|
+
removeDataListener(stdin, onData);
|
|
87
|
+
exit(1);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (ch === "\u007f" || ch === "\b") {
|
|
91
|
+
if (input.length > 0) {
|
|
92
|
+
input = input.slice(0, -1);
|
|
93
|
+
write("\b \b");
|
|
94
|
+
}
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
// Ignore other control characters.
|
|
98
|
+
if (ch < " ") continue;
|
|
99
|
+
input += ch;
|
|
100
|
+
write("*");
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
stdin.on("data", onData);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Detach the raw-mode data listener when the host supports it.
|
|
109
|
+
*
|
|
110
|
+
* @param stdin - Prompt stdin
|
|
111
|
+
* @param listener - Handler to remove
|
|
112
|
+
*/
|
|
113
|
+
function removeDataListener(
|
|
114
|
+
stdin: SecurePromptStdin,
|
|
115
|
+
listener: (chunk: string | Buffer) => void,
|
|
116
|
+
): void {
|
|
117
|
+
if (typeof stdin.off === "function") {
|
|
118
|
+
stdin.off("data", listener);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (typeof stdin.removeListener === "function") {
|
|
122
|
+
stdin.removeListener("data", listener);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -120,6 +120,9 @@ const WRITE_METHODS = new Set([
|
|
|
120
120
|
"putImage",
|
|
121
121
|
]);
|
|
122
122
|
|
|
123
|
+
/** `fx.vault.*` methods whose first argument is a secret path. */
|
|
124
|
+
const VAULT_PATH_METHODS = new Set(["get", "set", "rotate", "delete"]);
|
|
125
|
+
|
|
123
126
|
/** Methods whose first argument is a table / collection identifier. */
|
|
124
127
|
const TABLE_ARG_METHODS = new Set([
|
|
125
128
|
"insert",
|
|
@@ -189,6 +192,10 @@ export function inferEffects(options: InferEffectsOptions): InferredEffects {
|
|
|
189
192
|
}
|
|
190
193
|
|
|
191
194
|
if (chain.rootMethod === "vault" && call === chain.rootCall) {
|
|
195
|
+
// `fx.vault.list()` / `fx.vault.status()` take no path — nothing to
|
|
196
|
+
// declare. Every other method's first argument is the secret.
|
|
197
|
+
const method = chain.methods[1] ?? "get";
|
|
198
|
+
if (!VAULT_PATH_METHODS.has(method)) continue;
|
|
192
199
|
const ref = resolveNamed(call.arguments[0], options.bindings, "secret");
|
|
193
200
|
if (ref) secrets.add(ref);
|
|
194
201
|
continue;
|
package/src/compiler/extract.ts
CHANGED
|
@@ -1022,8 +1022,20 @@ function collectConfig(opts: AstNode | undefined, scope: ProjectScope): void {
|
|
|
1022
1022
|
const images = objectProp(opts, "images");
|
|
1023
1023
|
if (images) {
|
|
1024
1024
|
const map: Record<string, string> = {};
|
|
1025
|
+
// Nested like `drivers`: `store.*` / `channel.*` flatten to dotted keys;
|
|
1026
|
+
// everything else (`vault`, `ai`, `pgdog`, `proxy`) is already flat.
|
|
1027
|
+
for (const nestKey of ["store", "channel"] as const) {
|
|
1028
|
+
const nested = objectProp(images, nestKey);
|
|
1029
|
+
if (!nested || nested.type !== "ObjectExpression") continue;
|
|
1030
|
+
for (const prop of objectProperties(nested)) {
|
|
1031
|
+
const key = propKey(prop);
|
|
1032
|
+
const val = stringArg((prop as AstNode & { value?: AstNode }).value);
|
|
1033
|
+
if (key && val) map[`${nestKey}.${key}`] = val;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1025
1036
|
for (const prop of objectProperties(images)) {
|
|
1026
1037
|
const key = propKey(prop);
|
|
1038
|
+
if (key === "store" || key === "channel") continue;
|
|
1027
1039
|
const val = stringArg((prop as AstNode & { value?: AstNode }).value);
|
|
1028
1040
|
if (key && val) map[key] = val;
|
|
1029
1041
|
}
|
|
@@ -2,21 +2,23 @@ import { defineConfig } from "okengine/config";
|
|
|
2
2
|
|
|
3
3
|
export default defineConfig({
|
|
4
4
|
drivers: {
|
|
5
|
-
prod: ["postgres", "redis", "s3", "smtp", "
|
|
5
|
+
prod: ["postgres", "redis", "s3", "smtp", "vault", "anthropic", "pgvector"],
|
|
6
6
|
store: {
|
|
7
|
-
sql: {
|
|
7
|
+
sql: { dev: { driver: "postgres" }, test: "pglite", prod: { driver: "postgres" } },
|
|
8
8
|
kv: { prod: "redis" },
|
|
9
9
|
files: { prod: "s3" },
|
|
10
10
|
index: { prod: "pgvector" },
|
|
11
11
|
},
|
|
12
12
|
signal: { prod: "redis" },
|
|
13
|
-
vault: { prod: "
|
|
13
|
+
vault: { prod: "vault" },
|
|
14
14
|
channel: { email: { prod: "smtp" } },
|
|
15
15
|
ai: { prod: { driver: "anthropic" } },
|
|
16
16
|
},
|
|
17
17
|
images: {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
store: {
|
|
19
|
+
sql: "pgvector/pgvector:pg17",
|
|
20
|
+
kv: "valkey/valkey:8-alpine",
|
|
21
|
+
},
|
|
20
22
|
},
|
|
21
23
|
i18n: { locales: ["en", "ar"], default: "ar", dir: { ar: "rtl" } },
|
|
22
24
|
tenancy: { isolation: "row" },
|
|
@@ -7,7 +7,7 @@ export const chargeBooking = flow("payments.chargeBooking", {
|
|
|
7
7
|
// Journal only serializable step values — a Redacted is not journaled.
|
|
8
8
|
const intent = await fx.step("create-intent", async () => ({
|
|
9
9
|
id: `pi_${orderId}`,
|
|
10
|
-
key: fx.vault(stripeKey).reveal(),
|
|
10
|
+
key: (await fx.vault.get(stripeKey)).reveal(),
|
|
11
11
|
}));
|
|
12
12
|
await fx.clock.sleep("verify-window", "2m");
|
|
13
13
|
return fx.step("confirm", () => intent);
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* `<rootDir>/src/flows/*` has an `index.ts` barrel.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import { readdir } from "node:fs/promises";
|
|
15
|
+
import { mkdir, readdir, rename, writeFile } from "node:fs/promises";
|
|
16
16
|
import { join } from "node:path";
|
|
17
17
|
|
|
18
18
|
/** Options for {@link generateAdoptBarrel}. */
|
|
@@ -37,9 +37,35 @@ const GENERATED_HEADER =
|
|
|
37
37
|
"// AUTO-GENERATED by `oke dev` / `oke build` — do not edit by hand.\n" +
|
|
38
38
|
"// Regenerated from every `src/flows/<unit>/index.ts` unit folder.\n";
|
|
39
39
|
|
|
40
|
+
/** Filename of the on-disk `.adopt()` barrel under the flows directory. */
|
|
41
|
+
export const ADOPT_BARREL_FILE = "generated.ts";
|
|
42
|
+
|
|
40
43
|
/** A folder name usable as an `export * as <name>` binding. */
|
|
41
44
|
const VALID_UNIT_NAME = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
42
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Write the adopt barrel atomically: `generated.ts.tmp` → rename to
|
|
48
|
+
* `generated.ts`. Concurrent readers (e.g. `bun --hot` racing a save) never
|
|
49
|
+
* observe a torn/partial file — plain `writeFile` on the destination would
|
|
50
|
+
* truncate first.
|
|
51
|
+
*
|
|
52
|
+
* @param rootDir - Project root
|
|
53
|
+
* @param source - Full barrel source from {@link generateAdoptBarrel}
|
|
54
|
+
* @param flowsDir - Flows directory relative to root (default `"src/flows"`)
|
|
55
|
+
*/
|
|
56
|
+
export async function writeAdoptBarrel(
|
|
57
|
+
rootDir: string,
|
|
58
|
+
source: string,
|
|
59
|
+
flowsDir = "src/flows",
|
|
60
|
+
): Promise<void> {
|
|
61
|
+
const dir = join(rootDir, flowsDir);
|
|
62
|
+
const target = join(dir, ADOPT_BARREL_FILE);
|
|
63
|
+
const tmp = `${target}.tmp`;
|
|
64
|
+
await mkdir(dir, { recursive: true });
|
|
65
|
+
await writeFile(tmp, source);
|
|
66
|
+
await rename(tmp, target);
|
|
67
|
+
}
|
|
68
|
+
|
|
43
69
|
/**
|
|
44
70
|
* Scan `<rootDir>/<flowsDir>/*` and emit a barrel re-exporting every unit
|
|
45
71
|
* folder's `index.ts` under its folder name — the same shape
|
|
@@ -1,82 +1,146 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `defineConfig` fills missing `
|
|
2
|
+
* `defineConfig` fills missing `dev` pins from `prod` and normalizes legacy keys.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { describe, expect, test } from "bun:test";
|
|
6
|
-
import { defineConfig,
|
|
6
|
+
import { defineConfig, fillDevFromProd, normalizeEnvDriverMap } from "./index.ts";
|
|
7
7
|
|
|
8
|
-
describe("
|
|
9
|
-
test("copies prod onto
|
|
10
|
-
const filled =
|
|
11
|
-
|
|
8
|
+
describe("fillDevFromProd / defineConfig", () => {
|
|
9
|
+
test("copies prod onto dev when dev is omitted", () => {
|
|
10
|
+
const filled = fillDevFromProd({
|
|
11
|
+
test: "pglite",
|
|
12
12
|
prod: "postgres",
|
|
13
13
|
});
|
|
14
|
-
expect(filled?.
|
|
15
|
-
expect(filled?.
|
|
14
|
+
expect(filled?.dev).toBe("postgres");
|
|
15
|
+
expect(filled?.test).toBe("pglite");
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
test("does not overwrite an explicit
|
|
18
|
+
test("does not overwrite an explicit dev pin", () => {
|
|
19
19
|
expect(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
docker: "memory",
|
|
20
|
+
fillDevFromProd({
|
|
21
|
+
dev: "memory",
|
|
23
22
|
prod: "postgres",
|
|
24
|
-
})?.
|
|
23
|
+
})?.dev,
|
|
25
24
|
).toBe("memory");
|
|
26
25
|
});
|
|
27
26
|
|
|
28
|
-
test("vault prod →
|
|
29
|
-
expect(
|
|
27
|
+
test("vault prod → dev copies the prod driver", () => {
|
|
28
|
+
expect(fillDevFromProd({ prod: "vault" })?.dev).toBe("vault");
|
|
30
29
|
});
|
|
31
30
|
|
|
32
31
|
test("defineConfig fills every element from prod", () => {
|
|
33
32
|
const cfg = defineConfig({
|
|
34
33
|
drivers: {
|
|
35
34
|
store: {
|
|
36
|
-
sql: {
|
|
37
|
-
kv: {
|
|
38
|
-
files: {
|
|
35
|
+
sql: { test: "pglite", prod: "postgres" },
|
|
36
|
+
kv: { test: "memory", prod: "redis" },
|
|
37
|
+
files: { test: "memory", prod: "s3" },
|
|
39
38
|
},
|
|
40
|
-
signal: {
|
|
41
|
-
clock: {
|
|
42
|
-
vault: {
|
|
39
|
+
signal: { test: "memory", prod: "redis" },
|
|
40
|
+
clock: { test: "frozen", prod: "file" },
|
|
41
|
+
vault: { test: "memory", prod: "vault" },
|
|
43
42
|
channel: {
|
|
44
|
-
email: {
|
|
43
|
+
email: { test: "console", prod: "smtp" },
|
|
45
44
|
},
|
|
46
|
-
ai: {
|
|
45
|
+
ai: { test: "mock", prod: "anthropic" },
|
|
47
46
|
},
|
|
48
47
|
});
|
|
49
|
-
expect(cfg.drivers?.store?.sql
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
expect(cfg.drivers?.
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
expect(cfg.drivers?.store?.sql).toMatchObject({
|
|
49
|
+
dev: "postgres",
|
|
50
|
+
test: "pglite",
|
|
51
|
+
prod: "postgres",
|
|
52
|
+
});
|
|
53
|
+
expect(cfg.drivers?.store?.kv).toMatchObject({
|
|
54
|
+
dev: "redis",
|
|
55
|
+
test: "memory",
|
|
56
|
+
prod: "redis",
|
|
57
|
+
});
|
|
58
|
+
expect(cfg.drivers?.store?.files).toMatchObject({
|
|
59
|
+
dev: "s3",
|
|
60
|
+
test: "memory",
|
|
61
|
+
prod: "s3",
|
|
62
|
+
});
|
|
63
|
+
expect(cfg.drivers?.signal).toMatchObject({
|
|
64
|
+
dev: "redis",
|
|
65
|
+
test: "memory",
|
|
66
|
+
prod: "redis",
|
|
67
|
+
});
|
|
68
|
+
expect(cfg.drivers?.clock).toMatchObject({
|
|
69
|
+
dev: "file",
|
|
70
|
+
test: "frozen",
|
|
71
|
+
prod: "file",
|
|
72
|
+
});
|
|
73
|
+
expect(cfg.drivers?.vault).toMatchObject({
|
|
74
|
+
dev: "vault",
|
|
75
|
+
test: "memory",
|
|
76
|
+
prod: "vault",
|
|
77
|
+
});
|
|
78
|
+
expect(cfg.drivers?.channel?.email).toMatchObject({
|
|
79
|
+
dev: "smtp",
|
|
80
|
+
test: "console",
|
|
81
|
+
prod: "smtp",
|
|
82
|
+
});
|
|
83
|
+
expect(cfg.drivers?.ai).toMatchObject({
|
|
84
|
+
dev: "anthropic",
|
|
85
|
+
test: "mock",
|
|
86
|
+
prod: "anthropic",
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("normalizeEnvDriverMap expands a bare string to all envs", () => {
|
|
91
|
+
expect(normalizeEnvDriverMap("redis")).toEqual({
|
|
92
|
+
dev: "redis",
|
|
93
|
+
test: "redis",
|
|
94
|
+
prod: "redis",
|
|
95
|
+
});
|
|
57
96
|
});
|
|
58
97
|
|
|
59
|
-
test("normalizeEnvDriverMap
|
|
98
|
+
test("normalizeEnvDriverMap keeps only dev/test/prod keys", () => {
|
|
60
99
|
const normalized = normalizeEnvDriverMap({
|
|
61
|
-
dev: "
|
|
62
|
-
|
|
100
|
+
dev: "postgres",
|
|
101
|
+
test: "pglite",
|
|
102
|
+
prod: "postgres",
|
|
103
|
+
});
|
|
104
|
+
expect(normalized).toEqual({
|
|
105
|
+
dev: "postgres",
|
|
106
|
+
test: "pglite",
|
|
63
107
|
prod: "postgres",
|
|
64
108
|
});
|
|
65
|
-
expect(normalized?.local).toBe("sqlite");
|
|
66
|
-
expect(normalized?.docker).toBe("postgres");
|
|
67
|
-
expect((normalized as { dev?: string } | undefined)?.dev).toBeUndefined();
|
|
68
|
-
expect((normalized as { stack?: string } | undefined)?.stack).toBeUndefined();
|
|
69
109
|
});
|
|
70
110
|
|
|
71
|
-
test("defineConfig
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
111
|
+
test("defineConfig rejects sqlite", () => {
|
|
112
|
+
expect(() =>
|
|
113
|
+
defineConfig({
|
|
114
|
+
drivers: {
|
|
115
|
+
store: {
|
|
116
|
+
sql: { dev: "sqlite", test: "pglite", prod: "postgres" },
|
|
117
|
+
},
|
|
76
118
|
},
|
|
77
|
-
},
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
119
|
+
}),
|
|
120
|
+
).toThrow(/sqlite/);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("defineConfig rejects libsql", () => {
|
|
124
|
+
expect(() =>
|
|
125
|
+
defineConfig({
|
|
126
|
+
drivers: {
|
|
127
|
+
store: {
|
|
128
|
+
sql: { dev: "libsql", test: "pglite", prod: "postgres" },
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
}),
|
|
132
|
+
).toThrow(/libsql/);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("defineConfig rejects non-pglite test SQL", () => {
|
|
136
|
+
expect(() =>
|
|
137
|
+
defineConfig({
|
|
138
|
+
drivers: {
|
|
139
|
+
store: {
|
|
140
|
+
sql: { dev: "postgres", test: "memory", prod: "postgres" },
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
}),
|
|
144
|
+
).toThrow(/pglite/);
|
|
81
145
|
});
|
|
82
146
|
});
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Driver-map defaults — per-key merge onto the real established defaults,
|
|
3
|
+
* never a whole-object replace and never leaking across driver maps.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, test } from "bun:test";
|
|
7
|
+
import { mergeEnvDriverMap } from "./index.ts";
|
|
8
|
+
import {
|
|
9
|
+
CHANNEL_EMAIL_DEFAULTS,
|
|
10
|
+
CHANNEL_SMS_DEFAULTS,
|
|
11
|
+
CLOCK_DEFAULTS,
|
|
12
|
+
JOURNAL_DEFAULTS,
|
|
13
|
+
resolveEffectiveDrivers,
|
|
14
|
+
SIGNAL_DEFAULTS,
|
|
15
|
+
STORE_FILES_DEFAULTS,
|
|
16
|
+
STORE_KV_DEFAULTS,
|
|
17
|
+
STORE_SQL_DEFAULTS,
|
|
18
|
+
VAULT_DEFAULTS,
|
|
19
|
+
} from "./driver-defaults.ts";
|
|
20
|
+
|
|
21
|
+
describe("mergeEnvDriverMap", () => {
|
|
22
|
+
test("an unset key keeps the real default, not a sibling key's value", () => {
|
|
23
|
+
const merged = mergeEnvDriverMap({ test: "pglite" }, STORE_SQL_DEFAULTS);
|
|
24
|
+
expect(merged).toEqual({
|
|
25
|
+
dev: "postgres",
|
|
26
|
+
test: "pglite",
|
|
27
|
+
prod: "postgres",
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("undefined override yields the untouched default map", () => {
|
|
32
|
+
expect(mergeEnvDriverMap(undefined, STORE_KV_DEFAULTS)).toEqual(STORE_KV_DEFAULTS);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("a fully-specified override wins on every key", () => {
|
|
36
|
+
const override = { dev: "a", test: "b", prod: "c" };
|
|
37
|
+
expect(mergeEnvDriverMap(override, STORE_SQL_DEFAULTS)).toEqual(override);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("resolveEffectiveDrivers", () => {
|
|
42
|
+
test("`{ store: { sql: { test: 'pglite' } } }` keeps postgres on dev/prod", () => {
|
|
43
|
+
const effective = resolveEffectiveDrivers({
|
|
44
|
+
store: { sql: { test: "pglite" } },
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
expect(effective.store.sql).toEqual({
|
|
48
|
+
dev: "postgres",
|
|
49
|
+
test: "pglite",
|
|
50
|
+
prod: "postgres",
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("every other driver stays at its full, real, untouched default map", () => {
|
|
55
|
+
const effective = resolveEffectiveDrivers({
|
|
56
|
+
store: { sql: { test: "pglite" } },
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
expect(effective.store.kv).toEqual(STORE_KV_DEFAULTS);
|
|
60
|
+
expect(effective.store.files).toEqual(STORE_FILES_DEFAULTS);
|
|
61
|
+
expect(effective.signal).toEqual(SIGNAL_DEFAULTS);
|
|
62
|
+
expect(effective.clock).toEqual(CLOCK_DEFAULTS);
|
|
63
|
+
expect(effective.journal).toEqual(JOURNAL_DEFAULTS);
|
|
64
|
+
expect(effective.vault).toEqual(VAULT_DEFAULTS);
|
|
65
|
+
expect(effective.channel.email).toEqual(CHANNEL_EMAIL_DEFAULTS);
|
|
66
|
+
expect(effective.channel.sms).toEqual(CHANNEL_SMS_DEFAULTS);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("overriding one driver's map has zero effect on a sibling driver's defaults", () => {
|
|
70
|
+
const effective = resolveEffectiveDrivers({
|
|
71
|
+
store: { kv: { dev: "redis" } },
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(effective.store.kv).toEqual({
|
|
75
|
+
dev: "redis",
|
|
76
|
+
test: "memory",
|
|
77
|
+
prod: "redis",
|
|
78
|
+
});
|
|
79
|
+
expect(effective.store.sql).toEqual(STORE_SQL_DEFAULTS);
|
|
80
|
+
expect(effective.store.files).toEqual(STORE_FILES_DEFAULTS);
|
|
81
|
+
expect(effective.signal).toEqual(SIGNAL_DEFAULTS);
|
|
82
|
+
expect(effective.vault).toEqual(VAULT_DEFAULTS);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("overriding one env key leaves the other two at real defaults for that driver", () => {
|
|
86
|
+
const effective = resolveEffectiveDrivers({
|
|
87
|
+
vault: { dev: "keychain" },
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
expect(effective.vault).toEqual({
|
|
91
|
+
dev: "keychain",
|
|
92
|
+
test: "memory",
|
|
93
|
+
prod: "vault",
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("no drivers config at all yields the real, untouched defaults for every map", () => {
|
|
98
|
+
const effective = resolveEffectiveDrivers(undefined);
|
|
99
|
+
expect(effective).toEqual({
|
|
100
|
+
store: {
|
|
101
|
+
sql: STORE_SQL_DEFAULTS,
|
|
102
|
+
kv: STORE_KV_DEFAULTS,
|
|
103
|
+
files: STORE_FILES_DEFAULTS,
|
|
104
|
+
},
|
|
105
|
+
signal: SIGNAL_DEFAULTS,
|
|
106
|
+
clock: CLOCK_DEFAULTS,
|
|
107
|
+
journal: JOURNAL_DEFAULTS,
|
|
108
|
+
vault: VAULT_DEFAULTS,
|
|
109
|
+
channel: {
|
|
110
|
+
email: CHANNEL_EMAIL_DEFAULTS,
|
|
111
|
+
sms: CHANNEL_SMS_DEFAULTS,
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|