Skip to content

Instantly share code, notes, and snippets.

@Gobot1234
Created November 11, 2025 03:16
Show Gist options
  • Select an option

  • Save Gobot1234/c7e024914c7a753a2e57ca0dcee321f9 to your computer and use it in GitHub Desktop.

Select an option

Save Gobot1234/c7e024914c7a753a2e57ca0dcee321f9 to your computer and use it in GitHub Desktop.
import { EventPublisher } from "@orpc/client";
import { sign_in } from "@packages/db/interfaces";
import { createFileRoute, useNavigate } from "@tanstack/react-router";
// import { use, useEffect } from "react";
import z from "zod";
import { InitialiseStep, UCardNumber } from "@/api/locations/$name/sign-in/_flows/_steps"; // TODO double check if this actually problematically not shaken
import type {
Finalise as _Finalise,
Initialise as _Initialise,
Receive as _Receive,
Transmit as _Transmit,
Graph,
} from "@/api/locations/$name/sign-in/_flows/_types";
import type { PUBLISHER as SERVER_PUBLISHER } from "@/api/locations/$name/sign-in/$ucard";
import { client, orpc } from "@/lib/orpc";
import type { SignInUser } from "@/lib/utils/queries";
type Initialise = z.infer<typeof _Initialise>;
type Receive = z.infer<typeof _Receive>;
type Transmit = z.infer<typeof _Transmit>;
type Finalise = z.infer<typeof _Finalise>;
export const PUBLISHER: typeof SERVER_PUBLISHER = new EventPublisher();
// represents https://www.mermaidchart.com/play#pako:eNptVE2P2jAQ_SujHNrtAZWwsLAc2iJaVXtopbbsoWr24CQDWCR21mNDEeK_d-x88FEuiEzePL_3PJNDlOkco2nU6_USlWm1lKtpogDsGkucgkLtnwqtN6cHsdfOTmEp_2KeqNC5LPQuWwtjYfHZYwDU5JBEz4QGMqGA5EqBVJAKwhy0gleHDoGssJhER-j14Lvm3w-g4tGfJHoiMLiSZNHwGdFLy-mBv5Fq5ODwH_DYAAfnjEPGfRMbDKagMnorSWolimJfCxMrg2xX2SuC7qT4vjWjtA097ILtYEG4W_PRp8ahb5y1hOBUjoas1jkIlbetgXTEnDPagNVALqXMyLSRyJVSyEKqFRRsja7YF1pD6mhf0zxwXF_Rdp3Bkau8zwoNW-S0-R3sMCVpMciwTRqMd8b_MQh3KWbCkQeC4GcqRFli_u6U_tgL7pxla8w2VF-ejyjmt3NdVq4gbfawMEIq72DucScHcdzg-6z7JwpieU-qcpz9C7zh-pjrX4zRBnQotodfzMjwlmlpr7yeuketyFZFvykMmKiTKr0OuPN3bPDVSR4pWLIQgxW9xy27prM44vuaY-xlD_q3Zceji0F6bO5cLr3OPewEJ8n6wzqchTS6cPvw6cBbl2IxBZ54xZLKoIk5RMgAnJ9NSeqtvVgH6Agn9a78CGs3y6zcYrDm98JQJTL82F3lpG26MW3x402fFHP5l9_057kwfmMbeMflPdBaVPxRMZhZFhYd_wHo9mxr
// I'm calling this structure an adjacency object (It's a named adjacency list)
const GRAPH = {
INITIALISE: ["AGREEMENTS", "QUEUE", "REASON", "SIGN_OUT"],
AGREEMENTS: ["MAILING_LISTS"],
CANCEL: [undefined],
MAILING_LISTS: ["REASON"],
PERSONAL_TOOLS_AND_MATERIALS: ["TOOLS"],
QUEUE: [undefined],
REASON: ["FINALISE", "PERSONAL_TOOLS_AND_MATERIALS"],
TOOLS: ["FINALISE"],
FINALISE: [undefined],
SIGN_OUT: [undefined],
} as const satisfies Graph;
type InitialiseToTransmitMap = { [K in Initialise["type"]]: Extract<Transmit, { type: K }> };
type ReceiveToFinaliseMap = { [K in Receive["type"]]: Extract<Finalise, { type: K }> };
const flow = async (
uCardNumber: z.infer<typeof UCardNumber>,
locationName: sign_in.LocationName,
signal: AbortSignal,
) => {
const commonData = {
ucard_number: uCardNumber,
name: locationName,
};
const key = `${locationName}-${uCardNumber}` as const;
const initKey = `${key}-INITIALISE` as const;
const recvKey = `${key}-RECEIVE` as const;
const [initialiseTx, receiveTx] = await Promise.all([
client.locations.signIn.initialise(PUBLISHER.subscribe(initKey, { signal })),
client.locations.signIn.receive(PUBLISHER.subscribe(recvKey, { signal })),
]);
const fn = await client.locations.signIn.flow(commonData, { signal });
// send the data to server, uses the same terminology as server
const initialise = async <T extends Omit<Initialise, keyof typeof commonData>>(initialise: T) => {
PUBLISHER.publish(initKey, { ...initialise, ...commonData });
await initialiseTx.next(); // send it
return (await fn.next()).value as InitialiseToTransmitMap[T["type"]];
};
const receive = async <T extends Omit<Receive, keyof typeof commonData>>(receive: T) => {
PUBLISHER.publish(recvKey, { ...receive, ...commonData } as Receive);
await receiveTx.next(); // send it
type FinaliseT = ReceiveToFinaliseMap[T["type"]];
return (await fn.next()).value as FinaliseT extends never
? T["type"] extends "FINALISE" // only FINALISE returns a value of the ends of the graph
? { id: string }
: undefined
: FinaliseT;
};
return { initialise, receive };
};
export const Route = createFileRoute("/test/$name/$ucard_number")({
params: InitialiseStep,
// loader: async ({ abortController }) => ({ abortController }),
component: async () => {
const { ucard_number: uCardNumber, name: locationName } = Route.useParams();
// const [user, setUser] = useState<SignInUser | null>(null);
const { initialise, receive } = await flow(uCardNumber, locationName, new AbortController().signal);
const { user } = await initialise({ type: "INITIALISE" });
if (!user) {
return <div>No user found</div>;
}
console.log("Got the user", user);
let {next} = await receive({type: "INITIALISE"})
const {agreements} = await initialise({ type: next as "AGREEMENTS"});
if (agreements.length !== 0) {
} else {
next = (await receive({ type: "AGREEMENTS" } )).next;
}
// useEffect(() => {
// (async () => {
// console.log("Out of flow")
// const { user: user_ } = await initialise({ type: "INITIALISE" });
// setUser(user_)
// })();
// });
return (
// <Button
// onClick={() =>
// (async () => {
// // setName(user.display_name);
// const finalise = await receive({ type: "INITIALISE" });
// console.log("Next step is", finalise.next);
// })()
// }
// >
// Begin {name}
// </Button>
<div>Hi {user?.display_name}</div>
)
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment