feat(geo): добавить раздел IP-регионов
Docker / build (push) Failing after 26s

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
DenozordecandCursor committed 2026-08-25 15:16:17 +07:00
1 parent 60a22b9450
commit 235ae03489
37 files changed
+4938 -34

No files matched your search

+2
View File
@@ -6,6 +6,8 @@ import {
const TABLE_ORDER_DELETE = [
'vps_grants',
'ipregion_results',
'ipregion_runs',
'censorcheck_results',
'censorcheck_runs',
'notification_log',
@@ -0,0 +1,66 @@
import { describe, expect, it } from 'vitest'
import {
canonicalizeCountryValue,
inferIpregionGroup,
} from '@cfdm/shared/contracts/ipregion'
import { normalizeIngestResult, summarizeResults } from './normalize.js'
describe('canonicalizeCountryValue', () => {
it('мапит ISO в ok', () => {
expect(canonicalizeCountryValue('RU')).toEqual({ status: 'ok', country: 'RU' })
expect(canonicalizeCountryValue(' de ')).toEqual({ status: 'ok', country: 'DE' })
})
it('мапит статусы ipregion', () => {
expect(canonicalizeCountryValue('N/A').status).toBe('na')
expect(canonicalizeCountryValue('Denied').status).toBe('denied')
expect(canonicalizeCountryValue('Rate-limit').status).toBe('rate_limit')
expect(canonicalizeCountryValue('Rate limit').status).toBe('rate_limit')
expect(canonicalizeCountryValue('Server error').status).toBe('server_error')
})
})
describe('ipregion normalize', () => {
it('нормализует сервис и группу', () => {
const row = normalizeIngestResult({
service: 'Maxmind.com',
ipv4: 'NL',
ipv6: 'N/A',
})
expect(row.serviceKey).toBe('maxmind.com')
expect(row.group).toBe('primary')
expect(row.status).toBe('ok')
expect(row.countryIpv4).toBe('NL')
expect(row.countryIpv6).toBeNull()
})
it('берёт IPv6 если IPv4 N/A', () => {
const row = normalizeIngestResult({
service: 'YouTube CDN',
group: 'cdn',
ipv4: 'N/A',
ipv6: 'US',
})
expect(row.status).toBe('ok')
expect(row.countryIpv6).toBe('US')
expect(row.group).toBe('cdn')
})
it('считает summary и partial', () => {
const { summary, runStatus } = summarizeResults([
{ status: 'ok' },
{ status: 'na' },
{ status: 'denied' },
])
expect(summary.total).toBe(3)
expect(summary.ok).toBe(1)
expect(summary.denied).toBe(1)
expect(runStatus).toBe('partial')
})
it('угадывает группу по имени', () => {
expect(inferIpregionGroup('cloudflare.com')).toBe('primary')
expect(inferIpregionGroup('Netflix')).toBe('custom')
expect(inferIpregionGroup('YouTube CDN')).toBe('cdn')
})
})
@@ -0,0 +1,52 @@
import {
canonicalizeCountryValue,
emptyIpregionSummary,
inferIpregionGroup,
type IpregionGroup,
type IpregionIngestResult,
type IpregionRunStatus,
type IpregionStatus,
type IpregionSummary,
} from '@cfdm/shared/contracts/ipregion'
export type NormalizedIpregionResult = {
serviceKey: string
serviceLabel: string
group: IpregionGroup
countryIpv4: string | null
countryIpv6: string | null
status: IpregionStatus
}
export function normalizeIngestResult(item: IpregionIngestResult): NormalizedIpregionResult {
const serviceLabel = item.service.trim()
const serviceKey = serviceLabel.toLowerCase()
const ipv4 = canonicalizeCountryValue(item.ipv4)
const ipv6 = canonicalizeCountryValue(item.ipv6)
const status = ipv4.status !== 'na' ? ipv4.status : ipv6.status
return {
serviceKey,
serviceLabel,
group: item.group ?? inferIpregionGroup(serviceKey),
countryIpv4: ipv4.country,
countryIpv6: ipv6.country,
status,
}
}
export function summarizeResults(results: { status: IpregionStatus }[]): {
summary: IpregionSummary
runStatus: IpregionRunStatus
} {
const summary = emptyIpregionSummary()
summary.total = results.length
for (const row of results) {
summary[row.status] += 1
}
const runStatus: IpregionRunStatus =
summary.denied > 0 || summary.rate_limit > 0 || summary.server_error > 0
? 'partial'
: 'complete'
return { summary, runStatus }
}