@brightoutcome/guidistry-client
Typed client and sign-in helpers for the Guidistry API. Every path, parameter and response type is generated from the API's OpenAPI contract, so an API change shows up as a type error.
npm install @brightoutcome/guidistry-client aws-amplify
Set up once
import { createGuidistryClient } from "@brightoutcome/guidistry-client";
import { configureAuth, getAccessToken } from "@brightoutcome/guidistry-client/auth";
configureAuth(); // Guidistry QA user pool
let activeContext: string | null = null; // a membership ID from GET /v1/me
export const api = createGuidistryClient({
baseUrl: import.meta.env.VITE_GUIDISTRY_API_URL ?? "/guidistry/api",
getAccessToken,
getContext: () => activeContext,
});
export const setContext = (membershipId: string | null) => {
activeContext = membershipId;
};
Sign in (identifier first)
import { confirmSignIn, startSignIn } from "@brightoutcome/guidistry-client/auth";
const start = await startSignIn(api, "[email protected]");
if (start.kind === "sso") {
// later: redirect to the organization's sign-in (not used in January)
} else {
const { nextStep } = start.output;
// "CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION": show nextStep.availableChallenges
// (EMAIL_OTP, WEB_AUTHN, PASSWORD, …) and send the choice:
// await confirmSignIn({ challengeResponse: "EMAIL_OTP" })
// "CONFIRM_SIGN_IN_WITH_EMAIL_CODE": await confirmSignIn({ challengeResponse: code })
// "CONFIRM_SIGN_IN_WITH_PASSWORD": await confirmSignIn({ challengeResponse: password })
// "DONE": signed in
}
After a first sign-in, offer a passkey: registerPasskey(). Sign out with signOut().
Calling the API
const { data: me } = await api.GET("/v1/me");
// me.memberships: the contexts this person can act in; pick one with setContext(m.id)
const { data: people } = await api.GET("/v1/people", { params: { query: { q: "lind" } } });
await api.POST("/v1/invitations", {
body: { email: "[email protected]", role: "provider", names: { given: "Mara", family: "Whitfield" } },
});
Program templates (called courses in the API) and programs:
const { data: templates } = await api.GET("/v1/courses");
// each: name, current_version ("v1.3"), versions (e.g. Groups / Community / Solo), levels, rights
const { data: owl } = await api.GET("/v1/courses/{course_id}/content", {
params: { path: { course_id: templates![0].id }, query: { version: "groups", view: "participant" } },
});
// owl.modules[].topics[].blocks[]: text blocks carry sanitized `html`; media carry a short-lived `signed_url`
const { data: program } = await api.POST("/v1/programs", {
body: { name: "Lakeside OWL", course_id: templates![0].id, version_key: "groups" },
});
await api.GET("/v1/programs/{program_id}/content", { params: { path: { program_id: program!.id } } });
Signed media links expire (two hours by default): fetch content again rather than storing them.
Failed calls throw GuidistryError with status and problem (title, detail, request_id). A 409 from most endpoints means "choose a context" (the person has more than one membership).
Versioning
Semantic versioning: a new major version means a breaking API change and comes with a handoff note. Releases are published only by the Guidistry pipeline (npm trusted publishing).