okengine 0.6.0 → 0.7.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/AGENTS.md +2 -2
- package/README.md +98 -71
- package/package.json +4 -4
- package/site/content/docs/console/clock.mdx +25 -5
- package/site/content/docs/console/signals.mdx +13 -4
- package/site/content/docs/elements/ai.mdx +29 -2
- package/site/content/docs/elements/channel.mdx +90 -20
- package/site/content/docs/elements/clock.mdx +56 -24
- package/site/content/docs/elements/flow.mdx +2 -0
- package/site/content/docs/elements/gate.mdx +8 -1
- package/site/content/docs/elements/signal.mdx +173 -29
- package/site/content/docs/elements/store.mdx +464 -73
- package/site/content/docs/elements/vault.mdx +15 -5
- package/site/content/docs/get-started/basic-usage.mdx +13 -6
- package/site/content/docs/get-started/installation.mdx +49 -13
- package/site/content/docs/get-started/introduction.mdx +1 -1
- package/site/content/docs/reference/cli.md +30 -2
- package/site/content/docs/reference/configuration.mdx +18 -17
- package/site/content/docs/reference/environment-variables.mdx +44 -18
- package/site/content/docs/reference/errors.mdx +12 -11
- package/site/content/docs/reference/fx.mdx +15 -13
- package/site/content/docs/reference/security.md +3 -1
- package/src/cli/ai-setup/ai-setup.test.ts +144 -0
- package/src/cli/ai-setup/apply.ts +214 -0
- package/src/cli/ai-setup/catalog.ts +263 -0
- package/src/cli/ai-setup/detect-ollama.ts +166 -0
- package/src/cli/ai-setup/index.ts +228 -0
- package/src/cli/ai-setup/prompts.ts +649 -0
- package/src/cli/ai-setup/recommend.test.ts +100 -0
- package/src/cli/ai-setup/recommend.ts +203 -0
- package/src/cli/ai.ts +38 -0
- package/src/cli/db-auto-push.test.ts +6 -1
- package/src/cli/db-auto-push.ts +8 -3
- package/src/cli/dev-db-push.test.ts +59 -0
- package/src/cli/dev.test.ts +40 -0
- package/src/cli/dev.ts +55 -1
- package/src/cli/docker-clean.test.ts +179 -0
- package/src/cli/docker-clean.ts +406 -0
- package/src/cli/docker.ts +16 -4
- package/src/cli/ensure-drizzle-config.ts +1 -1
- package/src/cli/hero-meta.test.ts +6 -5
- package/src/cli/hero-meta.ts +7 -1
- package/src/cli/index.ts +5 -0
- package/src/cli/load-config.ts +4 -4
- package/src/cli/openbao-bootstrap.test.ts +1 -0
- package/src/cli/openbao-bootstrap.ts +9 -2
- package/src/cli/openbao-restart.integration.test.ts +106 -97
- package/src/cli/registry.ts +79 -1
- package/src/client/live-gap.test.ts +35 -0
- package/src/client/transport.test.ts +21 -0
- package/src/client/transport.ts +27 -5
- package/src/compiler/fixtures/skyport/oke.config.ts +1 -1
- package/src/config/define-config.test.ts +6 -6
- package/src/config/index.ts +1 -1
- package/src/console/server/console.test.ts +45 -0
- package/src/console/server/flows.ts +39 -9
- package/src/console/server/i18n.ts +41 -0
- package/src/console/server/vault.ts +12 -38
- package/src/console/ui/dist/assets/index-ClX0ZCe5.js +10 -0
- package/src/console/ui/dist/assets/{panel-access-BGv45snf.js → panel-access-ri1X9Otj.js} +1 -1
- package/src/console/ui/dist/assets/{panel-ai-B2S7LEii.js → panel-ai-DLHjRoJk.js} +1 -1
- package/src/console/ui/dist/assets/{panel-architecture-D7UJh91v.js → panel-architecture-DI3bQF3J.js} +1 -1
- package/src/console/ui/dist/assets/{panel-channels-9T3ybqRu.js → panel-channels-BDYWX29p.js} +1 -1
- package/src/console/ui/dist/assets/{panel-clock-Cb1UXGRQ.js → panel-clock-i-JpTjVB.js} +1 -1
- package/src/console/ui/dist/assets/{panel-diff-DmYbKWmN.js → panel-diff-CFuWxiXy.js} +1 -1
- package/src/console/ui/dist/assets/{panel-flows-PiHwT55z.js → panel-flows-B8TRhcoe.js} +1 -1
- package/src/console/ui/dist/assets/{panel-gates-BQGYXvjT.js → panel-gates-CfkBgco7.js} +1 -1
- package/src/console/ui/dist/assets/{panel-overview-BBnRO18l.js → panel-overview-DONDzBd2.js} +1 -1
- package/src/console/ui/dist/assets/{panel-plugins-D0PsmVw2.js → panel-plugins-DDJwTehL.js} +1 -1
- package/src/console/ui/dist/assets/{panel-runs-CWuRDe0r.js → panel-runs-D5zf-D9c.js} +1 -1
- package/src/console/ui/dist/assets/{panel-signals-Bbg4ewpP.js → panel-signals-Dsxdu_AR.js} +1 -1
- package/src/console/ui/dist/assets/{panel-store-CPCbsDRa.js → panel-store-hy7O8HOs.js} +1 -1
- package/src/console/ui/dist/assets/{panel-traces-DVAzuA_S.js → panel-traces-CBiAe5go.js} +1 -1
- package/src/console/ui/dist/assets/{panel-vault-D1_MvOmo.js → panel-vault-Za1GyJfM.js} +1 -1
- package/src/console/ui/dist/index.html +1 -1
- package/src/console/ui/shell/components/ui.tsx +5 -1
- package/src/console/ui/shell/setup/Wizard.tsx +26 -5
- package/src/docker/cleanup.test.ts +193 -0
- package/src/docker/cleanup.ts +355 -0
- package/src/docker/docker.test.ts +4 -0
- package/src/docker/dockerfile.integration.test.ts +126 -119
- package/src/docker/index.ts +19 -0
- package/src/docker/recipes/ollama.ts +10 -5
- package/src/docker/stack.integration.test.ts +118 -102
- package/src/drivers/ai-ollama-tools.integration.test.ts +8 -6
- package/src/drivers/ai-ollama.integration.test.ts +3 -19
- package/src/drivers/ai-ollama.ts +45 -2
- package/src/drivers/ai-providers.test.ts +31 -0
- package/src/drivers/channel-fcm.ts +49 -53
- package/src/drivers/channel-msegat.ts +61 -0
- package/src/drivers/channel-sently-map.ts +57 -0
- package/src/drivers/channel-sently.test.ts +99 -0
- package/src/drivers/channel-sndr.ts +28 -0
- package/src/drivers/channel-taqnyat.ts +57 -0
- package/src/drivers/channel-types.ts +79 -2
- package/src/drivers/channel-unifonic.ts +26 -43
- package/src/drivers/channel-wa-cloud.ts +33 -47
- package/src/drivers/channel-webpush.ts +39 -239
- package/src/drivers/index.ts +7 -0
- package/src/drivers/signal-engine.ts +98 -25
- package/src/drivers/signal-nats.ts +4 -4
- package/src/drivers/signal-postgres.ts +158 -64
- package/src/drivers/signal-redis.ts +4 -4
- package/src/drivers/signal-types.ts +61 -2
- package/src/drivers/vault-driver-removal.test.ts +5 -1
- package/src/elements/channel/costs.test.ts +2 -2
- package/src/elements/channel/costs.ts +14 -2
- package/src/elements/channel/mime.ts +11 -0
- package/src/elements/channel/runtime.ts +94 -0
- package/src/elements/channel/sndr-webhooks.test.ts +26 -0
- package/src/elements/channel.ts +10 -1
- package/src/elements/clock/chaos-child.ts +150 -0
- package/src/elements/clock/chaos.test.ts +204 -0
- package/src/elements/clock/reconcile.ts +110 -0
- package/src/elements/clock/runtime.ts +11 -0
- package/src/elements/clock.test.ts +164 -2
- package/src/elements/clock.ts +1 -0
- package/src/elements/gate/runtime.ts +6 -0
- package/src/elements/index.ts +9 -0
- package/src/elements/signal/chaos-child.ts +41 -4
- package/src/elements/signal/declare.ts +4 -1
- package/src/elements/signal/delivery-modes.test.ts +179 -0
- package/src/elements/signal/key-ordering.test.ts +306 -0
- package/src/elements/signal/lease-reclaim.test.ts +123 -0
- package/src/elements/signal/optional-emit.test.ts +76 -0
- package/src/elements/signal/order-lifecycle.test.ts +130 -0
- package/src/elements/signal/orphan-messages.test.ts +152 -0
- package/src/elements/signal/runtime.ts +11 -4
- package/src/elements/signal/schema-emit.test.ts +107 -0
- package/src/elements/signal.test.ts +89 -5
- package/src/elements/store/files-fx.ts +104 -0
- package/src/elements/store/files-image.test.ts +251 -0
- package/src/elements/store/files-image.ts +494 -0
- package/src/elements/store/runtime.ts +60 -0
- package/src/elements/store.ts +24 -0
- package/src/elements/vault/boot-chain.ts +150 -0
- package/src/elements/vault/runtime.ts +8 -0
- package/src/kernel/app.ts +3 -1
- package/src/kernel/boot-bind/channel.test.ts +68 -3
- package/src/kernel/boot-bind/channel.ts +93 -2
- package/src/kernel/boot-bind/clock.ts +52 -7
- package/src/kernel/boot-bind/gate.ts +71 -3
- package/src/kernel/boot-bind/honor-config.test.ts +247 -0
- package/src/kernel/boot-bind/signal.ts +64 -7
- package/src/kernel/boot-bind/vault.ts +27 -8
- package/src/kernel/boot.ts +10 -2
- package/src/kernel/errors.ts +8 -2
- package/src/kernel/fx.test.ts +13 -0
- package/src/kernel/fx.ts +27 -4
- package/src/plugins/auth-delivery.mailpit.integration.test.ts +10 -4
- package/src/release/exports.test.ts +26 -0
- package/src/release/exports.ts +64 -5
- package/src/release/index.ts +5 -0
- package/src/release/measure.exports.test.ts +13 -1
- package/src/release/measure.ts +76 -13
- package/src/release/official-plugins.ts +46 -0
- package/src/release/readme.test.ts +30 -2
- package/src/runtime/dev-request-log.test.ts +20 -1
- package/src/runtime/dev-request-log.ts +38 -0
- package/src/term.test.ts +15 -0
- package/src/term.ts +8 -3
- package/src/console/ui/dist/assets/index-CjxwRGVv.js +0 -10
|
@@ -83,6 +83,14 @@ still reaches `fx.log` is scrubbed by the boot redactor as before.
|
|
|
83
83
|
|
|
84
84
|
That's the whole loop: declare → set → read. Everything below is what OKE guarantees on top of it.
|
|
85
85
|
|
|
86
|
+
## Redacted until you reveal
|
|
87
|
+
|
|
88
|
+
<VaultRedacted />
|
|
89
|
+
|
|
90
|
+
Pass the wrapper freely — `fx.log`, `String()`, and `JSON.stringify` all yield
|
|
91
|
+
`[redacted]`. Call `.reveal()` once at the provider boundary that needs the
|
|
92
|
+
credential.
|
|
93
|
+
|
|
86
94
|
## Two kinds of contracts
|
|
87
95
|
|
|
88
96
|
| Declaration | Sensitive? | Console shows | Use for |
|
|
@@ -143,17 +151,19 @@ In docker mode, `oke vault set` writes straight to the running OpenBao — no gi
|
|
|
143
151
|
The **Console** (`:6533`) can also set and rotate values, but it is **write-only**: it shows a salted fingerprint (`sha256:…`) per secret, never the cleartext. When you rotate a key there, the panel shows the **blast radius** — which in-flight durable runs will wake up with the new value.
|
|
144
152
|
|
|
145
153
|
<Callout title="Secrets never reach logs">
|
|
146
|
-
|
|
147
|
-
|
|
154
|
+
`fx.vault` returns `Redacted` — `fx.log` shows `[redacted]`. A revealed string that still reaches
|
|
155
|
+
a log is scrubbed by the boot redactor to `[redacted:secret]`. Traces and the Console get
|
|
156
|
+
fingerprints, never cleartext.
|
|
148
157
|
</Callout>
|
|
149
158
|
|
|
150
159
|
## Per-environment drivers
|
|
151
160
|
|
|
152
|
-
Which backend holds your values depends on the mode — configured once in `oke.config.ts
|
|
161
|
+
Which backend holds your values depends on the mode — configured once in `oke.config.ts`.
|
|
162
|
+
App boot and the Console share the same resolution-chain builder (`env` layers → backend):
|
|
153
163
|
|
|
154
164
|
```typescript title="oke.config.ts"
|
|
155
165
|
vault: {
|
|
156
|
-
local: "
|
|
166
|
+
local: "env", // .env.local — zero ceremony
|
|
157
167
|
docker: "openbao", // real vault in the compose stack
|
|
158
168
|
test: "memory", // seeded map — deterministic tests
|
|
159
169
|
prod: "openbao", // real vault in production
|
|
@@ -162,7 +172,7 @@ vault: {
|
|
|
162
172
|
|
|
163
173
|
| Driver | Backend | Best for |
|
|
164
174
|
| --------- | --------------- | ------------------------------------------ |
|
|
165
|
-
| `
|
|
175
|
+
| `env` | `.env.local` | Local loop — no infra at all |
|
|
166
176
|
| `openbao` | OpenBao (KV v2) | Docker + prod — durable, access-controlled |
|
|
167
177
|
| `memory` | in-process map | Tests |
|
|
168
178
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Basic Usage
|
|
3
|
-
description: Scaffold the standard starter, call
|
|
4
|
-
source: packages/create-oke/
|
|
3
|
+
description: Scaffold the standard Notes starter, call health and notes Flows, and inspect them in the Console.
|
|
4
|
+
source: packages/create-oke/templates/standard
|
|
5
5
|
icon: SquareTerminal
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
Write your first Flow, call it from a typed client, and prove it with
|
|
9
|
-
`bun:test` — using the same standard starter `create-oke` scaffolds.
|
|
9
|
+
`bun:test` — using the same standard Notes starter `create-oke` scaffolds.
|
|
10
10
|
|
|
11
11
|
<Callout title="The one rule">
|
|
12
12
|
All reads, writes, emits, sends, and external calls belong behind `fx`. That is what makes effects
|
|
@@ -26,6 +26,9 @@ cd my-app
|
|
|
26
26
|
oke dev
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
Use `--template advanced` for the same Notes domain with files attach, a daily
|
|
30
|
+
digest Clock, and an AI summarize stub.
|
|
31
|
+
|
|
29
32
|
<Surfaces />
|
|
30
33
|
|
|
31
34
|
</Step>
|
|
@@ -33,7 +36,7 @@ oke dev
|
|
|
33
36
|
<Step>
|
|
34
37
|
### Read the health Flow
|
|
35
38
|
|
|
36
|
-
The standard starter already exports a health Flow:
|
|
39
|
+
The standard starter already exports a named health Flow:
|
|
37
40
|
|
|
38
41
|
```typescript title="flows/main"
|
|
39
42
|
import { on, flow, http, gate } from "okengine";
|
|
@@ -42,13 +45,16 @@ import { z } from "zod";
|
|
|
42
45
|
export const health = on(
|
|
43
46
|
http.get("/health").gate(gate.public),
|
|
44
47
|
flow({
|
|
48
|
+
name: "main.health",
|
|
49
|
+
unit: "main",
|
|
45
50
|
out: z.object({ ok: z.literal(true) }),
|
|
46
51
|
do: () => ({ ok: true as const }),
|
|
47
52
|
}),
|
|
48
53
|
);
|
|
49
54
|
```
|
|
50
55
|
|
|
51
|
-
|
|
56
|
+
Named flows show up as `main.health` (not `flow_1`) in `oke dev` logs.
|
|
57
|
+
Change the route or output and save — App and Console update together from the
|
|
52
58
|
same Manifest.
|
|
53
59
|
|
|
54
60
|
</Step>
|
|
@@ -61,8 +67,9 @@ Adopted modules become namespaces on the client:
|
|
|
61
67
|
```typescript title="app"
|
|
62
68
|
import { oke } from "okengine";
|
|
63
69
|
import * as main from "./flows/main";
|
|
70
|
+
import * as notes from "./flows/notes";
|
|
64
71
|
|
|
65
|
-
export const app = oke({ name: "
|
|
72
|
+
export const app = oke({ name: "notes" }).adopt({ main, notes });
|
|
66
73
|
export type App = typeof app;
|
|
67
74
|
```
|
|
68
75
|
|
|
@@ -6,11 +6,11 @@ icon: Download
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
This page gets you from zero to a running app on Bun. The engine targets
|
|
9
|
-
**Bun ≥ 1.3** — prefer it for install, scaffold, and `oke dev`.
|
|
9
|
+
**Bun ≥ 1.3.14** — prefer it for install, scaffold, and `oke dev`.
|
|
10
10
|
|
|
11
11
|
<Callout title="The one rule">
|
|
12
|
-
|
|
13
|
-
the library API only.
|
|
12
|
+
The npm package is `okengine`; the CLI binary is `oke`. Use `bun add` in a project or `bun install
|
|
13
|
+
-g okengine` for a global `oke` on PATH. JSR is the library API only.
|
|
14
14
|
</Callout>
|
|
15
15
|
|
|
16
16
|
## Quick start
|
|
@@ -20,7 +20,7 @@ This page gets you from zero to a running app on Bun. The engine targets
|
|
|
20
20
|
<Step>
|
|
21
21
|
### Prerequisites
|
|
22
22
|
|
|
23
|
-
- [Bun](https://bun.sh) ≥ 1.3 (`bun --version`)
|
|
23
|
+
- [Bun](https://bun.sh) ≥ 1.3.14 (`bun --version`)
|
|
24
24
|
- A terminal and a code editor
|
|
25
25
|
|
|
26
26
|
</Step>
|
|
@@ -28,10 +28,18 @@ This page gets you from zero to a running app on Bun. The engine targets
|
|
|
28
28
|
<Step>
|
|
29
29
|
### Install the package
|
|
30
30
|
|
|
31
|
+
Project dependency (framework + local `oke`):
|
|
32
|
+
|
|
31
33
|
```bash title="Terminal"
|
|
32
34
|
bun add okengine
|
|
33
35
|
```
|
|
34
36
|
|
|
37
|
+
Global CLI (`oke` on PATH):
|
|
38
|
+
|
|
39
|
+
```bash title="Terminal"
|
|
40
|
+
bun install -g okengine
|
|
41
|
+
```
|
|
42
|
+
|
|
35
43
|
Library-only via JSR:
|
|
36
44
|
|
|
37
45
|
```bash title="Terminal"
|
|
@@ -46,12 +54,23 @@ bunx jsr add @omqkhafi/okengine
|
|
|
46
54
|
```bash title="Terminal"
|
|
47
55
|
bunx create-oke@latest my-app
|
|
48
56
|
bunx create-oke@latest my-app --template standard
|
|
57
|
+
bunx create-oke@latest my-app --template advanced
|
|
49
58
|
bunx create-oke@latest my-app --sql postgres
|
|
59
|
+
bunx create-oke@latest my-app --yes
|
|
50
60
|
```
|
|
51
61
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
62
|
+
Two Notes starters: **standard** (local-first) and **advanced** (docker-ready +
|
|
63
|
+
files/digest/AI). On a TTY: pick a template, then **recommended defaults**,
|
|
64
|
+
**customize** (choose **local** or **docker** first, walk that side’s facets,
|
|
65
|
+
optionally customize the other; saved to `~/.oke/create-defaults.json`), or
|
|
66
|
+
**reuse** when saved settings match that template. The project-name step rejects
|
|
67
|
+
a path that already exists and is not empty.
|
|
68
|
+
|
|
69
|
+
Non-TTY / `--yes` stay scriptable. Default pins: local SQLite · Docker/prod
|
|
70
|
+
Postgres. `--sql postgres` pins SQL envs; `--ai` runs the AI model wizard
|
|
71
|
+
**before** install. Scaffold writes `.oke/mode` from the primary side
|
|
72
|
+
(recommended: standard → `local`, advanced → `docker`) so the first `oke dev`
|
|
73
|
+
skips the mode prompt unless you delete that file or pass `--local` / `--docker`.
|
|
55
74
|
|
|
56
75
|
</Step>
|
|
57
76
|
|
|
@@ -63,11 +82,14 @@ cd my-app
|
|
|
63
82
|
oke dev
|
|
64
83
|
```
|
|
65
84
|
|
|
66
|
-
|
|
85
|
+
Four ports come up together (mnemonic: **O·K·E = 6·5·3**):
|
|
67
86
|
|
|
68
87
|
<Surfaces />
|
|
69
88
|
|
|
70
|
-
Open `http://localhost:6533`.
|
|
89
|
+
Open `http://localhost:6533`. On first boot, claim the Console with the
|
|
90
|
+
**claim code** printed once in the `oke dev` log, then create the first
|
|
91
|
+
operator. Password policy matches Gate auth: **≥ 12 characters, with a letter
|
|
92
|
+
and a number.** After that, if the Console lists your flows, the install
|
|
71
93
|
worked — **derived, not configured.**
|
|
72
94
|
|
|
73
95
|
</Step>
|
|
@@ -103,8 +125,9 @@ Uses the `docker` driver profile in `oke.config.ts` (filled from `prod` when
|
|
|
103
125
|
omitted). Compose and credentials land under `docker/` (`.env.docker` beside
|
|
104
126
|
compose); host ports are unique per project.
|
|
105
127
|
|
|
106
|
-
Bare `oke dev`
|
|
107
|
-
to
|
|
128
|
+
Bare `oke dev` uses `.oke/mode` when present (seeded by create-oke). On a TTY
|
|
129
|
+
with no saved mode it prompts once and writes the file; non-TTY defaults to
|
|
130
|
+
`local`.
|
|
108
131
|
|
|
109
132
|
| Protocol | Env shape (generated) |
|
|
110
133
|
| ------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
@@ -122,8 +145,9 @@ controls are preserved when `oke dev --docker` regenerates the file.
|
|
|
122
145
|
<Accordions>
|
|
123
146
|
|
|
124
147
|
<Accordion title="oke: command not found after install">
|
|
125
|
-
|
|
126
|
-
invoke via `bunx oke dev
|
|
148
|
+
Install the npm package `okengine` (not JSR alone): `bun add okengine` in the project, or `bun
|
|
149
|
+
install -g okengine` for a global binary. Or invoke via `bunx oke dev`. There is no separate `oke`
|
|
150
|
+
package name — only `okengine`.
|
|
127
151
|
</Accordion>
|
|
128
152
|
|
|
129
153
|
<Accordion title="Console is empty / no flows listed">
|
|
@@ -131,11 +155,23 @@ controls are preserved when `oke dev --docker` regenerates the file.
|
|
|
131
155
|
boots and the Manifest is extracted — fix TypeScript errors in the terminal first.
|
|
132
156
|
</Accordion>
|
|
133
157
|
|
|
158
|
+
<Accordion title="Create first operator fails (password / claim code)">
|
|
159
|
+
Use a password with at least 12 characters, including a letter and a number. Copy the claim code
|
|
160
|
+
from the current `oke dev` boot log (it expires in 30 minutes; restart mint a new one). The form
|
|
161
|
+
and the request log now show the reason — not a bare `TransportError` / `500`.
|
|
162
|
+
</Accordion>
|
|
163
|
+
|
|
134
164
|
<Accordion title="Database out of sync after editing schema">
|
|
135
165
|
Local `oke dev` auto-pushes by default. If you passed `--no-db-push` or set `db.autoPush: false`,
|
|
136
166
|
run `oke db push` yourself, or re-enable auto-push.
|
|
137
167
|
</Accordion>
|
|
138
168
|
|
|
169
|
+
<Accordion title="Docker containers left after deleting a project">
|
|
170
|
+
Each project gets its own `oke-dev-<id>` compose stack; `oke dev` stop keeps volumes. Run
|
|
171
|
+
`oke docker clean` (TTY picker) or `oke docker clean --all --yes` from anywhere to remove
|
|
172
|
+
leftover containers, networks, and volumes.
|
|
173
|
+
</Accordion>
|
|
174
|
+
|
|
139
175
|
</Accordions>
|
|
140
176
|
|
|
141
177
|
## Learn more
|
|
@@ -60,7 +60,7 @@ on(db.table(users).changed("email"), reverify);
|
|
|
60
60
|
<Step>
|
|
61
61
|
### See what was derived
|
|
62
62
|
|
|
63
|
-
Run `oke dev`.
|
|
63
|
+
Run `oke dev`. Four surfaces come up together — nothing configured by hand in
|
|
64
64
|
a separate dashboard.
|
|
65
65
|
|
|
66
66
|
<Surfaces />
|
|
@@ -8,13 +8,15 @@ source: "docs/cli.md"
|
|
|
8
8
|
### Commands
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
bun add okengine # ONE package
|
|
11
|
+
bun add okengine # ONE package (project)
|
|
12
|
+
bun install -g okengine # global `oke` on PATH
|
|
12
13
|
|
|
13
14
|
oke dev # watch · hot reload · Console :6533 · app :6530 · MCP :6535 · docs MCP :6536
|
|
14
15
|
# → client types + domain schema push on save (local)
|
|
15
16
|
oke dev --local # -l session-only local (in-memory; never writes .oke/mode)
|
|
16
|
-
oke dev --no-db-push # opt out of auto oke db push on schema
|
|
17
|
+
oke dev --no-db-push # opt out of auto oke db push on schema input save
|
|
17
18
|
oke dev --docker # -d infra compose under docker/ (no app container; host Bun)
|
|
19
|
+
# Ctrl-C / close terminal → docker compose stop (volumes kept)
|
|
18
20
|
oke dev -d store.sql,signal # partial: only these roles get real backends
|
|
19
21
|
oke mode local|docker # get/set default oke dev mode (saved in .oke/mode)
|
|
20
22
|
|
|
@@ -31,10 +33,14 @@ oke client add <url> # types for a separate frontend repo
|
|
|
31
33
|
|
|
32
34
|
oke docker # docker/Dockerfile + docker/compose.<role>.yml · …
|
|
33
35
|
oke docker --prod # healthchecks, volumes, limits, secret refs, deploy.replicas
|
|
36
|
+
oke docker clean # TTY: pick oke-dev-* stacks → down -v (containers, networks, volumes)
|
|
37
|
+
oke docker clean --yes # non-TTY: current project stack only
|
|
38
|
+
oke docker clean --all --yes # non-TTY: every oke-dev-* stack on this machine
|
|
34
39
|
oke images pin # tags → digests in oke.images.lock
|
|
35
40
|
|
|
36
41
|
oke build --target edge # < 15 kB kernel profile
|
|
37
42
|
oke eval # run prompt eval sets; fails CI on regression
|
|
43
|
+
oke ai setup # configure AI driver + models (TTY wizard or flags)
|
|
38
44
|
oke branch prod --at "yesterday" # fork journaled state into a sandbox
|
|
39
45
|
oke privacy erase --subject <id> # crypto-shredding: deletes the key, not the terabytes
|
|
40
46
|
oke upgrade # run codemods for a breaking change, print the diff
|
|
@@ -44,6 +50,24 @@ In development, app, Console, MCP, and docs MCP prefer the canonical ports and m
|
|
|
44
50
|
when occupied. Docker infrastructure uses stable per-project offsets in disjoint ranges for
|
|
45
51
|
each built-in service, preventing one service's offset port from overlapping another's.
|
|
46
52
|
|
|
53
|
+
### create-oke
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
bunx create-oke@latest my-app # TTY: template → recommended / reuse / customize
|
|
57
|
+
bunx create-oke@latest my-app --template advanced
|
|
58
|
+
bunx create-oke@latest my-app --yes # non-interactive recommended defaults
|
|
59
|
+
bunx create-oke@latest my-app --sql postgres
|
|
60
|
+
bunx create-oke@latest my-app --ai # AI model wizard before install
|
|
61
|
+
bunx create-oke@latest my-app --no-ai
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
On a TTY: pick **standard** or **advanced**, then recommended defaults or
|
|
65
|
+
customize. Customize asks **local** or **docker** first, walks facets for that
|
|
66
|
+
side only, then whether to customize the other (defaults if no). Writes
|
|
67
|
+
user-global `~/.oke/create-defaults.json` (reuse only when `template` matches).
|
|
68
|
+
Scaffold writes `.oke/mode` from the primary side. Non-TTY / `--yes` / explicit
|
|
69
|
+
`--template` never prompt.
|
|
70
|
+
|
|
47
71
|
### Additional commands
|
|
48
72
|
|
|
49
73
|
```bash
|
|
@@ -52,6 +76,8 @@ oke doctor --json # -j JSON on stdout; hints on stderr (agents /
|
|
|
52
76
|
oke stack --json # -j
|
|
53
77
|
oke images list # recipe · image · tag · digest · size (--json|-j)
|
|
54
78
|
oke gates list # Module:Action catalogue (--json|-j)
|
|
79
|
+
oke ai setup --provider ollama --yes # non-interactive AI config
|
|
80
|
+
# TTY Ollama: needs quiz → RAM-tier panel → recommend / installed / manual (+ ← Back)
|
|
55
81
|
```
|
|
56
82
|
|
|
57
83
|
### Shell completion
|
|
@@ -74,6 +100,8 @@ Long form is canonical in docs; short form is convenience only. Shared letters f
|
|
|
74
100
|
| `--docker` | `-d` | `dev` |
|
|
75
101
|
| `--no-db-push` | | `dev` |
|
|
76
102
|
| `--prod` | `-p` | `docker` |
|
|
103
|
+
| `--yes` | `-y` | `docker clean` |
|
|
104
|
+
| `--all` | | `docker clean` |
|
|
77
105
|
| `--port` | `-p` | `start` |
|
|
78
106
|
| `--check` | `-c` | `schema generate` |
|
|
79
107
|
| `--config` | `-c` | `stack`, `docker`, `images`, `db *` (drizzle) |
|
|
@@ -25,11 +25,12 @@ drivers: {
|
|
|
25
25
|
kv: { local: "memory", docker: "redis", test: "memory", prod: "redis" },
|
|
26
26
|
files: { local: "fs", docker: "s3", test: "memory", prod: "s3" },
|
|
27
27
|
},
|
|
28
|
-
signal: { local: "memory", docker: "
|
|
29
|
-
clock: { local: "memory", docker: "
|
|
30
|
-
vault: { local: "
|
|
28
|
+
signal: { local: "memory", docker: "redis", test: "memory", prod: "redis" },
|
|
29
|
+
clock: { local: "memory", docker: "file", test: "frozen", prod: "file" },
|
|
30
|
+
vault: { local: "env", docker: "openbao", test: "memory", prod: "openbao" },
|
|
31
31
|
channel: {
|
|
32
32
|
email: { local: "console", docker: "smtp", test: "console", prod: "smtp" },
|
|
33
|
+
sms: { local: "console", docker: "taqnyat", test: "console", prod: "taqnyat" },
|
|
33
34
|
},
|
|
34
35
|
},
|
|
35
36
|
```
|
|
@@ -40,13 +41,13 @@ drivers: {
|
|
|
40
41
|
| `store.kv` | env driver map | `memory` · `redis` |
|
|
41
42
|
| `store.files` | env driver map | `memory` · `fs` · `s3` |
|
|
42
43
|
| `store.index` | env driver map | `memory` · `pgvector` · `libsql` · `meilisearch` |
|
|
43
|
-
| `signal` | env driver map | `memory` · `
|
|
44
|
-
| `clock` | env driver map | `memory` · `
|
|
45
|
-
| `vault` | env driver map | `
|
|
46
|
-
| `channel.email` | env driver map | `console` · `smtp` · `resend`
|
|
47
|
-
| `channel.sms` | env driver map | `console` · `unifonic`
|
|
48
|
-
| `channel.whatsapp` | env driver map |
|
|
49
|
-
| `channel.push` | env driver map |
|
|
44
|
+
| `signal` | env driver map | `memory` · `redis` (boot); `postgres` · `nats` fail loud until clients bind |
|
|
45
|
+
| `clock` | env driver map | `memory` · `file` · `frozen` |
|
|
46
|
+
| `vault` | env driver map | `env` · `openbao` · `memory` · `managed` |
|
|
47
|
+
| `channel.email` | env driver map | `console` · `smtp` · `resend` · `sndr` |
|
|
48
|
+
| `channel.sms` | env driver map | `console` · `taqnyat` · `msegat` · `unifonic` |
|
|
49
|
+
| `channel.whatsapp` | env driver map | `console` · `wa-cloud` |
|
|
50
|
+
| `channel.push` | env driver map | `console` · `webpush` · `fcm` |
|
|
50
51
|
| `ai` | env driver map | `mock` · `anthropic` · `openai-compatible` · `bedrock` · `vertex` · `ollama` |
|
|
51
52
|
| `runs` | env driver map | runs-store driver (distinct from top-level `runs`) |
|
|
52
53
|
| `prod` | `string[]` | flat protocol list for the Manifest — nested maps are preferred |
|
|
@@ -127,13 +128,13 @@ Runs retention and redaction at the config surface — **not** the same key as `
|
|
|
127
128
|
|
|
128
129
|
Domain schema sync for `oke db push | generate | migrate` (Drizzle). Unrelated to `oke schema generate`.
|
|
129
130
|
|
|
130
|
-
| Option | Default | Meaning
|
|
131
|
-
| ----------- | --------------------------- |
|
|
132
|
-
| `autoPush` | `true` (local only) | Auto-run `db push`
|
|
133
|
-
| `config` | `"drizzle.config.ts"` | Path to the drizzle-kit config
|
|
134
|
-
| `declare` | `"src/schema.decl.ts"` | Abstract schema module (`store.schema.table` exports)
|
|
135
|
-
| `generated` | `"src/schema.generated.ts"` | Where `oke db` emits dialect Drizzle
|
|
136
|
-
| `entry` | `src/app.ts` | App entry for collecting plugin table contributions
|
|
131
|
+
| Option | Default | Meaning |
|
|
132
|
+
| ----------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
133
|
+
| `autoPush` | `true` (local only) | Auto-run `db push` when schema inputs change in `oke dev` (not on emit of `generated`); forced off in docker/prod |
|
|
134
|
+
| `config` | `"drizzle.config.ts"` | Path to the drizzle-kit config |
|
|
135
|
+
| `declare` | `"src/schema.decl.ts"` | Abstract schema module (`store.schema.table` exports) |
|
|
136
|
+
| `generated` | `"src/schema.generated.ts"` | Where `oke db` emits dialect Drizzle |
|
|
137
|
+
| `entry` | `src/app.ts` | App entry for collecting plugin table contributions |
|
|
137
138
|
|
|
138
139
|
## topology
|
|
139
140
|
|
|
@@ -61,27 +61,53 @@ Written by the first-boot bootstrap; you normally only set these when pointing a
|
|
|
61
61
|
| `OKE_VAULT_TOKEN` | App token (least-privilege) | — |
|
|
62
62
|
| `OKE_VAULT_MOUNT` | KV v2 mount path | `"secret"` |
|
|
63
63
|
|
|
64
|
-
## Channel (email)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
|
69
|
-
|
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
64
|
+
## Channel (email) — boot binder
|
|
65
|
+
|
|
66
|
+
Read when `drivers.channel.email` resolves to that driver id.
|
|
67
|
+
|
|
68
|
+
| Variable | Used for |
|
|
69
|
+
| ----------------------- | ------------------------------------------------ |
|
|
70
|
+
| `SMTP_URL` | `smtp` — full SMTP URL (`smtp://…`) |
|
|
71
|
+
| `SMTP_USER` | Overrides the user embedded in `SMTP_URL` |
|
|
72
|
+
| `SMTP_PASSWORD` | Overrides the password in `SMTP_URL` |
|
|
73
|
+
| `OKE_CHANNEL_EMAIL_URL` | Alternative to `SMTP_URL` |
|
|
74
|
+
| `RESEND_API_KEY` | `resend` API key |
|
|
75
|
+
| `SNDR_API_KEY` | `sndr` API key |
|
|
76
|
+
| `SNDR_BASE_URL` | Optional SNDR API origin (default `api.sndr.sh`) |
|
|
77
|
+
|
|
78
|
+
## Channel (SMS) — boot binder
|
|
79
|
+
|
|
80
|
+
Read when `drivers.channel.sms` resolves to that driver id (`console` opens nothing).
|
|
81
|
+
|
|
82
|
+
| Variable | Used for |
|
|
83
|
+
| ---------------------- | -------------------------------- |
|
|
84
|
+
| `TAQNYAT_BEARER_TOKEN` | `taqnyat` bearer token |
|
|
85
|
+
| `TAQNYAT_TOKEN` | Alias for `TAQNYAT_BEARER_TOKEN` |
|
|
86
|
+
| `TAQNYAT_SENDER` | Taqnyat pre-approved sender id |
|
|
87
|
+
| `MSEGAT_USERNAME` | `msegat` account username |
|
|
88
|
+
| `MSEGAT_API_KEY` | `msegat` API key |
|
|
89
|
+
| `MSEGAT_SENDER` | Msegat pre-approved sender id |
|
|
90
|
+
| `UNIFONIC_APPSID` | `unifonic` AppSid |
|
|
91
|
+
| `UNIFONIC_APP_SID` | Alias for `UNIFONIC_APPSID` |
|
|
92
|
+
| `UNIFONIC_SENDER` | Unifonic SenderID (optional) |
|
|
93
|
+
|
|
94
|
+
WhatsApp (`wa-cloud`) and push (`webpush` / `fcm`) are not opened from env at
|
|
95
|
+
boot — pass them on `BootOptions.channel.drivers` with their open options.
|
|
72
96
|
|
|
73
97
|
## AI providers
|
|
74
98
|
|
|
75
|
-
| Variable
|
|
76
|
-
|
|
|
77
|
-
| `ANTHROPIC_API_KEY`
|
|
78
|
-
| `ANTHROPIC_MODEL`
|
|
79
|
-
| `OPENAI_API_KEY`
|
|
80
|
-
| `OPENAI_BASE_URL`
|
|
81
|
-
| `OKE_AI_DRIVER`
|
|
82
|
-
| `OKE_AI_URL`
|
|
83
|
-
| `OKE_AI_MODEL`
|
|
84
|
-
| `
|
|
99
|
+
| Variable | Used for | Default when unset |
|
|
100
|
+
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- |
|
|
101
|
+
| `ANTHROPIC_API_KEY` | `anthropic` driver credential | — |
|
|
102
|
+
| `ANTHROPIC_MODEL` | Model override for the anthropic driver | — |
|
|
103
|
+
| `OPENAI_API_KEY` | `openai-compatible` driver credential | — |
|
|
104
|
+
| `OPENAI_BASE_URL` | `openai-compatible` base URL | OpenAI cloud |
|
|
105
|
+
| `OKE_AI_DRIVER` | Force the AI driver id (honoured in docker mode) | config map |
|
|
106
|
+
| `OKE_AI_URL` | Ollama (or openai-compatible) base URL | `http://127.0.0.1:11434` (ollama) |
|
|
107
|
+
| `OKE_AI_MODEL` | Default model for `ollama` (any pulled model; `qwen3.5:9b` is a balanced local-dev starting point; on Apple Silicon try `qwen3.5:9b-mlx`) | `qwen3.5:9b` |
|
|
108
|
+
| `OKE_AI_VISION_MODEL` | Vision model id written by `oke ai setup` (logical `ai.model("vision")`) | — |
|
|
109
|
+
| `OKE_AI_EMBED_MODEL` | Embedding model id written by `oke ai setup` | — |
|
|
110
|
+
| `OLLAMA_HOST` | Alternate Ollama host (`host:port` or URL) when `OKE_AI_URL` is unset | — |
|
|
85
111
|
|
|
86
112
|
## Framework behavior
|
|
87
113
|
|
|
@@ -29,17 +29,18 @@ string. Custom app codes stay message-less until registered.
|
|
|
29
29
|
|
|
30
30
|
## OKE numeric codes
|
|
31
31
|
|
|
32
|
-
| Code | Name | Cause | Fix
|
|
33
|
-
| ------ | ----------------- | ------------------------------------------------ |
|
|
34
|
-
| `1001` | undeclared read | Flow reads a resource not in `effects.reads` | Add it to the flow's `effects.reads`
|
|
35
|
-
| `1002` | undeclared write | Flow writes a resource not in `effects.writes` | Add it to the flow's `effects.writes`
|
|
36
|
-
| `1003` | undeclared emit | Flow emits a signal not in `effects.emits` | Add it to the flow's `effects.emits`
|
|
37
|
-
| `1004` | undeclared send | Flow sends a template not in `effects.sends` | Add it to the flow's `effects.sends`
|
|
38
|
-
| `1005` | undeclared ask | Flow asks a prompt not in `effects.asks` | Add it to the flow's `effects.asks`
|
|
39
|
-
| `1006` | undeclared secret | Flow reads a secret not in `effects.secrets` | Add it to the flow's `effects.secrets`
|
|
40
|
-
| `1007` | undeclared call | Flow calls a flow not in `effects.calls` | Add it to the flow's `effects.calls`
|
|
41
|
-
| `1042` | orphan emit |
|
|
42
|
-
| `
|
|
32
|
+
| Code | Name | Cause | Fix |
|
|
33
|
+
| ------ | ----------------- | ------------------------------------------------ | -------------------------------------------------- |
|
|
34
|
+
| `1001` | undeclared read | Flow reads a resource not in `effects.reads` | Add it to the flow's `effects.reads` |
|
|
35
|
+
| `1002` | undeclared write | Flow writes a resource not in `effects.writes` | Add it to the flow's `effects.writes` |
|
|
36
|
+
| `1003` | undeclared emit | Flow emits a signal not in `effects.emits` | Add it to the flow's `effects.emits` |
|
|
37
|
+
| `1004` | undeclared send | Flow sends a template not in `effects.sends` | Add it to the flow's `effects.sends` |
|
|
38
|
+
| `1005` | undeclared ask | Flow asks a prompt not in `effects.asks` | Add it to the flow's `effects.asks` |
|
|
39
|
+
| `1006` | undeclared secret | Flow reads a secret not in `effects.secrets` | Add it to the flow's `effects.secrets` |
|
|
40
|
+
| `1007` | undeclared call | Flow calls a flow not in `effects.calls` | Add it to the flow's `effects.calls` |
|
|
41
|
+
| `1042` | orphan emit | Emit with zero subscribers and `optional` false | Add `on(signal, …)` or declare `optional: true` |
|
|
42
|
+
| `1043` | signal schema | Emit payload failed the signal's `schema` | Pass a payload that matches `schema`, or remove it |
|
|
43
|
+
| `1101` | schema missing | Domain table absent in docker/prod — no auto-DDL | Run `oke db migrate` against this environment |
|
|
43
44
|
|
|
44
45
|
<Callout title="Effects are usually inferred">
|
|
45
46
|
The 1001–1007 family exists for flows that declare effects explicitly. Most apps never write an
|
|
@@ -16,24 +16,26 @@ flow({
|
|
|
16
16
|
|
|
17
17
|
## Stores
|
|
18
18
|
|
|
19
|
-
| Signature | Records | Returns
|
|
20
|
-
| ------------------------------------------------------------------- | ------------ |
|
|
21
|
-
| `fx.store(sqlDecl).select().from(t)…` | `read` | rows (`where` · `orderBy` · `limit` · `offset` chainable)
|
|
22
|
-
| `fx.store(sqlDecl).insert(t).values(v)` | `write` | `Promise<void>`
|
|
23
|
-
| `fx.store(sqlDecl).update(t).set(v).where(…)` | `write` | `Promise<void>`
|
|
24
|
-
| `fx.store(sqlDecl).delete(t).where(…)` | `write` | `Promise<void>`
|
|
25
|
-
| `fx.store(sqlDecl).findById(t, id)` | `read` | row \| undefined
|
|
26
|
-
| `fx.store(kv).get / set(key, value, ttl?) / delete / list(prefix?)` | read / write | per op
|
|
27
|
-
| `fx.store(files).put / get / delete / list(prefix?)` | read / write | per op
|
|
28
|
-
| `fx.store(
|
|
19
|
+
| Signature | Records | Returns |
|
|
20
|
+
| ------------------------------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------- |
|
|
21
|
+
| `fx.store(sqlDecl).select().from(t)…` | `read` | rows (`where` · `orderBy` · `limit` · `offset` chainable) |
|
|
22
|
+
| `fx.store(sqlDecl).insert(t).values(v)` | `write` | `Promise<void>` |
|
|
23
|
+
| `fx.store(sqlDecl).update(t).set(v).where(…)` | `write` | `Promise<void>` |
|
|
24
|
+
| `fx.store(sqlDecl).delete(t).where(…)` | `write` | `Promise<void>` |
|
|
25
|
+
| `fx.store(sqlDecl).findById(t, id)` | `read` | row \| undefined |
|
|
26
|
+
| `fx.store(kv).get / set(key, value, ttl?) / delete / list(prefix?)` | read / write | per op |
|
|
27
|
+
| `fx.store(files).put / get / delete / list(prefix?)` | read / write | per op |
|
|
28
|
+
| `fx.store(files).image(key\|bytes).…` | read / write | Bun.Image chain; terminals gate (see [Store](/docs/elements/store#images--image--putimage)) |
|
|
29
|
+
| `fx.store(files).putImage(key, data, opts?)` | `write` | original + variants (+ optional LQIP) |
|
|
30
|
+
| `fx.store(index).upsert / search(vector, topK?) / delete` | read / write | per op |
|
|
29
31
|
|
|
30
32
|
See [Store](/docs/elements/store) for the query-builder surface.
|
|
31
33
|
|
|
32
34
|
## Signals
|
|
33
35
|
|
|
34
|
-
| Signature
|
|
35
|
-
|
|
|
36
|
-
| `fx.emit(signal, payload?)` | `emit` |
|
|
36
|
+
| Signature | Records | Notes |
|
|
37
|
+
| ------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
38
|
+
| `fx.emit(signal, payload?, { key? })` | `emit` | Commits the signal outbox when the call resolves; optional `key` serializes `once` per key; throws **OKE1042** (orphan) or **OKE1043** (schema) |
|
|
37
39
|
|
|
38
40
|
## Flows
|
|
39
41
|
|
|
@@ -45,7 +45,9 @@ Our path is concrete: a booking name containing "ignore previous instructions an
|
|
|
45
45
|
- **Plugin panels** run in a sandboxed iframe without `allow-same-origin`, communicating only over a `postMessage` bridge with their own CSP, no access to the operator session token, and exposure limited to that plugin's declared flows.
|
|
46
46
|
- **Session and framing:** `frame-ancestors 'none'`, `SameSite=Strict`, step-up authentication before destructive actions.
|
|
47
47
|
- **Secret write path:** TLS required, no autocomplete, never echoed, never logged, not retained in browser memory after submission.
|
|
48
|
-
- **The setup claim code** is rate-limited and compared in constant time.
|
|
48
|
+
- **The setup claim code** is rate-limited and compared in constant time. The first-operator password
|
|
49
|
+
uses the same policy as Gate auth (minLength 12, letter + number); weak passwords return
|
|
50
|
+
`ClaimFailed` / `password_policy`, not an opaque 500.
|
|
49
51
|
|
|
50
52
|
#### 10.5 Reversibility governs the confirmation pattern
|
|
51
53
|
|