/**
* Boot-level proof: compiled/inferred effects reaching a REAL running app's
* capability token — not an isolated compiler-only or kernel-only test.
*
* Before this file existed, `flow(name, {...})` with no hand-declared `effects`
* always minted an OPEN capability token (every access allowed, no gate at
* all) in every environment, including `docker` / `prod` — `extractManifest`
* inference only ever fed the static `manifest.oke.json` artifact (Console,
* docs, publish), never the live boot path. Confirmed via real `oke()` boot
* + `app.fetch()`, not assumption.
*
* Also documents the sql:
(compiler inference) vs sql:
* (kernel `gatedSqlHandle`) naming mismatch this stamping bridge surfaces:
* once inference actually reaches the runtime, a flow relying on it for a
* real `fx.store(db).insert(table)` write must not throw `UNDECLARED_WRITE`
* for touching the exact table it declared.
*/
import { afterEach, describe, expect, test } from "bun:test";
import { mkdtemp, rm, writeFile, mkdir } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { z } from "zod";
import { gate } from "../elements/gate.ts";
import { field, id, now, store } from "../elements/store.ts";
import { passkey } from "../plugins/passkey.ts";
import { oke } from "./app.ts";
import { resetNoEffectsWarnForTests } from "./boot.ts";
import { flow, resetFlowSeq } from "./flow.ts";
import { on, resetBindings } from "./on.ts";
import { createTestApp } from "../test/create-test-app.ts";
import { http } from "./triggers.ts";
afterEach(() => {
resetBindings();
resetFlowSeq();
resetNoEffectsWarnForTests();
});
const notes = store.schema.table("notes", {
id: field.text().primaryKey().defaultFn(id),
title: field.text().notNull(),
createdAt: field.integer().notNull().defaultFn(now),
});
const CreateIn = z.object({ id: z.string(), title: z.string() });
const CreateOut = z.object({ ok: z.boolean() });
function buildUnannotatedCreateFlow(db: ReturnType) {
return on(
http.post("/notes", { in: CreateIn, out: CreateOut }).public(),
flow("notes.create", {
// Deliberately no `effects` — the "let the compiler infer it" case.
do: async (input, fx) => {
await fx.store(db).insert(notes).values({ id: input.id, title: input.title, createdAt: 1 });
return { ok: true };
},
}),
);
}
describe("boot-level: undeclared-effects flow, no manifest / rootDir", () => {
test("local / test: open token — real insert succeeds (documented dev-loop fallback)", async () => {
resetBindings();
resetFlowSeq();
const db = store.sql("app", { schema: { notes } });
// `on(...)` (inside buildUnannotatedCreateFlow) must run BEFORE `oke(...)`
// is constructed — oke() synchronously drains the global on() registry
// at construction time; a binding created only as .adopt()'s argument
// (after oke() already ran) never gets wired to a route.
const create = buildUnannotatedCreateFlow(db);
const app = oke({ name: "stamp-open", gate: { policies: [gate.public] } }).adopt({ create });
Object.assign(app.$options, { stores: [db] });
await createTestApp(app, { capability: "open" });
const res = await app.fetch(
new Request("http://localhost/notes", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ id: "x1", title: "hi" }),
}),
);
expect(res.status).toBe(200);
});
test("docker: hard fail at boot — OKE1020, never an open token in a deploy-shaped env", async () => {
resetBindings();
resetFlowSeq();
const db = store.sql("app", { schema: { notes } });
const create = buildUnannotatedCreateFlow(db);
const app = oke({ name: "stamp-docker", gate: { policies: [gate.public] } }).adopt({ create });
const memoryDrivers = {
store: {
sql: { dev: "memory", prod: "memory" },
kv: { dev: "memory", prod: "memory" },
},
channel: { email: { dev: "console", prod: "console" } },
} as const;
await expect(
app.boot({
env: "dev",
docker: true,
stores: [db],
unguardedHttp: "allow",
startScheduler: false,
config: { drivers: memoryDrivers },
}),
).rejects.toThrow(/OKE1020/);
});
test("prod: hard fail at boot — same posture as docker", async () => {
resetBindings();
resetFlowSeq();
const db = store.sql("app", { schema: { notes } });
const create = buildUnannotatedCreateFlow(db);
const app = oke({ name: "stamp-prod", gate: { policies: [gate.public] } }).adopt({ create });
await expect(
app.boot({
env: "prod",
stores: [db],
unguardedHttp: "allow",
startScheduler: false,
config: {
drivers: {
store: { sql: { prod: "memory" }, kv: { prod: "memory" } },
channel: { email: { prod: "console" } },
},
},
}),
).rejects.toThrow(/OKE1020/);
});
});
describe("boot-level: table-ref resolution stays backward compatible", () => {
test("older store-level effects (sql:) still cover a schema-table op — every existing template's convention", async () => {
resetBindings();
resetFlowSeq();
const db = store.sql("app", { schema: { notes } });
const create = on(
http.post("/notes", { in: CreateIn, out: CreateOut }).public(),
flow("notes.create", {
// The convention every template/test predates Direction B with —
// store-level, not table-level. Must keep working unchanged.
effects: { writes: ["sql:app"] },
do: async (input, fx) => {
await fx
.store(db)
.insert(notes)
.values({ id: input.id, title: input.title, createdAt: 1 });
return { ok: true };
},
}),
);
const app = oke({ name: "stamp-back-compat", gate: { policies: [gate.public] } }).adopt({
create,
});
Object.assign(app.$options, { stores: [db] });
await createTestApp(app, { capability: "open" });
const res = await app.fetch(
new Request("http://localhost/notes", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ id: "x1", title: "hi" }),
}),
);
expect(res.status).toBe(200);
});
});
describe("boot-level: undeclared-effects flow, rootDir stamping from a real source tree", () => {
test("real fx.store(db).insert(table) write succeeds once inference is stamped onto the capability token", async () => {
resetBindings();
resetFlowSeq();
const dir = await mkdtemp(join(tmpdir(), "oke-stamp-"));
try {
await mkdir(join(dir, "flows", "notes"), { recursive: true });
// A real source file with NO manual `effects:` — extractManifest infers
// `writes: ["sql:notes"]` for this from the real `fx.store(db).insert`
// call, exactly like the kernel test flow above.
await writeFile(
join(dir, "flows", "notes", "index.ts"),
`
import { on, flow, http, gate } from "okengine";
// Unresolved bindings are fine — extraction is AST-only, never executed.
// What matters is the literal shape: fx.store(db).insert(notes) so the
// same table-name inference that produced "sql:notes" earlier fires here.
const db = {} as any;
const notes = {} as any;
export const create = on(
http.post("/notes").public(),
flow("notes.create", {
do: async (input, fx) => {
await fx.store(db).insert(notes).values({ id: input.id, title: input.title, createdAt: 1 });
return { ok: true };
},
}),
);
`,
);
const db = store.sql("app", { schema: { notes } });
const create = buildUnannotatedCreateFlow(db);
const app = oke({ name: "stamp-rootdir", gate: { policies: [gate.public] } }).adopt({
create,
});
Object.assign(app.$options, { stores: [db] });
await createTestApp(app, { boot: { rootDir: dir } });
const res = await app.fetch(
new Request("http://localhost/notes", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ id: "x1", title: "hi" }),
}),
);
const body = (await res.json()) as { data: unknown; error: { message?: string } | null };
expect(res.status, body.error?.message ?? "").toBe(200);
expect(body.data).toEqual({ ok: true });
} finally {
await rm(dir, { recursive: true, force: true });
}
});
});
describe("boot-level: built-in auth flows under docker", () => {
test("emailAndPassword + passkey boot with docker:true — empty stamp from Manifest, no hand-declared effects", async () => {
resetBindings();
resetFlowSeq();
const memoryDrivers = {
store: {
sql: { dev: "memory", prod: "memory" },
kv: { dev: "memory", prod: "memory" },
},
channel: { email: { dev: "console", prod: "console" } },
} as const;
const app = oke({
name: "auth-stamp-docker",
registry: "ignore",
gate: {
auth: {
secret: "test-secret-at-least-16",
emailAndPassword: { enabled: true },
},
},
}).plug(passkey({ origins: ["http://localhost"] }));
// Explicit Manifest (as `oke dev` extract would supply for app Flows).
// Framework auth Flows are absent → mintCapabilities stamps `{}`.
await app.boot({
env: "dev",
docker: true,
unguardedHttp: "allow",
startScheduler: false,
manifest: { oke: "1.0", app: "auth-stamp-docker", flows: {} },
config: { drivers: memoryDrivers },
});
await app.stop();
});
});
describe("boot-level: OKE1020 names a failed extract", () => {
test("docker boot includes Manifest extract failed when rootDir extract throws", async () => {
resetBindings();
resetFlowSeq();
const dir = await mkdtemp(join(tmpdir(), "oke-stamp-extract-fail-"));
try {
await mkdir(join(dir, "src"), { recursive: true });
await writeFile(
join(dir, "src/poison.ts"),
`
import { on, flow, signal } from "okengine";
export const inbound = on(signal.once("x"), flow({ do: () => ({}) }));
`,
);
const create = on(
http.get("/x").public(),
flow("main.health", { do: () => ({ ok: true as const }) }),
);
const app = oke({ name: "stamp-extract-fail", gate: { policies: [gate.public] } }).adopt({
create,
});
const memoryDrivers = {
store: {
sql: { dev: "memory", prod: "memory" },
kv: { dev: "memory", prod: "memory" },
},
channel: { email: { dev: "console", prod: "console" } },
} as const;
await expect(
app.boot({
env: "dev",
docker: true,
rootDir: dir,
unguardedHttp: "allow",
startScheduler: false,
config: { drivers: memoryDrivers },
}),
).rejects.toThrow(/OKE1020[\s\S]*Manifest extract failed/);
} finally {
await rm(dir, { recursive: true, force: true });
}
});
});