Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
ba03271
docs to useService
jbolda Dec 12, 2025
418b9ca
spike out dag to start services
jbolda Dec 12, 2025
785a24e
tests and service filter
jbolda Dec 27, 2025
387652c
Merge branch 'main' into use-service-graph
jbolda Jan 2, 2026
6645a87
adjust useServiceGraph to more directly pass dep returns
jbolda Jan 3, 2026
0ba7f2d
useSimulation helper
jbolda Jan 4, 2026
e60b092
spawn simulators each as a child_process
jbolda Jan 8, 2026
5701126
CLI handles subset
jbolda Jan 8, 2026
61ac59f
handle services through a coordination layer
jbolda Jan 9, 2026
2a5322a
edge cases and various todo items
jbolda Jan 11, 2026
5d9d3cb
watch debouncing
jbolda Jan 12, 2026
eb33736
shift logs to logger
jbolda Jan 12, 2026
689eeff
lint
jbolda Jan 12, 2026
57c5717
pass data to simulation from simulacrum service
jbolda Jan 14, 2026
57f1197
process uses daemon
jbolda Jan 14, 2026
ef4db1c
pass initData in
jbolda Jan 14, 2026
dae9a9e
fix type errors
jbolda Jan 15, 2026
e6cfde8
more docs
jbolda Jan 15, 2026
0e330f0
clean up, flesh out tests
jbolda Jan 15, 2026
eafa7cd
readme getting started
jbolda Jan 15, 2026
927afeb
readme updates
jbolda Jan 16, 2026
703fa6b
Merge branch 'main' into use-service-graph
jbolda Jan 16, 2026
43ffdd1
bug fixes, logging and debugging DX
jbolda Mar 23, 2026
c4351a5
refine tests for useServiceGraph as test rig
jbolda Mar 23, 2026
36922c3
extend watcher timer
jbolda Mar 23, 2026
6f4df80
Merge branch 'main' into use-service-graph
jbolda Mar 30, 2026
3f87f0b
bump effectionx packages
jbolda Mar 30, 2026
eee8d88
Merge branch 'main' into use-service-graph
jbolda Apr 1, 2026
11c468d
lint with new oxlint setup
jbolda Apr 1, 2026
9e8cce1
foundation sim as devDep
jbolda Apr 1, 2026
1d41e2f
fix test tsx and path refs
jbolda Apr 1, 2026
bf2b1eb
watch startup waits
jbolda Apr 1, 2026
b32c542
fuzzy watch on loop
jbolda Apr 1, 2026
872388e
deprioritize initial store updates
jbolda Apr 2, 2026
5513e85
bump effectionx packages
jbolda Apr 17, 2026
bc603b7
combine into single useSimulation
jbolda Apr 22, 2026
4e11243
polish off logging for new process api
jbolda Apr 23, 2026
fc06fca
gate type strip by node version
jbolda Apr 23, 2026
ace7d02
process provide is always filled
jbolda Apr 23, 2026
16782be
lint
jbolda Apr 23, 2026
b3a45ef
import path relative to simulation file
jbolda Apr 23, 2026
bc71c0f
fmt
jbolda Apr 23, 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
5 changes: 5 additions & 0 deletions .changes/deprioritize-initial-store-updates-in-foundation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@simulacrum/foundation-simulator": patch:bug
---

