create-oke 0.2.6 → 0.3.2

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 (126) hide show
  1. package/README.md +26 -35
  2. package/package.json +10 -12
  3. package/src/cli.test.ts +124 -144
  4. package/src/cli.ts +62 -160
  5. package/src/docs-origin.ts +2 -3
  6. package/src/index.ts +1 -2
  7. package/src/scaffold.ts +52 -32
  8. package/src/templates.ts +12 -91
  9. package/src/transform.ts +60 -10
  10. package/template/.env.example +56 -0
  11. package/template/README.md +77 -0
  12. package/template/bun.lock +845 -0
  13. package/template/drizzle.config.ts +25 -0
  14. package/{templates/standard → template}/oke.config.ts +22 -25
  15. package/{templates/standard → template}/package.json +3 -0
  16. package/{templates/minimal → template}/src/core.ts +1 -1
  17. package/template/src/schema.decl.ts +12 -0
  18. package/examples/linkly/oke.config.ts +0 -10
  19. package/examples/linkly/package.json +0 -15
  20. package/examples/linkly/src/app.ts +0 -21
  21. package/examples/linkly/src/core.ts +0 -4
  22. package/examples/linkly/src/flows/analytics/index.ts +0 -24
  23. package/examples/linkly/src/flows/links/index.ts +0 -59
  24. package/examples/linkly/src/flows/links/shapes.ts +0 -22
  25. package/examples/linkly/src/flows/links/signals.ts +0 -13
  26. package/examples/linkly/src/gates.ts +0 -8
  27. package/examples/linkly/src/schema.ts +0 -17
  28. package/examples/linkly/tests/linkly.test.ts +0 -19
  29. package/examples/notes/oke.config.ts +0 -14
  30. package/examples/notes/package.json +0 -16
  31. package/examples/notes/src/app.ts +0 -13
  32. package/examples/notes/src/core.ts +0 -4
  33. package/examples/notes/src/flows/notes/index.ts +0 -44
  34. package/examples/notes/src/schema.ts +0 -9
  35. package/examples/notes/tests/notes.test.ts +0 -10
  36. package/examples/provisions/oke.config.ts +0 -17
  37. package/examples/provisions/package.json +0 -15
  38. package/examples/provisions/src/app.ts +0 -60
  39. package/examples/provisions/src/channels.ts +0 -14
  40. package/examples/provisions/src/core.ts +0 -4
  41. package/examples/provisions/src/flows/notifications/index.ts +0 -19
  42. package/examples/provisions/src/flows/orders/index.ts +0 -70
  43. package/examples/provisions/src/flows/orders/shapes.ts +0 -21
  44. package/examples/provisions/src/flows/orders/signals.ts +0 -19
  45. package/examples/provisions/src/flows/payments/index.ts +0 -37
  46. package/examples/provisions/src/flows/payments/shapes.ts +0 -3
  47. package/examples/provisions/src/flows/payments/stripe.ts +0 -18
  48. package/examples/provisions/src/gates.ts +0 -4
  49. package/examples/provisions/src/locales/ar.ts +0 -1
  50. package/examples/provisions/src/locales/en.ts +0 -1
  51. package/examples/provisions/src/plugins/audit-schema.ts +0 -2
  52. package/examples/provisions/src/plugins/audit.ts +0 -14
  53. package/examples/provisions/src/schema.ts +0 -16
  54. package/examples/provisions/src/vault.ts +0 -16
  55. package/examples/provisions/tests/orders.test.ts +0 -18
  56. package/examples/skyport/evals/triage.jsonl +0 -1
  57. package/examples/skyport/oke.config.ts +0 -44
  58. package/examples/skyport/oke.images.lock +0 -4
  59. package/examples/skyport/package.json +0 -16
  60. package/examples/skyport/src/ai.ts +0 -25
  61. package/examples/skyport/src/app.ts +0 -57
  62. package/examples/skyport/src/channels.ts +0 -12
  63. package/examples/skyport/src/core.ts +0 -4
  64. package/examples/skyport/src/flows/bookings/index.ts +0 -50
  65. package/examples/skyport/src/flows/bookings/shapes.ts +0 -6
  66. package/examples/skyport/src/flows/bookings/signals.ts +0 -9
  67. package/examples/skyport/src/flows/notifications/index.ts +0 -16
  68. package/examples/skyport/src/flows/payments/index.ts +0 -14
  69. package/examples/skyport/src/flows/payments/shapes.ts +0 -5
  70. package/examples/skyport/src/flows/support/index.ts +0 -38
  71. package/examples/skyport/src/flows/users/elements.ts +0 -2
  72. package/examples/skyport/src/flows/users/index.ts +0 -12
  73. package/examples/skyport/src/flows/users/shapes.ts +0 -6
  74. package/examples/skyport/src/gates.ts +0 -10
  75. package/examples/skyport/src/journeys.ts +0 -9
  76. package/examples/skyport/src/locales/ar.ts +0 -4
  77. package/examples/skyport/src/locales/en.ts +0 -4
  78. package/examples/skyport/src/plugins/audit-schema.ts +0 -7
  79. package/examples/skyport/src/plugins/audit.ts +0 -14
  80. package/examples/skyport/src/plugins/panel.tsx +0 -4
  81. package/examples/skyport/src/schema.ts +0 -22
  82. package/examples/skyport/src/vault.ts +0 -24
  83. package/examples/skyport/tests/support.test.ts +0 -16
  84. package/src/sync-templates.ts +0 -86
  85. package/templates/full/README.md +0 -49
  86. package/templates/full/oke.config.ts +0 -68
  87. package/templates/full/package.json +0 -15
  88. package/templates/full/src/ai.ts +0 -11
  89. package/templates/full/src/app.ts +0 -34
  90. package/templates/full/src/channels.ts +0 -9
  91. package/templates/full/src/core.ts +0 -4
  92. package/templates/full/src/flows/main/index.ts +0 -45
  93. package/templates/full/src/flows/main/shapes.ts +0 -3
  94. package/templates/full/src/flows/main/signals.ts +0 -8
  95. package/templates/full/src/gates.ts +0 -4
  96. package/templates/full/src/locales/ar.ts +0 -3
  97. package/templates/full/src/locales/en.ts +0 -3
  98. package/templates/full/src/schema.ts +0 -8
  99. package/templates/full/src/vault.ts +0 -9
  100. package/templates/full/tests/full.test.ts +0 -11
  101. package/templates/hello/README.md +0 -38
  102. package/templates/hello/oke.config.ts +0 -3
  103. package/templates/hello/package.json +0 -14
  104. package/templates/hello/src/app.ts +0 -10
  105. package/templates/hello/src/flows/hello/index.ts +0 -27
  106. package/templates/hello/tests/hello.test.ts +0 -10
  107. package/templates/minimal/README.md +0 -41
  108. package/templates/minimal/oke.config.ts +0 -14
  109. package/templates/minimal/package.json +0 -15
  110. package/templates/minimal/src/app.ts +0 -13
  111. package/templates/minimal/src/flows/main/index.ts +0 -49
  112. package/templates/minimal/src/schema.ts +0 -8
  113. package/templates/minimal/tests/minimal.test.ts +0 -13
  114. package/templates/standard/README.md +0 -47
  115. package/templates/standard/src/core.ts +0 -4
  116. package/templates/standard/src/schema.ts +0 -9
  117. /package/{templates/standard → template}/src/app.ts +0 -0
  118. /package/{templates/standard → template}/src/channels.ts +0 -0
  119. /package/{templates/standard → template}/src/flows/main/index.ts +0 -0
  120. /package/{templates/standard → template}/src/flows/main/shapes.ts +0 -0
  121. /package/{templates/standard → template}/src/flows/main/signals.ts +0 -0
  122. /package/{templates/standard → template}/src/gates.ts +0 -0
  123. /package/{templates/standard → template}/src/locales/ar.ts +0 -0
  124. /package/{templates/standard → template}/src/locales/en.ts +0 -0
  125. /package/{templates/standard → template}/src/vault.ts +0 -0
  126. /package/{templates/standard → template}/tests/standard.test.ts +0 -0
