Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
128 commits
Select commit Hold shift + click to select a range
95db7ba
docs(stack): align runtime architecture documentation
jgoux Aug 5, 2026
b2943a0
fix(process-compose): make unhealthy lifecycle terminal
jgoux Aug 5, 2026
7d19e70
refactor(stack): establish explicit domain model
jgoux Aug 5, 2026
c4aabe0
chore(stack): integrate lifecycle prerequisites
jgoux Aug 5, 2026
442698f
refactor(process-compose): isolate supervisor policies
jgoux Aug 5, 2026
3e56622
refactor(stack): consolidate local lifecycle ownership
jgoux Aug 5, 2026
a650edd
Merge branch 'agent/process-compose-supervisor-cleanup' into agent/st…
jgoux Aug 5, 2026
6c577a4
refactor(stack): restore service factory locality
jgoux Aug 5, 2026
b7a45d1
refactor(stack): make functions configuration explicit
jgoux Aug 5, 2026
854f874
Merge remote-tracking branch 'origin/develop' into agent/stack-domain…
jgoux Aug 5, 2026
47d1387
Merge branch 'agent/stack-domain-model' into agent/stack-runtime-impl…
jgoux Aug 5, 2026
1fa1c33
Merge branch 'agent/stack-runtime-implementation' into agent/stack-fa…
jgoux Aug 5, 2026
d6dd4dd
chore(process-compose): merge current develop
jgoux Aug 5, 2026
83a0f4a
Merge branch 'agent/stack-factory-resource-locality' into agent/funct…
jgoux Aug 5, 2026
5ca2c1b
chore(process-compose): reconcile updated lifecycle imports
jgoux Aug 5, 2026
4a6a049
Merge branch 'agent/stack-factory-resource-locality' into agent/funct…
jgoux Aug 5, 2026
a596636
chore(process-compose): update supervisor branch base
jgoux Aug 5, 2026
55f8013
test(stack): make partial startup cleanup deterministic
jgoux Aug 5, 2026
8b2e172
Merge branch 'agent/stack-factory-resource-locality' into agent/funct…
jgoux Aug 5, 2026
d188f8b
Merge remote-tracking branch 'origin/develop' into agent/stack-domain…
jgoux Aug 5, 2026
fa591c0
Merge branch 'agent/stack-domain-model' into agent/stack-runtime-impl…
jgoux Aug 5, 2026
f601375
Merge branch 'agent/stack-runtime-implementation' into agent/stack-fa…
jgoux Aug 5, 2026
c7256a1
Merge branch 'agent/stack-factory-resource-locality' into agent/funct…
jgoux Aug 5, 2026
8e2ed76
fix(process-compose): handle terminal health failures
jgoux Aug 5, 2026
21b5638
Merge branch 'agent/process-compose-lifecycle-correctness' into agent…
jgoux Aug 5, 2026
57979d5
fix(process-compose): bound supervisor cleanup commands
jgoux Aug 5, 2026
daeffc2
Merge branch 'agent/process-compose-lifecycle-correctness' into agent…
jgoux Aug 5, 2026
3817fcd
fix(stack): scope readiness deadlines to health waits
jgoux Aug 5, 2026
d552e46
Merge branch 'agent/stack-runtime-implementation' into agent/stack-fa…
jgoux Aug 5, 2026
e4ba7c3
Merge branch 'agent/process-compose-supervisor-cleanup' into agent/st…
jgoux Aug 5, 2026
77782df
test(stack): await lazy Docker service readiness
jgoux Aug 5, 2026
f6703e4
Merge branch 'agent/stack-runtime-implementation' into agent/stack-fa…
jgoux Aug 5, 2026
042464b
Merge branch 'agent/stack-factory-resource-locality' into agent/funct…
jgoux Aug 5, 2026
a570b9e
chore(stack): format merged readiness test
jgoux Aug 5, 2026
b7e84b6
fix(stack): terminate daemon after lazy timeout
jgoux Aug 5, 2026
f757348
Merge branch 'agent/stack-runtime-implementation' into agent/stack-fa…
jgoux Aug 5, 2026
ffe68d5
Merge branch 'agent/stack-factory-resource-locality' into agent/funct…
jgoux Aug 5, 2026
d24cdb9
fix(process-compose): surface recovery hook failures
jgoux Aug 5, 2026
384e0ee
Merge branch 'agent/process-compose-lifecycle-correctness' into agent…
jgoux Aug 5, 2026
4c9bb66
Merge branch 'agent/process-compose-supervisor-cleanup' into agent/st…
jgoux Aug 5, 2026
734b815
Merge branch 'agent/stack-runtime-implementation' into agent/stack-fa…
jgoux Aug 5, 2026
92cd8cf
Merge branch 'agent/stack-factory-resource-locality' into agent/funct…
jgoux Aug 5, 2026
6017cc3
test(process-compose): cover recovery hook transition
jgoux Aug 5, 2026
7aec419
Merge branch 'agent/process-compose-supervisor-cleanup' into agent/st…
jgoux Aug 5, 2026
5fd81e2
Merge branch 'agent/stack-runtime-implementation' into agent/stack-fa…
jgoux Aug 5, 2026
903c87a
Merge branch 'agent/stack-factory-resource-locality' into agent/funct…
jgoux Aug 5, 2026
f1ade49
fix(process-compose): fail blocked healthy dependents
jgoux Aug 5, 2026
851479d
Merge branch 'agent/process-compose-lifecycle-correctness' into agent…
jgoux Aug 5, 2026
ccdc785
Merge branch 'agent/process-compose-supervisor-cleanup' into agent/st…
jgoux Aug 5, 2026
37bc585
Merge branch 'agent/stack-runtime-implementation' into agent/stack-fa…
jgoux Aug 5, 2026
4fcb5b2
Merge branch 'agent/stack-factory-resource-locality' into agent/funct…
jgoux Aug 5, 2026
27e8561
fix(process-compose): hard-kill timed-out cleanup
jgoux Aug 5, 2026
7fe14af
Merge branch 'agent/process-compose-supervisor-cleanup' of github.com…
jgoux Aug 5, 2026
a1f7a11
fix(stack): make readiness teardown terminal
jgoux Aug 5, 2026
1cb73c9
Merge branch 'agent/stack-runtime-implementation' of github.com:supab…
jgoux Aug 5, 2026
58214a1
Merge branch 'agent/stack-factory-resource-locality' of github.com:su…
jgoux Aug 5, 2026
42c775c
fix(process-compose): await restartable dependencies
jgoux Aug 5, 2026
39cc38d
Merge branch 'agent/process-compose-lifecycle-correctness' of github.…
jgoux Aug 5, 2026
c9de7d0
Merge branch 'agent/process-compose-supervisor-cleanup' of github.com…
jgoux Aug 5, 2026
8c44089
Merge branch 'agent/stack-runtime-implementation' of github.com:supab…
jgoux Aug 5, 2026
23ccdfe
Merge branch 'agent/stack-factory-resource-locality' of github.com:su…
jgoux Aug 5, 2026
48a6057
fix(stack): synchronize status after readiness
jgoux Aug 5, 2026
62f861a
Merge branch 'agent/process-compose-lifecycle-correctness' of github.…
jgoux Aug 5, 2026
0985e68
Merge branch 'agent/process-compose-supervisor-cleanup' of github.com…
jgoux Aug 5, 2026
62a5a0a
Merge branch 'agent/stack-runtime-implementation' of github.com:supab…
jgoux Aug 5, 2026
861ec01
Merge branch 'agent/stack-factory-resource-locality' of github.com:su…
jgoux Aug 5, 2026
c9de546
fix(stack): derive startup coordination timeouts
jgoux Aug 5, 2026
759dd1f
Merge branch 'agent/process-compose-lifecycle-correctness' of github.…
jgoux Aug 5, 2026
6f815fb
Merge branch 'agent/process-compose-supervisor-cleanup' of github.com…
jgoux Aug 5, 2026
5867864
Merge remote-tracking branch 'origin/agent/stack-runtime-implementati…
jgoux Aug 5, 2026
66c64bb
Merge remote-tracking branch 'origin/agent/stack-factory-resource-loc…
jgoux Aug 5, 2026
a14d408
fix(stack): align startup budget deadlines
jgoux Aug 6, 2026
db7d015
fix(process-compose): await restarting completed dependencies
jgoux Aug 6, 2026
2c825a0
chore(process-compose): integrate lifecycle hardening
jgoux Aug 6, 2026
6a1cdfe
chore(stack): integrate lifecycle hardening
jgoux Aug 6, 2026
3c03ea6
chore(stack): integrate runtime hardening
jgoux Aug 6, 2026
5c0cd57
chore(stack): integrate runtime hardening
jgoux Aug 6, 2026
af6c027
fix(stack): align dependent startup deadlines
jgoux Aug 6, 2026
908ed4d
chore(stack): document dependency startup path
jgoux Aug 6, 2026
7c40a83
chore(stack): integrate dependency path documentation
jgoux Aug 6, 2026
28a6113
chore(stack): integrate dependency path documentation
jgoux Aug 6, 2026
5a298f1
test(stack): align Docker setup timeout
jgoux Aug 6, 2026
1184ec5
fix(process-compose): terminate timed-out cleanup trees
jgoux Aug 6, 2026
1abd493
fix(stack): keep pre-start failures retryable
jgoux Aug 6, 2026
e01aaf7
fix(stack): align activation lifecycle ownership
jgoux Aug 6, 2026
d5ae582
fix(stack): harden functions bundle reloads
jgoux Aug 6, 2026
5bd8454
Merge remote-tracking branch 'origin/agent/process-compose-supervisor…
jgoux Aug 6, 2026
bc3c975
Merge remote-tracking branch 'origin/agent/stack-runtime-implementati…
jgoux Aug 6, 2026
ce37d40
Merge remote-tracking branch 'origin/agent/stack-factory-resource-loc…
jgoux Aug 6, 2026
65feb43
Merge remote-tracking branch 'origin/agent/process-compose-lifecycle-…
jgoux Aug 6, 2026
e403043
Merge remote-tracking branch 'origin/agent/process-compose-supervisor…
jgoux Aug 6, 2026
1a6b5ad
Merge remote-tracking branch 'origin/agent/stack-runtime-implementati…
jgoux Aug 6, 2026
c3e1bf6
Merge remote-tracking branch 'origin/agent/stack-factory-resource-loc…
jgoux Aug 6, 2026
7505537
fix(stack): close foreground runtime on readiness timeout
jgoux Aug 6, 2026
c859ed2
Merge remote-tracking branch 'origin/agent/stack-runtime-implementati…
jgoux Aug 6, 2026
a0dcac5
Merge remote-tracking branch 'origin/agent/stack-factory-resource-loc…
jgoux Aug 6, 2026
e089d7d
fix(process-compose): preserve active restart policy
jgoux Aug 6, 2026
f275859
fix(stack): serialize projected state snapshots
jgoux Aug 6, 2026
6a737c2
Merge remote-tracking branch 'origin/agent/process-compose-lifecycle-…
jgoux Aug 6, 2026
eb18b78
Merge remote-tracking branch 'origin/agent/process-compose-supervisor…
jgoux Aug 6, 2026
70914be
Merge remote-tracking branch 'origin/agent/stack-runtime-implementati…
jgoux Aug 6, 2026
e74eb8c
Merge remote-tracking branch 'origin/agent/stack-factory-resource-loc…
jgoux Aug 6, 2026
665f8cc
fix(stack): propagate terminal local disposal
jgoux Aug 6, 2026
e302ffe
Merge remote-tracking branch 'origin/agent/stack-factory-resource-loc…
jgoux Aug 6, 2026
ed31de0
fix(process-compose): use active policy for readiness
jgoux Aug 6, 2026
267de27
fix(stack): budget native database initialization
jgoux Aug 6, 2026
58c889b
Merge branch 'agent/process-compose-lifecycle-correctness' into agent…
jgoux Aug 6, 2026
bd2aa0a
Merge branch 'agent/process-compose-supervisor-cleanup' into agent/st…
jgoux Aug 6, 2026
5822afd
Merge branch 'agent/stack-runtime-implementation' into agent/stack-fa…
jgoux Aug 6, 2026
096f0c8
Merge branch 'agent/stack-factory-resource-locality' into agent/funct…
jgoux Aug 6, 2026
858e882
fix(stack): stop daemon after terminal disposal
jgoux Aug 6, 2026
c860c9a
fix(stack): strip functions from daemon startup
jgoux Aug 6, 2026
f5955c6
Merge branch 'agent/stack-factory-resource-locality' into agent/funct…
jgoux Aug 6, 2026
eeac2a0
fix(process-compose): handle stopped dependencies
jgoux Aug 6, 2026
1131ac6
Merge branch 'agent/process-compose-lifecycle-correctness' into agent…
jgoux Aug 6, 2026
24a9dca
Merge branch 'agent/process-compose-supervisor-cleanup' into agent/st…
jgoux Aug 6, 2026
4cce96f
Merge branch 'agent/stack-runtime-implementation' into agent/stack-fa…
jgoux Aug 6, 2026
31fde24
Merge branch 'agent/stack-factory-resource-locality' into agent/funct…
jgoux Aug 6, 2026
32bc3b6
fix(stack): flush terminal daemon responses
jgoux Aug 6, 2026
54e6404
Merge branch 'agent/stack-factory-resource-locality' into agent/funct…
jgoux Aug 6, 2026
0369f52
fix(stack): reject function path symlink escapes
jgoux Aug 6, 2026
6b27914
Merge remote-tracking branch 'origin/develop' into agent/stack-domain…
jgoux Aug 6, 2026
4358f44
Merge remote-tracking branch 'origin/agent/stack-domain-model' into a…
jgoux Aug 6, 2026
3ced584
Merge remote-tracking branch 'origin/agent/process-compose-supervisor…
jgoux Aug 6, 2026
60786d5
Merge remote-tracking branch 'origin/agent/stack-runtime-implementati…
jgoux Aug 6, 2026
4727261
Merge remote-tracking branch 'origin/agent/stack-factory-resource-loc…
jgoux Aug 6, 2026
7309f34
fix(stack): preserve runtime reload state
jgoux Aug 6, 2026
eff78f8
Merge remote-tracking branch 'origin/develop' into agent/functions-bu…
jgoux Aug 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 82 additions & 11 deletions apps/cli/src/next/commands/functions/dev/functions-dev-config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { basename, dirname, resolve } from "node:path";
import type { FunctionsConfig } from "@supabase/stack/effect";
import { Effect, Option } from "effect";
import {
inferFunctionsManifest,
loadDotEnvFile,
loadProjectConfig,
loadProjectEnvironment,
resolveProjectSubtree,
} from "@supabase/config";
import type { ResolvedFunctionsBundle } from "@supabase/stack/effect";
import { Effect, Option, Redacted } from "effect";
import { basename, dirname, join, resolve } from "node:path";
import { ProjectHome } from "../../../config/project-home.service.ts";
import { RuntimeInfo } from "../../../../shared/runtime/runtime-info.service.ts";

