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.
Files changed (59) hide show
  1. package/README.md +2 -2
  2. package/package.json +2 -2
  3. package/src/ai-setup/apply.ts +123 -31
  4. package/src/ai-setup/catalog.ts +3 -3
  5. package/src/ai-setup/from-pref.ts +1 -1
  6. package/src/ai-setup/prompts.ts +1 -1
  7. package/src/cli.test.ts +183 -142
  8. package/src/cli.ts +190 -32
  9. package/src/create-defaults.test.ts +21 -15
  10. package/src/create-defaults.ts +33 -13
  11. package/src/customize-flow.test.ts +30 -35
  12. package/src/customize-flow.ts +68 -229
  13. package/src/drivers-catalog.ts +42 -48
  14. package/src/local-okengine.test.ts +50 -41
  15. package/src/local-okengine.ts +28 -14
  16. package/src/locales.test.ts +128 -0
  17. package/src/locales.ts +321 -0
  18. package/src/scaffold.ts +277 -33
  19. package/src/templates.ts +2 -8
  20. package/src/transform.test.ts +102 -38
  21. package/src/transform.ts +378 -132
  22. package/templates/advanced/.env.example +23 -3
  23. package/templates/advanced/README.md +1 -1
  24. package/templates/advanced/drizzle.config.ts +10 -13
  25. package/templates/advanced/oke.config.ts +21 -62
  26. package/templates/advanced/package.json +3 -1
  27. package/templates/advanced/src/app.ts +3 -10
  28. package/templates/advanced/src/core.ts +58 -0
  29. package/templates/advanced/src/db/schema.decl.ts +1 -1
  30. package/templates/advanced/src/db/seed/index.ts +2 -2
  31. package/templates/advanced/src/flows/notes/index.ts +3 -15
  32. package/templates/advanced/src/locales/index.ts +6 -0
  33. package/templates/advanced/tests/advanced.test.ts +1 -1
  34. package/templates/advanced/tsconfig.json +3 -0
  35. package/templates/standard/.env.example +23 -3
  36. package/templates/standard/README.md +1 -1
  37. package/templates/standard/drizzle.config.ts +10 -13
  38. package/templates/standard/oke.config.ts +18 -60
  39. package/templates/standard/package.json +3 -1
  40. package/templates/standard/src/app.ts +3 -10
  41. package/templates/standard/src/core.ts +55 -0
  42. package/templates/standard/src/db/schema.decl.ts +1 -1
  43. package/templates/standard/src/db/seed/index.ts +2 -2
  44. package/templates/standard/src/flows/notes/index.ts +3 -12
  45. package/templates/standard/src/locales/index.ts +6 -0
  46. package/templates/standard/tests/standard.test.ts +1 -1
  47. package/templates/standard/tsconfig.json +3 -0
  48. package/templates/advanced/src/core/channels.ts +0 -13
  49. package/templates/advanced/src/core/gates.ts +0 -12
  50. package/templates/advanced/src/core/index.ts +0 -12
  51. package/templates/advanced/src/core/store.ts +0 -8
  52. package/templates/advanced/src/core/vault.ts +0 -7
  53. package/templates/advanced/src/locales/ar.ts +0 -18
  54. package/templates/standard/src/core/channels.ts +0 -13
  55. package/templates/standard/src/core/gates.ts +0 -12
  56. package/templates/standard/src/core/index.ts +0 -12
  57. package/templates/standard/src/core/store.ts +0 -5
  58. package/templates/standard/src/core/vault.ts +0 -7
  59. 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
- # OKE_AI_DRIVER=ollama
91
- # OKE_AI_URL=http://127.0.0.1:11434
92
- # OKE_AI_MODEL=qwen3.5:9b
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 sqlite/memory/fs · docker postgres/redis/s3/openbao/smtp.
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
- * Dialect comes from OKE's `store.sql` driver map (resolved by the CLI and
7
- * injected as `OKE_DRIZZLE_DIALECT`) never inferred from `DATABASE_URL`
8
- * presence. `src/db/schema.generated.ts` is emitted from `src/db/schema.decl.ts`
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
- * Versioned prod migrations land in `./src/db/migrations` never mix with `.oke/`.
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.generated.ts",
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, docker-ready driver map.
5
- * Recommended create path seeds `.oke/mode` as docker.
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.generated.ts",
11
+ generated: "src/db/schema.drizzle.ts",
11
12
  },
