chore: test deploy snapshot

This commit is contained in:
2026-05-28 08:09:49 +09:00
parent e195ac8088
commit 983887dc05
30 changed files with 1730 additions and 108 deletions

View File

@@ -2,6 +2,7 @@ import type { Knex } from 'knex';
import { z } from 'zod';
import { db } from '../db/client.js';
import { sendNotifications } from './notification-service.js';
import { getSharedResourceTokenDetail } from './shared-resource-token-service.js';
const TICKET_BAY_ORIGIN = 'https://www.ticketbay.co.kr';
const SPORTS_SEARCH_KEY = '5';
@@ -695,6 +696,7 @@ export type BaseballTicketBayAlertItem = {
clientId: string;
ownerType: BaseballTicketBayOwnerType;
ownerId: string;
ownerLabel?: string | null;
title: string;
eventDate: string;
team: string;
@@ -722,6 +724,7 @@ export type BaseballTicketBayAlertLogItem = {
clientId: string;
ownerType: BaseballTicketBayOwnerType;
ownerId: string;
ownerLabel?: string | null;
alertId: string | null;
alertTitle: string;
action: BaseballTicketBayAlertLogAction;
@@ -902,6 +905,7 @@ function mapAlertRow(row: BaseballTicketBayAlertRow): BaseballTicketBayAlertItem
clientId: normalizeText(row.client_id),
ownerType: normalizeOwnerType(row.owner_type),
ownerId: normalizeOwnerId(row),
ownerLabel: null,
title: normalizeText(row.title),
eventDate: normalizeText(row.event_date),
team: normalizeText(row.team) || '전체',
@@ -938,6 +942,7 @@ function mapLogRow(row: BaseballTicketBayLogRow): BaseballTicketBayAlertLogItem
clientId: normalizeText(row.client_id),
ownerType: normalizeOwnerType(row.owner_type),
ownerId: normalizeOwnerId(row),
ownerLabel: null,
alertId: row.alert_id ? normalizeText(row.alert_id) : null,
alertTitle: normalizeText(row.alert_title),
action: row.action,
@@ -949,6 +954,34 @@ function mapLogRow(row: BaseballTicketBayLogRow): BaseballTicketBayAlertLogItem
};
}
async function attachOwnerLabels<T extends { ownerType: BaseballTicketBayOwnerType; ownerId: string; ownerLabel?: string | null }>(items: T[]) {
const sharedTokenOwnerIds = Array.from(
new Set(
items
.filter((item) => item.ownerType === 'shared-token')
.map((item) => normalizeText(item.ownerId))
.filter(Boolean),
),
);
if (!sharedTokenOwnerIds.length) {
return items;
}
const labelEntries = await Promise.all(
sharedTokenOwnerIds.map(async (tokenId) => {
const detail = await getSharedResourceTokenDetail(tokenId);
return [tokenId, detail?.token.resourceLabel?.trim() || detail?.token.name?.trim() || null] as const;
}),
);
const labelMap = new Map(labelEntries);
return items.map((item) => ({
...item,
ownerLabel: item.ownerType === 'shared-token' ? labelMap.get(normalizeText(item.ownerId)) ?? null : null,
}));
}
function formatTimeInKst(date: Date) {
return new Intl.DateTimeFormat('en-GB', {
timeZone: 'Asia/Seoul',
@@ -1162,7 +1195,7 @@ export async function listBaseballTicketBayAlerts(scope: BaseballTicketBayOwnerS
{ column: 'client_id', order: 'asc' },
{ column: 'created_at', order: 'desc' },
])) as BaseballTicketBayAlertRow[];
return rows.map((row: BaseballTicketBayAlertRow) => mapAlertRow(row));
return attachOwnerLabels(rows.map((row: BaseballTicketBayAlertRow) => mapAlertRow(row)));
}
export async function listBaseballTicketBayLogs(
@@ -1177,7 +1210,7 @@ export async function listBaseballTicketBayLogs(
}
const rows = (await query) as BaseballTicketBayLogRow[];
return rows.map((row: BaseballTicketBayLogRow) => mapLogRow(row));
return attachOwnerLabels(rows.map((row: BaseballTicketBayLogRow) => mapLogRow(row)));
}
export async function createBaseballTicketBayLog(args: {
@@ -1208,7 +1241,7 @@ export async function createBaseballTicketBayLog(args: {
payload_json: args.payload ? JSON.stringify(args.payload) : null,
};
await db(BASEBALL_TICKET_BAY_LOG_TABLE).insert(row);
return mapLogRow(row);
return attachOwnerLabels([mapLogRow(row)]).then(([item]) => item);
}
export async function deleteBaseballTicketBayLog(logId: string, scope: BaseballTicketBayOwnerScope) {
@@ -1234,7 +1267,7 @@ export async function deleteBaseballTicketBayLog(logId: string, scope: BaseballT
scope,
).delete();
return mapLogRow(existing as BaseballTicketBayLogRow);
return attachOwnerLabels([mapLogRow(existing as BaseballTicketBayLogRow)]).then(([item]) => item);
}
export async function createBaseballTicketBayAlert(
@@ -1269,20 +1302,26 @@ export async function createBaseballTicketBayAlert(
last_match_at: null,
};
await db(BASEBALL_TICKET_BAY_ALERT_TABLE).insert(row);
return mapAlertRow(row);
return attachOwnerLabels([mapAlertRow(row)]).then(([item]) => item);
}
export async function updateBaseballTicketBayAlert(
alertId: string,
payload: Partial<BaseballTicketBayAlertMutation>,
context: { clientId: string; ownerType: BaseballTicketBayOwnerType; ownerId: string; appOrigin?: string; appDomain?: string },
context:
| { scope: BaseballTicketBayOwnerScope; appOrigin?: string; appDomain?: string }
| { clientId: string; ownerType: BaseballTicketBayOwnerType; ownerId: string; appOrigin?: string; appDomain?: string },
) {
await ensureBaseballTicketBayTables();
const scope =
'scope' in context
? context.scope
: ({ kind: 'owner', ownerType: context.ownerType, ownerId: context.ownerId } as const);
const current = await applyOwnerScope(
db(BASEBALL_TICKET_BAY_ALERT_TABLE)
.select('*')
.where({ id: alertId }),
{ kind: 'owner', ownerType: context.ownerType, ownerId: context.ownerId },
scope,
).first();
if (!current) {
@@ -1309,18 +1348,15 @@ export async function updateBaseballTicketBayAlert(
if (context.appOrigin) patch.app_origin = normalizeText(context.appOrigin);
if (context.appDomain) patch.app_domain = normalizeText(context.appDomain);
await applyOwnerScope(
db(BASEBALL_TICKET_BAY_ALERT_TABLE).where({ id: alertId }),
{ kind: 'owner', ownerType: context.ownerType, ownerId: context.ownerId },
).update(patch);
await applyOwnerScope(db(BASEBALL_TICKET_BAY_ALERT_TABLE).where({ id: alertId }), scope).update(patch);
const updated = await applyOwnerScope(
db(BASEBALL_TICKET_BAY_ALERT_TABLE)
.select('*')
.where({ id: alertId }),
{ kind: 'owner', ownerType: context.ownerType, ownerId: context.ownerId },
scope,
).first();
return mapAlertRow(updated as BaseballTicketBayAlertRow);
return attachOwnerLabels([mapAlertRow(updated as BaseballTicketBayAlertRow)]).then(([item]) => item);
}
export async function deleteBaseballTicketBayAlert(alertId: string, scope: BaseballTicketBayOwnerScope) {
@@ -1340,7 +1376,7 @@ export async function deleteBaseballTicketBayAlert(alertId: string, scope: Baseb
db(BASEBALL_TICKET_BAY_ALERT_TABLE).where({ id: alertId }),
scope,
).delete();
return mapAlertRow(row as BaseballTicketBayAlertRow);
return attachOwnerLabels([mapAlertRow(row as BaseballTicketBayAlertRow)]).then(([item]) => item);
}
async function getAlertRow(alertId: string, scope?: BaseballTicketBayOwnerScope) {