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
package/src/templates.ts
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Standard template resolution.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Teaching apps live in repo-root `examples/<id>` (`--from-example`).
|
|
6
|
-
* Published installs use the prepack copies under this package.
|
|
4
|
+
* The only starter lives in this package at `template/`.
|
|
7
5
|
*/
|
|
8
6
|
|
|
9
7
|
import { existsSync, readFileSync } from "node:fs";
|
|
10
8
|
import { dirname, join, resolve } from "node:path";
|
|
11
9
|
import { fileURLToPath } from "node:url";
|
|
12
10
|
|
|
13
|
-
/**
|
|
14
|
-
export const TEMPLATES = ["
|
|
11
|
+
/** The single supported starter template. */
|
|
12
|
+
export const TEMPLATES = ["standard"] as const;
|
|
15
13
|
|
|
16
14
|
/** A known clean starter template. */
|
|
17
15
|
export type TemplateId = (typeof TEMPLATES)[number];
|
|
@@ -19,33 +17,9 @@ export type TemplateId = (typeof TEMPLATES)[number];
|
|
|
19
17
|
/** Default when `--template` is omitted (recommended project layout). */
|
|
20
18
|
export const DEFAULT_TEMPLATE: TemplateId = "standard";
|
|
21
19
|
|
|
22
|
-
/** One-line purpose for
|
|
20
|
+
/** One-line purpose for the starter (interactive select + help). */
|
|
23
21
|
export const TEMPLATE_PURPOSES: Readonly<Record<TemplateId, string>> = {
|
|
24
|
-
hello: 'Fastest possible "it works" — one flow, no Store',
|
|
25
|
-
minimal: "Smallest shape you'd actually ship — Store + 1–2 flows",
|
|
26
22
|
standard: "Full recommended file layout, empty scaffolding",
|
|
27
|
-
full: "Every element present and wired, no business logic",
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/** Teaching example ids — match `examples/*` and four-applications.md. */
|
|
31
|
-
export const EXAMPLES = ["notes", "linkly", "provisions", "skyport"] as const;
|
|
32
|
-
|
|
33
|
-
/** A known teaching example. */
|
|
34
|
-
export type ExampleId = (typeof EXAMPLES)[number];
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* "New ideas" one-liners from four-applications.md — reused for
|
|
38
|
-
* `--from-example` help and the interactive example select.
|
|
39
|
-
*/
|
|
40
|
-
export const EXAMPLE_NEW_IDEAS: Readonly<Record<ExampleId, string>> = {
|
|
41
|
-
notes:
|
|
42
|
-
"`oke`, `on`, `flow`, `http`, `store.sql`, `fx`, typed errors, the typed client.",
|
|
43
|
-
linkly:
|
|
44
|
-
"`signal` and its three delivery physics · `clock` · `gate` · triggers beyond HTTP · transactional emit · cross-unit decoupling.",
|
|
45
|
-
provisions:
|
|
46
|
-
"`durable` flows and the journal · `vault` · `channel` with fallback chains and i18n · live queries · plugins · a CDC trigger · the three cache tiers.",
|
|
47
|
-
skyport:
|
|
48
|
-
"the `ai` element (models, prompts, RAG, agents) · multi-tenancy · SLOs and journeys · distributed topology · the three scaling axes.",
|
|
49
23
|
};
|
|
50
24
|
|
|
51
25
|
/**
|
|
@@ -57,15 +31,6 @@ export function isTemplateId(value: string): value is TemplateId {
|
|
|
57
31
|
return (TEMPLATES as readonly string[]).includes(value);
|
|
58
32
|
}
|
|
59
33
|
|
|
60
|
-
/**
|
|
61
|
-
* Whether `value` is a known {@link ExampleId}.
|
|
62
|
-
*
|
|
63
|
-
* @param value - Candidate string
|
|
64
|
-
*/
|
|
65
|
-
export function isExampleId(value: string): value is ExampleId {
|
|
66
|
-
return (EXAMPLES as readonly string[]).includes(value);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
34
|
/**
|
|
70
35
|
* Directory that contains this package (`packages/create-oke`).
|
|
71
36
|
*/
|
|
@@ -74,67 +39,23 @@ export function packageRoot(): string {
|
|
|
74
39
|
}
|
|
75
40
|
|
|
76
41
|
/**
|
|
77
|
-
* Resolve the directory to copy for
|
|
42
|
+
* Resolve the directory to copy for the starter.
|
|
78
43
|
*
|
|
79
44
|
* Order:
|
|
80
|
-
* 1. `
|
|
81
|
-
* 2.
|
|
82
|
-
* 3. Bundled `templates/<template>` (npm prepack copy)
|
|
45
|
+
* 1. `CREATE_OKE_TEMPLATE` env (absolute path to a template)
|
|
46
|
+
* 2. Bundled `template/`
|
|
83
47
|
*
|
|
84
48
|
* @param template - Template id
|
|
85
49
|
* @returns Absolute path to the template source tree
|
|
86
50
|
*/
|
|
87
51
|
export function resolveTemplateDir(template: TemplateId): string {
|
|
88
|
-
const envRoot = process.env["
|
|
89
|
-
if (envRoot)
|
|
90
|
-
const fromEnv = resolve(envRoot, template);
|
|
91
|
-
if (existsSync(fromEnv)) return fromEnv;
|
|
92
|
-
}
|
|
93
|
-
|
|
52
|
+
const envRoot = process.env["CREATE_OKE_TEMPLATE"];
|
|
53
|
+
if (envRoot && existsSync(envRoot)) return resolve(envRoot);
|
|
94
54
|
const pkg = packageRoot();
|
|
95
|
-
const
|
|
96
|
-
if (existsSync(monorepo)) return monorepo;
|
|
97
|
-
|
|
98
|
-
const bundled = resolve(pkg, "templates", template);
|
|
99
|
-
if (existsSync(bundled)) return bundled;
|
|
100
|
-
|
|
101
|
-
throw new Error(
|
|
102
|
-
`create-oke: template "${template}" not found.\n` +
|
|
103
|
-
` looked at: ${monorepo}\n` +
|
|
104
|
-
` ${bundled}`,
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Resolve the directory to copy for `--from-example`.
|
|
110
|
-
*
|
|
111
|
-
* Order:
|
|
112
|
-
* 1. `CREATE_OKE_EXAMPLES` env (absolute path to an `examples/` tree)
|
|
113
|
-
* 2. Monorepo `examples/<example>` (two levels up from this package)
|
|
114
|
-
* 3. Bundled `examples/<example>` (npm prepack copy)
|
|
115
|
-
*
|
|
116
|
-
* @param example - Example id
|
|
117
|
-
* @returns Absolute path to the example source tree
|
|
118
|
-
*/
|
|
119
|
-
export function resolveExampleDir(example: ExampleId): string {
|
|
120
|
-
const envRoot = process.env["CREATE_OKE_EXAMPLES"];
|
|
121
|
-
if (envRoot) {
|
|
122
|
-
const fromEnv = resolve(envRoot, example);
|
|
123
|
-
if (existsSync(fromEnv)) return fromEnv;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const pkg = packageRoot();
|
|
127
|
-
const monorepo = resolve(pkg, "../../examples", example);
|
|
128
|
-
if (existsSync(monorepo)) return monorepo;
|
|
129
|
-
|
|
130
|
-
const bundled = resolve(pkg, "examples", example);
|
|
55
|
+
const bundled = resolve(pkg, "template");
|
|
131
56
|
if (existsSync(bundled)) return bundled;
|
|
132
57
|
|
|
133
|
-
throw new Error(
|
|
134
|
-
`create-oke: example "${example}" not found.\n` +
|
|
135
|
-
` looked at: ${monorepo}\n` +
|
|
136
|
-
` ${bundled}`,
|
|
137
|
-
);
|
|
58
|
+
throw new Error(`create-oke: template "${template}" not found at ${bundled}`);
|
|
138
59
|
}
|
|
139
60
|
|
|
140
61
|
/**
|
package/src/transform.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Rewrites applied when copying
|
|
2
|
+
* Rewrites applied when copying the bundled starter
|
|
3
3
|
* into a new project.
|
|
4
4
|
*
|
|
5
5
|
* Exactly:
|
|
@@ -8,12 +8,31 @@
|
|
|
8
8
|
* (absolute `file:<okengine-root>` in the monorepo; registry version otherwise)
|
|
9
9
|
* 3. Drop monorepo-only files that import paths outside the source tree
|
|
10
10
|
* (today: `tests/docker.test.ts`)
|
|
11
|
+
* 4. Optional `--sql` / wizard choice → Drizzle dialect + `store.sql` pins
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
import { readFileSync } from "node:fs";
|
|
14
15
|
import { join } from "node:path";
|
|
15
16
|
import { packageRoot } from "./templates.ts";
|
|
16
17
|
|
|
18
|
+
/** SQL store drivers selectable at scaffold time. */
|
|
19
|
+
export const SQL_DRIVERS = ["sqlite", "postgres"] as const;
|
|
20
|
+
|
|
21
|
+
/** A known store.sql driver id for create-oke. */
|
|
22
|
+
export type SqlDriverId = (typeof SQL_DRIVERS)[number];
|
|
23
|
+
|
|
24
|
+
/** Default when `--sql` / wizard choice is omitted (matches template sources). */
|
|
25
|
+
export const DEFAULT_SQL_DRIVER: SqlDriverId = "sqlite";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Whether `value` is a known {@link SqlDriverId}.
|
|
29
|
+
*
|
|
30
|
+
* @param value - Candidate string
|
|
31
|
+
*/
|
|
32
|
+
export function isSqlDriverId(value: string): value is SqlDriverId {
|
|
33
|
+
return (SQL_DRIVERS as readonly string[]).includes(value);
|
|
34
|
+
}
|
|
35
|
+
|
|
17
36
|
/** Shape of an example / scaffolded `package.json`. */
|
|
18
37
|
export type ScaffoldPackageJson = {
|
|
19
38
|
name?: string;
|
|
@@ -33,9 +52,7 @@ export type ScaffoldPackageJson = {
|
|
|
33
52
|
*
|
|
34
53
|
* @param localOkengineRoot - Absolute path when available
|
|
35
54
|
*/
|
|
36
|
-
export function resolveOkengineDependency(
|
|
37
|
-
localOkengineRoot: string | null,
|
|
38
|
-
): string {
|
|
55
|
+
export function resolveOkengineDependency(localOkengineRoot: string | null): string {
|
|
39
56
|
if (localOkengineRoot) return `file:${localOkengineRoot}`;
|
|
40
57
|
const pkgPath = join(packageRoot(), "package.json");
|
|
41
58
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf8")) as { version: string };
|
|
@@ -94,6 +111,43 @@ export function shouldSkipTemplatePath(relativePath: string): boolean {
|
|
|
94
111
|
return false;
|
|
95
112
|
}
|
|
96
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Rewrite a Drizzle schema file to the dialect for `driver`.
|
|
116
|
+
*
|
|
117
|
+
* Templates ship as `sqliteTable` / `drizzle-orm/sqlite-core`. Choosing
|
|
118
|
+
* `postgres` swaps to `pgTable` / `pg-core` (and the reverse is idempotent).
|
|
119
|
+
*
|
|
120
|
+
* @param source - Schema TypeScript source
|
|
121
|
+
* @param driver - Target store.sql driver
|
|
122
|
+
*/
|
|
123
|
+
export function transformSchemaForSqlDriver(source: string, driver: SqlDriverId): string {
|
|
124
|
+
if (driver === "postgres") {
|
|
125
|
+
return source
|
|
126
|
+
.replaceAll("drizzle-orm/sqlite-core", "drizzle-orm/pg-core")
|
|
127
|
+
.replaceAll("sqliteTable", "pgTable");
|
|
128
|
+
}
|
|
129
|
+
return source
|
|
130
|
+
.replaceAll("drizzle-orm/pg-core", "drizzle-orm/sqlite-core")
|
|
131
|
+
.replaceAll("pgTable", "sqliteTable");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Pin `store.sql` `local` / `docker` / `prod` in `oke.config.ts` to `driver`.
|
|
136
|
+
*
|
|
137
|
+
* Leaves `test: "memory"` (and every other facet) untouched.
|
|
138
|
+
*
|
|
139
|
+
* @param source - Config TypeScript source
|
|
140
|
+
* @param driver - Target store.sql driver
|
|
141
|
+
*/
|
|
142
|
+
export function transformConfigForSqlDriver(source: string, driver: SqlDriverId): string {
|
|
143
|
+
return source.replace(/sql:\s*\{[\s\S]*?\n\s*\}/, (block) =>
|
|
144
|
+
block
|
|
145
|
+
.replace(/local:\s*"(?:sqlite|postgres)"/, `local: "${driver}"`)
|
|
146
|
+
.replace(/docker:\s*"(?:sqlite|postgres)"/, `docker: "${driver}"`)
|
|
147
|
+
.replace(/prod:\s*"(?:sqlite|postgres)"/, `prod: "${driver}"`),
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
97
151
|
/**
|
|
98
152
|
* Sanitize a directory / package name for npm.
|
|
99
153
|
*
|
|
@@ -106,13 +160,9 @@ export function sanitizeProjectName(raw: string): string {
|
|
|
106
160
|
}
|
|
107
161
|
// Allow scoped names; otherwise lowercase npm-safe slug.
|
|
108
162
|
if (trimmed.startsWith("@")) {
|
|
109
|
-
const m = /^(@[a-z0-9-~][a-z0-9-._~]*\/[a-z0-9-~][a-z0-9-._~]*)$/.exec(
|
|
110
|
-
trimmed,
|
|
111
|
-
);
|
|
163
|
+
const m = /^(@[a-z0-9-~][a-z0-9-._~]*\/[a-z0-9-~][a-z0-9-._~]*)$/.exec(trimmed);
|
|
112
164
|
if (!m) {
|
|
113
|
-
throw new Error(
|
|
114
|
-
`create-oke: invalid scoped package name "${trimmed}"`,
|
|
115
|
-
);
|
|
165
|
+
throw new Error(`create-oke: invalid scoped package name "${trimmed}"`);
|
|
116
166
|
}
|
|
117
167
|
return trimmed;
|
|
118
168
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Environment template — copy to `.env.local` for local overrides.
|
|
2
|
+
# create-oke copies this file to `.env.local` when you scaffold a new project.
|
|
3
|
+
#
|
|
4
|
+
# Resolution order (first hit wins):
|
|
5
|
+
# process.env → .env.local → docker/.env.docker → vault driver → dev fallback
|
|
6
|
+
#
|
|
7
|
+
# --- Vault (app secrets) ---
|
|
8
|
+
# Declare secrets in src/vault.ts with `vault.secret(...)`, then uncomment lines here.
|
|
9
|
+
#
|
|
10
|
+
# --- Infrastructure ---
|
|
11
|
+
# Same keys as `docker/.env.docker` after `oke dev --docker`.
|
|
12
|
+
# Uncomment to override compose credentials for a host-managed service.
|
|
13
|
+
# Host ports under docker mode are unique per project — do not assume defaults.
|
|
14
|
+
|
|
15
|
+
# ── channel.email — Mailpit (SMTP + UI) ─────────────────────
|
|
16
|
+
# OKE_CHANNEL_EMAIL_URL=smtp://127.0.0.1:1025
|
|
17
|
+
# SMTP_URL=smtp://127.0.0.1:1025
|
|
18
|
+
# SMTP_HOST=127.0.0.1
|
|
19
|
+
# SMTP_PORT=1025
|
|
20
|
+
# MAILPIT_UI_URL=http://127.0.0.1:8025
|
|
21
|
+
# Optional controls:
|
|
22
|
+
# SMTP_USER=
|
|
23
|
+
# SMTP_PASSWORD=
|
|
24
|
+
# MP_MAX_MESSAGES=500
|
|
25
|
+
# MP_SMTP_AUTH_ACCEPT_ANY=1
|
|
26
|
+
# MP_SMTP_AUTH_ALLOW_INSECURE=1
|
|
27
|
+
|
|
28
|
+
# ── store.files — object storage (S3) ───────────────────────
|
|
29
|
+
# OKE_STORE_FILES_URL=http://access-key:secret-key@127.0.0.1:9000/oke
|
|
30
|
+
# S3_ACCESS_KEY_ID=access-key
|
|
31
|
+
# S3_SECRET_ACCESS_KEY=secret-key
|
|
32
|
+
# S3_BUCKET=oke
|
|
33
|
+
# S3_URL=http://access-key:secret-key@127.0.0.1:9000/oke
|
|
34
|
+
# S3_ENDPOINT=http://127.0.0.1:9000
|
|
35
|
+
# S3_CONSOLE_URL=http://127.0.0.1:9001
|
|
36
|
+
# S3_REGION=us-east-1
|
|
37
|
+
# Optional controls:
|
|
38
|
+
# S3_SESSION_TOKEN=
|
|
39
|
+
|
|
40
|
+
# ── store.kv — Redis ────────────────────────────────────────
|
|
41
|
+
# OKE_STORE_KV_PASSWORD=password
|
|
42
|
+
# OKE_STORE_KV_URL=redis://:password@127.0.0.1:6379
|
|
43
|
+
# REDIS_URL=redis://:password@127.0.0.1:6379
|
|
44
|
+
# Optional controls:
|
|
45
|
+
# OKE_STORE_KV_MAXMEMORY=256mb
|
|
46
|
+
# OKE_STORE_KV_MAXMEMORY_POLICY=allkeys-lru
|
|
47
|
+
|
|
48
|
+
# ── store.sql — Postgres ────────────────────────────────────
|
|
49
|
+
# OKE_STORE_SQL_USER=oke
|
|
50
|
+
# OKE_STORE_SQL_PASSWORD=password
|
|
51
|
+
# OKE_STORE_SQL_DB=oke
|
|
52
|
+
# OKE_STORE_SQL_URL=postgres://oke:password@127.0.0.1:5432/oke
|
|
53
|
+
# DATABASE_URL=postgres://oke:password@127.0.0.1:5432/oke
|
|
54
|
+
# Optional controls:
|
|
55
|
+
# PGDATA=/var/lib/postgresql/data/pgdata
|
|
56
|
+
# POSTGRES_INITDB_ARGS=--data-checksums
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# standard
|
|
2
|
+
|
|
3
|
+
Full recommended file layout with **empty scaffolding** — structure without
|
|
4
|
+
business logic. Default `create-oke` template.
|
|
5
|
+
|
|
6
|
+
## Run
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
bun install
|
|
10
|
+
oke dev # app :6530 · Console :6533 · MCP :6535
|
|
11
|
+
# or: oke mode docker && oke dev # postgres · redis · Mailpit · RustFS · OpenBao
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Local `oke dev` auto-runs `oke db push` when `schema.decl.ts` changes (opt out:
|
|
15
|
+
`--no-db-push`). Docker/prod never auto-apply DDL — use `oke db migrate`.
|
|
16
|
+
|
|
17
|
+
| Port | Try |
|
|
18
|
+
| ------- | ------------------------- |
|
|
19
|
+
| `:6530` | `GET /` · `GET /health` |
|
|
20
|
+
| `:6533` | Console |
|
|
21
|
+
| `:6535` | MCP |
|
|
22
|
+
|
|
23
|
+
## What’s in this template
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
standard/
|
|
27
|
+
├── .env.example # copied to .env.local by create-oke
|
|
28
|
+
├── drizzle.config.ts # oke db push|generate|migrate
|
|
29
|
+
├── oke.config.ts # local: sqlite · docker/prod: postgres
|
|
30
|
+
├── src/
|
|
31
|
+
│ ├── app.ts # adopt({ main }); wires stores + side modules
|
|
32
|
+
│ ├── core.ts / schema.decl.ts # Store (replace the placeholder table)
|
|
33
|
+
│ ├── gates.ts # Gate stubs
|
|
34
|
+
│ ├── vault.ts # Vault stubs
|
|
35
|
+
│ ├── channels.ts # Channel stubs
|
|
36
|
+
│ ├── locales/en.ts · ar.ts # i18n stubs
|
|
37
|
+
│ └── flows/main/
|
|
38
|
+
│ ├── index.ts # GET / · GET /health
|
|
39
|
+
│ ├── shapes.ts # contracts live next to flows
|
|
40
|
+
│ └── signals.ts # Signal stubs
|
|
41
|
+
└── tests/standard.test.ts
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- **Elements stubbed:** Flow · Store · Signal · Gate · Vault · Channel (+ locales)
|
|
45
|
+
- **Unit:** `main`
|
|
46
|
+
- **Flows to replace:** `root`, `health` — delete or rename once your domain exists
|
|
47
|
+
|
|
48
|
+
Fill `schema.decl.ts` (abstract tables → `oke db` emits `schema.generated.ts`
|
|
49
|
+
for the active dialect), then add real flows under
|
|
50
|
+
`src/flows/<unit>/`.
|
|
51
|
+
|
|
52
|
+
## Docker mode (`oke dev --docker`)
|
|
53
|
+
|
|
54
|
+
Closest to production protocols: Postgres, Redis, SMTP (Mailpit), S3 (RustFS),
|
|
55
|
+
and a real OpenBao vault (durable Raft storage, real init/unseal — not a
|
|
56
|
+
`-dev` server). Compose credentials land in `docker/.env.docker`.
|
|
57
|
+
|
|
58
|
+
On first `oke dev --docker` / `oke docker --prod` bring-up, `oke` initializes
|
|
59
|
+
OpenBao, unseals it, and mints a least-privilege token for the app. The root
|
|
60
|
+
token and the single unseal key stay on the host under `.oke/openbao/`
|
|
61
|
+
(`0600`, gitignored) — never in `docker/.env.docker`, never in YAML.
|
|
62
|
+
|
|
63
|
+
> **Single point of failure by design:** back up `.oke/openbao/unseal.key` to
|
|
64
|
+
> a separate safe location. Losing it means losing every secret permanently,
|
|
65
|
+
> with no recovery.
|
|
66
|
+
|
|
67
|
+
Host ports are unique per project so multiple apps can run at once. Use
|
|
68
|
+
`oke stack` or the `oke dev` Docker summary for the Mailpit UI and RustFS
|
|
69
|
+
console URLs — do not assume `:8025` / `:9001`.
|
|
70
|
+
|
|
71
|
+
`docker/.env.docker` uses protocol-native keys (`DATABASE_URL`, `REDIS_URL`,
|
|
72
|
+
`S3_*`, `SMTP_*`, `MAILPIT_UI_URL`) and includes commented optional controls.
|
|
73
|
+
Supported controls you uncomment are preserved when the generated stack refreshes.
|
|
74
|
+
|
|
75
|
+
## Agent contract
|
|
76
|
+
|
|
77
|
+
See [`AGENTS.md`](./AGENTS.md). Handbook: [oke.omqkhafi.dev/docs](https://oke.omqkhafi.dev/docs)
|