Files
Jyotisha/frontend/src/lib/birth-time-journey-store.ts
T

142 lines
5.3 KiB
TypeScript

import "server-only";
import type { SupabaseClient } from "@supabase/supabase-js";
import type {
BirthTimeJourneyStore,
} from "./birth-time-journey-service.ts";
import {
BirthTimeJourneyStoreError,
caseStatus,
createJourneyLoadClient,
createJourneyTurnPersistence,
loadStoredRectificationCase,
profileStatus,
} from "./birth-time-journey-turn-persistence.ts";
import { createSupabaseScoringJobStore } from "./birth-time-scoring-job-store.ts";
import { createSupabaseGuidedCandidateStore } from "./birth-time-guided-candidate-store.ts";
import {
createDynamicTurnPersistence,
type DynamicRpcClient,
} from "./birth-time-journey-dynamic-persistence.ts";
import { saveDynamicAssessment } from "./birth-time-journey-dynamic-case.ts";
import { createDynamicScoringJobStore } from "./birth-time-dynamic-scoring-job-store.ts";
export { BirthTimeJourneyStoreError } from "./birth-time-journey-turn-persistence.ts";
export function createSupabaseBirthTimeJourneyStore(
supabase: SupabaseClient,
now: () => Date = () => new Date(),
): BirthTimeJourneyStore {
const loadClient = createJourneyLoadClient(supabase);
const loadCase = (userId: string, caseId: string) => loadStoredRectificationCase(loadClient, userId, caseId);
const turns = createJourneyTurnPersistence(supabase, loadCase);
const dynamicRpc: DynamicRpcClient = {
async rpc(name, args) {
const { data, error } = await supabase.rpc(name, args);
return { data, error: error ? { message: error.message } : null };
},
};
const dynamicTurns = createDynamicTurnPersistence(
dynamicRpc,
loadCase,
() => now().toISOString().slice(0, 10),
);
const scoringJobs = createSupabaseScoringJobStore(supabase, loadCase);
const dynamicScoringJobs = createDynamicScoringJobStore(dynamicRpc, loadCase);
const guidedCandidates = createSupabaseGuidedCandidateStore(supabase, loadCase);
return {
async saveAssessment(value) {
return saveDynamicAssessment(dynamicRpc, value, now());
},
loadCase,
saveTurn: turns.saveTurn,
...dynamicTurns,
...scoringJobs,
...dynamicScoringJobs,
...guidedCandidates,
async saveScoring(value) {
const { data, error } = await supabase
.from("birth_time_rectification_cases")
.update({
status: caseStatus(value.snapshot),
journey_snapshot: value.snapshot,
answers: value.answers,
scoring_result: value.scoring?.raw ?? {},
updated_at: new Date().toISOString(),
})
.eq("id", value.id)
.eq("user_id", value.userId)
.eq("journey_protocol", "legacy-guided-v1")
.select("id")
.maybeSingle();
if (error || !data) throw new BirthTimeJourneyStoreError("update_case");
const { error: profileError } = await supabase
.from("profiles")
.update({ birth_time_status: profileStatus(value.snapshot) })
.eq("id", value.userId)
.eq("rectification_case_id", value.id);
if (profileError) throw new BirthTimeJourneyStoreError("update_profile");
},
async saveCandidateResult(value) {
const winner = value.candidateResult?.winningSegment ?? null;
const { data, error } = await supabase
.from("birth_time_rectification_cases")
.update({
status: caseStatus(value.snapshot),
journey_snapshot: value.snapshot,
life_events: value.lifeEvents ?? [],
candidate_result: value.candidateResult ?? {},
event_scoring_version: value.candidateResult?.algorithmVersion ?? null,
candidate_result_id: value.candidateResult?.resultId ?? null,
candidate_start: winner?.startTime ?? null,
candidate_end: winner?.endTime ?? null,
updated_at: new Date().toISOString(),
})
.eq("id", value.id)
.eq("user_id", value.userId)
.eq("journey_protocol", "legacy-guided-v1")
.select("id")
.maybeSingle();
if (error || !data) throw new BirthTimeJourneyStoreError("update_case");
const { error: profileError } = await supabase
.from("profiles")
.update({
birth_time_status: profileStatus(value.snapshot),
rectification_confidence: value.candidateResult?.marginPercent ?? null,
})
.eq("id", value.userId)
.eq("rectification_case_id", value.id);
if (profileError) throw new BirthTimeJourneyStoreError("update_profile");
},
async saveCandidate(value) {
const { data, error } = await supabase
.from("birth_time_rectification_cases")
.update({ candidate_saved_at: new Date().toISOString(), updated_at: new Date().toISOString() })
.eq("id", value.id)
.eq("user_id", value.userId)
.eq("journey_protocol", "legacy-guided-v1")
.eq("candidate_result_id", value.candidateResult?.resultId ?? null)
.select("id")
.maybeSingle();
if (error || !data) throw new BirthTimeJourneyStoreError("update_case");
},
async confirmCandidate(value) {
const { error } = await supabase.rpc("confirm_birth_time_candidate", {
p_user_id: value.userId,
p_case_id: value.id,
p_result_id: value.candidateResult?.resultId,
p_time: value.snapshot.activeTime,
p_snapshot: value.snapshot,
});
if (error) throw new BirthTimeJourneyStoreError("update_case");
},
};
}