Ctrl K
ComunidadGuías…

scripts/check_plugin_runtime_isolation.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
/**
 * Fail if plugin_runtime imports any sibling _backend module outside itself,
 * or if the CF plugin worker imports non-plugin_runtime backend code.
 */
import { existsSync, readdirSync, readFileSync } from 'node:fs'
import { dirname, join, relative, resolve } from 'node:path'

const root = resolve(import.meta.dirname, '..')
const runtimeRoot = resolve(root, 'supabase/functions/_backend/plugin_runtime')
const pluginEntry = resolve(root, 'cloudflare_workers/plugin/index.ts')
const backendRoot = resolve(root, 'supabase/functions/_backend')

const errors = []

function walk(dir, out = []) {
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
    const abs = join(dir, entry.name)
    if (entry.isDirectory())
      walk(abs, out)
    else if (entry.name.endsWith('.ts'))
      out.push(abs)
  }
  return out
}

function resolveImport(from, spec) {
  if (!spec.startsWith('.'))
    return null
  const base = resolve(dirname(from), spec)
  for (const cand of [base, `${base}.ts`, `${base}.js`, join(base, 'index.ts')]) {
    if (existsSync(cand) && cand.endsWith('.ts'))
      return cand
  }
  return null
}

function collectImports(file) {
  const text = readFileSync(file, 'utf8')
  const specs = []
  const re = /(?:from\s+|import\s*\(\s*)['"]([^'"]+)['"]/g
  let m
  while ((m = re.exec(text)))
    specs.push(m[1])
  return specs
}

for (const file of walk(runtimeRoot)) {
  for (const spec of collectImports(file)) {
    const resolved = resolveImport(file, spec)
    if (!resolved)
      continue
    if (resolved.startsWith(`${backendRoot}/`) && !resolved.startsWith(`${runtimeRoot}/`)) {
      errors.push(`${relative(root, file)} imports ${relative(root, resolved)} (outside plugin_runtime)`)
    }
  }
}

for (const spec of collectImports(pluginEntry)) {
  const resolved = resolveImport(pluginEntry, spec)
  if (!resolved)
    continue
  if (resolved.startsWith(`${backendRoot}/`) && !resolved.startsWith(`${runtimeRoot}/`)) {
    errors.push(`cloudflare_workers/plugin/index.ts imports ${relative(root, resolved)} (must use plugin_runtime only)`)
  }
}

const denoEntries = [
  'supabase/functions/updates/index.ts',
  'supabase/functions/stats/index.ts',
  'supabase/functions/channel_self/index.ts',
  'supabase/functions/updates_debug/index.ts',
]

for (const rel of denoEntries) {
  const file = resolve(root, rel)
  for (const spec of collectImports(file)) {
    const resolved = resolveImport(file, spec)
    if (!resolved)
      continue
    // Request-path code must come from plugin_runtime. The only allowed
    // sibling _backend import is none — Deno supabase-js bridge lives in
    // shared/plugin_deno_stats_fallbacks.ts.
    if (resolved.startsWith(`${backendRoot}/`) && !resolved.startsWith(`${runtimeRoot}/`)) {
      errors.push(`${rel} imports ${relative(root, resolved)} (use plugin_runtime or shared Deno bridge)`)
    }
  }
}

if (errors.length) {
  console.error('plugin_runtime isolation check failed:\n')
  for (const err of errors)
    console.error(`- ${err}`)
  process.exit(1)
}

console.log('plugin_runtime isolation check passed')