{"version":3,"file":"index.cjs","names":[],"sources":["../../src/utils/url.ts","../../src/utils/getBeApiUrl.ts","../../src/utils/createBeApiUrl.ts","../../src/utils/generateRoute.ts","../../src/utils/getBaseUrl.ts"],"sourcesContent":["import {\n  getLocationOrigin,\n  isAbsoluteUrl,\n  pathHasPrefix\n} from \"@rzl-zone/core/url\";\n\nconst basePath = (process.env.__NEXT_ROUTER_BASEPATH as string) || \"\";\n\n/** -------------------------------------------------------------------\n * * ***Checks whether a given path is within the configured Next.js\n * router base path.***\n * --------------------------------------------------------------------\n *\n * This utility is typically used internally by the router to ensure\n * that navigation targets respect the configured base path.\n *\n * - **Behavior:**\n *      - Delegates prefix matching to `pathHasPrefix`\n *      - Uses the runtime router base path\n *\n * @param path - The path to check.\n *\n * @returns `true` if the path includes the base path, otherwise `false`.\n */\nexport function hasBasePathNextJs(path: string): boolean {\n  return pathHasPrefix(path, basePath);\n}\n\n/** -------------------------------------------------------------------\n * * ***Determines whether a given URL is routable by the Next.js router\n * in the browser.***\n * --------------------------------------------------------------------\n *\n * This function distinguishes between local (same-origin) URLs and\n * external URLs, ensuring compatibility with Next.js client-side routing.\n *\n * - **Behavior:**\n *      - Treats relative URLs as local\n *      - Resolves absolute URLs against the current origin\n *      - Ensures the resolved URL matches the current origin\n *      - Ensures the pathname respects the configured base path\n *      - Returns `false` for invalid URLs\n *\n * @param url - The URL string to evaluate.\n *\n * @returns `true` if the URL is local and routable, otherwise `false`.\n *\n * @example\n * ```ts\n * isLocalURLNextJs(\"/about\"); // true\n * isLocalURLNextJs(\"https://external.com\"); // false\n * ```\n */\nexport function isLocalURLNextJs(url: string): boolean {\n  if (!isAbsoluteUrl(url)) return true;\n\n  try {\n    const locationOrigin = getLocationOrigin();\n    const resolved = new URL(url, locationOrigin);\n\n    return (\n      resolved.origin === locationOrigin && hasBasePathNextJs(resolved.pathname)\n    );\n  } catch {\n    return false;\n  }\n}\n","import { assertIsString } from \"@rzl-zone/utils-js/assertions\";\nimport { hasOwnProp, isPlainObject } from \"@rzl-zone/utils-js/predicates\";\nimport { removeSpaces } from \"@rzl-zone/utils-js/strings\";\nimport { formatEnvPort } from \"@rzl-zone/utils-js/urls\";\n\ntype OptionsGetBeApiUrl = {\n  /** * ***The Suffix origin base api url, e.g:`http://localhost.com/api`, default: `\"/\"`.***\n   *\n   * @default \"/\"\n   */\n  suffix?: string;\n};\n\n/** ---------------------------------------------------\n * * ***Utility for NextJS: `getBeApiUrl`.***\n * ---------------------------------------------------\n *\n * **This function determines the backend API base URL from the `NEXT_PUBLIC_BACKEND_API_URL` environment variable (retrieves the base API URL of the backend).**\n * - **Behavior:**\n *    - If the variable is not set, it defaults to `\"http://localhost:8000\"`.\n *    - It also allows adding an optional suffix to the returned URL.\n * - ***⚠️ Warning:***\n *    - ***This function only support when using ***[`NextJS`](https://nextjs.org/)***.***\n *\n * @description\n * This function determines the backend API base URL from the `NEXT_PUBLIC_BACKEND_API_URL` environment variable.\n * - If `NEXT_PUBLIC_BACKEND_API_URL` is not set, it defaults to `\"http://localhost:8000\"`.\n * - If `NEXT_PUBLIC_BACKEND_API_URL` does **not** contain a port, it appends one from `NEXT_PUBLIC_PORT_BE` if available.\n * - Supports appending optional suffix (like `\"/api\"`).\n *\n * @param {OptionsGetBeApiUrl|undefined} options - Configuration options.\n * @param {OptionsGetBeApiUrl[\"suffix\"]} [options.suffix=\"/\"] - The suffix to append to the base API URL.\n *\n * @returns {string} The formatted backend API base URL.\n *\n * @throws **{@link TypeError | `TypeError`}** if `suffix` is not a `string`.\n * @throws **{@link Error | `Error`}** if `NEXT_PUBLIC_BACKEND_API_URL` is invalid.\n *\n * @example\n * // With NEXT_PUBLIC_BACKEND_API_URL set at `*.env` file\n * NEXT_PUBLIC_BACKEND_API_URL = \"https://api.example.com\";\n * getBeApiUrl();\n * // ➔ \"https://api.example.com/\"\n *\n * // With NEXT_PUBLIC_BACKEND_API_URL but no port, using NEXT_PUBLIC_PORT_BE at `*.env` file\n * NEXT_PUBLIC_BACKEND_API_URL = \"http://localhost\";\n * NEXT_PUBLIC_PORT_BE = \"5000\";\n * getBeApiUrl({ suffix: \"/api\" });\n * // ➔ \"http://localhost:5000/api\"\n *\n * // Without NEXT_PUBLIC_BACKEND_API_URL at `*.env` file (defaults to localhost:8000)\n * delete NEXT_PUBLIC_BACKEND_API_URL;\n * getBeApiUrl({ suffix: \"/v1\" });\n * // ➔ \"http://localhost:8000/v1\"\n */\nexport const getBeApiUrl = (options: OptionsGetBeApiUrl = {}): string => {\n  if (!isPlainObject(options)) options = {};\n\n  let suffix = hasOwnProp(options, \"suffix\") ? options.suffix : \"/\";\n\n  // Ensure suffix is a string\n  assertIsString(suffix, {\n    message({ currentType, validType }) {\n      return `Parameter \\`suffix\\` property of the first parameter must be of type \\`${validType}\\`, but received: \\`${currentType}\\`.`;\n    }\n  });\n\n  try {\n    let rawBaseUrl = process.env.NEXT_PUBLIC_BACKEND_API_URL?.trim();\n\n    if (rawBaseUrl) {\n      rawBaseUrl = removeSpaces(rawBaseUrl);\n\n      const urlObj = new URL(rawBaseUrl);\n      const hasPort = !!urlObj.port;\n\n      if (!hasPort && process.env.NEXT_PUBLIC_PORT_BE) {\n        rawBaseUrl =\n          urlObj.origin +\n          formatEnvPort(process.env.NEXT_PUBLIC_PORT_BE, {\n            prefixColon: true\n          });\n      }\n    } else {\n      // fallback\n      rawBaseUrl =\n        \"http://localhost\" +\n        formatEnvPort(process.env.NEXT_PUBLIC_PORT_BE || \"8000\", {\n          prefixColon: true\n        });\n    }\n\n    suffix = removeSpaces(suffix).length ? removeSpaces(suffix) : \"/\";\n    const baseApiUrl = new URL(rawBaseUrl.replace(/\\/+$/, \"\")).origin;\n\n    const finalSuffix =\n      suffix === \"/\"\n        ? \"/\"\n        : `${suffix.startsWith(\"/\") ? \"\" : \"/\"}${suffix.replace(/\\/+$/, \"\")}`;\n\n    return `${baseApiUrl}${finalSuffix}`;\n  } catch (error) {\n    throw new Error(\n      \"Invalid `NEXT_PUBLIC_BACKEND_API_URL`, failed to generate from `getBeApiUrl()`, Error:\" +\n        error,\n      { cause: error }\n    );\n  }\n};\n","import { assertIsBoolean, assertIsString } from \"@rzl-zone/utils-js/assertions\";\nimport {\n  getPreciseType,\n  isError,\n  isNil,\n  isPlainObject,\n  isString,\n  isUndefined\n} from \"@rzl-zone/utils-js/predicates\";\nimport { normalizePathname } from \"@rzl-zone/utils-js/urls\";\nimport { getBeApiUrl } from \"./getBeApiUrl\";\n\ntype OptionsCreateBeApiUrl = {\n  /** * The prefix pathname api url, e.g:`\"http://localhost.com/your-target-prefix-entri-point-api-is-here\"`, default: `\"/api\"`.\n   *\n   * @default \"/api\"\n   */\n  prefix?: string;\n  /** * Option to getting `prefix` and `pathname` of api url only `(removing origin base api url)`, default: `true`.\n   *\n   * @default true\n   */\n  withOrigin?: boolean;\n};\n\n/** ---------------------------------------------------\n * * ***Utility for NextJS: `createBeApiUrl`.***\n * ---------------------------------------------------\n *\n * **Constructs a backend API URL by appending a given pathname to the base API URL.**\n * - **ℹ️ Note:**\n *    - This function builds on top of `getBeApiUrl()`.\n * - **Determines the base API URL from:**\n *    - `NEXT_PUBLIC_BACKEND_API_URL` environment variable (or defaults to `\"http://localhost:8000\"`).\n *    - Automatically appends `NEXT_PUBLIC_PORT_BE` if the base URL does not already include a port.\n * - **Features of this function:**\n *    - Allows customizing the API path with an optional `prefix` (defaults to `\"/api\"`).\n *    - Can include or exclude the origin (protocol + host) via `withOrigin`.\n *    - Normalizes paths to avoid duplicate slashes.\n * - ***⚠️ Warning:***\n *    - ***This function only support when using ***[`NextJS`](https://nextjs.org/)***.***\n *\n * @param {string|null|undefined} pathname - The API endpoint path (e.g., `/users` or `/v1/posts`), defaultValue: `\"\"`.\n * @param {OptionsCreateBeApiUrl} [options] - Configuration options.\n * @param {OptionsCreateBeApiUrl[\"prefix\"]} [options.prefix=\"/api\"] - The prefix for the API path (default is `\"/api\"`).\n * @param {OptionsCreateBeApiUrl[\"withOrigin\"]} [options.withOrigin=true] - Whether to include the full base URL or return only the API path.\n *\n * @returns {string} The formatted API URL.\n *\n * @throws **{@link TypeError | `TypeError`}** if `withOrigin` is not a boolean.\n * @throws **{@link TypeError | `TypeError`}** if `prefix` and `pathname` is not a string.\n * @throws **{@link Error | `Error`}** if constructing the API URL fails due to an invalid base URL.\n *\n * @example\n * createBeApiUrl(\"/users\");\n * // ➔ \"http://localhost:8000/api/users\"\n *\n * createBeApiUrl(\"/api/users\");\n * // ➔ \"http://localhost:8000/api/users\"\n *\n * createBeApiUrl(\"/v1\", { prefix: \"/v1\" });\n * // ➔ \"http://localhost:8000/v1\"\n *\n * createBeApiUrl(\"/v1/users\");\n * // ➔ \"http://localhost:8000/api/v1/users\"\n *\n * createBeApiUrl(\"/v1/users\", { prefix: \"/v1\" });\n * // ➔ \"http://localhost:8000/v1/users\"\n *\n * createBeApiUrl(\"/users\", { withOrigin: false });\n * // ➔ \"/api/users\"\n *\n * createBeApiUrl(null, { withOrigin: false });\n * // ➔ \"/api\"\n *\n * createBeApiUrl(undefined, { withOrigin: false });\n * // ➔ \"/api\"\n */\nexport const createBeApiUrl = (\n  /** * The pathname api url, e.g:`\"http://localhost.com/your-target-prefix-entri-point-api-is-here/your-target-pathname-is-here\"`.\n   *\n   * @default \"\"\n   */\n  pathname: string | null | undefined,\n  options: OptionsCreateBeApiUrl = {}\n): string => {\n  try {\n    // ✅ Type checks\n    assertIsString(isNil(pathname) ? \"\" : pathname, {\n      message({ currentType, validType }) {\n        return `First parameter (\\`pathname\\`) must be of type \\`${validType}\\`, but received: \\`${currentType}\\`.`;\n      }\n    });\n\n    if (!isPlainObject(options)) {\n      options = {};\n    }\n\n    let { prefix = \"/api\", withOrigin = true } = options;\n\n    if (!isUndefined(prefix) && !isString(prefix)) {\n      throw new TypeError(\n        `Parameter \\`prefix\\` property of the \\`options\\` (second parameter) must be of type \\`string\\`, but received: \\`${getPreciseType(\n          prefix\n        )}\\`.`\n      );\n    }\n\n    assertIsBoolean(withOrigin, {\n      message: ({ currentType, validType }) =>\n        `Parameter \\`withOrigin\\` property of the \\`options\\` (second parameter) must be of type \\`${validType}\\`, but received: \\`${currentType}\\`.`\n    });\n\n    // Normalize pathname\n    pathname = normalizePathname(pathname);\n    // Normalize prefix\n    prefix = normalizePathname(prefix);\n\n    const normalizedPrefix = prefix.endsWith(\"/\") ? prefix : prefix + \"/\";\n\n    // Remove duplicate prefix in pathname\n    if (\n      pathname === prefix ||\n      pathname === prefix + \"/\" ||\n      pathname.startsWith(normalizedPrefix)\n    ) {\n      pathname = pathname.slice(prefix.length);\n      pathname = normalizePathname(pathname);\n    }\n\n    // Get the base API URL\n    const baseApiUrl = getBeApiUrl({ suffix: prefix });\n\n    function joinPath(a: string, b: string) {\n      return `${a.replace(/\\/+$/, \"\")}/${b.replace(/^\\/+/, \"\")}`;\n    }\n\n    const fullPath = withOrigin\n      ? joinPath(baseApiUrl, pathname)\n      : joinPath(new URL(baseApiUrl).pathname, pathname);\n\n    return fullPath.replace(/\\/+$/, \"\");\n  } catch (err) {\n    if (isError(err)) {\n      throw err;\n    } else {\n      throw new Error(\n        \"Failed to generate backend API URL in `createBeApiUrl()`, Error: \" +\n          String(err).trim(),\n        { cause: err }\n      );\n    }\n  }\n};\n","import type { IsAny } from \"@rzl-zone/ts-types-plus\";\n\nimport { assertIsPlainObject } from \"@rzl-zone/utils-js/assertions\";\nimport { safeStableStringify } from \"@rzl-zone/utils-js/conversions\";\nimport {\n  getPreciseType,\n  isEmptyString,\n  isNil,\n  isNonEmptyArray,\n  isNonEmptyString,\n  isString\n} from \"@rzl-zone/utils-js/predicates\";\n\n/** ---------------------------------------------------------------------\n * * ***Extracts dynamic route parameters from a given route string.***\n * ----------------------------------------------------------------------\n *\n * **This utility type recursively searches for dynamic segments within a route,\n * extracting each parameter and constructing an object where each key represents\n * a dynamic segment and its value is of type `string`.**\n * - ***⚠️ Warning:***\n *    - ***This types only support when using ***[`NextJS`](https://nextjs.org/)***.***\n *\n * @template T - The route string containing potential dynamic segments.\n *\n * @example\n * ```ts\n * type Params1 = ExtractRouteParams<\"/user/[id]\">;\n * // ➔ { id: string }\n *\n * type Params2 = ExtractRouteParams<\"/post/[slug]/comment/[commentId]\">;\n * // ➔ { slug: string; commentId: string }\n *\n * type Params3 = ExtractRouteParams<\"/dashboard\">;\n * // ➔ {} (no dynamic parameters)\n * ```\n */\nexport type ExtractRouteParams<T> = T extends string\n  ? HasDynamicSegments<T> extends true\n    ? T extends `${infer _Start}[${infer Param}]${infer Rest}`\n      ? { [K in Param | keyof ExtractRouteParams<Rest>]: string }\n      : unknown\n    : unknown\n  : unknown; // Ensures an empty object if no dynamic segments are found.\n\n/** ---------------------------------------------------------\n * * ***Determines whether a given route contains dynamic segments.***\n * ---------------------------------------------------------\n * **This type checks if the route includes at least one `[param]` pattern.\n * If it does, the result is `true`, otherwise `false`.**\n * - ***⚠️ Warning:***\n *    - ***This types only support when using ***[`NextJS`](https://nextjs.org/)***.***\n * @template T - The route string to be evaluated.\n * @example\n * ```ts\n * type HasParams1 = HasDynamicSegments<\"/user/[id]\">;\n * // ➔ true\n * type HasParams2 = HasDynamicSegments<\"/settings/profile\">;\n * // ➔ false\n * type HasParams3 = HasDynamicSegments<\"/blog/[category]/[slug]\">;\n * // ➔ true\n * ```\n */\nexport type HasDynamicSegments<T> = T extends `${string}[${string}]${string}`\n  ? true\n  : false;\n\ntype GenerateRouteResult<T> =\n  true extends IsAny<T> ? unknown : T extends string ? string : unknown;\n\n/** ---------------------------------\n * * ***Utility for NextJS: `generateRoute`.***\n * ---------------------------------\n * **Generates a URL by replacing dynamic route parameters with provided values.**\n * - ***⚠️ Warning:***\n *    - ***This function only support when using ***[`NextJS`](https://nextjs.org/)***.***\n * @template T - The route string containing dynamic segments in the format `[param]`.\n * @param {T} route - The route string containing dynamic segments.\n * @param {ExtractRouteParams<T>} [params] - An object containing key-value pairs that match the dynamic segments in the route.\n * @returns {string} The formatted URL with all dynamic segments replaced.\n * @throws **{@link Error | `Error`}** if the route contains dynamic segments but no parameters object is provided.\n * @throws **{@link Error | `Error`}** if a required parameter is missing from the `params` object.\n * @throws **{@link Error | `Error`}** if a parameter value is an empty string.\n * @throws **{@link Error | `Error`}** if any parameter contains invalid characters like `?`, `&`, `=`, `#`, `/`, spaces, `'`, `\"`, `(`, `)`, `+`, `;`, `%`, `@`, or `:`, which can cause URL issues.\n * @example\n * // Basic usage\n * generateRoute(\"/user/[id]\", { id: \"123\" });\n * // ➔ \"/user/123\"\n *\n * // No dynamic segments, returns as-is\n * generateRoute(\"/dashboard\");\n * // ➔ \"/dashboard\"\n *\n * // Throws an error due to missing parameters object\n * generateRoute(\"/profile/[username]\");\n * // ➔ ❌ Error: ❌ Missing parameters object for route: \"/profile/[username]\"\n *\n * // Throws an error due to an empty parameter value\n * generateRoute(\"/post/[category]/[slug]\", { category: \"tech\", slug: \"\" });\n * // ➔ ❌ Error: ❌ Parameter \"slug\" cannot be empty in route: \"/post/[category]/[slug]\"\n *\n * // Throws an error due to parameter containing invalid characters\n * generateRoute(\"/search/[query]\", { query: \"how to?learn\" });\n * // ➔ ❌ Error: ❌ Parameter \"query\" contains invalid character \"?\" in route: \"/search/[query]\"\n *\n * // Handles leading/trailing slashes correctly\n * generateRoute(\"/blog/[category]/[slug]\", { category: \"/news/\", slug: \"/latest-update/\" });\n * // ➔ ❌ Error: ❌ Parameter \"category\" and \"slug\" contains slashes \"/\" which is not allowed.\n */\nexport function generateRoute<T extends string>(\n  route: T extends string\n    ? HasDynamicSegments<T> extends true\n      ? T\n      : never\n    : never,\n  params: T extends string ? ExtractRouteParams<T> : undefined\n): GenerateRouteResult<T>;\nexport function generateRoute<T extends string>(\n  route: T extends string ? T : never,\n  params?: Extract<ExtractRouteParams<T>, Record<string, unknown>>\n): GenerateRouteResult<T>;\nexport function generateRoute<T = unknown>(\n  route: T extends string\n    ? HasDynamicSegments<T> extends true\n      ? T\n      : unknown\n    : unknown,\n  params?: T extends string ? ExtractRouteParams<T> : undefined\n): unknown;\nexport function generateRoute<T>(\n  route: T,\n  params?: ExtractRouteParams<T>\n): string | unknown {\n  //todo: Validate the route string\n  if (!isString(route) || isEmptyString(route)) {\n    throw new TypeError(\n      `❌ 'generateRoute' Failed:\\n- Invalid 'route' value.\\n- Must be of type \\`string\\` and non-empty string, but received: \"${getPreciseType(\n        route\n      )}\": \\`${safeStableStringify(route, {\n        keepUndefined: true\n      })}\\`.`\n    );\n  }\n\n  //todo: If no dynamic segments exist, return the route as-is immediately\n  if (!/[\\\\[\\]]/.test(route)) {\n    return route;\n  }\n\n  //todo: Validate that params is a plain object\n  assertIsPlainObject(params, {\n    message: ({ validType }) =>\n      `❌ 'generateRoute' Failed cause in route \"${route}\":\\n- Missing or invalid parameters \\`${validType}\\` for route: \"${route}\", must be of type \\`${validType}\\` mapping parameters.`\n  });\n\n  //todo: Ensure parameters are provided for dynamic routes.\n  if (isNil(params)) {\n    throw new TypeError(\n      `❌ 'generateRoute' Failed cause in route \"${route}\":\\n- Missing parameters \\`plain-object\\` for route: \"${route}\".`\n    );\n  }\n\n  //todo: Check for invalid characters that can break the URL format\n  const invalidChars = [\n    \"?\",\n    \"&\",\n    \"#\",\n    \"=\",\n    \"/\",\n    \"'\",\n    // eslint-disable-next-line quotes\n    '\"',\n    \"(\",\n    \")\",\n    \"+\",\n    \";\",\n    \"%\",\n    \"@\",\n    \":\"\n  ];\n\n  const errors: string[] = [];\n\n  const requiredKeys = Array.from(route.matchAll(/\\[(\\w+)\\]/g)).map(\n    (m) => m[1] || \"\"\n  );\n\n  for (const key of requiredKeys) {\n    const value = params[key];\n\n    if (!isString(value)) {\n      errors.push(\n        `- Invalid parameter: \"${key}\" must be of type \\`string\\`, but received: \\`${getPreciseType(\n          value\n        )}\\`.`\n      );\n      continue;\n    }\n\n    if (isEmptyString(value)) {\n      errors.push(`- Parameter \"${key}\" cannot be empty string.`);\n      continue;\n    }\n\n    const foundInvalidChars = invalidChars.filter((char) =>\n      value.includes(char)\n    );\n\n    if (/\\s/.test(value)) {\n      foundInvalidChars.push(\"white-space(s)\");\n    }\n\n    if (foundInvalidChars.length > 0) {\n      const formattedChars = foundInvalidChars.map((c) =>\n        c === \"`\" ? \"backtick - (`)\" : `\\`${c}\\``\n      );\n\n      if (!invalidChars.includes(\"white-space(s)\"))\n        invalidChars.push(\"white-space(s)\");\n\n      const formattedInvalidChars = invalidChars.map((c) =>\n        c === \"`\" ? \"backtick - (`)\" : `\\`${c}\\``\n      );\n\n      errors.push(\n        `- Parameter \"${key}\" contains invalid characters (${formattedChars.join(\n          \", \"\n        )}). These characters are not allowed because they could cause issues in URL structure. The following characters are forbidden in route parameters: (${formattedInvalidChars.join(\n          \", \"\n        )}).`\n      );\n    }\n  }\n\n  if (isNonEmptyArray(errors)) {\n    throw new Error(\n      `❌ 'generateRoute' Failed cause in route \"${route}\":\\n${errors.join(\"\\n\")}.`\n    );\n  }\n\n  return route\n    .replace(/\\[(\\w+)\\]/g, (_, key) => {\n      const paramKey = isNonEmptyString(params[key]) ? params[key] : \"\";\n\n      return paramKey.trim().replace(/^\\/+|\\/+$/g, \"\");\n    })\n    .replace(/\\/+/g, \"/\");\n}\n","import { removeSpaces } from \"@rzl-zone/utils-js/strings\";\nimport { formatEnvPort } from \"@rzl-zone/utils-js/urls\";\n\n/** ---------------------------------------------------\n * * ***Utility for NextJS: `getBaseUrl`.***\n * ---------------------------------------------------\n * **Retrieves the base URL of the application.**\n * - **Behavior:**\n *    - It determines the base URL from the `NEXT_PUBLIC_BASE_URL` environment variable.\n *    - If `NEXT_PUBLIC_BASE_URL` is not set, it defaults to `\"http://localhost:3000\"`.\n *    - If `NEXT_PUBLIC_BASE_URL` does **not** contain a port, it appends one from `NEXT_PUBLIC_PORT_FE` if available.\n *    - Ensures the final URL is valid and normalized (no trailing slashes).\n *\n * - ***⚠️ Warning:***\n *    - ***This function only support when using ***[`NextJS`](https://nextjs.org/)***.***\n *\n * @returns {string} The resolved base URL of the application.\n *\n * @throws **{@link Error | `Error`}** if the constructed URL is invalid or malformed.\n *\n * @example\n * // With environment variable set at `*.env` file\n * NEXT_PUBLIC_BASE_URL = \"https://example.com\";\n * getBaseUrl();\n * // ➔ \"https://example.com\"\n *\n * // With custom port via NEXT_PUBLIC_PORT_FE at `*.env` file\n * NEXT_PUBLIC_BASE_URL = \"http://localhost\";\n * NEXT_PUBLIC_PORT_FE = \"4000\";\n * getBaseUrl();\n * // ➔ \"http://localhost:4000\"\n *\n * // Without environment variable at `*.env` file\n * delete NEXT_PUBLIC_BASE_URL;\n * getBaseUrl();\n * // ➔ \"http://localhost:3000\"\n */\nexport const getBaseUrl = (): string => {\n  try {\n    const baseEnv = process.env.NEXT_PUBLIC_BASE_URL?.trim();\n    const portEnv = process.env.NEXT_PUBLIC_PORT_FE?.trim();\n\n    let baseUrl = baseEnv || \"http://localhost\";\n\n    // Always clean trailing slashes first\n    baseUrl = removeSpaces(baseUrl).replace(/\\/+$/, \"\");\n\n    // Check if already contains port\n    const hasPort = /:\\/\\/[^/]+:\\d+/.test(baseUrl);\n\n    if (!hasPort && portEnv) {\n      baseUrl += formatEnvPort(portEnv, { prefixColon: true });\n    } else if (!hasPort && !baseEnv) {\n      baseUrl += \":3000\";\n    }\n\n    const url = new URL(baseUrl);\n    return `${url.protocol}//${url.hostname}${url.port ? `:${url.port}` : \"\"}`;\n  } catch (error) {\n    throw new Error(\n      \"Invalid `NEXT_PUBLIC_BASE_URL`, failed to generate from `getBaseUrl()`, Error:\" +\n        error,\n      { cause: error }\n    );\n  }\n};\n"],"mappings":"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"}
