create-oke 0.10.0 → 0.10.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-oke",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
4
4
  "description": "Scaffold an okengine app — bunx create-oke@latest <name>",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/agents-md.ts CHANGED
@@ -89,7 +89,7 @@ App \`:6530\` · Console \`:6533\` · MCP \`:6535\`.
89
89
  - ❌ Inventing a ninth “element” or a parallel handler stack beside Flows
90
90
  - ✅ New capability = new **driver** on an existing element, or a new Flow
91
91
  - ❌ Untyped HTTP handlers that skip \`on\` / \`flow\` / contracts
92
- - ✅ \`on(http.get("/…"), flow({ in, out, do }))\`
92
+ - ✅ \`on(http.get("/…"), flow(name, { in, out, do }))\`
93
93
 
94
94
  ## Learn more
95
95
 
package/src/cli.test.ts CHANGED
@@ -261,8 +261,8 @@ describe("interactive branches", () => {
261
261
  expect(code).toBe(0);
262
262
  expect(readFileSync(join(dir, ".oke", "mode"), "utf8").trim()).toBe("docker");
263
263
  const notes = readFileSync(join(dir, "src", "flows", "notes", "index.ts"), "utf8");
264
- expect(notes).toContain('name: "notes.digest"');
265
- expect(notes).toContain('name: "notes.attach"');
264
+ expect(notes).toContain('flow("notes.digest"');
265
+ expect(notes).toContain('flow("notes.attach"');
266
266
  } finally {
267
267
  rmSync(dir, { recursive: true, force: true });
268
268
  }
@@ -564,8 +564,10 @@ describe("scaffold structure", () => {
564
564
  const appTs = readFileSync(join(result.targetDir, "src/app.ts"), "utf8");
565
565
  expect(appTs).not.toMatch(/Object\.assign/);
566
566
  expect(appTs).not.toMatch(/env:\s*["']test["']/);
567
- expect(appTs).toMatch(/stores:\s*\[/);
568
- expect(appTs).toMatch(/oke\(\{[\s\S]*stores:/);
567
+ // stores/secrets/signals/channel.templates auto-register — the
568
+ // minimal `oke({ name: "notes" })` shape carries no explicit arrays.
569
+ expect(appTs).not.toMatch(/stores:\s*\[/);
570
+ expect(appTs).toMatch(/oke\(\{\s*name:\s*["']notes["']\s*\}\)/);
569
571
  const pkg = JSON.parse(readFileSync(join(result.targetDir, "package.json"), "utf8")) as {
570
572
  name: string;
571
573
  dependencies: { okengine: string };
@@ -610,8 +612,8 @@ describe("scaffold structure", () => {
610
612
  expect(result.files).toContain(path);
611
613
  }
612
614
  const notes = readFileSync(join(result.targetDir, "src/flows/notes/index.ts"), "utf8");
613
- expect(notes).toContain('name: "notes.create"');
614
- expect(notes).not.toContain('name: "notes.digest"');
615
+ expect(notes).toContain('flow("notes.create"');
616
+ expect(notes).not.toContain('flow("notes.digest"');
615
617
  const all = result.files
616
618
  .filter((f) => f.endsWith(".ts") || f.endsWith(".md"))
617
619
  .map((f) => readFileSync(join(result.targetDir, f), "utf8"))
@@ -29,13 +29,12 @@ export default defineConfig({
29
29
  test: "memory",
30
30
  prod: "s3",
31
31
  },
32
- // Opt in via create-oke customize or uncomment:
33
- // index: {
34
- // local: "memory",
35
- // docker: "meilisearch",
36
- // test: "memory",
37
- // prod: "meilisearch",
38
- // },
32
+ index: {
33
+ local: "memory",
34
+ docker: "meilisearch",
35
+ test: "memory",
36
+ prod: "meilisearch",
37
+ },
39
38
  },
40
39
  signal: {
41
40
  local: "memory",
@@ -49,7 +48,6 @@ export default defineConfig({
49
48
  test: "frozen",
50
49
  prod: "postgres",
51
50
  },
52
- // Durable-flow journal (durable: true runs) — shared + leased in docker/prod.
53
51
  journal: {
54
52
  local: "memory",
55
53
  docker: "postgres",
@@ -1,18 +1,15 @@
1
- import { db, files, noteCreatedMail, webhookSecret } from "./core";
1
+ import "./core";
2
2
  import "./locales/en";
3
3
  import "./locales/ar";
4
4
 
5
5
  import { oke } from "okengine";
6
- import * as main from "./flows/main";
7
- import * as notes from "./flows/notes";
8
- import { noteCreated } from "./flows/notes/signals";
6
+ import * as routes from "./flows/generated";
9
7
 
10
- export const app = oke({
11
- name: "notes",
12
- stores: [db, files],
13
- secrets: [webhookSecret],
14
- signals: [noteCreated],
15
- channel: { templates: [noteCreatedMail] },
16
- }).adopt({ main, notes });
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
+ export const app = oke({ name: "notes" }).adopt(routes);
17
14
 
18
15
  export type App = typeof app;
@@ -0,0 +1,4 @@
1
+ // AUTO-GENERATED by `oke dev` / `oke build` — do not edit by hand.
2
+ // Regenerated from every `src/flows/<unit>/index.ts` unit folder.
3
+ export * as main from "./main/index.ts";
4
+ export * as notes from "./notes/index.ts";
@@ -4,9 +4,7 @@ import { z } from "zod";
4
4
  /** First-run welcome — visit :6530/ after `oke dev`. */
5
5
  export const root = on(
6
6
  http.get("/").gate(gate.public),
7
- flow({
8
- name: "main.root",
9
- unit: "main",
7
+ flow("main.root", {
10
8
  out: z.object({
11
9
  ok: z.literal(true),
12
10
  app: z.string(),
@@ -25,9 +23,7 @@ export const root = on(
25
23
  /** Liveness for probes and `bun test`. */
26
24
  export const health = on(
27
25
  http.get("/health").gate(gate.public),
28
- flow({
29
- name: "main.health",
30
- unit: "main",
26
+ flow("main.health", {
31
27
  out: z.object({ ok: z.literal(true) }),
32
28
  do: () => ({ ok: true as const }),
33
29
  }),
@@ -23,9 +23,7 @@ import "./signals";
23
23
  /** List active (non-archived) notes, newest first. */
24
24
  export const list = on(
25
25
  http.get("/notes").gate(gate.public),
26
- flow({
27
- name: "notes.list",
28
- unit: "notes",
26
+ flow("notes.list", {
29
27
  out: NoteListOut,
30
28
  effects: { reads: ["sql:app"] },
31
29
  do: async (_input, fx) => {
@@ -47,9 +45,7 @@ export const list = on(
47
45
  /** Create a note, emit `note-created`, touch vault. */
48
46
  export const create = on(
49
47
  http.post("/notes").gate(gate.public),
50
- flow({
51
- name: "notes.create",
52
- unit: "notes",
48
+ flow("notes.create", {
53
49
  in: NoteCreateIn,
54
50
  out: NoteOut,
55
51
  effects: {
@@ -84,9 +80,7 @@ export const create = on(
84
80
  /** Fetch one note by id. */
85
81
  export const get = on(
86
82
  http.get("/notes/:id").gate(gate.public),
87
- flow({
88
- name: "notes.get",
89
- unit: "notes",
83
+ flow("notes.get", {
90
84
  in: NoteIdIn,
91
85
  out: NoteOut,
92
86
  errors: { NotFound },
@@ -108,9 +102,7 @@ export const get = on(
108
102
  /** Soft-archive a note. */
109
103
  export const archive = on(
110
104
  http.post("/notes/:id/archive").gate(gate.public),
111
- flow({
112
- name: "notes.archive",
113
- unit: "notes",
105
+ flow("notes.archive", {
114
106
  in: NoteIdIn,
115
107
  out: NoteOut,
116
108
  errors: { NotFound },
@@ -138,9 +130,7 @@ export const archive = on(
138
130
  /** On create → send the note-created email template. */
139
131
  export const onCreated = on(
140
132
  noteCreated,
141
- flow({
142
- name: "notes.onCreated",
143
- unit: "notes",
133
+ flow("notes.onCreated", {
144
134
  effects: { sends: ["note-created"] },
145
135
  do: async (payload, fx) => {
146
136
  await fx.send(noteCreatedMail, {
@@ -154,9 +144,7 @@ export const onCreated = on(
154
144
  /** Store a text attachment next to a note (`files:uploads`). */
155
145
  export const attach = on(
156
146
  http.post("/notes/:id/attach").gate(gate.public),
157
- flow({
158
- name: "notes.attach",
159
- unit: "notes",
147
+ flow("notes.attach", {
160
148
  in: NoteAttachIn,
161
149
  out: NoteAttachOut,
162
150
  errors: { NotFound },
@@ -174,9 +162,7 @@ export const attach = on(
174
162
  /** Daily count of active notes (frozen under test drivers). */
175
163
  export const digest = on(
176
164
  every("1d"),
177
- flow({
178
- name: "notes.digest",
179
- unit: "notes",
165
+ flow("notes.digest", {
180
166
  out: NoteDigestOut,
181
167
  effects: { reads: ["sql:app"] },
182
168
  do: async (_input, fx) => {
@@ -192,9 +178,7 @@ export const digest = on(
192
178
  */
193
179
  export const summarize = on(
194
180
  http.post("/notes/:id/summarize").gate(gate.public),
195
- flow({
196
- name: "notes.summarize",
197
- unit: "notes",
181
+ flow("notes.summarize", {
198
182
  in: NoteSummarizeIn,
199
183
  out: NoteSummarizeOut,
200
184
  errors: { NotFound },
@@ -42,7 +42,6 @@ export default defineConfig({
42
42
  test: "frozen",
43
43
  prod: "postgres",
44
44
  },
45
- // Durable-flow journal (durable: true runs) — shared + leased in docker/prod.
46
45
  journal: {
47
46
  local: "memory",
48
47
  docker: "postgres",
@@ -1,18 +1,15 @@
1
- import { db, noteCreatedMail, webhookSecret } from "./core";
1
+ import "./core";
2
2
  import "./locales/en";
3
3
  import "./locales/ar";
4
4
 
5
5
  import { oke } from "okengine";
6
- import * as main from "./flows/main";
7
- import * as notes from "./flows/notes";
8
- import { noteCreated } from "./flows/notes/signals";
6
+ import * as routes from "./flows/generated";
9
7
 
10
- export const app = oke({
11
- name: "notes",
12
- stores: [db],
13
- secrets: [webhookSecret],
14
- signals: [noteCreated],
15
- channel: { templates: [noteCreatedMail] },
16
- }).adopt({ main, notes });
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
+ export const app = oke({ name: "notes" }).adopt(routes);
17
14
 
18
15
  export type App = typeof app;
@@ -0,0 +1,4 @@
1
+ // AUTO-GENERATED by `oke dev` / `oke build` — do not edit by hand.
2
+ // Regenerated from every `src/flows/<unit>/index.ts` unit folder.
3
+ export * as main from "./main/index.ts";
4
+ export * as notes from "./notes/index.ts";
@@ -4,9 +4,7 @@ import { z } from "zod";
4
4
  /** First-run welcome — visit :6530/ after `oke dev`. */
5
5
  export const root = on(
6
6
  http.get("/").gate(gate.public),
7
- flow({
8
- name: "main.root",
9
- unit: "main",
7
+ flow("main.root", {
10
8
  out: z.object({
11
9
  ok: z.literal(true),
12
10
  app: z.string(),
@@ -25,9 +23,7 @@ export const root = on(
25
23
  /** Liveness for probes and `bun test`. */
26
24
  export const health = on(
27
25
  http.get("/health").gate(gate.public),
28
- flow({
29
- name: "main.health",
30
- unit: "main",
26
+ flow("main.health", {
31
27
  out: z.object({ ok: z.literal(true) }),
32
28
  do: () => ({ ok: true as const }),
33
29
  }),
@@ -12,9 +12,7 @@ import "./signals";
12
12
  /** List active (non-archived) notes, newest first. */
13
13
  export const list = on(
14
14
  http.get("/notes").gate(gate.public),
15
- flow({
16
- name: "notes.list",
17
- unit: "notes",
15
+ flow("notes.list", {
18
16
  out: NoteListOut,
19
17
  effects: { reads: ["sql:app"] },
20
18
  do: async (_input, fx) => {
@@ -36,9 +34,7 @@ export const list = on(
36
34
  /** Create a note, emit `note-created`, touch vault. */
37
35
  export const create = on(
38
36
  http.post("/notes").gate(gate.public),
39
- flow({
40
- name: "notes.create",
41
- unit: "notes",
37
+ flow("notes.create", {
42
38
  in: NoteCreateIn,
43
39
  out: NoteOut,
44
40
  effects: {
@@ -73,9 +69,7 @@ export const create = on(
73
69
  /** Fetch one note by id. */
74
70
  export const get = on(
75
71
  http.get("/notes/:id").gate(gate.public),
76
- flow({
77
- name: "notes.get",
78
- unit: "notes",
72
+ flow("notes.get", {
79
73
  in: NoteIdIn,
80
74
  out: NoteOut,
81
75
  errors: { NotFound },
@@ -97,9 +91,7 @@ export const get = on(
97
91
  /** Soft-archive a note. */
98
92
  export const archive = on(
99
93
  http.post("/notes/:id/archive").gate(gate.public),
100
- flow({
101
- name: "notes.archive",
102
- unit: "notes",
94
+ flow("notes.archive", {
103
95
  in: NoteIdIn,
104
96
  out: NoteOut,
105
97
  errors: { NotFound },
@@ -127,9 +119,7 @@ export const archive = on(
127
119
  /** On create → send the note-created email template. */
128
120
  export const onCreated = on(
129
121
  noteCreated,
130
- flow({
131
- name: "notes.onCreated",
132
- unit: "notes",
122
+ flow("notes.onCreated", {
133
123
  effects: { sends: ["note-created"] },
134
124
  do: async (payload, fx) => {
135
125
  await fx.send(noteCreatedMail, {