UNPKG

@paroicms/site-generator-plugin

Version:

ParoiCMS Site Generator Plugin

204 lines (203 loc) 7.49 kB
import { parseSqliteDateTime } from "@paroicms/internal-server-lib"; import { type } from "arktype"; import { ensureType, formatActivityCode, formatStepKind, formatStepStatus } from "./formatters.js"; const SessionRowAT = type({ id: "string", expireAt: "string|number|Date", successStepCount: "number", "+": "reject", }); export async function getInvalidSessionError(ctx, sessionId) { const { cn } = ctx; const row = await cn("PgSession as s") .leftJoin("PgSchemaStep as u", "u.sessionId", "s.id") .select("s.id", "s.expireAt", cn.raw("count(u.sessionId) as successStepCount")) .where({ "s.id": sessionId }) .groupBy("s.id") .first(); if (!row) return "not found"; const validated = SessionRowAT.assert(row); if (validated.successStepCount >= 20) return "too many steps"; const expireAt = parseSqliteDateTime(validated.expireAt).getTime(); if (expireAt < Date.now()) return "expired"; } const StepSchemaRowAT = type({ siteSchema: "string", l10n: "string", localizedValues: "string", "+": "reject", }); export async function readStepSchema(ctx, stepNumber) { const { cn, sessionId } = ctx; const row = await cn("PgSchemaStep") .select("siteSchema", "l10n", "localizedValues") .where({ sessionId, stepNumber }) .first(); if (!row) throw new Error(`[${sessionId}] Step "${stepNumber}" not found`); const validated = StepSchemaRowAT.assert(row); return { siteSchema: JSON.parse(validated.siteSchema), l10n: JSON.parse(validated.l10n), localizedValues: JSON.parse(validated.localizedValues), }; } const WorkSessionRowAT = type({ id: "string", createdAt: "string|number|Date", expireAt: "string|number|Date", language: "string", "+": "reject", }); export async function fetchWorkSession(ctx) { const { cn, sessionId } = ctx; const row = await cn("PgSession") .select("id", "createdAt", "expireAt", "language") .where({ id: sessionId }) .first(); if (!row) { throw new Error(`Session not found: ${sessionId}`); } const validated = WorkSessionRowAT.assert(row); const steps = await loadSessionSteps(ctx); return { id: validated.id, createdAt: parseSqliteDateTime(validated.createdAt).toISOString(), expireAt: parseSqliteDateTime(validated.expireAt).toISOString(), language: validated.language, steps, }; } async function loadSessionSteps(ctx) { const { cn, sessionId } = ctx; const rows = await buildStepsQuery(cn) .where({ "s.sessionId": sessionId }) .orderBy("s.stepNumber"); return rows.map((row) => mapRowToStep(row, sessionId)); } export async function loadStep(ctx, stepNumber) { const { cn, sessionId } = ctx; const row = await buildStepsQuery(cn) .where({ "s.sessionId": sessionId, "s.stepNumber": stepNumber }) .first(); if (!row) { throw new Error(`[Session "${sessionId}"] Step "${stepNumber}" not found`); } return mapRowToStep(row, sessionId); } function buildStepsQuery(cn) { return cn("PgStep as s") .select("s.stepNumber", "s.kind", "s.status", "s.currentActivity", "s.explanation", "c.promptTitle", "c.siteSchema", "c.l10n", "c.localizedValues as schemaLocalizedValues", "i.siteId", "i.localizedValues as siteLocalizedValues", "i.siteUrl", "i.loginEmail", "i.loginPassword") .leftJoin("PgSchemaStep as c", { "c.stepNumber": "s.stepNumber", "c.sessionId": "s.sessionId", }) .leftJoin("PgGeneratedSiteStep as i", { "i.stepNumber": "s.stepNumber", "i.sessionId": "s.sessionId", }); } const StepRowAT = type({ stepNumber: "number", explanation: "string|null", status: "string", kind: "string", currentActivity: "string|null", promptTitle: "string|null", siteSchema: "string|null", l10n: "string|null", schemaLocalizedValues: "string|null", siteId: "string|null", siteLocalizedValues: "string|null", siteUrl: "string|null", loginEmail: "string|null", loginPassword: "string|null", "+": "reject", }).pipe((r) => ({ ...r, explanation: r.explanation ?? undefined, currentActivity: r.currentActivity ?? undefined, promptTitle: r.promptTitle ?? undefined, siteSchema: r.siteSchema ?? undefined, l10n: r.l10n ?? undefined, schemaLocalizedValues: r.schemaLocalizedValues ?? undefined, siteId: r.siteId ?? undefined, siteLocalizedValues: r.siteLocalizedValues ?? undefined, siteUrl: r.siteUrl ?? undefined, loginEmail: r.loginEmail ?? undefined, loginPassword: r.loginPassword ?? undefined, })); function mapRowToStep(row, sessionId) { const validated = StepRowAT.assert(row); const baseStep = { stepNumber: validated.stepNumber, explanation: validated.explanation, }; const status = formatStepStatus(validated.status); const kind = formatStepKind(validated.kind); if (status === "pending") { return ensureType({ ...baseStep, status, kind, currentActivity: formatActivityCode(validated.currentActivity), }); } if (status === "completed") { if (kind === "initialSchema" || kind === "updateSchema") { if (!validated.siteSchema) { throw new Error(`[Session "${sessionId}"] PgSchemaStep row is missing for completed step "${validated.stepNumber}"`); } if (!validated.l10n || !validated.schemaLocalizedValues) { throw new Error(`[Session "${sessionId}"] Missing schema data for completed step "${validated.stepNumber}"`); } return ensureType({ ...baseStep, status, kind, promptTitle: validated.promptTitle, siteSchema: JSON.parse(validated.siteSchema), l10n: JSON.parse(validated.l10n), localizedValues: JSON.parse(validated.schemaLocalizedValues), }); } if (kind === "generateSite") { if (!validated.siteId) { throw new Error(`[Session "${sessionId}"] PgGeneratedSiteStep row is missing for completed step "${validated.stepNumber}"`); } if (!validated.siteUrl || !validated.loginEmail || !validated.loginPassword || !validated.siteLocalizedValues) { throw new Error(`[Session "${sessionId}"] Missing generated site data for completed step "${validated.stepNumber}"`); } return ensureType({ ...baseStep, status, kind, siteId: validated.siteId, siteUrl: validated.siteUrl, adminUiUrl: `${validated.siteUrl}/adm`, loginEmail: validated.loginEmail, loginPassword: validated.loginPassword, localizedValues: JSON.parse(validated.siteLocalizedValues), }); } throw new Error(`[Session "${sessionId}"] invalid step kind "${kind}"`); } if (status === "failed") { return ensureType({ ...baseStep, status, kind, }); } return ensureType({ ...baseStep, status, kind, }); }