{"version":3,"sources":["../src/cron.ts","../src/secret-compare.ts","../src/utils.ts","../src/utils/runtime-env.ts"],"sourcesContent":["import { farmSecretsMatch } from \"./secret-compare\";\nimport { toPosixPath } from \"./utils\";\nimport {\n  getFarmRuntimeBindings,\n  readFarmEnvironmentValue as readEnvironmentValue,\n} from \"./utils/runtime-env\";\n\nexport type FarmCronSchedule = string | string[];\n\nexport interface FarmCronJobConfig {\n  /** Portable five-field cron expression, or a list of expressions. */\n  schedule: FarmCronSchedule;\n  /** Farm API route invoked with GET when the schedule fires. */\n  path: string;\n  /** Human-readable purpose shown by local tooling and deployment manifests. */\n  description?: string;\n  /** Disable this schedule without removing its configuration. */\n  enabled?: boolean;\n}\n\nexport type FarmCronUserConfig = Record<string, FarmCronJobConfig>;\n\nexport interface FarmCronJob {\n  name: string;\n  schedule: string[];\n  path: string;\n  description?: string;\n}\n\nexport interface FarmCronResolvedConfig {\n  enabled: boolean;\n  secretEnv: typeof DEFAULT_FARM_CRON_SECRET_ENV;\n  jobs: FarmCronJob[];\n}\n\nexport interface PreparedFarmCron {\n  jobs: FarmCronJob[];\n  tasks: Record<string, { handler: string; description: string }>;\n  scheduledTasks: Record<string, string | string[]>;\n  manifestPath?: string;\n}\n\nexport interface FarmCronRouteOptions {\n  /** Environment variable containing the bearer token. */\n  secretEnv?: string;\n  /** Inline token, primarily useful in tests. Environment variables are preferred. */\n  secret?: string;\n  /** Allow a production route without a secret. Defaults to false. */\n  allowUnsecured?: boolean;\n}\n\nexport interface FarmCronCloudflareConfig {\n  deployConfig: true;\n  wrangler: {\n    triggers: {\n      crons: string[];\n    };\n  };\n}\n\nexport const DEFAULT_FARM_CRON_SECRET_ENV = \"CRON_SECRET\";\nexport const FARM_CRON_MANIFEST = \"cron-manifest.json\";\n\nconst CRON_FIELD_RANGES = [\n  [0, 59, \"minute\"],\n  [0, 23, \"hour\"],\n  [1, 31, \"day of month\"],\n  [1, 12, \"month\"],\n  [0, 6, \"day of week\"],\n] as const;\n\nexport function resolveCronConfig(\n  cron: FarmCronResolvedConfig | FarmCronUserConfig | false | undefined,\n): FarmCronResolvedConfig {\n  if (isResolvedCronConfig(cron)) return cron;\n  if (!cron) {\n    return {\n      enabled: false,\n      secretEnv: DEFAULT_FARM_CRON_SECRET_ENV,\n      jobs: [],\n    };\n  }\n\n  const jobs: FarmCronJob[] = [];\n  for (const [name, job] of Object.entries(cron)) {\n    if (!job || typeof job !== \"object\" || Array.isArray(job)) {\n      throw new TypeError(`Farm cron ${JSON.stringify(name)} must be a configuration object.`);\n    }\n    if (job.enabled === false) continue;\n    jobs.push(normalizeCronJob(name, job));\n  }\n\n  return {\n    enabled: jobs.length > 0,\n    secretEnv: DEFAULT_FARM_CRON_SECRET_ENV,\n    jobs,\n  };\n}\n\nexport async function prepareFarmCronForNitro(config: {\n  root?: string;\n  distDir?: string;\n  cron?: FarmCronResolvedConfig | FarmCronUserConfig | false;\n}): Promise<PreparedFarmCron> {\n  const cron = isResolvedCronConfig(config.cron) ? config.cron : resolveCronConfig(config.cron);\n  const root = config.root || process.cwd();\n  const distDir = config.distDir || \".farm\";\n  const fs = await import(\"node:fs/promises\");\n  const path = await import(\"node:path\");\n  const manifestPath = path.join(root, distDir, FARM_CRON_MANIFEST);\n  const generatedDir = path.join(root, distDir, \".nitro\", \"farm-cron\");\n\n  if (!cron.enabled) {\n    await Promise.all([\n      fs.rm(manifestPath, { force: true }),\n      fs.rm(generatedDir, { recursive: true, force: true }),\n    ]);\n    return {\n      jobs: [],\n      tasks: {},\n      scheduledTasks: {},\n    };\n  }\n\n  await fs.rm(generatedDir, { recursive: true, force: true });\n  await fs.mkdir(generatedDir, { recursive: true });\n\n  const tasks: PreparedFarmCron[\"tasks\"] = {};\n  const wrapperNames = resolveCronWrapperFileNames(cron.jobs.map((job) => job.name));\n  for (const job of cron.jobs) {\n    const taskName = getFarmCronTaskName(job.name);\n    const wrapperPath = toPosixPath(path.join(generatedDir, `${wrapperNames.get(job.name)}.mjs`));\n    await fs.writeFile(wrapperPath, createNitroCronTaskWrapper(job, cron.secretEnv), \"utf8\");\n    tasks[taskName] = {\n      handler: wrapperPath,\n      description: job.description || `Farm cron ${job.name}`,\n    };\n  }\n\n  const manifest = createFarmCronManifest(cron);\n  await fs.mkdir(path.dirname(manifestPath), { recursive: true });\n  await fs.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\\n`, \"utf8\");\n\n  return {\n    jobs: cron.jobs,\n    tasks,\n    scheduledTasks: createCronScheduledTasks(cron.jobs),\n    manifestPath,\n  };\n}\n\nexport function createFarmCronManifest(cron: FarmCronResolvedConfig) {\n  return {\n    schemaVersion: 1,\n    secretEnv: cron.secretEnv,\n    jobs: cron.jobs.map((job) => ({\n      name: job.name,\n      schedule: job.schedule,\n      path: job.path,\n      description: job.description || null,\n    })),\n  };\n}\n\nexport function createFarmCronVercelCrons(\n  jobs: FarmCronJob[],\n): Array<{ path: string; schedule: string }> {\n  return jobs.flatMap((job) =>\n    job.schedule.map((schedule) => ({\n      path: job.path,\n      schedule,\n    })),\n  );\n}\n\nexport function applyFarmCronVercelCrons(\n  vercelConfig: Record<string, any>,\n  jobs: FarmCronJob[],\n): Record<string, any> {\n  const existingCrons = Array.isArray(vercelConfig.crons) ? vercelConfig.crons : [];\n  const seen = new Set(existingCrons.map((cron) => `${cron.path}:${cron.schedule}`));\n  const crons = [...existingCrons];\n\n  for (const cron of createFarmCronVercelCrons(jobs)) {\n    const key = `${cron.path}:${cron.schedule}`;\n    if (seen.has(key)) continue;\n    seen.add(key);\n    crons.push(cron);\n  }\n\n  return crons.length > 0 ? { ...vercelConfig, crons } : vercelConfig;\n}\n\nexport function createFarmCronCloudflareTriggers(jobs: FarmCronJob[]): string[] {\n  return [...new Set(jobs.flatMap((job) => job.schedule))];\n}\n\nexport function createFarmCronCloudflareConfig(\n  jobs: FarmCronJob[],\n): FarmCronCloudflareConfig | undefined {\n  const crons = createFarmCronCloudflareTriggers(jobs);\n  if (crons.length === 0) return undefined;\n\n  return {\n    deployConfig: true,\n    wrangler: {\n      triggers: { crons },\n    },\n  };\n}\n\nexport function mergeScheduledTasks(\n  ...maps: Array<Record<string, string | string[]> | undefined>\n): Record<string, string | string[]> {\n  const merged = new Map<string, string[]>();\n\n  for (const map of maps) {\n    for (const [schedule, taskNames] of Object.entries(map || {})) {\n      const current = merged.get(schedule) || [];\n      for (const taskName of Array.isArray(taskNames) ? taskNames : [taskNames]) {\n        if (!current.includes(taskName)) current.push(taskName);\n      }\n      merged.set(schedule, current);\n    }\n  }\n\n  return Object.fromEntries(\n    [...merged].map(([schedule, taskNames]) => [\n      schedule,\n      taskNames.length === 1 ? taskNames[0] : taskNames,\n    ]),\n  );\n}\n\n/**\n * Whether the process explicitly declares a development or test environment.\n *\n * An absent NODE_ENV is not a development signal. Plenty of container images and\n * serverless runtimes leave it unset, so treating \"not production\" as\n * development leaves an unsecured cron route open wherever the variable simply\n * was never set. Matches the fail-closed gate the auth0 and workos integrations\n * use for their development secrets.\n */\nfunction isExplicitDevelopmentEnv(): boolean {\n  const nodeEnv = readEnvironmentValue(\"NODE_ENV\");\n  return nodeEnv === \"development\" || nodeEnv === \"test\";\n}\n\nexport function isCronRequestAuthorized(\n  request: Request,\n  options: FarmCronRouteOptions = {},\n): boolean {\n  const secretEnv = options.secretEnv || DEFAULT_FARM_CRON_SECRET_ENV;\n  const secret = options.secret || readEnvironmentValue(secretEnv);\n  if (!secret) {\n    return (\n      options.allowUnsecured === true || (!getFarmRuntimeBindings() && isExplicitDevelopmentEnv())\n    );\n  }\n\n  const authorization = request.headers.get(\"authorization\") || \"\";\n  const bearer = /^Bearer (.*)$/i.exec(authorization)?.[1] || \"\";\n  const headerSecret = request.headers.get(\"x-farm-cron-secret\") || \"\";\n  // Both are checked so a caller may use either header; neither short-circuits\n  // on the first differing character.\n  return farmSecretsMatch(bearer, secret) || farmSecretsMatch(headerSecret, secret);\n}\n\nexport function cronRoute<TArgs extends unknown[], TResult>(\n  handler: (request: Request, ...args: TArgs) => TResult,\n  options: FarmCronRouteOptions = {},\n): (request: Request, ...args: TArgs) => TResult | Promise<Response> {\n  return (request, ...args) => {\n    if (!isCronRequestAuthorized(request, options)) {\n      return Promise.resolve(\n        Response.json({ error: \"Unauthorized cron request.\" }, { status: 401 }),\n      );\n    }\n    return handler(request, ...args);\n  };\n}\n\nfunction normalizeCronJob(name: string, job: FarmCronJobConfig): FarmCronJob {\n  if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name)) {\n    throw new TypeError(\n      `Farm cron name ${JSON.stringify(name)} must start with a letter or number and contain only letters, numbers, dots, underscores, or hyphens.`,\n    );\n  }\n  if (!job || typeof job !== \"object\" || Array.isArray(job)) {\n    throw new TypeError(`Farm cron ${JSON.stringify(name)} must be a configuration object.`);\n  }\n\n  const path = normalizeCronPath(name, job.path);\n  const rawSchedule = Array.isArray(job.schedule) ? job.schedule : [job.schedule];\n  const schedule = [...new Set(rawSchedule.map((value) => normalizeCronExpression(name, value)))];\n  if (schedule.length === 0) {\n    throw new TypeError(`Farm cron ${JSON.stringify(name)} must define at least one schedule.`);\n  }\n\n  return {\n    name,\n    schedule,\n    path,\n    description: job.description?.trim() || undefined,\n  };\n}\n\nfunction normalizeCronPath(name: string, value: unknown): string {\n  if (typeof value !== \"string\" || !value.trim().startsWith(\"/\")) {\n    throw new TypeError(`Farm cron ${JSON.stringify(name)} path must start with \"/\".`);\n  }\n\n  const hasUnstableCharacters = (candidate: string) =>\n    candidate.includes(\"\\\\\") ||\n    Array.from(candidate).some((character) => {\n      const code = character.charCodeAt(0);\n      return code <= 31 || (code >= 127 && code <= 159);\n    });\n  if (hasUnstableCharacters(value)) {\n    throw new TypeError(\n      `Farm cron ${JSON.stringify(name)} path cannot contain backslashes or control characters.`,\n    );\n  }\n\n  const path = value.trim();\n  if (path.startsWith(\"//\") || path.includes(\"?\") || path.includes(\"#\")) {\n    throw new TypeError(\n      `Farm cron ${JSON.stringify(name)} path must be an application pathname without a host, query, or hash.`,\n    );\n  }\n  for (const segment of path.split(\"/\")) {\n    let decoded = segment;\n    try {\n      decoded = decodeURIComponent(segment);\n    } catch {\n      // Malformed escapes remain literal and cannot conceal a separator or dot segment.\n    }\n    if (hasUnstableCharacters(decoded)) {\n      throw new TypeError(\n        `Farm cron ${JSON.stringify(name)} path cannot contain backslashes or control characters.`,\n      );\n    }\n    if (decoded.includes(\"/\")) {\n      throw new TypeError(\n        `Farm cron ${JSON.stringify(name)} path cannot contain percent-encoded path separators.`,\n      );\n    }\n    if (decoded === \".\" || decoded === \"..\") {\n      throw new TypeError(\n        `Farm cron ${JSON.stringify(name)} path cannot contain \".\" or \"..\" path segments.`,\n      );\n    }\n  }\n  return path.length > 1 ? path.replace(/\\/+$/, \"\") : path;\n}\n\nfunction normalizeCronExpression(name: string, value: unknown): string {\n  if (typeof value !== \"string\") {\n    throw new TypeError(`Farm cron ${JSON.stringify(name)} schedule must be a string.`);\n  }\n\n  const expression = value.trim().replace(/\\s+/g, \" \");\n  const fields = expression.split(\" \");\n  if (fields.length !== CRON_FIELD_RANGES.length) {\n    throw new TypeError(\n      `Farm cron ${JSON.stringify(name)} schedule ${JSON.stringify(expression)} must use five fields: minute hour day-of-month month day-of-week.`,\n    );\n  }\n\n  fields.forEach((field, index) => {\n    const [minimum, maximum, label] = CRON_FIELD_RANGES[index];\n    validateCronField(name, expression, field, minimum, maximum, label);\n  });\n  if (fields[2] !== \"*\" && fields[4] !== \"*\") {\n    throw new TypeError(\n      `Farm cron ${JSON.stringify(name)} schedule ${JSON.stringify(expression)} cannot constrain both day-of-month and day-of-week.`,\n    );\n  }\n  return expression;\n}\n\nfunction validateCronField(\n  name: string,\n  expression: string,\n  field: string,\n  minimum: number,\n  maximum: number,\n  label: string,\n): void {\n  for (const segment of field.split(\",\")) {\n    const [range, stepText, ...extra] = segment.split(\"/\");\n    if (!range || extra.length > 0 || (stepText !== undefined && !isIntegerInRange(stepText, 1))) {\n      throwInvalidCronField(name, expression, label);\n    }\n\n    if (range === \"*\") continue;\n    const bounds = range.split(\"-\");\n    if (bounds.length > 2 || !bounds.every((value) => isIntegerInRange(value, minimum, maximum))) {\n      throwInvalidCronField(name, expression, label);\n    }\n    if (bounds.length === 2 && Number(bounds[0]) > Number(bounds[1])) {\n      throwInvalidCronField(name, expression, label);\n    }\n  }\n}\n\nfunction isIntegerInRange(value: string, minimum: number, maximum = Number.MAX_SAFE_INTEGER) {\n  if (!/^\\d+$/.test(value)) return false;\n  const parsed = Number(value);\n  return parsed >= minimum && parsed <= maximum;\n}\n\nfunction throwInvalidCronField(name: string, expression: string, label: string): never {\n  throw new TypeError(\n    `Farm cron ${JSON.stringify(name)} schedule ${JSON.stringify(expression)} has an invalid ${label} field.`,\n  );\n}\n\nfunction isResolvedCronConfig(value: unknown): value is FarmCronResolvedConfig {\n  return (\n    !!value &&\n    typeof value === \"object\" &&\n    \"enabled\" in value &&\n    typeof (value as FarmCronResolvedConfig).enabled === \"boolean\" &&\n    \"jobs\" in value &&\n    Array.isArray((value as FarmCronResolvedConfig).jobs) &&\n    \"secretEnv\" in value\n  );\n}\n\nfunction createCronScheduledTasks(jobs: FarmCronJob[]): Record<string, string | string[]> {\n  const scheduledTasks: Record<string, string | string[]> = {};\n  for (const job of jobs) {\n    const taskName = getFarmCronTaskName(job.name);\n    for (const schedule of job.schedule) {\n      scheduledTasks[schedule] = mergeTaskNames(scheduledTasks[schedule], taskName);\n    }\n  }\n  return scheduledTasks;\n}\n\nfunction mergeTaskNames(\n  current: string | string[] | undefined,\n  taskName: string,\n): string | string[] {\n  if (!current) return taskName;\n  const names = Array.isArray(current) ? current : [current];\n  return names.includes(taskName) ? names : [...names, taskName];\n}\n\nfunction getFarmCronTaskName(name: string): string {\n  return `farm:cron:${name}`;\n}\n\nfunction createNitroCronTaskWrapper(job: FarmCronJob, secretEnv: string): string {\n  return `\nimport { defineTask, useNitroApp } from \"nitro/runtime\";\n\nconst name = ${JSON.stringify(job.name)};\nconst path = ${JSON.stringify(job.path)};\nconst secretEnv = ${JSON.stringify(secretEnv)};\n\nfunction readSecret(event) {\n  const runtimeEnv = event?.context?.cloudflare?.env || event?.context?.env || {};\n  return runtimeEnv[secretEnv] || (typeof process !== \"undefined\" ? process.env?.[secretEnv] : \"\") || \"\";\n}\n\nexport default defineTask({\n  meta: {\n    name: ${JSON.stringify(getFarmCronTaskName(job.name))},\n    description: ${JSON.stringify(job.description || `Farm cron ${job.name}`)}\n  },\n  async run(event) {\n    const headers = new Headers({\n      \"x-farm-cron-name\": name,\n      \"x-farm-cron-scheduled-at\": String(event?.payload?.scheduledTime || Date.now())\n    });\n    const secret = readSecret(event);\n    if (secret) headers.set(\"authorization\", \"Bearer \" + secret);\n\n    const response = await useNitroApp().fetch(path, { method: \"GET\", headers });\n    const contentType = response.headers.get(\"content-type\") || \"\";\n    const body = response.status === 204\n      ? null\n      : contentType.includes(\"application/json\")\n        ? await response.json().catch(() => null)\n        : await response.text();\n\n    if (!response.ok) {\n      const detail = typeof body === \"string\" ? body : JSON.stringify(body);\n      throw new Error(\n        \"Farm cron \" + JSON.stringify(name) + \" received \" + response.status +\n        \" from \" + path + (detail ? \": \" + detail : \"\")\n      );\n    }\n\n    return { result: body };\n  }\n});\n`.trim();\n}\n\n/**\n * Wrapper file names for a set of cron job names.\n *\n * Cron names are case-sensitive and `Daily` and `daily` are both valid, distinct\n * jobs — but macOS and Windows use case-insensitive filesystems by default, so\n * their wrappers would overwrite one another and both jobs would run whichever\n * file was written last. Names are only disambiguated when they actually\n * collide case-insensitively, so ordinary names such as `dailyCleanup` keep a\n * readable wrapper; every name in a colliding group gets a digest of the exact\n * job name appended, which keeps the result independent of configuration order.\n */\nfunction resolveCronWrapperFileNames(names: readonly string[]): Map<string, string> {\n  const groups = new Map<string, number>();\n  for (const name of names) {\n    const key = safeFileName(name).toLowerCase();\n    groups.set(key, (groups.get(key) ?? 0) + 1);\n  }\n\n  const resolved = new Map<string, string>();\n  const claimed = new Map<string, string>();\n  for (const name of names) {\n    const base = safeFileName(name);\n    const key = base.toLowerCase();\n    const fileName = (groups.get(key) ?? 0) > 1 ? `${key}-${cronNameFingerprint(name)}` : base;\n    const claimedBy = claimed.get(fileName.toLowerCase());\n    if (claimedBy !== undefined) {\n      throw new Error(\n        `Farm cron jobs ${JSON.stringify(claimedBy)} and ${JSON.stringify(name)} generate the same wrapper file ${JSON.stringify(`${fileName}.mjs`)}. Rename one of them.`,\n      );\n    }\n    claimed.set(fileName.toLowerCase(), name);\n    resolved.set(name, fileName);\n  }\n  return resolved;\n}\n\n/**\n * FNV-1a. This module is bundled into server runtimes without node:crypto, and\n * the digest only needs to separate file names.\n */\nfunction cronNameFingerprint(value: string): string {\n  let hash = 0x811c9dc5;\n  for (let index = 0; index < value.length; index += 1) {\n    hash ^= value.charCodeAt(index);\n    hash = Math.imul(hash, 0x01000193);\n  }\n  return (hash >>> 0).toString(16).padStart(8, \"0\");\n}\n\nfunction safeFileName(value: string): string {\n  return value.replace(/[^a-zA-Z0-9._-]+/g, \"-\") || \"cron\";\n}\n","/**\n * Compare a caller-supplied secret against the configured one without leaking\n * how much of it matched.\n *\n * `===` on strings stops at the first differing character, so the time it takes\n * to reject a guess grows with the length of the correct prefix. Over enough\n * requests that recovers a cron or workflow secret one character at a time. This\n * always inspects every position instead.\n *\n * Deliberately not node:crypto's `timingSafeEqual`: these callers are bundled\n * into the generated Nitro runtime, which also targets edge and browser-like\n * environments where importing node:crypto breaks the build.\n */\nexport function farmSecretsMatch(provided: string, expected: string): boolean {\n  if (typeof provided !== \"string\" || typeof expected !== \"string\") return false;\n  // An unset secret must never authorize a request, including an empty guess.\n  if (expected.length === 0) return false;\n\n  // Folding the lengths in rejects a wrong-length guess without an early return.\n  let mismatch = provided.length ^ expected.length;\n  const length = Math.max(provided.length, expected.length);\n  for (let index = 0; index < length; index += 1) {\n    const providedCode = index < provided.length ? provided.charCodeAt(index) : 0;\n    const expectedCode = index < expected.length ? expected.charCodeAt(index) : 0;\n    mismatch |= providedCode ^ expectedCode;\n  }\n\n  return mismatch === 0;\n}\n","import type { RouteSegment, ParsedRoute } from \"./types\";\nimport path from \"path\";\nimport {\n  assertBrowserStableRoutePath,\n  assertTerminalCatchAll,\n  assertUniqueRouteParameters,\n} from \"./routing/specificity\";\nimport { searchParamsToObject } from \"./search-params\";\nimport { decodeRouteSegment } from \"./utils/decode\";\n\nexport function parseRoutePath(filePath: string): ParsedRoute {\n  const segments: RouteSegment[] = [];\n  const normalizedPath = filePath.replace(/\\\\/g, \"/\");\n  const pathParts = normalizedPath.split(\"/\").filter(Boolean);\n\n  const fileName = pathParts.pop() || \"\";\n  const fileType = getRouteType(fileName);\n  const routePath = `/${pathParts.join(\"/\")}`;\n  assertBrowserStableRoutePath(routePath);\n  assertTerminalCatchAll(routePath);\n  assertUniqueRouteParameters(routePath);\n\n  for (const part of pathParts) {\n    // Route groups like `(marketing)` organize files without adding URL\n    // segments. Mirrors isRouteGroup in router.ts for programmatic routes.\n    if (part.startsWith(\"(\") && part.endsWith(\")\")) continue;\n    if (part.startsWith(\"[\") && part.endsWith(\"]\")) {\n      let segment = part.slice(1, -1);\n      const isDynamic = true;\n      let isOptional = false;\n      let isCatchAll = false;\n\n      if (segment.startsWith(\"[\") && segment.endsWith(\"]\")) {\n        isOptional = true;\n        segment = segment.slice(1, -1);\n        if (segment.startsWith(\"...\")) {\n          segment = segment.slice(3);\n          isCatchAll = true;\n        }\n      } else if (segment.startsWith(\"...\")) {\n        segment = segment.slice(3);\n        isCatchAll = true;\n      }\n\n      segments.push({ segment, isDynamic, isOptional, isCatchAll });\n    } else {\n      segments.push({\n        segment: part,\n        isDynamic: false,\n        isOptional: false,\n        isCatchAll: false,\n      });\n    }\n  }\n\n  return {\n    segments,\n    filePath: normalizedPath,\n    type: fileType,\n  };\n}\n\nfunction getRouteType(fileName: string): ParsedRoute[\"type\"] {\n  const baseName = fileName.replace(/\\.(tsx?|jsx?|vue|svelte|mdx?|markdown)$/, \"\");\n\n  switch (baseName) {\n    case \"page\":\n      return \"page\";\n    case \"layout\":\n      return \"layout\";\n    case \"loading\":\n      return \"loading\";\n    case \"error\":\n      return \"error\";\n    case \"not-found\":\n      return \"not-found\";\n    default:\n      return \"page\";\n  }\n}\n\nexport function segmentsToPattern(segments: RouteSegment[]): string {\n  if (segments.length === 0) return \"/\";\n\n  return (\n    \"/\" +\n    segments\n      .map((segment) => {\n        if (!segment.isDynamic) return segment.segment;\n\n        if (segment.isCatchAll) {\n          return segment.isOptional ? `*${segment.segment}?` : `*${segment.segment}`;\n        }\n\n        return `:${segment.segment}`;\n      })\n      .join(\"/\")\n  );\n}\n\nexport function matchRoute(\n  url: string,\n  segments: RouteSegment[],\n): { params: Record<string, string>; matches: boolean } {\n  const urlParts = url.split(\"/\").filter(Boolean).map(decodeRouteSegment);\n  const params: Record<string, string> = {};\n  if (segments.length === 0) {\n    return { params, matches: urlParts.length === 0 };\n  }\n\n  let urlIndex = 0;\n  let segmentIndex = 0;\n\n  while (segmentIndex < segments.length && urlIndex <= urlParts.length) {\n    const segment = segments[segmentIndex];\n\n    if (!segment.isDynamic) {\n      if (urlParts[urlIndex] !== segment.segment) {\n        return { params: {}, matches: false };\n      }\n      urlIndex++;\n      segmentIndex++;\n    } else if (segment.isCatchAll) {\n      const remainingParts = urlParts.slice(urlIndex);\n\n      if (remainingParts.length === 0 && !segment.isOptional) {\n        return { params: {}, matches: false };\n      }\n\n      params[segment.segment] = remainingParts.join(\"/\");\n      urlIndex = urlParts.length;\n      segmentIndex++;\n    } else {\n      if (urlIndex >= urlParts.length) {\n        return { params: {}, matches: false };\n      }\n\n      params[segment.segment] = urlParts[urlIndex];\n      urlIndex++;\n      segmentIndex++;\n    }\n  }\n\n  const matches = segmentIndex === segments.length && urlIndex === urlParts.length;\n\n  return { params, matches };\n}\n\n/** Match a route segment chain as an owner of the pathname or one of its descendants. */\nexport function matchRoutePrefix(url: string, segments: RouteSegment[]): boolean {\n  const urlParts = url.split(\"/\").filter(Boolean).map(decodeRouteSegment);\n  let urlIndex = 0;\n\n  for (const segment of segments) {\n    if (segment.isCatchAll) {\n      return segment.isOptional || urlIndex < urlParts.length;\n    }\n\n    const urlPart = urlParts[urlIndex];\n    if (urlPart === undefined) return false;\n    if (!segment.isDynamic && segment.segment !== urlPart) return false;\n    urlIndex++;\n  }\n\n  return true;\n}\n\nexport function resolveAppPath(root: string, ...paths: string[]): string {\n  return path.resolve(root, ...paths);\n}\n\n/**\n * Convert an absolute module path inside the project root to a root-relative\n * URL path with forward slashes (e.g. `/src/app/page.tsx`), for values the\n * client passes to dynamic `import()`. On Windows the naive root-prefix slice\n * yields `\\src\\app\\page.tsx`, which is not a valid module specifier. Returns\n * undefined for paths outside the root so callers keep their own fallbacks.\n */\nexport function toRootRelativeUrlPath(\n  absolutePath: string,\n  projectRoot: string,\n): string | undefined {\n  if (absolutePath === projectRoot) return \"\";\n  if (absolutePath.startsWith(`${projectRoot}/`) || absolutePath.startsWith(`${projectRoot}\\\\`)) {\n    return absolutePath.slice(projectRoot.length).replace(/\\\\/g, \"/\");\n  }\n  return undefined;\n}\n\n/**\n * Normalize a filesystem path to forward slashes. Node's fs accepts these on\n * every platform, and module ids handed to bundlers (e.g. Nitro handler and\n * task entries) must not contain backslashes.\n */\nexport function toPosixPath(filePath: string): string {\n  return filePath.replace(/\\\\/g, \"/\");\n}\n\nexport function toViteModuleId(filePath: string, root: string): string {\n  if (!path.isAbsolute(filePath)) return filePath;\n\n  const relativePath = path.relative(root, filePath);\n  if (relativePath && !relativePath.startsWith(\"..\") && !path.isAbsolute(relativePath)) {\n    return `/${relativePath.split(path.sep).join(\"/\")}`;\n  }\n\n  const normalizedPath = filePath.replace(/\\\\/g, \"/\");\n  return normalizedPath.startsWith(\"/\") ? `/@fs${normalizedPath}` : `/@fs/${normalizedPath}`;\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n  try {\n    const fs = await import(\"fs/promises\");\n    await fs.access(filePath);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nexport async function globFiles(pattern: string, cwd: string): Promise<string[]> {\n  const glob = await import(\"fast-glob\");\n  return glob.default(pattern, { cwd, absolute: false });\n}\n\nexport function parseSearchParams(\n  searchParams: URLSearchParams,\n): Record<string, string | string[]> {\n  return searchParamsToObject(searchParams) as Record<string, string | string[]>;\n}\n\nexport const logger = {\n  info: (message: string) => console.log(`[info] ${message}`),\n  success: (message: string) => console.log(`[success] ${message}`),\n  warn: (message: string) => console.warn(`⚠️  ${message}`),\n  error: (message: string) => console.error(`❌ ${message}`),\n  ready: (message: string) => console.log(`${message}`),\n  event: (message: string) => console.log(`  ${message}`),\n};\n","/**\n * Environment access that works across the runtimes Farm targets.\n *\n * Serverless and edge runtimes (Cloudflare Workers in particular) expose\n * bindings on `globalThis.__env__` rather than `process.env`, so security\n * checks that read `process.env` directly see an empty value there and can\n * silently take an \"unconfigured\" code path in a deployed environment.\n */\nexport function getFarmRuntimeBindings(): Record<string, unknown> | undefined {\n  const runtimeBindings = (\n    globalThis as typeof globalThis & {\n      __env__?: Record<string, unknown>;\n    }\n  ).__env__;\n  return runtimeBindings && typeof runtimeBindings === \"object\" ? runtimeBindings : undefined;\n}\n\nexport function readFarmEnvironmentValue(name: string): string | undefined {\n  const runtimeValue = getFarmRuntimeBindings()?.[name];\n  if (typeof runtimeValue === \"string\") return runtimeValue;\n  return typeof process !== \"undefined\" ? process.env?.[name] : undefined;\n}\n\n/**\n * True when the process looks like a deployed runtime rather than local\n * development: either NODE_ENV is production, or runtime bindings are present\n * (a deployed worker where NODE_ENV is frequently unset).\n */\nexport function isFarmDeployedRuntime(): boolean {\n  if (getFarmRuntimeBindings()) return true;\n  return readFarmEnvironmentValue(\"NODE_ENV\") === \"production\";\n}\n"],"mappings":"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","names":[]}