okengine 0.10.2 → 0.10.3
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 +1 -1
- package/site/content/docs/ai/mcp.mdx +0 -1
- package/site/content/docs/elements/ai.mdx +0 -6
- package/site/content/docs/elements/channel.mdx +0 -6
- package/site/content/docs/elements/clock.mdx +0 -6
- package/site/content/docs/elements/flow.mdx +0 -7
- package/site/content/docs/elements/gate.mdx +0 -6
- package/site/content/docs/elements/signal.mdx +0 -6
- package/site/content/docs/elements/store.mdx +8 -15
- package/site/content/docs/elements/vault.mdx +0 -6
- package/site/content/docs/get-started/basic-usage.mdx +0 -6
- package/site/content/docs/get-started/why.mdx +1 -2
- package/site/content/docs/index.mdx +0 -1
- package/site/content/docs/meta.json +0 -1
- package/site/content/docs/reference/fx.mdx +3 -3
- package/src/cli/ai-setup/ai-setup.test.ts +3 -1
- package/src/cli/build.ts +7 -8
- package/src/cli/dev.test.ts +88 -1
- package/src/cli/dev.ts +15 -13
- package/src/cli/doctor.ts +98 -5
- package/src/cli/load-config.images.test.ts +31 -1
- package/src/cli/load-config.ts +2 -2
- package/src/cli/safe-defaults.test.ts +1 -1
- package/src/compiler/extract.ts +12 -0
- package/src/compiler/fixtures/skyport/oke.config.ts +4 -2
- package/src/compiler/generate-adopt.ts +27 -1
- package/src/config/driver-defaults.test.ts +122 -0
- package/src/config/driver-defaults.ts +186 -0
- package/src/config/index.ts +97 -7
- package/src/docker/images-config.test.ts +168 -0
- package/src/kernel/boot-bind/channel.ts +12 -4
- package/src/kernel/boot-bind/clock.ts +3 -3
- package/src/kernel/boot-bind/gate.ts +7 -4
- package/src/kernel/boot-bind/journal.ts +3 -3
- package/src/kernel/boot-bind/signal.ts +3 -1
- package/src/kernel/boot-bind/store.test.ts +19 -0
- package/src/kernel/boot-bind/store.ts +24 -9
- package/src/kernel/boot-bind/vault.ts +3 -3
- 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
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ImagesConfig` (config surface, nested) → internal flat role map.
|
|
3
|
+
*
|
|
4
|
+
* Two guarantees:
|
|
5
|
+
* 1. Every built-in image recipe is reachable through the nested shape,
|
|
6
|
+
* correctly placed under its owning element (or flat, for roles with no
|
|
7
|
+
* driver counterpart) — the type-safety gap this closes.
|
|
8
|
+
* 2. A nested config produces byte-identical `deriveInfrastructure()` output
|
|
9
|
+
* (Dockerfile / compose / stack env) to the flat-shape equivalent it
|
|
10
|
+
* replaces — nesting is a config-surface change only, never an internal
|
|
11
|
+
* representation change.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, expect, test } from "bun:test";
|
|
15
|
+
import { flattenImagesConfig, type ImagesConfig } from "../config/index.ts";
|
|
16
|
+
import { deriveInfrastructure } from "./derive.ts";
|
|
17
|
+
import { builtinRecipes, recipeFor } from "./recipes/index.ts";
|
|
18
|
+
import type { ServiceCredentials } from "./types.ts";
|
|
19
|
+
|
|
20
|
+
describe("ImagesConfig nesting — recipe coverage", () => {
|
|
21
|
+
test("every built-in recipe id is reachable, correctly nested/flat by role", () => {
|
|
22
|
+
const cases: ReadonlyArray<{ images: ImagesConfig; role: string; image: string }> = [
|
|
23
|
+
// store.sql — postgres-family
|
|
24
|
+
{
|
|
25
|
+
images: { store: { sql: "postgres:18-alpine" } },
|
|
26
|
+
role: "store.sql",
|
|
27
|
+
image: "postgres:18-alpine",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
images: { store: { sql: "cockroachdb/cockroach:v24.1.0" } },
|
|
31
|
+
role: "store.sql",
|
|
32
|
+
image: "cockroachdb/cockroach:v24.1.0",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
images: { store: { sql: "yugabytedb/yugabyte:2024.1.0.0-b1" } },
|
|
36
|
+
role: "store.sql",
|
|
37
|
+
image: "yugabytedb/yugabyte:2024.1.0.0-b1",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
images: { store: { sql: "timescale/timescaledb:2.15.0-pg16" } },
|
|
41
|
+
role: "store.sql",
|
|
42
|
+
image: "timescale/timescaledb:2.15.0-pg16",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
images: { store: { sql: "supabase/postgres:15.1.0.117" } },
|
|
46
|
+
role: "store.sql",
|
|
47
|
+
image: "supabase/postgres:15.1.0.117",
|
|
48
|
+
},
|
|
49
|
+
// store.kv — redis-family
|
|
50
|
+
{ images: { store: { kv: "redis:8-alpine" } }, role: "store.kv", image: "redis:8-alpine" },
|
|
51
|
+
{
|
|
52
|
+
images: { store: { kv: "valkey/valkey:8-alpine" } },
|
|
53
|
+
role: "store.kv",
|
|
54
|
+
image: "valkey/valkey:8-alpine",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
images: { store: { kv: "docker.dragonflydb.io/dragonflydb/dragonfly:v1.24.0" } },
|
|
58
|
+
role: "store.kv",
|
|
59
|
+
image: "docker.dragonflydb.io/dragonflydb/dragonfly:v1.24.0",
|
|
60
|
+
},
|
|
61
|
+
// store.files / store.index
|
|
62
|
+
{
|
|
63
|
+
images: { store: { files: "rustfs/rustfs:1.0.0-beta.11" } },
|
|
64
|
+
role: "store.files",
|
|
65
|
+
image: "rustfs/rustfs:1.0.0-beta.11",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
images: { store: { index: "getmeili/meilisearch:v1.37" } },
|
|
69
|
+
role: "store.index",
|
|
70
|
+
image: "getmeili/meilisearch:v1.37",
|
|
71
|
+
},
|
|
72
|
+
// channel.email
|
|
73
|
+
{
|
|
74
|
+
images: { channel: { email: "axllent/mailpit:v1.22.3" } },
|
|
75
|
+
role: "channel.email",
|
|
76
|
+
image: "axllent/mailpit:v1.22.3",
|
|
77
|
+
},
|
|
78
|
+
// flat roles — no driver counterpart in DriversConfig
|
|
79
|
+
{
|
|
80
|
+
images: { vault: "openbao/openbao:2.6.1" },
|
|
81
|
+
role: "vault",
|
|
82
|
+
image: "openbao/openbao:2.6.1",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
images: { ai: "ghcr.io/ggml-org/llama.cpp:server-b10290" },
|
|
86
|
+
role: "ai",
|
|
87
|
+
image: "ghcr.io/ggml-org/llama.cpp:server-b10290",
|
|
88
|
+
},
|
|
89
|
+
{ images: { ai: "vllm/vllm-openai:v0.26.0" }, role: "ai", image: "vllm/vllm-openai:v0.26.0" },
|
|
90
|
+
{
|
|
91
|
+
images: { ai: "lmsysorg/sglang:v0.5.16-runtime" },
|
|
92
|
+
role: "ai",
|
|
93
|
+
image: "lmsysorg/sglang:v0.5.16-runtime",
|
|
94
|
+
},
|
|
95
|
+
{ images: { ai: "ollama/ollama:0.32.6" }, role: "ai", image: "ollama/ollama:0.32.6" },
|
|
96
|
+
{
|
|
97
|
+
images: { pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.51" },
|
|
98
|
+
role: "pgdog",
|
|
99
|
+
image: "ghcr.io/pgdogdev/pgdog:v0.1.51",
|
|
100
|
+
},
|
|
101
|
+
{ images: { proxy: "caddy:2-alpine" }, role: "proxy", image: "caddy:2-alpine" },
|
|
102
|
+
{ images: { proxy: "traefik:v3.1" }, role: "proxy", image: "traefik:v3.1" },
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
const matchedIds = new Set<string>();
|
|
106
|
+
for (const { images, role, image } of cases) {
|
|
107
|
+
// The nested literal flattens to exactly the dotted/flat role key the
|
|
108
|
+
// rest of the pipeline (buildSpecs, credentials, env prefixes) expects.
|
|
109
|
+
expect(flattenImagesConfig(images)).toEqual({ [role]: image });
|
|
110
|
+
matchedIds.add(recipeFor(image).id);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
expect(matchedIds).toEqual(new Set(builtinRecipes.map((r) => r.id)));
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe("ImagesConfig nesting — compose output parity", () => {
|
|
118
|
+
test("nested config derives byte-identical output to its flat-shape equivalent", () => {
|
|
119
|
+
const flatImages: Readonly<Record<string, string>> = {
|
|
120
|
+
"store.sql": "postgres:18-alpine",
|
|
121
|
+
pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.51",
|
|
122
|
+
"store.kv": "redis:8-alpine",
|
|
123
|
+
"store.files": "rustfs/rustfs:1.0.0-beta.11",
|
|
124
|
+
"channel.email": "axllent/mailpit:v1.22.3",
|
|
125
|
+
vault: "openbao/openbao:2.6.1",
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const nestedImages: ImagesConfig = {
|
|
129
|
+
store: {
|
|
130
|
+
sql: "postgres:18-alpine",
|
|
131
|
+
kv: "redis:8-alpine",
|
|
132
|
+
files: "rustfs/rustfs:1.0.0-beta.11",
|
|
133
|
+
},
|
|
134
|
+
channel: { email: "axllent/mailpit:v1.22.3" },
|
|
135
|
+
vault: "openbao/openbao:2.6.1",
|
|
136
|
+
pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.51",
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Same nested→flat set, written in a different field order — proves the
|
|
140
|
+
// parity holds independent of source object key order.
|
|
141
|
+
expect(flattenImagesConfig(nestedImages)).toEqual(flatImages);
|
|
142
|
+
|
|
143
|
+
const credentials: Readonly<Record<string, ServiceCredentials>> = {
|
|
144
|
+
"store.sql": { user: "oke", password: "fixed-pw-sql", database: "oke" },
|
|
145
|
+
"store.kv": { user: "oke", password: "fixed-pw-kv", database: "oke" },
|
|
146
|
+
"store.files": { user: "oke", password: "fixed-pw-files", database: "oke" },
|
|
147
|
+
"channel.email": { user: "oke", password: "fixed-pw-email", database: "oke" },
|
|
148
|
+
vault: { user: "oke", password: "fixed-pw-vault", database: "oke" },
|
|
149
|
+
pgdog: { user: "oke", password: "fixed-pw-pgdog", database: "oke" },
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const fromFlat = deriveInfrastructure({
|
|
153
|
+
images: flatImages,
|
|
154
|
+
app: "images-nesting-parity",
|
|
155
|
+
credentials,
|
|
156
|
+
});
|
|
157
|
+
const fromNested = deriveInfrastructure({
|
|
158
|
+
images: flattenImagesConfig(nestedImages),
|
|
159
|
+
app: "images-nesting-parity",
|
|
160
|
+
credentials,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
expect(fromNested.specs).toEqual(fromFlat.specs);
|
|
164
|
+
expect(fromNested.files).toEqual(fromFlat.files);
|
|
165
|
+
expect(fromNested.stackEnv).toEqual(fromFlat.stackEnv);
|
|
166
|
+
expect(fromNested.composeFiles).toEqual(fromFlat.composeFiles);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { resolveDriverId, type ConfigEnv } from "../../config/index.ts";
|
|
6
|
+
import {
|
|
7
|
+
CHANNEL_EMAIL_DEFAULTS,
|
|
8
|
+
CHANNEL_SMS_DEFAULTS,
|
|
9
|
+
dockerFlagDefaults,
|
|
10
|
+
} from "../../config/driver-defaults.ts";
|
|
6
11
|
import { openConsoleChannel } from "../../drivers/channel-console.ts";
|
|
7
12
|
import { openMsegatChannel } from "../../drivers/channel-msegat.ts";
|
|
8
13
|
import { openResendChannel } from "../../drivers/channel-resend.ts";
|
|
@@ -81,9 +86,12 @@ export function resolveEmailDriverId(
|
|
|
81
86
|
env: ConfigEnv,
|
|
82
87
|
docker: boolean,
|
|
83
88
|
): string {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
// Defaults cover every ConfigEnv key, so this is never undefined.
|
|
90
|
+
return resolveDriverId(
|
|
91
|
+
options.config?.drivers?.channel?.email,
|
|
92
|
+
env,
|
|
93
|
+
dockerFlagDefaults(CHANNEL_EMAIL_DEFAULTS, docker),
|
|
94
|
+
)!;
|
|
87
95
|
}
|
|
88
96
|
|
|
89
97
|
/**
|
|
@@ -93,7 +101,7 @@ export function resolveEmailDriverId(
|
|
|
93
101
|
* @param env - Active environment
|
|
94
102
|
*/
|
|
95
103
|
export function resolveSmsDriverId(options: BootOptions, env: ConfigEnv): string | undefined {
|
|
96
|
-
return resolveDriverId(options.config?.drivers?.channel?.sms, env);
|
|
104
|
+
return resolveDriverId(options.config?.drivers?.channel?.sms, env, CHANNEL_SMS_DEFAULTS);
|
|
97
105
|
}
|
|
98
106
|
|
|
99
107
|
/**
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from "../../elements/clock.ts";
|
|
16
16
|
import { createPostgresCronStore } from "../../drivers/clock-postgres.ts";
|
|
17
17
|
import { resolveDriverId, type ConfigEnv } from "../../config/index.ts";
|
|
18
|
+
import { CLOCK_DEFAULTS } from "../../config/driver-defaults.ts";
|
|
18
19
|
import type { BootOptions } from "../boot.ts";
|
|
19
20
|
|
|
20
21
|
/** Result of binding a clock runtime. */
|
|
@@ -33,9 +34,8 @@ export const DEFAULT_FILE_CRON_PATH = ".oke/crons.json";
|
|
|
33
34
|
* @param env - Active environment
|
|
34
35
|
*/
|
|
35
36
|
export function resolveClockDriverId(options: BootOptions, env: ConfigEnv): string {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return env === "test" ? "frozen" : "memory";
|
|
37
|
+
// Defaults cover every ConfigEnv key, so this is never undefined.
|
|
38
|
+
return resolveDriverId(options.config?.drivers?.clock, env, CLOCK_DEFAULTS)!;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/**
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { resolveDriverId, type ConfigEnv } from "../../config/index.ts";
|
|
6
|
+
import { dockerFlagDefaults, STORE_KV_DEFAULTS } from "../../config/driver-defaults.ts";
|
|
6
7
|
import { memoryDrivers } from "../../drivers/memory.ts";
|
|
7
8
|
import { redisDriver } from "../../drivers/redis.ts";
|
|
8
9
|
import type { KvClientLike } from "../../drivers/types.ts";
|
|
@@ -27,10 +28,12 @@ export function resolveGateKvDriverId(
|
|
|
27
28
|
const fromEnv = process.env.OKE_KV_DRIVER?.trim();
|
|
28
29
|
if (docker && fromEnv === "redis") return "redis";
|
|
29
30
|
if (docker && fromEnv === "memory") return "memory";
|
|
30
|
-
const resolved = resolveDriverId(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
const resolved = resolveDriverId(
|
|
32
|
+
options.config?.drivers?.store?.kv,
|
|
33
|
+
env,
|
|
34
|
+
dockerFlagDefaults(STORE_KV_DEFAULTS, docker),
|
|
35
|
+
);
|
|
36
|
+
return resolved === "redis" ? "redis" : "memory";
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
function kvUrlFor(docker: boolean): string {
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from "../journal.ts";
|
|
13
13
|
import { createPostgresJournalStore } from "../../drivers/journal-postgres.ts";
|
|
14
14
|
import { resolveDriverId, type ConfigEnv } from "../../config/index.ts";
|
|
15
|
+
import { JOURNAL_DEFAULTS } from "../../config/driver-defaults.ts";
|
|
15
16
|
import type { BootOptions } from "../boot.ts";
|
|
16
17
|
|
|
17
18
|
/** Bound journal runtime — store + this instance's lease identity. */
|
|
@@ -37,9 +38,8 @@ export const DEFAULT_FILE_JOURNAL_PATH = ".oke/journal.json";
|
|
|
37
38
|
* @param env - Active environment
|
|
38
39
|
*/
|
|
39
40
|
export function resolveJournalDriverId(options: BootOptions, env: ConfigEnv): string {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return "memory";
|
|
41
|
+
// Defaults cover every ConfigEnv key, so this is never undefined.
|
|
42
|
+
return resolveDriverId(options.config?.drivers?.journal, env, JOURNAL_DEFAULTS)!;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/**
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { resolveDriverId, type ConfigEnv } from "../../config/index.ts";
|
|
6
|
+
import { SIGNAL_DEFAULTS } from "../../config/driver-defaults.ts";
|
|
6
7
|
import { memorySignalDriver } from "../../drivers/signal-memory.ts";
|
|
7
8
|
import { createBunSignalRedisClient, redisSignalDriver } from "../../drivers/signal-redis.ts";
|
|
8
9
|
import type { SignalRedisClientLike } from "../../drivers/signal-types.ts";
|
|
@@ -17,7 +18,8 @@ import type { BootOptions } from "../boot.ts";
|
|
|
17
18
|
* @param env - Active environment
|
|
18
19
|
*/
|
|
19
20
|
export function resolveSignalDriverId(options: BootOptions, env: ConfigEnv): string {
|
|
20
|
-
|
|
21
|
+
// Defaults cover every ConfigEnv key, so this is never undefined.
|
|
22
|
+
return resolveDriverId(options.config?.drivers?.signal, env, SIGNAL_DEFAULTS)!;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
function redisUrlFor(docker: boolean): string | undefined {
|
|
@@ -78,6 +78,25 @@ describe("bindStore driver resolution", () => {
|
|
|
78
78
|
expect(resolveKvDriverId({}, "docker", true)).toBe("redis");
|
|
79
79
|
expect(resolveFilesDriverId({}, "docker", true)).toBe("s3");
|
|
80
80
|
});
|
|
81
|
+
|
|
82
|
+
test("pinning only `local` never leaks into docker/test/prod — each keeps its real default", () => {
|
|
83
|
+
const options = {
|
|
84
|
+
config: {
|
|
85
|
+
drivers: {
|
|
86
|
+
store: {
|
|
87
|
+
sql: { local: "pglite" },
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
expect(resolveSqlDriverId(options, "local", false)).toBe("pglite");
|
|
93
|
+
expect(resolveSqlDriverId(options, "docker", true)).toBe("postgres");
|
|
94
|
+
expect(resolveSqlDriverId(options, "test", false)).toBe("memory");
|
|
95
|
+
expect(resolveSqlDriverId(options, "prod", true)).toBe("postgres");
|
|
96
|
+
// kv / files are untouched by the sql-only override.
|
|
97
|
+
expect(resolveKvDriverId(options, "local", false)).toBe("memory");
|
|
98
|
+
expect(resolveKvDriverId(options, "docker", true)).toBe("redis");
|
|
99
|
+
});
|
|
81
100
|
});
|
|
82
101
|
|
|
83
102
|
describe("bindStore files fs multi-instance warn", () => {
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { resolveDomainDdlMode, resolveDriverId, type ConfigEnv } from "../../config/index.ts";
|
|
6
|
+
import {
|
|
7
|
+
dockerFlagDefaults,
|
|
8
|
+
STORE_FILES_DEFAULTS,
|
|
9
|
+
STORE_KV_DEFAULTS,
|
|
10
|
+
STORE_SQL_DEFAULTS,
|
|
11
|
+
} from "../../config/driver-defaults.ts";
|
|
6
12
|
import { fsDriver } from "../../drivers/fs.ts";
|
|
7
13
|
import { libsqlDriver, libsqlIndexDriver } from "../../drivers/libsql.ts";
|
|
8
14
|
import { meilisearchDriver } from "../../drivers/meilisearch.ts";
|
|
@@ -138,9 +144,12 @@ function resolveAutoPush(options: BootOptions): boolean {
|
|
|
138
144
|
export function resolveSqlDriverId(options: BootOptions, env: ConfigEnv, docker: boolean): string {
|
|
139
145
|
const fromEnv = process.env.OKE_SQL_DRIVER?.trim();
|
|
140
146
|
if (docker && fromEnv) return fromEnv;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
147
|
+
// Defaults cover every ConfigEnv key, so this is never undefined.
|
|
148
|
+
return resolveDriverId(
|
|
149
|
+
options.config?.drivers?.store?.sql,
|
|
150
|
+
env,
|
|
151
|
+
dockerFlagDefaults(STORE_SQL_DEFAULTS, docker),
|
|
152
|
+
)!;
|
|
144
153
|
}
|
|
145
154
|
|
|
146
155
|
/**
|
|
@@ -151,9 +160,12 @@ export function resolveSqlDriverId(options: BootOptions, env: ConfigEnv, docker:
|
|
|
151
160
|
export function resolveKvDriverId(options: BootOptions, env: ConfigEnv, docker: boolean): string {
|
|
152
161
|
const fromEnv = process.env.OKE_KV_DRIVER?.trim();
|
|
153
162
|
if (docker && fromEnv) return fromEnv;
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
163
|
+
// Defaults cover every ConfigEnv key, so this is never undefined.
|
|
164
|
+
return resolveDriverId(
|
|
165
|
+
options.config?.drivers?.store?.kv,
|
|
166
|
+
env,
|
|
167
|
+
dockerFlagDefaults(STORE_KV_DEFAULTS, docker),
|
|
168
|
+
)!;
|
|
157
169
|
}
|
|
158
170
|
|
|
159
171
|
/**
|
|
@@ -168,9 +180,12 @@ export function resolveFilesDriverId(
|
|
|
168
180
|
): string {
|
|
169
181
|
const fromEnv = process.env.OKE_FILES_DRIVER?.trim();
|
|
170
182
|
if (docker && fromEnv) return fromEnv;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
183
|
+
// Defaults cover every ConfigEnv key, so this is never undefined.
|
|
184
|
+
return resolveDriverId(
|
|
185
|
+
options.config?.drivers?.store?.files,
|
|
186
|
+
env,
|
|
187
|
+
dockerFlagDefaults(STORE_FILES_DEFAULTS, docker),
|
|
188
|
+
)!;
|
|
174
189
|
}
|
|
175
190
|
|
|
176
191
|
/**
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { resolveDriverId, type ConfigEnv } from "../../config/index.ts";
|
|
6
|
+
import { VAULT_DEFAULTS } from "../../config/driver-defaults.ts";
|
|
6
7
|
import { createVaultRuntime, type VaultRuntime } from "../../elements/vault.ts";
|
|
7
8
|
import { buildVaultBootChain, normalizeVaultDriverId } from "../../elements/vault/boot-chain.ts";
|
|
8
9
|
import type { BootOptions } from "../boot.ts";
|
|
@@ -14,9 +15,8 @@ import type { BootOptions } from "../boot.ts";
|
|
|
14
15
|
* @param env - Active environment
|
|
15
16
|
*/
|
|
16
17
|
export function resolveVaultDriverId(options: BootOptions, env: ConfigEnv): string {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return env === "test" ? "memory" : "env";
|
|
18
|
+
// Defaults cover every ConfigEnv key, so this is never undefined.
|
|
19
|
+
return resolveDriverId(options.config?.drivers?.vault, env, VAULT_DEFAULTS)!;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Access"
|
|
3
|
-
description: "Identities, roles, API keys."
|
|
4
|
-
icon: "Users"
|
|
5
|
-
source: "docs/spec/console.md"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
Answers: **identities, roles, API keys**
|
|
9
|
-
|
|
10
|
-
<Callout title="Governing rule">
|
|
11
|
-
Granting an application scope to an operator is impossible in the UI — taught by absence, not
|
|
12
|
-
refusal.
|
|
13
|
-
</Callout>
|
|
14
|
-
|
|
15
|
-
## What this panel shows
|
|
16
|
-
|
|
17
|
-
<Cards>
|
|
18
|
-
<Card title="Two planes" description="Operators and application users never mix." />
|
|
19
|
-
<Card title="Key creation" description="Value shown once; attenuation to creator scopes only." />
|
|
20
|
-
<Card title="Revocation" description="Blast radius plus honest JWT validity delay." />
|
|
21
|
-
<Card title="Hygiene" description="Unused keys, never-signed-in operators, expired invites." />
|
|
22
|
-
</Cards>
|
|
23
|
-
|
|
24
|
-
## Catalog
|
|
25
|
-
|
|
26
|
-
<Cards>
|
|
27
|
-
<Card title="Dev" description="✓" />
|
|
28
|
-
<Card title="Prod" description="✓ (admin)" />
|
|
29
|
-
</Cards>
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "AI"
|
|
3
|
-
description: "Prompt versions, eval scores, cost, agent runs."
|
|
4
|
-
icon: "Sparkles"
|
|
5
|
-
source: "docs/spec/console.md"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
Answers: **prompt versions, eval scores, cost, agent runs**
|
|
9
|
-
|
|
10
|
-
<Callout title="Governing rule">
|
|
11
|
-
Everything else in the Console is deterministic; this panel is built on distributions, not single
|
|
12
|
-
values.
|
|
13
|
-
</Callout>
|
|
14
|
-
|
|
15
|
-
## What this panel shows
|
|
16
|
-
|
|
17
|
-
<Cards>
|
|
18
|
-
<Card title="Prompt versions" description="A version bump is Manifest Diff blast radius." />
|
|
19
|
-
<Card title="Eval + shape" description="Schema-validation failure is its own class." />
|
|
20
|
-
<Card
|
|
21
|
-
title="Agent tools"
|
|
22
|
-
description="Tools are the app’s own flows — undeclared reach is denied and shown."
|
|
23
|
-
/>
|
|
24
|
-
<Card
|
|
25
|
-
title="Budgets"
|
|
26
|
-
description="Cost, semantic cache, and `allowPii` as standing review surfaces."
|
|
27
|
-
/>
|
|
28
|
-
</Cards>
|
|
29
|
-
|
|
30
|
-
## Catalog
|
|
31
|
-
|
|
32
|
-
<Cards>
|
|
33
|
-
<Card title="Dev" description="full" />
|
|
34
|
-
<Card title="Prod" description="read + budgets" />
|
|
35
|
-
</Cards>
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Architecture"
|
|
3
|
-
description: "How it all connects — the diagram that is the code."
|
|
4
|
-
icon: "Network"
|
|
5
|
-
source: "docs/spec/console.md"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
Answers: **how it all connects — the diagram that _is_ the code**
|
|
9
|
-
|
|
10
|
-
<Callout title="Governing rule">
|
|
11
|
-
Flows answers “which one”; Architecture answers “what shape”. Never shows the whole system by
|
|
12
|
-
default.
|
|
13
|
-
</Callout>
|
|
14
|
-
|
|
15
|
-
## What this panel shows
|
|
16
|
-
|
|
17
|
-
<Cards>
|
|
18
|
-
<Card title="Unit clusters" description="Default aggregated edges; focus one or two hops." />
|
|
19
|
-
<Card title="Element layers" description="Toggle data, messaging, time, external edges." />
|
|
20
|
-
<Card
|
|
21
|
-
title="Live traffic"
|
|
22
|
-
description="Edge thickness from real traffic; dashed = never traversed."
|
|
23
|
-
/>
|
|
24
|
-
<Card
|
|
25
|
-
title="Pathologies"
|
|
26
|
-
description="Cycles, god nodes, orphan signals, SPOFs — computed from the graph."
|
|
27
|
-
/>
|
|
28
|
-
</Cards>
|
|
29
|
-
|
|
30
|
-
## Catalog
|
|
31
|
-
|
|
32
|
-
<Cards>
|
|
33
|
-
<Card title="Dev" description="✓" />
|
|
34
|
-
<Card title="Prod" description="✓" />
|
|
35
|
-
</Cards>
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Channels"
|
|
3
|
-
description: "Templates, delivery receipts, bounces, opt-outs."
|
|
4
|
-
icon: "Mailbox"
|
|
5
|
-
source: "docs/spec/console.md"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
Answers: **templates, delivery receipts, bounces, opt-outs, deliverability (SPF/DKIM/DMARC)**
|
|
9
|
-
|
|
10
|
-
<Callout title="Governing rule">
|
|
11
|
-
Suppression is not failure — the taxonomy of “did not arrive” has seven states with verdicts.
|
|
12
|
-
</Callout>
|
|
13
|
-
|
|
14
|
-
## What this panel shows
|
|
15
|
-
|
|
16
|
-
<Cards>
|
|
17
|
-
<Card title="Dev inbox" description="`console` driver lands every medium locally." />
|
|
18
|
-
<Card
|
|
19
|
-
title="Deliverability"
|
|
20
|
-
description="SPF/DKIM/DMARC, bounces, complaints, suppression list."
|
|
21
|
-
/>
|
|
22
|
-
<Card
|
|
23
|
-
title="Fallback chains"
|
|
24
|
-
description="Recorded as chains (e.g. WhatsApp → SMS), not single outcomes."
|
|
25
|
-
/>
|
|
26
|
-
<Card
|
|
27
|
-
title="Locale previews"
|
|
28
|
-
description="Template data bound to schema; RTL-accurate previews."
|
|
29
|
-
/>
|
|
30
|
-
</Cards>
|
|
31
|
-
|
|
32
|
-
## Catalog
|
|
33
|
-
|
|
34
|
-
<Cards>
|
|
35
|
-
<Card title="Dev" description="full + console inbox" />
|
|
36
|
-
<Card title="Prod" description="send test, inspect delivery" />
|
|
37
|
-
</Cards>
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Clock"
|
|
3
|
-
description: "Upcoming crons, sleeping durable flows, journal."
|
|
4
|
-
icon: "Clock"
|
|
5
|
-
source: "docs/spec/console.md"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
Answers: **upcoming crons, sleeping durable flows, journal**
|
|
9
|
-
|
|
10
|
-
<Callout title="Governing rule">
|
|
11
|
-
Looks like time — a forward timeline for schedules and pending wakes, not a flat grid.
|
|
12
|
-
</Callout>
|
|
13
|
-
|
|
14
|
-
## What this panel shows
|
|
15
|
-
|
|
16
|
-
<Cards>
|
|
17
|
-
<Card title="Schedules" description="Drift, overdue, missed runs · catch-up one, lease holder." />
|
|
18
|
-
<Card title="Pending wakes" description="Every sleeping durable flow and when it wakes." />
|
|
19
|
-
<Card
|
|
20
|
-
title="DST warnings"
|
|
21
|
-
description="Gap or overlap badge — detect only, no schedule rewrite."
|
|
22
|
-
/>
|
|
23
|
-
<Card title="Actions" description="Run now, wake early, pause; edit when overridable." />
|
|
24
|
-
</Cards>
|
|
25
|
-
|
|
26
|
-
## Health numbers
|
|
27
|
-
|
|
28
|
-
Each cron row projects four numbers plus the lease holder:
|
|
29
|
-
|
|
30
|
-
| Field | Meaning |
|
|
31
|
-
| --------------- | ----------------------------------------------------------------- |
|
|
32
|
-
| Drift | How far the last run sat from the expected slot |
|
|
33
|
-
| Overdue | Whether the schedule is past due |
|
|
34
|
-
| Missed + policy | Slot count while down · always catch-up `"one"` (one fire, not N) |
|
|
35
|
-
| Lease | Which instance holds the leader lease (empty when none) |
|
|
36
|
-
|
|
37
|
-
## Actions
|
|
38
|
-
|
|
39
|
-
| Action | When |
|
|
40
|
-
| ------------- | ---------------------------------------------------------------------- |
|
|
41
|
-
| Pause | Any cron — not gated by `overridable` |
|
|
42
|
-
| Edit schedule | Only when the declaration has `overridable: true`; else loud refuse |
|
|
43
|
-
| Wake early | Sleeping durable run — advances `wakeAt` and can resume the journal |
|
|
44
|
-
| Run now | Still requires the leader lease across replicas that share a CronStore |
|
|
45
|
-
|
|
46
|
-
## Catalog
|
|
47
|
-
|
|
48
|
-
<Cards>
|
|
49
|
-
<Card title="Dev" description="full" />
|
|
50
|
-
<Card title="Prod" description="trigger/pause; edit if `overridable`" />
|
|
51
|
-
</Cards>
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Flows"
|
|
3
|
-
description: "What exists; call it; read its contract."
|
|
4
|
-
icon: "GitBranch"
|
|
5
|
-
source: "docs/spec/console.md"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
Answers: **what exists; call it; read its contract**
|
|
9
|
-
|
|
10
|
-
<Callout title="Governing rule">
|
|
11
|
-
Renders the one law as three columns: `Causes ← Flows → Effects` — not a tree.
|
|
12
|
-
</Callout>
|
|
13
|
-
|
|
14
|
-
## What this panel shows
|
|
15
|
-
|
|
16
|
-
<Cards>
|
|
17
|
-
<Card title="Causes column" description="Triggers and callers — what runs this." />
|
|
18
|
-
<Card title="Flows column" description="Context-adaptive centre with contracts and invoke." />
|
|
19
|
-
<Card title="Effects column" description="What changes — store, signal, channel, AI, vault." />
|
|
20
|
-
<Card
|
|
21
|
-
title="Flow drawer"
|
|
22
|
-
description="Workshop peek/expand — save as bun:test from a real response."
|
|
23
|
-
/>
|
|
24
|
-
</Cards>
|
|
25
|
-
|
|
26
|
-
## Catalog
|
|
27
|
-
|
|
28
|
-
<Cards>
|
|
29
|
-
<Card title="Dev" description="full + source links" />
|
|
30
|
-
<Card title="Prod" description="read + invoke per gates" />
|
|
31
|
-
</Cards>
|