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.
- package/README.md +26 -35
- package/package.json +10 -12
- package/src/cli.test.ts +124 -144
- package/src/cli.ts +62 -160
- package/src/docs-origin.ts +2 -3
- package/src/index.ts +1 -2
- package/src/scaffold.ts +52 -32
- package/src/templates.ts +12 -91
- package/src/transform.ts +60 -10
- package/template/.env.example +56 -0
- package/template/README.md +77 -0
- package/template/bun.lock +845 -0
- package/template/drizzle.config.ts +25 -0
- package/{templates/standard → template}/oke.config.ts +22 -25
- package/{templates/standard → template}/package.json +3 -0
- package/{templates/minimal → template}/src/core.ts +1 -1
- package/template/src/schema.decl.ts +12 -0
- package/examples/linkly/oke.config.ts +0 -10
- package/examples/linkly/package.json +0 -15
- package/examples/linkly/src/app.ts +0 -21
- package/examples/linkly/src/core.ts +0 -4
- package/examples/linkly/src/flows/analytics/index.ts +0 -24
- package/examples/linkly/src/flows/links/index.ts +0 -59
- package/examples/linkly/src/flows/links/shapes.ts +0 -22
- package/examples/linkly/src/flows/links/signals.ts +0 -13
- package/examples/linkly/src/gates.ts +0 -8
- package/examples/linkly/src/schema.ts +0 -17
- package/examples/linkly/tests/linkly.test.ts +0 -19
- package/examples/notes/oke.config.ts +0 -14
- package/examples/notes/package.json +0 -16
- package/examples/notes/src/app.ts +0 -13
- package/examples/notes/src/core.ts +0 -4
- package/examples/notes/src/flows/notes/index.ts +0 -44
- package/examples/notes/src/schema.ts +0 -9
- package/examples/notes/tests/notes.test.ts +0 -10
- package/examples/provisions/oke.config.ts +0 -17
- package/examples/provisions/package.json +0 -15
- package/examples/provisions/src/app.ts +0 -60
- package/examples/provisions/src/channels.ts +0 -14
- package/examples/provisions/src/core.ts +0 -4
- package/examples/provisions/src/flows/notifications/index.ts +0 -19
- package/examples/provisions/src/flows/orders/index.ts +0 -70
- package/examples/provisions/src/flows/orders/shapes.ts +0 -21
- package/examples/provisions/src/flows/orders/signals.ts +0 -19
- package/examples/provisions/src/flows/payments/index.ts +0 -37
- package/examples/provisions/src/flows/payments/shapes.ts +0 -3
- package/examples/provisions/src/flows/payments/stripe.ts +0 -18
- package/examples/provisions/src/gates.ts +0 -4
- package/examples/provisions/src/locales/ar.ts +0 -1
- package/examples/provisions/src/locales/en.ts +0 -1
- package/examples/provisions/src/plugins/audit-schema.ts +0 -2
- package/examples/provisions/src/plugins/audit.ts +0 -14
- package/examples/provisions/src/schema.ts +0 -16
- package/examples/provisions/src/vault.ts +0 -16
- package/examples/provisions/tests/orders.test.ts +0 -18
- package/examples/skyport/evals/triage.jsonl +0 -1
- package/examples/skyport/oke.config.ts +0 -44
- package/examples/skyport/oke.images.lock +0 -4
- package/examples/skyport/package.json +0 -16
- package/examples/skyport/src/ai.ts +0 -25
- package/examples/skyport/src/app.ts +0 -57
- package/examples/skyport/src/channels.ts +0 -12
- package/examples/skyport/src/core.ts +0 -4
- package/examples/skyport/src/flows/bookings/index.ts +0 -50
- package/examples/skyport/src/flows/bookings/shapes.ts +0 -6
- package/examples/skyport/src/flows/bookings/signals.ts +0 -9
- package/examples/skyport/src/flows/notifications/index.ts +0 -16
- package/examples/skyport/src/flows/payments/index.ts +0 -14
- package/examples/skyport/src/flows/payments/shapes.ts +0 -5
- package/examples/skyport/src/flows/support/index.ts +0 -38
- package/examples/skyport/src/flows/users/elements.ts +0 -2
- package/examples/skyport/src/flows/users/index.ts +0 -12
- package/examples/skyport/src/flows/users/shapes.ts +0 -6
- package/examples/skyport/src/gates.ts +0 -10
- package/examples/skyport/src/journeys.ts +0 -9
- package/examples/skyport/src/locales/ar.ts +0 -4
- package/examples/skyport/src/locales/en.ts +0 -4
- package/examples/skyport/src/plugins/audit-schema.ts +0 -7
- package/examples/skyport/src/plugins/audit.ts +0 -14
- package/examples/skyport/src/plugins/panel.tsx +0 -4
- package/examples/skyport/src/schema.ts +0 -22
- package/examples/skyport/src/vault.ts +0 -24
- package/examples/skyport/tests/support.test.ts +0 -16
- package/src/sync-templates.ts +0 -86
- package/templates/full/README.md +0 -49
- package/templates/full/oke.config.ts +0 -68
- package/templates/full/package.json +0 -15
- package/templates/full/src/ai.ts +0 -11
- package/templates/full/src/app.ts +0 -34
- package/templates/full/src/channels.ts +0 -9
- package/templates/full/src/core.ts +0 -4
- package/templates/full/src/flows/main/index.ts +0 -45
- package/templates/full/src/flows/main/shapes.ts +0 -3
- package/templates/full/src/flows/main/signals.ts +0 -8
- package/templates/full/src/gates.ts +0 -4
- package/templates/full/src/locales/ar.ts +0 -3
- package/templates/full/src/locales/en.ts +0 -3
- package/templates/full/src/schema.ts +0 -8
- package/templates/full/src/vault.ts +0 -9
- package/templates/full/tests/full.test.ts +0 -11
- package/templates/hello/README.md +0 -38
- package/templates/hello/oke.config.ts +0 -3
- package/templates/hello/package.json +0 -14
- package/templates/hello/src/app.ts +0 -10
- package/templates/hello/src/flows/hello/index.ts +0 -27
- package/templates/hello/tests/hello.test.ts +0 -10
- package/templates/minimal/README.md +0 -41
- package/templates/minimal/oke.config.ts +0 -14
- package/templates/minimal/package.json +0 -15
- package/templates/minimal/src/app.ts +0 -13
- package/templates/minimal/src/flows/main/index.ts +0 -49
- package/templates/minimal/src/schema.ts +0 -8
- package/templates/minimal/tests/minimal.test.ts +0 -13
- package/templates/standard/README.md +0 -47
- package/templates/standard/src/core.ts +0 -4
- package/templates/standard/src/schema.ts +0 -9
- /package/{templates/standard → template}/src/app.ts +0 -0
- /package/{templates/standard → template}/src/channels.ts +0 -0
- /package/{templates/standard → template}/src/flows/main/index.ts +0 -0
- /package/{templates/standard → template}/src/flows/main/shapes.ts +0 -0
- /package/{templates/standard → template}/src/flows/main/signals.ts +0 -0
- /package/{templates/standard → template}/src/gates.ts +0 -0
- /package/{templates/standard → template}/src/locales/ar.ts +0 -0
- /package/{templates/standard → template}/src/locales/en.ts +0 -0
- /package/{templates/standard → template}/src/vault.ts +0 -0
- /package/{templates/standard → template}/tests/standard.test.ts +0 -0
|
@@ -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,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
|
-
});
|
package/src/sync-templates.ts
DELETED
|
@@ -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
|
-
}
|
package/templates/full/README.md
DELETED
|
@@ -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
|
-
}
|
package/templates/full/src/ai.ts
DELETED
|
@@ -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,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,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,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)
|