12
13
  drivers: {
13
14
  store: {
14
- sql: {
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
- signal: {
40
- local: "memory",
41
- docker: "redis",
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
- local: "env",
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/ai.ts
27
+ // Opt in: create-oke --ai / oke ai setup writes drivers.ai + models in src/core.ts
72
28
  },
73
29
  images: {
74
- "store.sql": "postgres:18-alpine",
75
- pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.51",
76
- "store.kv": "redis:8-alpine",
77
- "store.files": "rustfs/rustfs:1.0.0-beta.11",
78
- "channel.email": "axllent/mailpit:v1.22.3",
79
- vault: "openbao/openbao:2.6.1",
80
- // "store.index": "getmeili/meilisearch:v1.37",
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", "ar"], default: "en", dir: { ar: "rtl" } },
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": "bun test",
20
+ "test": "oke test",
19
21
  "dev": "oke dev"
20
22
  }
21
23
  }
@@ -1,15 +1,8 @@
1
- import "./core";
2
- import "./locales/en";
3
- import "./locales/ar";
1
+ import "@/core";
4
2
 
5
- import { oke } from "okengine";
6
- import * as routes from "./flows/generated";
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.generated.ts` for the active dialect by `oke db` / `oke dev`.
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 "../../core";
3
- import { notes } from "../schema.decl";
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 "../../core";
5
- import { notes } from "../../db/schema.decl";
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 });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Message catalogs — imported once from `src/core.ts`.
3
+ * Add a sibling import when you add a locale file.
4
+ */
5
+
6
+ import "./en";
@@ -1,6 +1,6 @@
1
1
  import { afterAll, beforeAll, expect, test } from "bun:test";
2
2
  import { createTestApp, type TestApp } from "okengine/test";
3
- import { app, type App } from "../src/app";
3
+ import { app, type App } from "@/app";
4
4
 
5
5
  let t: TestApp<App>;
6
6
 
@@ -6,6 +6,9 @@
6
6
  "moduleDetection": "force",
7
7
  "types": ["bun"],
8
8
  "moduleResolution": "bundler",
9
+ "paths": {
10
+ "@/*": ["./src/*"]
11
+ },
9
12
  "allowImportingTsExtensions": true,
10
13
  "verbatimModuleSyntax": true,
11
14
  "noEmit": true,
@@ -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
- # OKE_AI_DRIVER=ollama
91
- # OKE_AI_URL=http://127.0.0.1:11434
92
- # OKE_AI_MODEL=qwen3.5:9b
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 sqlite · docker postgres (+ redis/s3/openbao/smtp) |
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
- * Dialect comes from OKE's `store.sql` driver map (resolved by the CLI and
7
- * injected as `OKE_DRIZZLE_DIALECT`) never inferred from `DATABASE_URL`
8
- * presence. `src/db/schema.generated.ts` is emitted from `src/db/schema.decl.ts`
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
- * Versioned prod migrations land in `./src/db/migrations` never mix with `.oke/`.
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.generated.ts",
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 — local-first Notes.
5
- * Docker/prod pins stay ready when you switch `oke mode docker`.
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.generated.ts",
11
+ generated: "src/db/schema.drizzle.ts",
11
12
  },
12
13
  drivers: {
13
- store: {
14
- sql: {
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
- },
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
- local: "env",
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
- "store.sql": "postgres:18-alpine",
68
- pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.51",
69
- "store.kv": "redis:8-alpine",
70
- "store.files": "rustfs/rustfs:1.0.0-beta.11",
71
- "channel.email": "axllent/mailpit:v1.22.3",
72
- vault: "openbao/openbao:2.6.1",
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", "ar"], default: "en", dir: { ar: "rtl" } },
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": "bun test",
20
+ "test": "oke test",
19
21
  "dev": "oke dev"
20
22
  }
21
23
  }
@@ -1,15 +1,8 @@
1
- import "./core";
2
- import "./locales/en";
3
- import "./locales/ar";
1
+ import "@/core";
4
2
 
5
- import { oke } from "okengine";
6
- import * as routes from "./flows/generated";
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;