@@ -1,7 +0,0 @@
1
- import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
2
-
3
- export const auditLog = sqliteTable("audit_log", {
4
- id: text("id").primaryKey(),
5
- at: integer("at").notNull(),
6
- payload: text("payload"),
7
- });
@@ -1,14 +0,0 @@
1
- import { plugin, store } from "okengine";
2
- import { z } from "zod";
3
-
4
- export const audit = plugin("audit", { version: "1.0.0" })
5
- .config(z.object({ retain: z.string().default("2y") }))
6
- .element(store.sql("audit", { schema: () => import("./audit-schema") }))
7
- .needs("store.kv")
8
- .decorate("audit", { enabled: true })
9
- .hook("afterHandle", async (ctx, fx) => {
10
- if (ctx.trigger.meta?.audit) await fx.store("audit").log(ctx);
11
- })
12
- .errors({ AuditWriteFailed: z.object({ reason: z.string() }) })
13
- .consolePanel({ id: "audit", title: "Audit Trail", entry: "./panel.tsx" })
14
- .cli("audit:export", ({ fx }) => fx.store("audit").exportCsv());
@@ -1,4 +0,0 @@
1
- /** Audit Console panel stub (Skyport tree). */
2
- export default function AuditPanel() {
3
- return null;
4
- }
@@ -1,22 +0,0 @@
1
- import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
2
- import { id } from "okengine/store";
3
-
4
- export const bookings = sqliteTable("bookings", {
5
- id: text("id").primaryKey().$defaultFn(id),
6
- userId: text("user_id").notNull(),
7
- flightId: text("flight_id").notNull(),
8
- seats: integer("seats").notNull(),
9
- status: text("status").notNull().default("pending"),
10
- createdAt: integer("created_at").notNull(),
11
- });
12
-
13
- export const flights = sqliteTable("flights", {
14
- id: text("id").primaryKey(),
15
- seatsAvailable: integer("seats_available").notNull(),
16
- });
17
-
18
- export const tickets = sqliteTable("tickets", {
19
- id: text("id").primaryKey(), subject: text("subject").notNull(),
20
- body: text("body").notNull(), urgency: text("urgency"), team: text("team"),
21
- summary: text("summary"),
22
- });
@@ -1,24 +0,0 @@
1
- import { vault } from "okengine";
2
- import { z } from "zod";
3
-
4
- export const dbUrl = vault.secret("DATABASE_URL", {
5
- schema: z.string().url(),
6
- dev: vault.fromStack("store.sql"),
7
- });
8
-
9
- export const dbReplica1 = vault.secret("DATABASE_REPLICA_1", {
10
- schema: z.string().url(),
11
- dev: "postgres://localhost/oke-replica",
12
- });
13
-
14
- export const anthropicKey = vault.secret("ANTHROPIC_KEY", {
15
- schema: z.string().min(1),
16
- dev: "sk-ant-test",
17
- });
18
-
19
- export const stripeKey = vault.secret("STRIPE_KEY", {
20
- schema: z.string().startsWith("sk_"),
21
- description: "Payments gateway key",
22
- rotate: "90d",
23
- dev: "sk_test_local",
24
- });
@@ -1,16 +0,0 @@
1
- import { test, expect } from "bun:test";
2
- import { createTestApp } from "okengine/test";
3
- import { app } from "../src/app";
4
- import { triage } from "../src/ai";
5
-
6
- test("AI triage is mockable and cost-bounded", async () => {
7
- const t = await createTestApp(app);
8
- t.ai.mock(triage, { urgency: "high", team: "ops", summary: "seat dispute" });
9
-
10
- const u = await t.auth.loginAs({});
11
- const { data } = await t.api.support.createTicket({ subject: "…", body: "…" }, { as: u });
12
-
13
- expect(data!.urgency).toBe("high");
14
- expect(t.ai.cost()).toBeLessThan(0.02); // budgets are assertable
15
- await t.close();
16
- });
@@ -1,86 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * prepack: copy repo-root `templates/` and `examples/` into this package so the
4
- * published npm package can scaffold without the monorepo checkout.
5
- *
6
- * Applies the same skip rules as runtime scaffold (no node_modules, no
7
- * monorepo-only docker.test.ts).
8
- */
9
-
10
- import {
11
- cpSync,
12
- existsSync,
13
- mkdirSync,
14
- readdirSync,
15
- rmSync,
16
- statSync,
17
- } from "node:fs";
18
- import { join, relative, resolve } from "node:path";
19
- import { EXAMPLES, packageRoot, TEMPLATES } from "./templates.ts";
20
- import { shouldSkipTemplatePath } from "./transform.ts";
21
-
22
- const pkg = packageRoot();
23
- const templatesRoot = resolve(pkg, "../../templates");
24
- const examplesRoot = resolve(pkg, "../../examples");
25
- const outTemplates = join(pkg, "templates");
26
- const outExamples = join(pkg, "examples");
27
-
28
- if (!existsSync(templatesRoot)) {
29
- console.error(
30
- `create-oke prepack: templates/ not found at ${templatesRoot}`,
31
- );
32
- process.exit(1);
33
- }
34
- if (!existsSync(examplesRoot)) {
35
- console.error(`create-oke prepack: examples/ not found at ${examplesRoot}`);
36
- process.exit(1);
37
- }
38
-
39
- rmSync(outTemplates, { recursive: true, force: true });
40
- rmSync(outExamples, { recursive: true, force: true });
41
- mkdirSync(outTemplates, { recursive: true });
42
- mkdirSync(outExamples, { recursive: true });
43
-
44
- for (const id of TEMPLATES) {
45
- const src = join(templatesRoot, id);
46
- const dst = join(outTemplates, id);
47
- if (!existsSync(src)) {
48
- console.error(`create-oke prepack: missing template ${src}`);
49
- process.exit(1);
50
- }
51
- copyFiltered(src, dst, src);
52
- console.log(`create-oke prepack: template ${id}`);
53
- }
54
-
55
- for (const id of EXAMPLES) {
56
- const src = join(examplesRoot, id);
57
- const dst = join(outExamples, id);
58
- if (!existsSync(src)) {
59
- console.error(`create-oke prepack: missing example ${src}`);
60
- process.exit(1);
61
- }
62
- copyFiltered(src, dst, src);
63
- console.log(`create-oke prepack: example ${id}`);
64
- }
65
-
66
- /**
67
- * @param src - Source file or directory
68
- * @param dst - Destination path
69
- * @param root - Template root for relative skip paths
70
- */
71
- function copyFiltered(src: string, dst: string, root: string): void {
72
- const st = statSync(src);
73
- const rel = relative(root, src).split(/[/\\]/).join("/");
74
- if (rel && shouldSkipTemplatePath(rel)) return;
75
- if (st.isDirectory()) {
76
- mkdirSync(dst, { recursive: true });
77
- for (const entry of readdirSync(src)) {
78
- copyFiltered(join(src, entry), join(dst, entry), root);
79
- }
80
- return;
81
- }
82
- if (st.isFile()) {
83
- mkdirSync(join(dst, ".."), { recursive: true });
84
- cpSync(src, dst);
85
- }
86
- }
@@ -1,49 +0,0 @@
1
- # full
2
-
3
- **Every element present and wired** — no business logic. Use when you want the
4
- complete surface ready to fill in.
5
-
6
- ## Run
7
-
8
- ```bash
9
- bun install
10
- oke dev # app :6530 · Console :6533 · MCP :6535
11
- ```
12
-
13
- | Port | Try |
14
- |---|---|
15
- | `:6530` | `GET /` · `GET /health` |
16
- | `:6533` | Console |
17
- | `:6535` | MCP |
18
-
19
- ## What’s in this template
20
-
21
- ```text
22
- full/
23
- ├── oke.config.ts
24
- ├── src/
25
- │ ├── app.ts # gates, secrets, signals, stores, channel, ai
26
- │ ├── core.ts / schema.ts # Store
27
- │ ├── gates.ts # open gate (used on HTTP)
28
- │ ├── vault.ts # appSecret
29
- │ ├── channels.ts # welcome template
30
- │ ├── ai.ts # stub model + echo prompt
31
- │ ├── locales/en.ts · ar.ts
32
- │ └── flows/main/
33
- │ ├── index.ts # GET / · GET /health · every("1d")
34
- │ ├── shapes.ts
35
- │ └── signals.ts # pinged
36
- └── tests/full.test.ts
37
- ```
38
-
39
- - **Elements wired:** Flow · Store · Signal · Clock (`every`) · Gate · Vault · Channel · AI
40
- - **Unit:** `main`
41
- - **App `$options`:** `gates`, `secrets`, `signals`, `stores`, `channel`, `ai`
42
- - **Flows:** `root`, `health` (emits `pinged`), plus a trivial daily cron
43
-
44
- Replace stubs with real models, prompts, channels, and domain flows. Prefer
45
- `standard` if you do not need AI / clock / vault on day one.
46
-
47
- ## Agent contract
48
-
49
- See [`AGENTS.md`](./AGENTS.md). Handbook: [okengine.vercel.app/docs](https://okengine.vercel.app/docs)
@@ -1,68 +0,0 @@
1
- import { defineConfig } from "okengine/config";
2
-
3
- export default defineConfig({
4
- drivers: {
5
- store: {
6
- sql: {
7
- dev: "sqlite",
8
- stack: "postgres",
9
- test: "memory",
10
- prod: "postgres",
11
- },
12
- kv: {
13
- dev: "memory",
14
- stack: "redis",
15
- test: "memory",
16
- prod: "redis",
17
- },
18
- },
19
- signal: {
20
- dev: "memory",
21
- stack: "postgres",
22
- test: "memory",
23
- prod: "postgres",
24
- },
25
- clock: {
26
- dev: "memory",
27
- stack: "postgres",
28
- test: "frozen",
29
- prod: "postgres",
30
- },
31
- vault: {
32
- dev: "dotenv",
33
- stack: "dotenv",
34
- test: "memory",
35
- prod: "sops",
36
- },
37
- channel: {
38
- email: {
39
- dev: "console",
40
- stack: "smtp",
41
- test: "console",
42
- prod: "smtp",
43
- },
44
- sms: {
45
- dev: "console",
46
- stack: "unifonic",
47
- test: "console",
48
- prod: "unifonic",
49
- },
50
- whatsapp: {
51
- dev: "console",
52
- stack: "wa-cloud",
53
- test: "console",
54
- prod: "wa-cloud",
55
- },
56
- },
57
- ai: {
58
- dev: "mock",
59
- stack: "mock",
60
- test: "mock",
61
- },
62
- },
63
- images: {
64
- "store.sql": "postgres:18-alpine",
65
- "store.kv": "redis:8-alpine",
66
- },
67
- i18n: { locales: ["en", "ar"], default: "en", dir: { ar: "rtl" } },
68
- });
@@ -1,15 +0,0 @@
1
- {
2
- "name": "@oke/template-full",
3
- "version": "0.0.1",
4
- "private": true,
5
- "type": "module",
6
- "dependencies": {
7
- "okengine": "file:../..",
8
- "drizzle-orm": "^1.0.0-rc.4",
9
- "zod": "^4.4.3"
10
- },
11
- "scripts": {
12
- "test": "bun test",
13
- "dev": "oke dev"
14
- }
15
- }
@@ -1,11 +0,0 @@
1
- import { ai } from "okengine";
2
- import { z } from "zod";
3
-
4
- export const stub = ai.model("stub", { provider: "anthropic", tier: "haiku" });
5
-
6
- /** Stub prompt — replace with real versioned prompts. */
7
- export const echo = stub.prompt("echo", {
8
- in: z.object({ text: z.string() }),
9
- out: z.object({ text: z.string() }),
10
- version: 1,
11
- });
@@ -1,34 +0,0 @@
1
- import { db } from "./core";
2
- import { open } from "./gates";
3
- import { appSecret } from "./vault";
4
- import { welcome } from "./channels";
5
- import { stub, echo } from "./ai";
6
- import { pinged } from "./flows/main/signals";
7
- import "./channels";
8
- import "./gates";
9
- import "./ai";
10
- import "./locales/en";
11
- import "./locales/ar";
12
-
13
- import { oke } from "okengine";
14
- import * as main from "./flows/main";
15
-
16
- export const app = oke({ name: "full" }).adopt({ main });
17
-
18
- export type App = typeof app;
19
-
20
- Object.assign(app.$options, {
21
- env: "test",
22
- gates: [open],
23
- secrets: [appSecret],
24
- signals: [pinged],
25
- stores: [db],
26
- channel: {
27
- templates: [welcome],
28
- defaultLocale: "en",
29
- },
30
- ai: {
31
- models: [stub],
32
- prompts: [echo],
33
- },
34
- });
@@ -1,9 +0,0 @@
1
- import { channel } from "okengine";
2
- import { z } from "zod";
3
-
4
- export const mail = channel.email({ from: "App <no-reply@example.com>" });
5
-
6
- /** Stub channel template — replace with real copy. */
7
- export const welcome = mail.template("welcome", {
8
- schema: z.object({ name: z.string() }),
9
- });
@@ -1,4 +0,0 @@
1
- import { store } from "okengine";
2
- import * as schema from "./schema";
3
-
4
- export const db = store.sql("app", { schema });
@@ -1,45 +0,0 @@
1
- import { on, flow, http, every } from "okengine";
2
- import { z } from "zod";
3
- import { open } from "../../gates";
4
- import { Health } from "./shapes";
5
- import { pinged } from "./signals";
6
-
7
- /** First-run welcome — visit :6530/ after `oke dev`. */
8
- export const root = on(
9
- http.get("/").gate(open),
10
- flow({
11
- out: z.object({
12
- ok: z.literal(true),
13
- console: z.string(),
14
- try: z.string(),
15
- }),
16
- do: () => ({
17
- ok: true as const,
18
- console: "http://127.0.0.1:6533",
19
- try: "/health",
20
- }),
21
- }),
22
- );
23
-
24
- export const health = on(
25
- http.get("/health").gate(open),
26
- flow({
27
- out: Health,
28
- do: async (_input, fx) => {
29
- await fx.emit(pinged, { at: Date.now() });
30
- return { ok: true as const };
31
- },
32
- }),
33
- );
34
-
35
- on(pinged, flow({
36
- do: async () => {},
37
- }));
38
-
39
- /** Trivial cron — replace with real schedules. */
40
- on(
41
- every("1d"),
42
- flow({
43
- do: async () => {},
44
- }),
45
- );
@@ -1,3 +0,0 @@
1
- import { z } from "zod";
2
-
3
- export const Health = z.object({ ok: z.literal(true) });
@@ -1,8 +0,0 @@
1
- import { signal } from "okengine";
2
- import { z } from "zod";
3
-
4
- /** Trivial signal — replace with real events. */
5
- export const pinged = signal("pinged", {
6
- schema: z.object({ at: z.number() }),
7
- delivery: "once",
8
- });
@@ -1,4 +0,0 @@
1
- import { gate } from "okengine";
2
-
3
- /** Trivial shared gate — replace with real policies. */
4
- export const open = gate.policy("open", () => true);
@@ -1,3 +0,0 @@
1
- export default {
2
- "welcome.subject": "أهلاً",
3
- };
@@ -1,3 +0,0 @@
1
- export default {
2
- "welcome.subject": "Welcome",
3
- };
@@ -1,8 +0,0 @@
1
- import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
2
- import { id, now } from "okengine/store";
3
-
4
- export const entries = sqliteTable("entries", {
5
- id: text("id").primaryKey().$defaultFn(id),
6
- body: text("body").notNull(),
7
- createdAt: integer("created_at").notNull().$defaultFn(now),
8
- });
@@ -1,9 +0,0 @@
1
- import { vault } from "okengine";
2
- import { z } from "zod";
3
-
4
- /** Stub secret contract — replace with your secrets. */
5
- export const appSecret = vault.secret("APP_SECRET", {
6
- schema: z.string().min(1),
7
- description: "Application secret",
8
- dev: "dev-only-secret",
9
- });
@@ -1,11 +0,0 @@
1
- import { test, expect } from "bun:test";
2
- import { createTestApp } from "okengine/test";
3
- import { app } from "../src/app";
4
-
5
- test("boots — health flow with wired elements", async () => {
6
- const t = await createTestApp(app);
7
- const { data, error } = await t.api.main.health({});
8
- expect(error).toBeNull();
9
- expect(data).toEqual({ ok: true });
10
- await t.signals.drain();
11
- });
@@ -1,38 +0,0 @@
1
- # hello
2
-
3
- Fastest possible “it works” — one unit, two HTTP flows, **no Store**.
4
-
5
- ## Run
6
-
7
- ```bash
8
- bun install
9
- oke dev # app :6530 · Console :6533 · MCP :6535
10
- ```
11
-
12
- | Port | Try |
13
- |---|---|
14
- | `:6530` | `GET /` · `GET /hello` |
15
- | `:6533` | Console |
16
- | `:6535` | MCP |
17
-
18
- ## What’s in this template
19
-
20
- ```text
21
- hello/
22
- ├── oke.config.ts
23
- ├── src/
24
- │ ├── app.ts # oke({ name: "hello" }).adopt({ hello })
25
- │ └── flows/hello/index.ts # GET / · GET /hello
26
- └── tests/hello.test.ts
27
- ```
28
-
29
- - **Elements:** Flow only (no `store`, `gate`, `vault`, `channel`, or `ai`)
30
- - **Unit:** `hello`
31
- - **Flows:** `root` (`GET /`), `hello` (`GET /hello` → `{ message: "ok" }`)
32
-
33
- Replace `/hello` with your first real route. When you need persistence, move up to
34
- `minimal` or `standard` — or keep growing this tree.
35
-
36
- ## Agent contract
37
-
38
- See [`AGENTS.md`](./AGENTS.md). Handbook: [okengine.vercel.app/docs](https://okengine.vercel.app/docs)
@@ -1,3 +0,0 @@
1
- import { defineConfig } from "okengine/config";
2
-
3
- export default defineConfig({});
@@ -1,14 +0,0 @@
1
- {
2
- "name": "@oke/template-hello",
3
- "version": "0.0.1",
4
- "private": true,
5
- "type": "module",
6
- "dependencies": {
7
- "okengine": "file:../..",
8
- "zod": "^4.4.3"
9
- },
10
- "scripts": {
11
- "test": "bun test",
12
- "dev": "oke dev"
13
- }
14
- }
@@ -1,10 +0,0 @@
1
- import { oke } from "okengine";
2
- import * as hello from "./flows/hello";
3
-
4
- export const app = oke({ name: "hello" }).adopt({ hello });
5
-
6
- export type App = typeof app;
7
-
8
- Object.assign(app.$options, {
9
- env: "test",
10
- });
@@ -1,27 +0,0 @@
1
- import { on, flow, http } from "okengine";
2
- import { z } from "zod";
3
-
4
- /** First-run welcome — visit :6530/ after `oke dev`. */
5
- export const root = on(
6
- http.get("/"),
7
- flow({
8
- out: z.object({
9
- ok: z.literal(true),
10
- console: z.string(),
11
- try: z.string(),
12
- }),
13
- do: () => ({
14
- ok: true as const,
15
- console: "http://127.0.0.1:6533",
16
- try: "/hello",
17
- }),
18
- }),
19
- );
20
-
21
- export const hello = on(
22
- http.get("/hello"),
23
- flow({
24
- out: z.object({ message: z.string() }),
25
- do: () => ({ message: "ok" }),
26
- }),
27
- );
@@ -1,10 +0,0 @@
1
- import { test, expect } from "bun:test";
2
- import { createTestApp } from "okengine/test";
3
- import { app } from "../src/app";
4
-
5
- test("boots and answers /hello", async () => {
6
- const t = await createTestApp(app);
7
- const { data, error } = await t.api.hello.hello({});
8
- expect(error).toBeNull();
9
- expect(data?.message).toBe("ok");
10
- });
@@ -1,41 +0,0 @@
1
- # minimal
2
-
3
- Smallest shape you’d actually ship — **Store + HTTP flows** over a single table.
4
-
5
- ## Run
6
-
7
- ```bash
8
- bun install
9
- oke dev # app :6530 · Console :6533 · MCP :6535
10
- ```
11
-
12
- | Port | Try |
13
- |---|---|
14
- | `:6530` | `GET /` · `GET /entries` · `POST /entries` |
15
- | `:6533` | Console |
16
- | `:6535` | MCP |
17
-
18
- ## What’s in this template
19
-
20
- ```text
21
- minimal/
22
- ├── oke.config.ts
23
- ├── src/
24
- │ ├── app.ts # adopt({ main }), stores: [db]
25
- │ ├── core.ts # store.sql("…")
26
- │ ├── schema.ts # entries table (Drizzle)
27
- │ └── flows/main/index.ts # GET / · GET|POST /entries
28
- └── tests/minimal.test.ts
29
- ```
30
-
31
- - **Elements:** Flow · Store (`sql`)
32
- - **Unit:** `main`
33
- - **Flows:** `root`, `list` (`GET /entries`), `create` (`POST /entries` with `{ body }`)
34
- - **Schema:** `entries` — `id`, `body`, `createdAt`
35
-
36
- Swap `entries` for your domain table and grow flows beside it. Need gates,
37
- channels, or locales? Use `standard`.
38
-
39
- ## Agent contract
40
-
41
- See [`AGENTS.md`](./AGENTS.md). Handbook: [okengine.vercel.app/docs](https://okengine.vercel.app/docs)
@@ -1,14 +0,0 @@
1
- import { defineConfig } from "okengine/config";
2
-
3
- export default defineConfig({
4
- drivers: {
5
- store: {
6
- sql: {
7
- dev: "sqlite",
8
- stack: "postgres",
9
- test: "memory",
10
- prod: "postgres",
11
- },
12
- },
13
- },
14
- });