summaryrefslogtreecommitdiff
path: root/scripts/check-tier-parity.ts
blob: d7ee8a448b4cb69dea928f1c98e87e300fa72053 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import { readFileSync } from "fs"
import { resolve } from "path"
import { TIER_LIMITS } from "../packages/shared/source/index.ts"

const TRIGGER_MAP: Record<string, keyof (typeof TIER_LIMITS)["free"]> = {
  check_subscription_limit: "maximumFeeds",
  check_folder_limit: "maximumFolders",
  check_muted_keyword_limit: "maximumMutedKeywords",
  check_custom_feed_limit: "maximumCustomFeeds",
}

const CASE_PATTERN = /when\s+'(\w+)'\s+then\s+(\d+)/g

function extractSqlLimits(
  schemaContent: string,
  functionName: string
): Record<string, number> {
  const functionPattern = new RegExp(
    `FUNCTION\\s+"public"\\."${functionName}".*?\\$\\$;`,
    "is"
  )
  const functionMatch = schemaContent.match(functionPattern)
  if (!functionMatch) {
    throw new Error(`function ${functionName} not found in schema`)
  }

  const caseLinePattern =
    /maximum_allowed\s*:=\s*case\s+current_tier\s+(.*?)\s+end/is
  const caseMatch = functionMatch[0].match(caseLinePattern)
  if (!caseMatch) {
    throw new Error(`case expression not found in ${functionName}`)
  }

  const limits: Record<string, number> = {}
  let match: RegExpExecArray | null
  while ((match = CASE_PATTERN.exec(caseMatch[1])) !== null) {
    limits[match[1]] = parseInt(match[2], 10)
  }
  return limits
}

const schemaPath = resolve(process.cwd(), "supabase", "schema.sql")
const schemaContent = readFileSync(schemaPath, "utf-8")

let hasErrors = false

for (const [functionName, tsKey] of Object.entries(TRIGGER_MAP)) {
  const sqlLimits = extractSqlLimits(schemaContent, functionName)

  for (const tier of ["free", "pro", "developer"] as const) {
    const tsValue = TIER_LIMITS[tier][tsKey]
    const sqlValue = sqlLimits[tier]

    if (sqlValue === undefined) {
      console.error(
        `MISSING: ${functionName} has no case for tier '${tier}'`
      )
      hasErrors = true
    } else if (tsValue !== sqlValue) {
      console.error(
        `MISMATCH: ${tsKey} for ${tier} — TS=${tsValue}, SQL=${sqlValue} (in ${functionName})`
      )
      hasErrors = true
    }
  }
}

if (hasErrors) {
  console.error("\nTier limit parity check FAILED")
  process.exit(1)
} else {
  console.log("Tier limit parity check PASSED — all limits match")
}