Expand All @@ -14,16 +21,80 @@ export interface FunctionsDevWatchPath {
readonly names?: ReadonlyArray<string>;
}

export function toStackFunctionsConfig(opts: FunctionsDevConfigOptions): FunctionsConfig {
return {
envFile: Option.match(opts.envFile, {
onNone: () => undefined,
onSome: (path) => path,
}),
noVerifyJwt: opts.noVerifyJwt,
};
function reveal(value: string | Redacted.Redacted<string>): string {
return Redacted.isRedacted(value) ? Redacted.value(value) : value;
}

function absoluteProjectPath(supabaseDir: string, path: string): string {
const withoutDotSlash = path.startsWith("./") ? path.slice(2) : path;
return resolve(supabaseDir, withoutDotSlash);
}

export const resolveFunctionsBundle = Effect.fnUntraced(function* (
opts: FunctionsDevConfigOptions,
) {
const projectHome = yield* ProjectHome;
const runtimeInfo = yield* RuntimeInfo;
const projectEnvironment = yield* loadProjectEnvironment({
cwd: projectHome.projectRoot,
baseEnv: process.env,
});
const loadedConfig = yield* loadProjectConfig(projectHome.projectRoot);
const projectConfig =
projectEnvironment === null || loadedConfig === null
? undefined
: {
...loadedConfig.config,
functions: Object.fromEntries(
Object.entries(
yield* resolveProjectSubtree(
loadedConfig.config.functions,
projectEnvironment,
"functions",
),
).map(([name, config]) => [
name,
{
...config,
entrypoint: reveal(config.entrypoint),
import_map: reveal(config.import_map),
static_files: config.static_files.map(reveal),
env: Object.fromEntries(
Object.entries(config.env).map(([key, value]) => [key, reveal(value)]),
),
},
]),
),
};
const manifest = yield* inferFunctionsManifest({
cwd: projectHome.projectRoot,
...(projectConfig === undefined ? {} : { config: projectConfig }),
});
const envFilePath = Option.match(opts.envFile, {
onNone: () => join(projectHome.supabaseDir, "functions", ".env"),
onSome: (path) => resolve(runtimeInfo.cwd, path),
});

return {
env: yield* loadDotEnvFile(envFilePath),
functions: Object.entries(manifest)
.filter(([, config]) => config.enabled)
.map(([name, config]) => ({
name,
verifyJWT: opts.noVerifyJwt ? false : config.verify_jwt,
entrypointPath: absoluteProjectPath(projectHome.supabaseDir, config.entrypoint),
importMapPath:
config.import_map === ""
? null
: absoluteProjectPath(projectHome.supabaseDir, config.import_map),
staticFiles: config.static_files.map((path) =>
absoluteProjectPath(projectHome.supabaseDir, path),
),
env: config.env,
})),
} satisfies ResolvedFunctionsBundle;
});

export const functionsDevWatchPaths = Effect.fnUntraced(function* (envFile: Option.Option<string>) {
const projectHome = yield* ProjectHome;
const runtimeInfo = yield* RuntimeInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ import { join } from "node:path";
import { Effect, Exit, Layer, Option } from "effect";
import { ProjectHome } from "../../../config/project-home.service.ts";
import { RuntimeInfo } from "../../../../shared/runtime/runtime-info.service.ts";
import {
functionsDevWatchPaths,
toStackFunctionsConfig,
type FunctionsDevConfigOptions,
} from "./functions-dev-config.ts";
import { functionsDevWatchPaths, resolveFunctionsBundle } from "./functions-dev-config.ts";
import {
FunctionsDevEdgeRuntimeDisabledError,
resolveFunctionsDevEdgeRuntimeConfig,
Expand Down Expand Up @@ -61,16 +57,60 @@ describe("functions dev config", () => {
expect(connectOrStartFunctionsDevStack).toBeTypeOf("function");
});

it("converts CLI options to stack Functions config", () => {
const opts: FunctionsDevConfigOptions = {
envFile: Option.some("./custom.env"),
noVerifyJwt: true,
};
it.live("resolves project functions, environment and absolute paths before stack handoff", () => {
const cwd = makeTempProject();

return Effect.gen(function* () {
yield* Effect.tryPromise(() =>
mkdir(join(cwd, "supabase", "functions", "hello", "assets"), { recursive: true }),
);
yield* Effect.tryPromise(() =>
writeFile(join(cwd, "supabase", "functions", "hello", "index.ts"), "export {};\n"),
);
yield* Effect.tryPromise(() =>
writeFile(join(cwd, "supabase", "functions", "hello", "deno.json"), "{}\n"),
);
yield* Effect.tryPromise(() =>
writeFile(join(cwd, "supabase", ".env"), "FUNCTION_VALUE=resolved-secret\n"),
);
yield* Effect.tryPromise(() => writeFile(join(cwd, "custom.env"), "SHARED=custom\n"));
yield* Effect.tryPromise(() =>
writeFile(
join(cwd, "supabase", "config.toml"),
`[functions.hello]
verify_jwt = true
entrypoint = "./functions/hello/index.ts"
import_map = "./functions/hello/deno.json"
static_files = ["./functions/hello/assets/*"]

[functions.hello.env]
FUNCTION_VALUE = "env(FUNCTION_VALUE)"
`,
),
);

expect(toStackFunctionsConfig(opts)).toEqual({
envFile: "./custom.env",
noVerifyJwt: true,
});
const bundle = yield* resolveFunctionsBundle({
envFile: Option.some("./custom.env"),
noVerifyJwt: true,
});

expect(bundle).toEqual({
env: { SHARED: "custom" },
functions: [
{
name: "hello",
verifyJWT: false,
entrypointPath: join(cwd, "supabase", "functions", "hello", "index.ts"),
importMapPath: join(cwd, "supabase", "functions", "hello", "deno.json"),
staticFiles: [join(cwd, "supabase", "functions", "hello", "assets", "*")],
env: { FUNCTION_VALUE: "resolved-secret" },
},
],
});
}).pipe(
Effect.ensuring(Effect.tryPromise(() => rm(cwd, { recursive: true, force: true }))),
Effect.provide(projectLayer(cwd)),
);
});

it.live("selects supabase and explicit env directory watch paths", () => {
Expand Down
85 changes: 43 additions & 42 deletions apps/cli/src/next/commands/functions/dev/functions-dev-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { RuntimeInfo } from "../../../../shared/runtime/runtime-info.service.ts"
import { startStackWithProgress } from "../../../stack/stack.shared.ts";
import {
functionsDevWatchPaths,
toStackFunctionsConfig,
resolveFunctionsBundle,
type FunctionsDevConfigOptions,
type FunctionsDevWatchPath,
} from "./functions-dev-config.ts";
Expand Down Expand Up @@ -76,7 +76,6 @@ const startFullStack = Effect.fnUntraced(function* (opts: FunctionsDevStackOptio
projectStateRoot: projectHome.projectHomeDir,
name: opts.stack,
edgeRuntime: opts.edgeRuntime,
functions: toStackFunctionsConfig(opts),
...versionsFromContext(serviceVersionContext),
},
daemonEntryPoint,
Expand Down Expand Up @@ -180,9 +179,9 @@ function reloadEdgeRuntime(
opts: FunctionsDevRuntimeOptions,
edgeRuntime: EdgeRuntimeConfig,
) {
return stack.reloadEdgeRuntime({
edgeRuntime,
functions: toStackFunctionsConfig(opts),
return Effect.gen(function* () {
const functions = yield* resolveFunctionsBundle(opts);
Comment thread
jgoux marked this conversation as resolved.
yield* stack.reloadEdgeRuntime({ edgeRuntime, functions });
});
}

Expand Down Expand Up @@ -226,49 +225,51 @@ export const runFunctionsDevRuntime = Effect.fnUntraced(function* (
...opts,
edgeRuntime: edgeRuntimeState.config,
});
yield* ensureFunctionsDirectory();
yield* reloadEdgeRuntime(stack, opts, edgeRuntimeState.config);
const info = yield* stack.getInfo();
const watchPathList = yield* functionsDevWatchPaths(opts.envFile);

yield* output.success("Edge Functions dev server is running.", {
functions_url: `${info.url}/functions/v1`,
});
yield* output.info(`Functions URL: ${info.url}/functions/v1/<function-name>`);

const restartOnChange = watchPaths(watchPathList).pipe(
Stream.runForEach((change) =>
Effect.gen(function* () {
const result = yield* applyWatchedChange(edgeRuntimeState, change);
if (result.action === "edge-runtime") {
yield* output.info("Edge runtime config changed. Restarting edge-runtime...");
yield* reloadEdgeRuntime(stack, opts, result.state.config);
const restoreFunctions = startedByCommand
? undefined
: yield* resolveFunctionsBundle({ envFile: Option.none(), noVerifyJwt: false });

yield* Effect.gen(function* () {
yield* ensureFunctionsDirectory();
yield* reloadEdgeRuntime(stack, opts, edgeRuntimeState.config);
const info = yield* stack.getInfo();
const watchPathList = yield* functionsDevWatchPaths(opts.envFile);

yield* output.success("Edge Functions dev server is running.", {
functions_url: `${info.url}/functions/v1`,
});
yield* output.info(`Functions URL: ${info.url}/functions/v1/<function-name>`);

const restartOnChange = watchPaths(watchPathList).pipe(
Stream.runForEach((change) =>
Effect.gen(function* () {
const result = yield* applyWatchedChange(edgeRuntimeState, change);
if (result.action === "edge-runtime") {
yield* output.info("Edge runtime config changed. Restarting edge-runtime...");
yield* reloadEdgeRuntime(stack, opts, result.state.config);
edgeRuntimeState = result.state;
return;
}
edgeRuntimeState = result.state;
return;
}
edgeRuntimeState = result.state;
yield* output.info("Function files changed. Restarting edge-runtime...");
yield* stack.reloadFunctions(toStackFunctionsConfig(opts));
}).pipe(
Effect.catch((error) =>
output.error(error instanceof Error ? error.message : String(error)),
yield* output.info("Function files changed. Restarting edge-runtime...");
yield* stack.reloadFunctions({ functions: yield* resolveFunctionsBundle(opts) });
}).pipe(
Effect.catch((error) =>
output.error(error instanceof Error ? error.message : String(error)),
),
),
),
),
);
);

const logs = logEntryStream(stack).pipe(Stream.runForEach((event) => output.event(event)));
const shutdown = processControl.awaitShutdown;
const logs = logEntryStream(stack).pipe(Stream.runForEach((event) => output.event(event)));
const shutdown = processControl.awaitShutdown;

yield* Effect.raceFirst(Effect.raceFirst(restartOnChange, logs), shutdown).pipe(
yield* Effect.raceFirst(Effect.raceFirst(restartOnChange, logs), shutdown);
}).pipe(
Effect.ensuring(
Effect.gen(function* () {
if (startedByCommand) {
yield* stack.dispose().pipe(Effect.ignore);
} else {
yield* stack.reloadFunctions({}).pipe(Effect.ignore);
}
}),
startedByCommand
? stack.dispose().pipe(Effect.ignore)
: stack.reloadFunctions({ functions: restoreFunctions }).pipe(Effect.ignore),
),
);
});
Expand Down
1 change: 1 addition & 0 deletions packages/config/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export {
type ProjectEnvironment,
type ResolvedProjectValue,
type ResolveProjectOptions,
loadDotEnvFile,
loadProjectEnvironment,
resolveProjectSubtree,
resolveProjectValue,
Expand Down
9 changes: 9 additions & 0 deletions packages/config/src/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,15 @@ function parseDotEnv(
});
}

/** Parse one explicit dotenv file without applying ambient or project-local precedence. */
export const loadDotEnvFile = Effect.fnUntraced(function* (path: string) {
const fs = yield* FileSystem.FileSystem;
if (!(yield* fs.exists(path))) {
return {};
}
return yield* parseDotEnv(path, yield* fs.readFileString(path));
});

function applySource(
target: Record<string, string>,
sources: Record<string, "ambient" | ".env" | ".env.local">,
Expand Down
34 changes: 34 additions & 0 deletions packages/stack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,40 @@ const stack = await createStack({
});
```

### Edge Functions

The stack accepts an explicit, fully resolved Functions bundle. Paths must be absolute and the
caller owns project-file discovery, environment-file parsing, and manifest interpretation:

```typescript
const projectDir = "/absolute/project";
const stack = await createStack({
projectDir,
functions: {
env: { SHARED_VALUE: "available to every function" },
functions: [
{
name: "hello",
verifyJWT: true,
entrypointPath: "/absolute/project/supabase/functions/hello/index.ts",
importMapPath: null,
staticFiles: [],
env: { FUNCTION_VALUE: "available only to hello" },
},
],
},
});
```

Every referenced path must be contained by `projectDir` so the same bundle works when Edge Runtime
runs in Docker and the project directory is bind-mounted into the container.

Per-function environment values override shared values. Stack-owned runtime URLs and credentials
take final precedence. To update the active bundle, call
`reloadFunctions({ functions: nextBundle })`; `reloadFunctions()` preserves and reapplies the most
recent bundle. `reloadEdgeRuntime()` follows the same preservation rule when its optional
`functions` field is omitted.

## Docker Mode

Set `mode: "docker"` to force all services to run in Docker containers, bypassing native binary resolution:
Expand Down
Loading
Loading