ci: trigga på master + formatfix inför Gitea Actions
CI / Typecheck, test & build (push) Failing after 2s
CI / Typecheck, test & build (push) Failing after 2s
This commit is contained in:
@@ -111,8 +111,7 @@ async function aiScanBlock(
|
||||
AND properties->>'latencyMs' IS NOT NULL
|
||||
`);
|
||||
const latencyRow = (Array.isArray(latency) ? latency[0] : latency.rows[0]) as
|
||||
| { p50: string | number | null; p95: string | number | null }
|
||||
| undefined;
|
||||
{ p50: string | number | null; p95: string | number | null } | undefined;
|
||||
|
||||
const latestErrors = await db.execute(sql`
|
||||
SELECT properties->>'errorCode' AS code, occurred_at AS tid
|
||||
@@ -122,7 +121,9 @@ async function aiScanBlock(
|
||||
ORDER BY occurred_at DESC
|
||||
LIMIT 5
|
||||
`);
|
||||
const latestErrorsRows = (Array.isArray(latestErrors) ? latestErrors : latestErrors.rows) as Array<{
|
||||
const latestErrorsRows = (
|
||||
Array.isArray(latestErrors) ? latestErrors : latestErrors.rows
|
||||
) as Array<{
|
||||
code: string | null;
|
||||
tid: string | Date;
|
||||
}>;
|
||||
@@ -132,8 +133,10 @@ async function aiScanBlock(
|
||||
FROM ai_usage_counters
|
||||
WHERE month = to_char(now() AT TIME ZONE 'UTC', 'YYYY-MM')
|
||||
`);
|
||||
const monthRow = (Array.isArray(month) ? month[0] : month.rows[0]) as { total: bigint | number } | undefined;
|
||||
const monthlyCostMicrocents = typeof monthRow?.total === "bigint" ? Number(monthRow.total) : asNumber(monthRow?.total);
|
||||
const monthRow = (Array.isArray(month) ? month[0] : month.rows[0]) as
|
||||
{ total: bigint | number } | undefined;
|
||||
const monthlyCostMicrocents =
|
||||
typeof monthRow?.total === "bigint" ? Number(monthRow.total) : asNumber(monthRow?.total);
|
||||
|
||||
const exact24h = await db.execute(sql`
|
||||
SELECT COALESCE(sum(cost_usd), 0)::float AS total
|
||||
@@ -142,7 +145,8 @@ async function aiScanBlock(
|
||||
AND updated_at >= now() - interval '24 hours'
|
||||
AND status IN ('awaiting_confirmation', 'completed')
|
||||
`);
|
||||
const exact24hRow = (Array.isArray(exact24h) ? exact24h[0] : exact24h.rows[0]) as { total: number } | undefined;
|
||||
const exact24hRow = (Array.isArray(exact24h) ? exact24h[0] : exact24h.rows[0]) as
|
||||
{ total: number } | undefined;
|
||||
const exactCostUsd = asNumber(exact24hRow?.total);
|
||||
|
||||
let cost24hMicrocents: number | null = null;
|
||||
@@ -209,8 +213,7 @@ async function conversionWithin(
|
||||
(SELECT count(*) FROM converted) AS converted
|
||||
`);
|
||||
const row = (Array.isArray(result) ? result[0] : result.rows[0]) as
|
||||
| { total: number; converted: number }
|
||||
| undefined;
|
||||
{ total: number; converted: number } | undefined;
|
||||
if (!row || asNumber(row.total) === 0) return null;
|
||||
return asNumber(row.converted) / asNumber(row.total);
|
||||
}
|
||||
@@ -242,8 +245,7 @@ async function householdConversionWithin(
|
||||
(SELECT count(*) FROM converted) AS converted
|
||||
`);
|
||||
const row = (Array.isArray(result) ? result[0] : result.rows[0]) as
|
||||
| { total: number; converted: number }
|
||||
| undefined;
|
||||
{ total: number; converted: number } | undefined;
|
||||
if (!row || asNumber(row.total) === 0) return null;
|
||||
return asNumber(row.converted) / asNumber(row.total);
|
||||
}
|
||||
@@ -269,8 +271,7 @@ async function cohortRetention(db: Database, day: number): Promise<number | null
|
||||
(SELECT count(*) FROM active) AS active
|
||||
`);
|
||||
const row = (Array.isArray(result) ? result[0] : result.rows[0]) as
|
||||
| { total: number; active: number }
|
||||
| undefined;
|
||||
{ total: number; active: number } | undefined;
|
||||
if (!row || asNumber(row.total) === 0) return null;
|
||||
return asNumber(row.active) / asNumber(row.total);
|
||||
}
|
||||
@@ -305,8 +306,7 @@ async function engagementBlock(db: Database): Promise<OpsEngagementBlock> {
|
||||
FROM product_analytics_events
|
||||
`);
|
||||
const row = (Array.isArray(result) ? result[0] : result.rows[0]) as
|
||||
| { c24: number; c7: number; opened: number; viewed: number }
|
||||
| undefined;
|
||||
{ c24: number; c7: number; opened: number; viewed: number } | undefined;
|
||||
|
||||
const tips = await db.execute(sql`
|
||||
SELECT count(*)::int AS n
|
||||
@@ -333,8 +333,7 @@ async function paymentBlock(db: Database): Promise<OpsPaymentBlock> {
|
||||
FROM subscriptions
|
||||
`);
|
||||
const row = (Array.isArray(result) ? result[0] : result.rows[0]) as
|
||||
| { failed: number; grace: number }
|
||||
| undefined;
|
||||
{ failed: number; grace: number } | undefined;
|
||||
|
||||
const trials = await db.execute(sql`
|
||||
SELECT count(*)::int AS n
|
||||
@@ -342,7 +341,8 @@ async function paymentBlock(db: Database): Promise<OpsPaymentBlock> {
|
||||
WHERE ends_at >= now()
|
||||
AND ends_at <= now() + interval '48 hours'
|
||||
`);
|
||||
const trialsRow = (Array.isArray(trials) ? trials[0] : trials.rows[0]) as { n: number } | undefined;
|
||||
const trialsRow = (Array.isArray(trials) ? trials[0] : trials.rows[0]) as
|
||||
{ n: number } | undefined;
|
||||
|
||||
const store = await db.execute(sql`
|
||||
SELECT
|
||||
@@ -352,8 +352,7 @@ async function paymentBlock(db: Database): Promise<OpsPaymentBlock> {
|
||||
WHERE created_at >= now() - interval '7 days'
|
||||
`);
|
||||
const storeRow = (Array.isArray(store) ? store[0] : store.rows[0]) as
|
||||
| { refunds: number; chargebacks: number }
|
||||
| undefined;
|
||||
{ refunds: number; chargebacks: number } | undefined;
|
||||
|
||||
return {
|
||||
failed_nu: asNumber(row?.failed),
|
||||
@@ -547,8 +546,12 @@ async function subscriptionsBlock(db: Database): Promise<OpsSubscriptionsBlock>
|
||||
|
||||
return {
|
||||
trial_aktiva: trialAktiva,
|
||||
trial_konverterade_24h: asNumber((Array.isArray(trialConv24h) ? trialConv24h[0] : trialConv24h.rows[0]).n),
|
||||
trial_konverterade_7d: asNumber((Array.isArray(trialConv7d) ? trialConv7d[0] : trialConv7d.rows[0]).n),
|
||||
trial_konverterade_24h: asNumber(
|
||||
(Array.isArray(trialConv24h) ? trialConv24h[0] : trialConv24h.rows[0]).n,
|
||||
),
|
||||
trial_konverterade_7d: asNumber(
|
||||
(Array.isArray(trialConv7d) ? trialConv7d[0] : trialConv7d.rows[0]).n,
|
||||
),
|
||||
konverteringsgrad_30d: roundRate(konv30d),
|
||||
betalande,
|
||||
avslutade_24h: asNumber((Array.isArray(avslutade) ? avslutade[0] : avslutade.rows[0]).n),
|
||||
@@ -561,17 +564,22 @@ function storeBlock(): OpsStoreBlock {
|
||||
|
||||
export function buildWall(summary: OpsSummary): OpsWallBlock {
|
||||
const budgetUsd = Number(process.env.GEMINI_DAILY_BUDGET_USD ?? 0);
|
||||
const dailySpendUsd = summary.ai_scan.budget_andel != null && budgetUsd > 0
|
||||
? summary.ai_scan.budget_andel * budgetUsd
|
||||
: null;
|
||||
const budgetLabel = dailySpendUsd != null && budgetUsd > 0
|
||||
? `${dailySpendUsd.toFixed(2)} / ${budgetUsd} USD`
|
||||
: "—";
|
||||
const dailySpendUsd =
|
||||
summary.ai_scan.budget_andel != null && budgetUsd > 0
|
||||
? summary.ai_scan.budget_andel * budgetUsd
|
||||
: null;
|
||||
const budgetLabel =
|
||||
dailySpendUsd != null && budgetUsd > 0 ? `${dailySpendUsd.toFixed(2)} / ${budgetUsd} USD` : "—";
|
||||
const budgetTone: OpsWallTile["tone"] =
|
||||
budgetUsd <= 0 ? "ok" :
|
||||
summary.ai_scan.budget_andel == null ? "warn" :
|
||||
summary.ai_scan.budget_andel >= 1 ? "crit" :
|
||||
summary.ai_scan.budget_andel >= 0.8 ? "warn" : "ok";
|
||||
budgetUsd <= 0
|
||||
? "ok"
|
||||
: summary.ai_scan.budget_andel == null
|
||||
? "warn"
|
||||
: summary.ai_scan.budget_andel >= 1
|
||||
? "crit"
|
||||
: summary.ai_scan.budget_andel >= 0.8
|
||||
? "warn"
|
||||
: "ok";
|
||||
|
||||
const tiles: OpsWallTile[] = [
|
||||
{
|
||||
@@ -722,22 +730,35 @@ function alarmBlock(budgetUsd: number, dailySpendUsd: number | null | undefined)
|
||||
export async function computeOpsSummary(options: ComputeOpsSummaryOptions): Promise<OpsSummary> {
|
||||
const { db, budgetUsd, dailySpendUsd, queueSummary, planPrices: planPricesOverride } = options;
|
||||
const planPrices = { ...getPlanPrices(), ...(planPricesOverride ?? {}) };
|
||||
const [app, economy, users, subscriptions, butik, feedbackData, ai, activation, engagement, payment, safety, larm, gemini] =
|
||||
await Promise.all([
|
||||
Promise.resolve(appBlock()),
|
||||
economyBlock(db, planPrices),
|
||||
usersBlock(db),
|
||||
subscriptionsBlock(db),
|
||||
Promise.resolve(storeBlock()),
|
||||
feedbackBlock(db),
|
||||
aiScanBlock(db, budgetUsd, dailySpendUsd),
|
||||
activationBlock(db),
|
||||
engagementBlock(db),
|
||||
paymentBlock(db),
|
||||
safetyBlock(db),
|
||||
Promise.resolve(alarmBlock(budgetUsd, dailySpendUsd)),
|
||||
geminiBlock(db),
|
||||
]);
|
||||
const [
|
||||
app,
|
||||
economy,
|
||||
users,
|
||||
subscriptions,
|
||||
butik,
|
||||
feedbackData,
|
||||
ai,
|
||||
activation,
|
||||
engagement,
|
||||
payment,
|
||||
safety,
|
||||
larm,
|
||||
gemini,
|
||||
] = await Promise.all([
|
||||
Promise.resolve(appBlock()),
|
||||
economyBlock(db, planPrices),
|
||||
usersBlock(db),
|
||||
subscriptionsBlock(db),
|
||||
Promise.resolve(storeBlock()),
|
||||
feedbackBlock(db),
|
||||
aiScanBlock(db, budgetUsd, dailySpendUsd),
|
||||
activationBlock(db),
|
||||
engagementBlock(db),
|
||||
paymentBlock(db),
|
||||
safetyBlock(db),
|
||||
Promise.resolve(alarmBlock(budgetUsd, dailySpendUsd)),
|
||||
geminiBlock(db),
|
||||
]);
|
||||
|
||||
const base: OpsSummary = {
|
||||
app,
|
||||
|
||||
Reference in New Issue
Block a user