fix(webapp): resolve realtime stream parent/root target across both run tables

The two realtime v1-streams routes (read/create + append) resolved a
target:"parent"|"root" via a table-bound parentTaskRun/rootTaskRun relation
select, which returns null for a cross-table parent/root in the runTableV2 mixed
window and 404s a target that exists. Select the scalar
parentTaskRunId/rootTaskRunId and resolve the target by id through RunStore
(routes by id format), matching the presenter fixes. The "self" target is
unchanged.
This commit is contained in:
Dan Sutton
2026-06-22 21:04:33 +01:00
parent 5e5577ab90
commit 43dffdf8ed
2 changed files with 58 additions and 48 deletions
@@ -36,16 +36,8 @@ const { action } = createActionApiRoute(
select: {
id: true,
friendlyId: true,
parentTaskRun: {
select: {
friendlyId: true,
},
},
rootTaskRun: {
select: {
friendlyId: true,
},
},
parentTaskRunId: true,
rootTaskRunId: true,
},
},
$replica
@@ -55,12 +47,24 @@ const { action } = createActionApiRoute(
return new Response("Run not found", { status: 404 });
}
const targetId =
params.target === "self"
? run.friendlyId
: params.target === "parent"
? run.parentTaskRun?.friendlyId
: run.rootTaskRun?.friendlyId;
// parentTaskRunId/rootTaskRunId are scalar ids that may point at a run in
// the OTHER physical table (the runTableV2 mixed window), so resolve the
// target's friendlyId by id (RunStore routes by id format) rather than via a
// table-bound relation select, which would return null cross-table.
let targetId: string | undefined;
if (params.target === "self") {
targetId = run.friendlyId;
} else {
const targetScalarId = params.target === "parent" ? run.parentTaskRunId : run.rootTaskRunId;
if (targetScalarId) {
const target = await runStore.findRun(
{ id: targetScalarId, runtimeEnvironmentId: authentication.environment.id },
{ select: { friendlyId: true } },
$replica
);
targetId = target?.friendlyId;
}
}
if (!targetId) {
return new Response("Target not found", { status: 404 });
@@ -14,6 +14,23 @@ const ParamsSchema = z.object({
streamId: z.string(),
});
// Resolve a parent/root stream target across BOTH run tables. The scalar
// parentTaskRunId/rootTaskRunId may reference a run in the other physical table
// during the runTableV2 mixed window; findRun routes by id format, so this
// resolves the target whichever table it lives in (a table-bound relation
// select would resolve null for a cross-table parent/root).
async function resolveStreamTargetById(
targetScalarId: string | null,
runtimeEnvironmentId: string
): Promise<{ friendlyId: string; streamBasinName: string | null } | null> {
if (!targetScalarId) return null;
return runStore.findRun(
{ id: targetScalarId, runtimeEnvironmentId },
{ select: { friendlyId: true, streamBasinName: true } },
$replica
);
}
const { action } = createActionApiRoute(
{
params: ParamsSchema,
@@ -29,18 +46,8 @@ const { action } = createActionApiRoute(
id: true,
friendlyId: true,
streamBasinName: true,
parentTaskRun: {
select: {
friendlyId: true,
streamBasinName: true,
},
},
rootTaskRun: {
select: {
friendlyId: true,
streamBasinName: true,
},
},
parentTaskRunId: true,
rootTaskRunId: true,
},
},
$replica
@@ -50,12 +57,18 @@ const { action } = createActionApiRoute(
return new Response("Run not found", { status: 404 });
}
// Resolve the target across BOTH run tables. parentTaskRunId/rootTaskRunId
// are scalar pointers that may reference a run in the OTHER physical table
// (the runTableV2 mixed window); a table-bound relation select would resolve
// null and 404 a target that exists. findRun routes by id format; "self" is
// the run itself.
const targetRun =
params.target === "self"
? run
: params.target === "parent"
? run.parentTaskRun
: run.rootTaskRun;
? { friendlyId: run.friendlyId, streamBasinName: run.streamBasinName }
: await resolveStreamTargetById(
params.target === "parent" ? run.parentTaskRunId : run.rootTaskRunId,
authentication.environment.id
);
if (!targetRun?.friendlyId) {
return new Response("Target not found", { status: 404 });
@@ -164,18 +177,8 @@ const loader = createLoaderApiRoute(
id: true,
friendlyId: true,
streamBasinName: true,
parentTaskRun: {
select: {
friendlyId: true,
streamBasinName: true,
},
},
rootTaskRun: {
select: {
friendlyId: true,
streamBasinName: true,
},
},
parentTaskRunId: true,
rootTaskRunId: true,
},
},
$replica
@@ -187,12 +190,15 @@ const loader = createLoaderApiRoute(
return new Response("Run not found", { status: 404 });
}
// Resolve the target across both run tables by id (the scalar parent/root
// pointer may be cross-table in the mixed window); "self" is the run itself.
const targetRun =
params.target === "self"
? run
: params.target === "parent"
? run.parentTaskRun
: run.rootTaskRun;
? { friendlyId: run.friendlyId, streamBasinName: run.streamBasinName }
: await resolveStreamTargetById(
params.target === "parent" ? run.parentTaskRunId : run.rootTaskRunId,
authentication.environment.id
);
if (!targetRun?.friendlyId) {
return new Response("Target not found", { status: 404 });