Order initial log dispatching to help avoid the race condition made more prevalent by more direct sync vs async handling in effection v4.
3 changes: 0 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"oxc.useExecPath": true,
"oxc.fmt.configPath": ".oxfmtrc.json",
"editor.defaultFormatter": "oxc.oxc-vscode",
"editor.formatOnSave": false, // disable default behavior
"editor.codeActionsOnSave": {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
"covector": "pnpm dlx covector",
"fmt": "oxfmt --write .",
"fmt:check": "oxfmt --check .",
"lint": "pnpm -r --if-present run lint",
"lint:fix": "pnpm -r exec oxlint --fix",
"lint": "oxlint",
"lint:fix": "oxlint --fix",
"prepack": "pnpm -r --if-present run prepack",
"test": "pnpm -r --if-present run test",
"tsc": "pnpm -r --if-present run tsc"
Expand Down
32 changes: 18 additions & 14 deletions packages/foundation/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import { apiProxy } from "./middleware/proxy.ts";
import { delayMiddleware } from "./middleware/delay.ts";
import { generateRoutesHTML } from "./routeTemplate.ts";
import { createAppServer } from "./server.ts";
import type { IdProp } from "starfx";
import { sleep, type AnyState, type IdProp } from "starfx";

// for use in the OpenAPI handler functions
type SimulationHandlerFunctions = (
Expand Down Expand Up @@ -170,6 +170,7 @@ export function createFoundationSimulationServer<
app.use(express.urlencoded({ extended: false }));

let simulationStore = createSimulationStore(extendStore);
const simulationRoutes = [] as ((s: AnyState) => void)[];
app.use(delayMiddleware(delayResponses));

app.use((req, _res, next) => {
Expand All @@ -193,7 +194,6 @@ export function createFoundationSimulationServer<
.map((stack) => stack.route)
.filter((route): route is NonNullable<typeof route> => Boolean(route));

const simulationRoutes = [];
for (let layer of layers) {
for (let stack of layer.stack) {
simulationRoutes.push(
Expand All @@ -210,8 +210,6 @@ export function createFoundationSimulationServer<
);
}
}

simulationStore.store.dispatch(simulationStore.actions.batchUpdater(simulationRoutes));
}
}

Expand All @@ -224,7 +222,6 @@ export function createFoundationSimulationServer<
.sync();

if (jsonFiles.length > 0) {
const simulationRoutes = [];
for (let jsonFile of jsonFiles) {
const route = `/${jsonFile.slice(0, jsonFile.length - 5)}`;
const filename = path.join(serveJsonFiles, jsonFile);
Expand All @@ -246,8 +243,6 @@ export function createFoundationSimulationServer<
}),
);
}

simulationStore.store.dispatch(simulationStore.actions.batchUpdater(simulationRoutes));
}
}

Expand Down Expand Up @@ -324,11 +319,11 @@ export function createFoundationSimulationServer<
},
});

// initalize the backend
// initialize the backend
api.init().then((init) => {
const router = init.router;
const operations = router.getOperations();
const simulationRoutes = operations.reduce(
const oasSimulationRoutes = operations.reduce(
(routes, operation) => {
const url = `${router.apiRoot === "/" ? "" : router.apiRoot}${operation.path}`;
routes[`${operation.method}:${url}`] = {
Expand All @@ -343,11 +338,7 @@ export function createFoundationSimulationServer<
},
{} as Record<string, SimulationRoute>,
);
simulationStore.store.dispatch(
simulationStore.actions.batchUpdater([
simulationStore.schema.simulationRoutes.add(simulationRoutes),
]),
);
simulationRoutes.push(simulationStore.schema.simulationRoutes.add(oasSimulationRoutes));
return init;
});
app.use((req, res, next) => {
Expand Down Expand Up @@ -393,7 +384,20 @@ export function createFoundationSimulationServer<
// if no extendRouter routes or openapi routes handle this, return 404
app.all("/{*splat}", (_req, res) => res.status(404).json({ error: "not found" }));

// wait to start passing route records to give the store a moment to register
// which is technically race-y but in practice should be fine
// as we don't have a way to wait currently
simulationStore.store
.run(function* () {
// forces some async work to allow children scopes to start, e.g. the thunks
yield* sleep(0);
})
.then(() => {
simulationStore.store.dispatch(simulationStore.actions.batchUpdater(simulationRoutes));
});

const genericAppServer = createAppServer(app, protocol);

return {
listen: async (...listenArgs: Parameters<typeof genericAppServer.listen> | undefined[]) => {
// over and above the `net` listen behavior, allow setting:
Expand Down
7 changes: 4 additions & 3 deletions packages/foundation/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,9 @@ export function createSimulationStore<
const route = yield* select(schema.simulationRoutes.selectById, {
id,
});
if (route.url !== "")
if (route.url !== "") {
yield* schema.update(schema.simulationRoutes.merge({ [id]: { calls: route.calls + 1 } }));
}

yield* next();
});
Expand All @@ -202,11 +203,11 @@ export function createSimulationStore<
};
const userTasks = inputTasks({ createWebhook, store, schema });

let inputedActions = inputActions({ thunks, store, schema });
let inputtedActions = inputActions({ thunks, store, schema });
let actions = {
simulationLog,
batchUpdater,
...inputedActions,
...inputtedActions,
...userTasks.actions,
};

Expand Down
Loading
Loading