create-oke 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/README.md +2 -2
- package/package.json +2 -2
- package/src/ai-setup/apply.ts +123 -31
- package/src/ai-setup/catalog.ts +3 -3
- package/src/ai-setup/from-pref.ts +1 -1
- package/src/ai-setup/prompts.ts +1 -1
- package/src/cli.test.ts +183 -142
- package/src/cli.ts +190 -32
- package/src/create-defaults.test.ts +21 -15
- package/src/create-defaults.ts +33 -13
- package/src/customize-flow.test.ts +30 -35
- package/src/customize-flow.ts +68 -229
- package/src/drivers-catalog.ts +42 -48
- package/src/local-okengine.test.ts +50 -41
- package/src/local-okengine.ts +28 -14
- package/src/locales.test.ts +128 -0
- package/src/locales.ts +321 -0
- package/src/scaffold.ts +277 -33
- package/src/templates.ts +2 -8
- package/src/transform.test.ts +102 -38
- package/src/transform.ts +378 -132
- package/templates/advanced/.env.example +23 -3
- package/templates/advanced/README.md +1 -1
- package/templates/advanced/drizzle.config.ts +10 -13
- package/templates/advanced/oke.config.ts +21 -62
- package/templates/advanced/package.json +3 -1
- package/templates/advanced/src/app.ts +3 -10
- package/templates/advanced/src/core.ts +58 -0
- package/templates/advanced/src/db/schema.decl.ts +1 -1
- package/templates/advanced/src/db/seed/index.ts +2 -2
- package/templates/advanced/src/flows/notes/index.ts +3 -15
- package/templates/advanced/src/locales/index.ts +6 -0
- package/templates/advanced/tests/advanced.test.ts +1 -1
- package/templates/advanced/tsconfig.json +3 -0
- package/templates/standard/.env.example +23 -3
- package/templates/standard/README.md +1 -1
- package/templates/standard/drizzle.config.ts +10 -13
- package/templates/standard/oke.config.ts +18 -60
- package/templates/standard/package.json +3 -1
- package/templates/standard/src/app.ts +3 -10
- package/templates/standard/src/core.ts +55 -0
- package/templates/standard/src/db/schema.decl.ts +1 -1
- package/templates/standard/src/db/seed/index.ts +2 -2
- package/templates/standard/src/flows/notes/index.ts +3 -12
- package/templates/standard/src/locales/index.ts +6 -0
- package/templates/standard/tests/standard.test.ts +1 -1
- package/templates/standard/tsconfig.json +3 -0
- package/templates/advanced/src/core/channels.ts +0 -13
- package/templates/advanced/src/core/gates.ts +0 -12
- package/templates/advanced/src/core/index.ts +0 -12
- package/templates/advanced/src/core/store.ts +0 -8
- package/templates/advanced/src/core/vault.ts +0 -7
- package/templates/advanced/src/locales/ar.ts +0 -18
- package/templates/standard/src/core/channels.ts +0 -13
- package/templates/standard/src/core/gates.ts +0 -12
- package/templates/standard/src/core/index.ts +0 -12
- package/templates/standard/src/core/store.ts +0 -5
- package/templates/standard/src/core/vault.ts +0 -7
- package/templates/standard/src/locales/ar.ts +0 -18
|
@@ -6,6 +6,25 @@
|
|
|
6
6
|
# --- Vault (app secrets) ---
|
|
7
7
|
# Declare secrets in src/vault.ts with `vault.secret(...)`, then uncomment lines here.
|
|
8
8
|
#
|
|
9
|
+
# ── vault — built-in encrypted-at-rest store ────────────────
|
|
10
|
+
# `drivers.vault` is "vault": secrets live encrypted in Postgres, no extra service.
|
|
11
|
+
# Nothing below is required to start — the dotenv layers above resolve first.
|
|
12
|
+
#
|
|
13
|
+
# oke vault init # creates the store, prints the master key ONCE
|
|
14
|
+
# export OKE_VAULT_MASTER_KEY=… # every later command / boot unseals with this
|
|
15
|
+
# oke vault status # sealed / initialized / kek generation
|
|
16
|
+
# oke vault audit # hash-chained operation log
|
|
17
|
+
#
|
|
18
|
+
# Keep the master key out of this file in production — read it from your KMS or
|
|
19
|
+
# secret manager at boot. Committing it defeats encryption at rest.
|
|
20
|
+
# OKE_VAULT_MASTER_KEY=
|
|
21
|
+
#
|
|
22
|
+
# For `drivers.vault: "managed"` instead, point at your provider secret store:
|
|
23
|
+
# OKE_VAULT_PROVIDER=aws-secrets-manager
|
|
24
|
+
# OKE_VAULT_REGION=us-east-1
|
|
25
|
+
# Optional prefix for secret names (defaults to oke/<env>/):
|
|
26
|
+
# OKE_VAULT_MOUNT=oke/prod/
|
|
27
|
+
#
|
|
9
28
|
# --- Infrastructure ---
|
|
10
29
|
# Same keys as `docker/.env.docker` after `oke dev --docker`.
|
|
11
30
|
# Uncomment to override compose credentials for a host-managed service.
|
|
@@ -87,8 +106,9 @@
|
|
|
87
106
|
# POSTGRES_INITDB_ARGS=--data-checksums
|
|
88
107
|
|
|
89
108
|
# ── AI ──────────────────────────────────────────────────────
|
|
90
|
-
#
|
|
91
|
-
#
|
|
92
|
-
#
|
|
109
|
+
# Default local: llama.cpp → openai-compatible (Ollama remains supported)
|
|
110
|
+
# OKE_AI_DRIVER=openai-compatible
|
|
111
|
+
# OKE_AI_URL=http://127.0.0.1:8080/v1
|
|
112
|
+
# OKE_AI_MODEL=granite3.3:2b
|
|
93
113
|
# ANTHROPIC_API_KEY=
|
|
94
114
|
# OPENAI_API_KEY=
|
|
@@ -46,5 +46,5 @@ Without AI, summarize returns a local excerpt (`via: "fallback"`).
|
|
|
46
46
|
|
|
47
47
|
## Drivers
|
|
48
48
|
|
|
49
|
-
See `oke.config.ts`: local
|
|
49
|
+
See `oke.config.ts`: local env/memory/fs · docker postgres/redis/s3/smtp; vault built-in.
|
|
50
50
|
Optional Meilisearch index pin is commented — enable via create-oke customize.
|
|
@@ -3,25 +3,22 @@ import { defineConfig } from "drizzle-kit";
|
|
|
3
3
|
/**
|
|
4
4
|
* Domain schema sync for `oke db push|generate|migrate`.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* for the active dialect as a pre-step of `oke db` / `oke dev`.
|
|
6
|
+
* SQL is PostgreSQL-only (postgres / pglite). Domain tables come from
|
|
7
|
+
* `src/db/schema.decl.ts` → `src/db/schema.drizzle.ts` (emitted as a
|
|
8
|
+
* pre-step of `oke db` / `oke dev`).
|
|
10
9
|
*
|
|
11
|
-
*
|
|
10
|
+
* System / auth / plugin stubs are separate: `oke schema generate` →
|
|
11
|
+
* `.oke/schema/oke.ts` (gitignored with `.oke/`). Re-run after adding plugins.
|
|
12
|
+
*
|
|
13
|
+
* Versioned prod migrations land in `./src/db/migrations`.
|
|
12
14
|
*/
|
|
13
|
-
const dialect = (process.env.OKE_DRIZZLE_DIALECT ?? "sqlite") as "sqlite" | "postgresql";
|
|
14
|
-
|
|
15
15
|
export default defineConfig({
|
|
16
|
-
dialect,
|
|
17
|
-
schema: "./src/db/schema.
|
|
16
|
+
dialect: "postgresql",
|
|
17
|
+
schema: "./src/db/schema.drizzle.ts",
|
|
18
18
|
out: "./src/db/migrations",
|
|
19
19
|
// Core runtime tables (oke_crons, …) are created by drivers — not domain schema.
|
|
20
20
|
tablesFilter: ["!oke_*"],
|
|
21
21
|
dbCredentials: {
|
|
22
|
-
url:
|
|
23
|
-
dialect === "postgresql"
|
|
24
|
-
? (process.env.DATABASE_URL ?? process.env.OKE_STORE_SQL_URL!)
|
|
25
|
-
: (process.env.OKE_SQLITE_URL ?? "file:.oke/app.sqlite"),
|
|
22
|
+
url: process.env.DATABASE_URL ?? process.env.OKE_STORE_SQL_URL!,
|
|
26
23
|
},
|
|
27
24
|
});
|
|
@@ -1,84 +1,43 @@
|
|
|
1
1
|
import { defineConfig } from "okengine/config";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Advanced starter — same Notes domain,
|
|
5
|
-
*
|
|
4
|
+
* Advanced starter — same Notes domain, Docker-first + store.index.
|
|
5
|
+
* `oke dev` always uses Docker Compose (dev). Tests use PGLite / memory.
|
|
6
|
+
* Pin only driver keys that differ from `DRIVER_DEFAULTS` (see okengine/config).
|
|
6
7
|
*/
|
|
7
8
|
export default defineConfig({
|
|
8
9
|
db: {
|
|
9
10
|
declare: "src/db/schema.decl.ts",
|
|
10
|
-
generated: "src/db/schema.
|
|
11
|
+
generated: "src/db/schema.drizzle.ts",
|
|
11
12
|
},
|
|
12
13
|
drivers: {
|
|
13
14
|
store: {
|
|
14
|
-
|
|
15
|
-
local: "sqlite",
|
|
16
|
-
docker: "postgres",
|
|
17
|
-
test: "memory",
|
|
18
|
-
prod: "postgres",
|
|
19
|
-
},
|
|
20
|
-
kv: {
|
|
21
|
-
local: "memory",
|
|
22
|
-
docker: "redis",
|
|
23
|
-
test: "memory",
|
|
24
|
-
prod: "redis",
|
|
25
|
-
},
|
|
26
|
-
files: {
|
|
27
|
-
local: "fs",
|
|
28
|
-
docker: "s3",
|
|
29
|
-
test: "memory",
|
|
30
|
-
prod: "s3",
|
|
31
|
-
},
|
|
15
|
+
// No three-env default table — set explicitly when you need search.
|
|
32
16
|
index: {
|
|
33
|
-
local: "memory",
|
|
34
|
-
docker: "meilisearch",
|
|
35
17
|
test: "memory",
|
|
36
18
|
prod: "meilisearch",
|
|
37
19
|
},
|
|
38
20
|
},
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
test: "memory",
|
|
43
|
-
prod: "redis",
|
|
44
|
-
},
|
|
45
|
-
clock: {
|
|
46
|
-
local: "memory",
|
|
47
|
-
docker: "postgres",
|
|
48
|
-
test: "frozen",
|
|
49
|
-
prod: "postgres",
|
|
50
|
-
},
|
|
51
|
-
journal: {
|
|
52
|
-
local: "memory",
|
|
53
|
-
docker: "postgres",
|
|
54
|
-
test: "memory",
|
|
55
|
-
prod: "postgres",
|
|
56
|
-
},
|
|
21
|
+
// Built-in encrypted-at-rest store — lives in Postgres, no extra service.
|
|
22
|
+
// Default `vault.dev` is `"env"`; pin built-in for local Docker-first apps.
|
|
23
|
+
// `oke vault init` prints the master key; set OKE_VAULT_MASTER_KEY to unseal.
|
|
57
24
|
vault: {
|
|
58
|
-
|
|
59
|
-
docker: "openbao",
|
|
60
|
-
test: "memory",
|
|
61
|
-
prod: "openbao",
|
|
62
|
-
},
|
|
63
|
-
channel: {
|
|
64
|
-
email: {
|
|
65
|
-
local: "console",
|
|
66
|
-
docker: "smtp",
|
|
67
|
-
test: "console",
|
|
68
|
-
prod: "smtp",
|
|
69
|
-
},
|
|
25
|
+
dev: "vault",
|
|
70
26
|
},
|
|
71
|
-
// Opt in: create-oke --ai / oke ai setup writes drivers.ai + src/core
|
|
27
|
+
// Opt in: create-oke --ai / oke ai setup writes drivers.ai + models in src/core.ts
|
|
72
28
|
},
|
|
73
29
|
images: {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
30
|
+
store: {
|
|
31
|
+
sql: "postgres:18-alpine",
|
|
32
|
+
kv: "redis:8-alpine",
|
|
33
|
+
files: "rustfs/rustfs:1.0.0-beta.11",
|
|
34
|
+
// index: "getmeili/meilisearch:v1.37",
|
|
35
|
+
},
|
|
36
|
+
channel: {
|
|
37
|
+
email: "axllent/mailpit:v1.22.3",
|
|
38
|
+
},
|
|
39
|
+
// pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.51", // create-oke wizard / --pgdog
|
|
81
40
|
// ai: "ghcr.io/ggml-org/llama.cpp:server-b10290", // or ollama/ollama:0.32.6
|
|
82
41
|
},
|
|
83
|
-
i18n: { locales: ["en"
|
|
42
|
+
i18n: { locales: ["en"], default: "en" },
|
|
84
43
|
});
|
|
@@ -9,13 +9,15 @@
|
|
|
9
9
|
"zod": "^4.4.3"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
|
+
"@electric-sql/pglite": "^0.5.4",
|
|
13
|
+
"@electric-sql/pglite-pgvector": "^0.0.5",
|
|
12
14
|
"@types/bun": "latest",
|
|
13
15
|
"drizzle-kit": "1.0.0-rc.4",
|
|
14
16
|
"typescript": "^7.0.2"
|
|
15
17
|
},
|
|
16
18
|
"scripts": {
|
|
17
19
|
"typecheck": "tsc --noEmit",
|
|
18
|
-
"test": "
|
|
20
|
+
"test": "oke test",
|
|
19
21
|
"dev": "oke dev"
|
|
20
22
|
}
|
|
21
23
|
}
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import "
|
|
2
|
-
import "./locales/en";
|
|
3
|
-
import "./locales/ar";
|
|
1
|
+
import "@/core";
|
|
4
2
|
|
|
5
|
-
import { oke } from "okengine";
|
|
6
|
-
import * as routes from "
|
|
3
|
+
import { oke } from "okengine/http";
|
|
4
|
+
import * as routes from "@/flows/generated";
|
|
7
5
|
|
|
8
|
-
// stores (store.sql/store.files) · secrets (vault.secret) · signals (signal())
|
|
9
|
-
// · channel templates (channel.<medium>().template()) auto-register from
|
|
10
|
-
// `./core` (and `./flows/notes/signals`) — no explicit arrays needed.
|
|
11
|
-
// `./flows/generated` is a real file, regenerated by `oke dev` / `oke build`
|
|
12
|
-
// from every `src/flows/<unit>/index.ts` folder — never edit it by hand.
|
|
13
6
|
export const app = oke({ name: "notes" }).adopt(routes);
|
|
14
7
|
|
|
15
8
|
export type App = typeof app;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App core — element wiring loaded by `import "@/core"` from `app.ts`.
|
|
3
|
+
*
|
|
4
|
+
* Order matches how you usually extend the starter:
|
|
5
|
+
* locales → store → gate → vault → channel → (AI via `oke ai setup`).
|
|
6
|
+
* Keep this file until a section outgrows it, then split by element.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import "@/locales";
|
|
10
|
+
|
|
11
|
+
import { channel, gate, store, vault } from "okengine";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import * as schema from "@/db/schema.decl";
|
|
14
|
+
|
|
15
|
+
// --- Store -------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
/** SQL store for Notes (`schema.decl`). Drivers: pglite locally · postgres in docker. */
|
|
18
|
+
export const db = store.sql("app", { schema });
|
|
19
|
+
|
|
20
|
+
/** Object storage for note attachments (fs locally · s3 in docker). */
|
|
21
|
+
export const files = store.files("uploads");
|
|
22
|
+
|
|
23
|
+
// --- Gate --------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Write policy for notes. Starter allows everyone — swap in real auth scopes:
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* export const notesWrite = gate.policy("notes:write", ({ auth }) =>
|
|
30
|
+
* auth.scopes.has("notes:write"),
|
|
31
|
+
* );
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export const notesWrite = gate.policy("notes:write", () => true);
|
|
35
|
+
|
|
36
|
+
// --- Vault -------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
/** HMAC secret for outbound note webhooks (`fx.vault.get` on create). */
|
|
39
|
+
export const webhookSecret = vault.secret("APP_WEBHOOK_SECRET", {
|
|
40
|
+
description: "HMAC secret for outbound note webhooks",
|
|
41
|
+
dev: "dev-webhook-secret-change-me",
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// --- Channel -----------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
const mail = channel.email({ from: "Notes <notes@localhost>" });
|
|
47
|
+
|
|
48
|
+
/** Fired when a note is created (console driver locally · SMTP in docker). */
|
|
49
|
+
export const noteCreatedMail = mail.template("note-created", {
|
|
50
|
+
locales: ["en"],
|
|
51
|
+
schema: z.object({
|
|
52
|
+
id: z.string(),
|
|
53
|
+
title: z.string(),
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// --- AI ----------------------------------------------------------------------
|
|
58
|
+
// `oke ai setup` / create-oke --ai appends models here.
|
|
@@ -2,7 +2,7 @@ import { store, field, id, now } from "okengine";
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Notes domain — abstract declarations, emitted to
|
|
5
|
-
* `src/db/schema.
|
|
5
|
+
* `src/db/schema.drizzle.ts` for the active dialect by `oke db` / `oke dev`.
|
|
6
6
|
*/
|
|
7
7
|
export const notes = store.schema.table("notes", {
|
|
8
8
|
id: field.text().primaryKey().defaultFn(id),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineSeed, type Fx } from "okengine";
|
|
2
|
-
import { db } from "
|
|
3
|
-
import { notes } from "
|
|
2
|
+
import { db } from "@/core";
|
|
3
|
+
import { notes } from "@/db/schema.decl";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Seed data — run explicitly with `oke db seed` (never at boot).
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { on, flow, http, every, gate, fail } from "okengine";
|
|
2
2
|
import { eq, isNull } from "drizzle-orm";
|
|
3
3
|
|
|
4
|
-
import { db, files, noteCreatedMail, webhookSecret } from "
|
|
5
|
-
import { notes } from "
|
|
4
|
+
import { db, files, noteCreatedMail, webhookSecret } from "@/core";
|
|
5
|
+
import { notes } from "@/db/schema.decl";
|
|
6
6
|
import {
|
|
7
7
|
NoteAttachIn,
|
|
8
8
|
NoteAttachOut,
|
|
@@ -25,7 +25,6 @@ export const list = on(
|
|
|
25
25
|
http.get("/notes").gate(gate.public),
|
|
26
26
|
flow("notes.list", {
|
|
27
27
|
out: NoteListOut,
|
|
28
|
-
effects: { reads: ["sql:app"] },
|
|
29
28
|
do: async (_input, fx) => {
|
|
30
29
|
const rows = await fx.store(db).select().from(notes).where(isNull(notes.archivedAt));
|
|
31
30
|
const sorted = [...rows].sort((a, b) => Number(b.createdAt) - Number(a.createdAt));
|
|
@@ -48,14 +47,9 @@ export const create = on(
|
|
|
48
47
|
flow("notes.create", {
|
|
49
48
|
in: NoteCreateIn,
|
|
50
49
|
out: NoteOut,
|
|
51
|
-
effects: {
|
|
52
|
-
writes: ["sql:app"],
|
|
53
|
-
emits: ["note-created"],
|
|
54
|
-
secrets: ["APP_WEBHOOK_SECRET"],
|
|
55
|
-
},
|
|
56
50
|
do: async (input, fx) => {
|
|
57
51
|
// Prove Vault is wired (local: env/dev fallback).
|
|
58
|
-
fx.vault(webhookSecret);
|
|
52
|
+
await fx.vault.get(webhookSecret);
|
|
59
53
|
const id = fx.id();
|
|
60
54
|
const createdAt = fx.clock.now();
|
|
61
55
|
await fx.store(db).insert(notes).values({
|
|
@@ -84,7 +78,6 @@ export const get = on(
|
|
|
84
78
|
in: NoteIdIn,
|
|
85
79
|
out: NoteOut,
|
|
86
80
|
errors: { NotFound },
|
|
87
|
-
effects: { reads: ["sql:app"] },
|
|
88
81
|
do: async (input, fx) => {
|
|
89
82
|
const row = await fx.store(db).findById(notes, input.id);
|
|
90
83
|
if (!row) return fail("NotFound", { id: input.id });
|
|
@@ -106,7 +99,6 @@ export const archive = on(
|
|
|
106
99
|
in: NoteIdIn,
|
|
107
100
|
out: NoteOut,
|
|
108
101
|
errors: { NotFound },
|
|
109
|
-
effects: { reads: ["sql:app"], writes: ["sql:app"] },
|
|
110
102
|
do: async (input, fx) => {
|
|
111
103
|
const row = await fx.store(db).findById(notes, input.id);
|
|
112
104
|
if (!row) return fail("NotFound", { id: input.id });
|
|
@@ -131,7 +123,6 @@ export const archive = on(
|
|
|
131
123
|
export const onCreated = on(
|
|
132
124
|
noteCreated,
|
|
133
125
|
flow("notes.onCreated", {
|
|
134
|
-
effects: { sends: ["note-created"] },
|
|
135
126
|
do: async (payload, fx) => {
|
|
136
127
|
await fx.send(noteCreatedMail, {
|
|
137
128
|
to: "you@localhost",
|
|
@@ -148,7 +139,6 @@ export const attach = on(
|
|
|
148
139
|
in: NoteAttachIn,
|
|
149
140
|
out: NoteAttachOut,
|
|
150
141
|
errors: { NotFound },
|
|
151
|
-
effects: { reads: ["sql:app"], writes: ["files:uploads"] },
|
|
152
142
|
do: async (input, fx) => {
|
|
153
143
|
const row = await fx.store(db).findById(notes, input.id);
|
|
154
144
|
if (!row) return fail("NotFound", { id: input.id });
|
|
@@ -164,7 +154,6 @@ export const digest = on(
|
|
|
164
154
|
every("1d"),
|
|
165
155
|
flow("notes.digest", {
|
|
166
156
|
out: NoteDigestOut,
|
|
167
|
-
effects: { reads: ["sql:app"] },
|
|
168
157
|
do: async (_input, fx) => {
|
|
169
158
|
const rows = await fx.store(db).select().from(notes).where(isNull(notes.archivedAt));
|
|
170
159
|
return { active: rows.length, at: fx.clock.now() };
|
|
@@ -182,7 +171,6 @@ export const summarize = on(
|
|
|
182
171
|
in: NoteSummarizeIn,
|
|
183
172
|
out: NoteSummarizeOut,
|
|
184
173
|
errors: { NotFound },
|
|
185
|
-
effects: { reads: ["sql:app"], asks: ["summarize-note"] },
|
|
186
174
|
do: async (input, fx) => {
|
|
187
175
|
const row = await fx.store(db).findById(notes, input.id);
|
|
188
176
|
if (!row) return fail("NotFound", { id: input.id });
|
|
@@ -6,6 +6,25 @@
|
|
|
6
6
|
# --- Vault (app secrets) ---
|
|
7
7
|
# Declare secrets in src/vault.ts with `vault.secret(...)`, then uncomment lines here.
|
|
8
8
|
#
|
|
9
|
+
# ── vault — built-in encrypted-at-rest store ────────────────
|
|
10
|
+
# `drivers.vault` is "vault": secrets live encrypted in Postgres, no extra service.
|
|
11
|
+
# Nothing below is required to start — the dotenv layers above resolve first.
|
|
12
|
+
#
|
|
13
|
+
# oke vault init # creates the store, prints the master key ONCE
|
|
14
|
+
# export OKE_VAULT_MASTER_KEY=… # every later command / boot unseals with this
|
|
15
|
+
# oke vault status # sealed / initialized / kek generation
|
|
16
|
+
# oke vault audit # hash-chained operation log
|
|
17
|
+
#
|
|
18
|
+
# Keep the master key out of this file in production — read it from your KMS or
|
|
19
|
+
# secret manager at boot. Committing it defeats encryption at rest.
|
|
20
|
+
# OKE_VAULT_MASTER_KEY=
|
|
21
|
+
#
|
|
22
|
+
# For `drivers.vault: "managed"` instead, point at your provider secret store:
|
|
23
|
+
# OKE_VAULT_PROVIDER=aws-secrets-manager
|
|
24
|
+
# OKE_VAULT_REGION=us-east-1
|
|
25
|
+
# Optional prefix for secret names (defaults to oke/<env>/):
|
|
26
|
+
# OKE_VAULT_MOUNT=oke/prod/
|
|
27
|
+
#
|
|
9
28
|
# --- Infrastructure ---
|
|
10
29
|
# Same keys as `docker/.env.docker` after `oke dev --docker`.
|
|
11
30
|
# Uncomment to override compose credentials for a host-managed service.
|
|
@@ -87,8 +106,9 @@
|
|
|
87
106
|
# POSTGRES_INITDB_ARGS=--data-checksums
|
|
88
107
|
|
|
89
108
|
# ── AI ──────────────────────────────────────────────────────
|
|
90
|
-
#
|
|
91
|
-
#
|
|
92
|
-
#
|
|
109
|
+
# Default local: llama.cpp → openai-compatible (Ollama remains supported)
|
|
110
|
+
# OKE_AI_DRIVER=openai-compatible
|
|
111
|
+
# OKE_AI_URL=http://127.0.0.1:8080/v1
|
|
112
|
+
# OKE_AI_MODEL=granite3.3:2b
|
|
93
113
|
# ANTHROPIC_API_KEY=
|
|
94
114
|
# OPENAI_API_KEY=
|
|
@@ -48,7 +48,7 @@ never anonymous `flow_1`.
|
|
|
48
48
|
| `src/db/migrations/` | versioned drizzle migrations |
|
|
49
49
|
| `src/flows/notes/` | list · create · get · archive · onCreated |
|
|
50
50
|
| `src/flows/main/` | root · health |
|
|
51
|
-
| `oke.config.ts` | local
|
|
51
|
+
| `oke.config.ts` | local env · docker postgres (+ redis/s3/smtp); vault built-in |
|
|
52
52
|
| `.github/workflows/ci.yml` | `bun run typecheck` + `bun test` on push/PR |
|
|
53
53
|
|
|
54
54
|
Switch mode anytime: `oke mode docker` then `oke dev` (or `oke dev --docker`).
|
|
@@ -3,25 +3,22 @@ import { defineConfig } from "drizzle-kit";
|
|
|
3
3
|
/**
|
|
4
4
|
* Domain schema sync for `oke db push|generate|migrate`.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* for the active dialect as a pre-step of `oke db` / `oke dev`.
|
|
6
|
+
* SQL is PostgreSQL-only (postgres / pglite). Domain tables come from
|
|
7
|
+
* `src/db/schema.decl.ts` → `src/db/schema.drizzle.ts` (emitted as a
|
|
8
|
+
* pre-step of `oke db` / `oke dev`).
|
|
10
9
|
*
|
|
11
|
-
*
|
|
10
|
+
* System / auth / plugin stubs are separate: `oke schema generate` →
|
|
11
|
+
* `.oke/schema/oke.ts` (gitignored with `.oke/`). Re-run after adding plugins.
|
|
12
|
+
*
|
|
13
|
+
* Versioned prod migrations land in `./src/db/migrations`.
|
|
12
14
|
*/
|
|
13
|
-
const dialect = (process.env.OKE_DRIZZLE_DIALECT ?? "sqlite") as "sqlite" | "postgresql";
|
|
14
|
-
|
|
15
15
|
export default defineConfig({
|
|
16
|
-
dialect,
|
|
17
|
-
schema: "./src/db/schema.
|
|
16
|
+
dialect: "postgresql",
|
|
17
|
+
schema: "./src/db/schema.drizzle.ts",
|
|
18
18
|
out: "./src/db/migrations",
|
|
19
19
|
// Core runtime tables (oke_crons, …) are created by drivers — not domain schema.
|
|
20
20
|
tablesFilter: ["!oke_*"],
|
|
21
21
|
dbCredentials: {
|
|
22
|
-
url:
|
|
23
|
-
dialect === "postgresql"
|
|
24
|
-
? (process.env.DATABASE_URL ?? process.env.OKE_STORE_SQL_URL!)
|
|
25
|
-
: (process.env.OKE_SQLITE_URL ?? "file:.oke/app.sqlite"),
|
|
22
|
+
url: process.env.DATABASE_URL ?? process.env.OKE_STORE_SQL_URL!,
|
|
26
23
|
},
|
|
27
24
|
});
|
|
@@ -1,75 +1,33 @@
|
|
|
1
1
|
import { defineConfig } from "okengine/config";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Standard starter —
|
|
5
|
-
*
|
|
4
|
+
* Standard starter — Docker-first Notes.
|
|
5
|
+
* `oke dev` always uses Docker Compose (dev). Tests use PGLite / memory.
|
|
6
|
+
* Pin only driver keys that differ from `DRIVER_DEFAULTS` (see okengine/config).
|
|
6
7
|
*/
|
|
7
8
|
export default defineConfig({
|
|
8
9
|
db: {
|
|
9
10
|
declare: "src/db/schema.decl.ts",
|
|
10
|
-
generated: "src/db/schema.
|
|
11
|
+
generated: "src/db/schema.drizzle.ts",
|
|
11
12
|
},
|
|
12
13
|
drivers: {
|
|
13
|
-
store
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
docker: "postgres",
|
|
17
|
-
test: "memory",
|
|
18
|
-
prod: "postgres",
|
|
19
|
-
},
|
|
20
|
-
kv: {
|
|
21
|
-
local: "memory",
|
|
22
|
-
docker: "redis",
|
|
23
|
-
test: "memory",
|
|
24
|
-
prod: "redis",
|
|
25
|
-
},
|
|
26
|
-
files: {
|
|
27
|
-
local: "fs",
|
|
28
|
-
docker: "s3",
|
|
29
|
-
test: "memory",
|
|
30
|
-
prod: "s3",
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
signal: {
|
|
34
|
-
local: "memory",
|
|
35
|
-
docker: "redis",
|
|
36
|
-
test: "memory",
|
|
37
|
-
prod: "redis",
|
|
38
|
-
},
|
|
39
|
-
clock: {
|
|
40
|
-
local: "memory",
|
|
41
|
-
docker: "postgres",
|
|
42
|
-
test: "frozen",
|
|
43
|
-
prod: "postgres",
|
|
44
|
-
},
|
|
45
|
-
journal: {
|
|
46
|
-
local: "memory",
|
|
47
|
-
docker: "postgres",
|
|
48
|
-
test: "memory",
|
|
49
|
-
prod: "postgres",
|
|
50
|
-
},
|
|
14
|
+
// Built-in encrypted-at-rest store — lives in Postgres, no extra service.
|
|
15
|
+
// Default `vault.dev` is `"env"`; pin built-in for local Docker-first apps.
|
|
16
|
+
// `oke vault init` prints the master key; set OKE_VAULT_MASTER_KEY to unseal.
|
|
51
17
|
vault: {
|
|
52
|
-
|
|
53
|
-
docker: "openbao",
|
|
54
|
-
test: "memory",
|
|
55
|
-
prod: "openbao",
|
|
56
|
-
},
|
|
57
|
-
channel: {
|
|
58
|
-
email: {
|
|
59
|
-
local: "console",
|
|
60
|
-
docker: "smtp",
|
|
61
|
-
test: "console",
|
|
62
|
-
prod: "smtp",
|
|
63
|
-
},
|
|
18
|
+
dev: "vault",
|
|
64
19
|
},
|
|
65
20
|
},
|
|
66
21
|
images: {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
22
|
+
store: {
|
|
23
|
+
sql: "postgres:18-alpine",
|
|
24
|
+
kv: "redis:8-alpine",
|
|
25
|
+
files: "rustfs/rustfs:1.0.0-beta.11",
|
|
26
|
+
},
|
|
27
|
+
channel: {
|
|
28
|
+
email: "axllent/mailpit:v1.22.3",
|
|
29
|
+
},
|
|
30
|
+
// pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.51", // create-oke wizard / --pgdog
|
|
73
31
|
},
|
|
74
|
-
i18n: { locales: ["en"
|
|
32
|
+
i18n: { locales: ["en"], default: "en" },
|
|
75
33
|
});
|
|
@@ -9,13 +9,15 @@
|
|
|
9
9
|
"zod": "^4.4.3"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
|
+
"@electric-sql/pglite": "^0.5.4",
|
|
13
|
+
"@electric-sql/pglite-pgvector": "^0.0.5",
|
|
12
14
|
"@types/bun": "latest",
|
|
13
15
|
"drizzle-kit": "1.0.0-rc.4",
|
|
14
16
|
"typescript": "^7.0.2"
|
|
15
17
|
},
|
|
16
18
|
"scripts": {
|
|
17
19
|
"typecheck": "tsc --noEmit",
|
|
18
|
-
"test": "
|
|
20
|
+
"test": "oke test",
|
|
19
21
|
"dev": "oke dev"
|
|
20
22
|
}
|
|
21
23
|
}
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import "
|
|
2
|
-
import "./locales/en";
|
|
3
|
-
import "./locales/ar";
|
|
1
|
+
import "@/core";
|
|
4
2
|
|
|
5
|
-
import { oke } from "okengine";
|
|
6
|
-
import * as routes from "
|
|
3
|
+
import { oke } from "okengine/http";
|
|
4
|
+
import * as routes from "@/flows/generated";
|
|
7
5
|
|
|
8
|
-
// stores (store.sql) · secrets (vault.secret) · signals (signal()) · channel
|
|
9
|
-
// templates (channel.<medium>().template()) auto-register from `./core`
|
|
10
|
-
// (and `./flows/notes/signals`) — no explicit arrays needed.
|
|
11
|
-
// `./flows/generated` is a real file, regenerated by `oke dev` / `oke build`
|
|
12
|
-
// from every `src/flows/<unit>/index.ts` folder — never edit it by hand.
|
|
13
6
|
export const app = oke({ name: "notes" }).adopt(routes);
|
|
14
7
|
|
|
15
8
|
export type App = typeof app;
|