mazey
    Preparing search index...

    mazey

    English | 简体中文

    npm version l

    Mazey is a functional library for daily frontend work. There are already many excellent libraries for frontend development, but creating a file named utils.js or common.js is generally used to supply common functions in projects. It's boring to copy similar functions across multiple projects. That's why I've created this library and will keep updating it to serve as a reliable resource for frontend needs.

    Use Mazey via npm.

    npm install mazey
    

    Use Mazey from CDN.

    <script src="https://cdn.jsdelivr.net/npm/mazey@latest/lib/mazey.min.js"></script>
    

    You can also download and serve the latest browser bundle yourself.

    Example: Use a function to verify if a value is a number suitable for standard calculations and comparisons.

    Import from npm.

    import { isNumber } from "mazey";

    const x = 123;
    const y = "abc";
    const z = Infinity;
    isNumber(x); // Output: true
    isNumber(y); // Output: false
    isNumber(z, { isInfinityAsNumber: true }); // Output: true

    Import from CDN.

    <script src="https://cdn.jsdelivr.net/npm/mazey@latest/lib/mazey.min.js"></script>
    <script>
    const x = 123;
    mazey.isNumber(x); // Output: true
    </script>

    There are some examples maintained by hand below. For more information, please check the full API documentation.

    Load a JavaScript file from the server and execute it.

    Usage:

    loadScript(
    "http://example.com/static/js/plugin-2.1.1.min.js",
    {
    id: "iamid", // (Optional) script ID, default none
    timeout: 5000, // (Optional) timeout, default `5000`
    }
    )
    .then(
    res => {
    console.log(`Load JavaScript script: ${res}`);
    }
    )
    .catch(
    err => {
    console.error(`Load JavaScript script: ${err.message}`);
    }
    );

    Output:

    Load JavaScript script: loaded
    

    Load a script from the given URL if it (window["attribute"]) has not already been loaded.

    Usage:

    loadScriptIfUndefined("xyz", "https://example.com/lib/xyz.min.js")
    .then(() => {
    console.log("xyz is loaded.");
    })
    .catch(err => {
    console.log("Failed to load xyz.", err);
    });

    Output:

    xyz is loaded.
    

    Load a CSS file from the server.

    Usage:

    loadCSS(
    "https://example.com/path/example.css",
    {
    id: "iamid", // Optional, link ID, default none
    }
    )
    .then(
    res => {
    console.log(`Load CSS Success: ${res}`);
    }
    )
    .catch(
    err => {
    console.error(`Load CSS Fail: ${err.message}`)
    }
    );

    Output:

    Load CSS Success: loaded
    

    Load an image from the given URL.

    The target image will be loaded in the background, and the Promise status will change after the image is loaded. If the image fails to load, the Promise status will change to reject with the error object. If the image is loaded successfully, the Promise status will change to resolve with the image object. This method can be used to preload images and cache them in the browser. It can also be used to implement lazy loading of images.

    Note that this method will not add the image to the DOM.

    Usage:

    loadImage("https://example.com/example.png")
    .then((img) => {
    console.log(img);
    })
    .catch((err) => {
    console.log(err);
    });

    Check whether the page is loaded successfully (Keep the compatibility if the browser's load event has been triggered).

    Usage:

    windowLoaded()
    .then(res => {
    console.log(`Load Success: ${res}`);
    })
    .catch(err => {
    console.log(`Load Timeout or Fail: ${err.message}`);
    });

    Output:

    Load Success: load
    

    Check whether it is a right number.

    Usage:

    const ret1 = isNumber(123);
    const ret2 = isNumber("123");
    // Default: NaN, Infinity is not Number
    const ret3 = isNumber(Infinity);
    const ret4 = isNumber(Infinity, { isInfinityAsNumber: true });
    const ret5 = isNumber(NaN);
    const ret6 = isNumber(NaN, { isNaNAsNumber: true, isInfinityAsNumber: true });
    console.log(ret1, ret2, ret3, ret4, ret5, ret6);

    Output:

    true false false true false true
    

    Check whether it is a valid JSON string.

    Usage:

    const ret1 = isJSONString(`['a', 'b', 'c']`);
    const ret2 = isJSONString(`["a", "b", "c"]`);
    console.log(ret1);
    console.log(ret2);

    Output:

    false
    true
    

    Parse JSON and return a caller-defined fallback instead of throwing when the input is malformed.

    const data = parseJsonSafe('{"enabled":true}');
    const fallback = parseJsonSafe("invalid", {});
    console.log(data, fallback);

    Generate a lowercase SHA-256 hexadecimal digest with the Web Crypto API. String input also requires TextEncoder.

    const digest = await sha256Hex("hello world");
    console.log(digest);

    Output:

    b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
    

    Determine the validity of the data.

    Usage:

    const validData = {
    a: {
    b: {
    c: 413
    }
    }
    };
    const isValidDataResA = isValidData(validData, ["a", "b", "c"], 2333);
    const isValidDataResB = isValidData(validData, ["a", "b", "c"], 413);
    const isValidDataResC = isValidData(validData, ["d", "d"], 413);
    console.log("isValidDataResA:", isValidDataResA);
    console.log("isValidDataResB:", isValidDataResB);
    console.log("isValidDataResC:", isValidDataResC);

    Output:

    isValidDataResA: false
    isValidDataResB: true
    isValidDataResC: false
    

    Produce a random string of number, genRndNumString(7) => "7658495".

    Usage:

    const ret1 = genRndNumString(4);
    const ret2 = genRndNumString(7);
    console.log(ret1);
    console.log(ret2);

    Output:

    9730
    2262490
    

    Strictly parse a normalized HTML datetime-local value as local wall-clock time. The function accepts a year with at least four digits, minute values with optional seconds and milliseconds, rejects timezone suffixes and impossible dates, and returns null for invalid input.

    Usage:

    const date = parseLocalDateTime("2026-07-21T14:30:45.123");
    console.log(date?.getFullYear());
    console.log(date?.getHours());
    console.log(date?.getMilliseconds());

    Output:

    2026
    14
    123
    

    Format a Date from its local calendar fields for an HTML datetime-local control. Precision defaults to minutes and can be set to second or millisecond. The year is padded to at least four digits, and the function does not convert the value to UTC.

    Usage:

    const date = new Date(2026, 6, 21, 14, 30, 45, 123);
    const minutes = formatLocalDateTime(date);
    const seconds = formatLocalDateTime(date, { precision: "second" });
    const milliseconds = formatLocalDateTime(date, {
    precision: "millisecond",
    });
    console.log(minutes);
    console.log(seconds);
    console.log(milliseconds);

    Output:

    2026-07-21T14:30
    2026-07-21T14:30:45
    2026-07-21T14:30:45.123
    

    Return the formatted date string in the given format.

    Usage:

    const ret1 = formatDate();
    const ret2 = formatDate("Tue Jan 11 2022 14:12:26 GMT+0800 (China Standard Time)", "yyyy-MM-dd hh:mm:ss");
    const ret3 = formatDate(1641881235000, "yyyy-MM-dd hh:mm:ss");
    const ret4 = formatDate(new Date(2014, 1, 11), "MM/dd/yyyy");
    console.log("Default formatDate value:", ret1);
    console.log("String formatDate value:", ret2);
    console.log("Number formatDate value:", ret3);
    console.log("Date formatDate value:", ret4);

    Output:

    Default formatDate value: 2023-01-11
    String formatDate value: 2022-01-11 14:12:26
    Number formatDate value: 2022-01-11 14:07:15
    Date formatDate value: 02/11/2014
    

    Check whether an unknown value represents a valid date. The function accepts Date instances, finite millisecond timestamps, supported local date strings, and ISO 8601 strings with Z or a numeric timezone offset.

    Supported string forms are YYYY-MM-DD, YYYY-MM-DD HH:mm[:ss], YYYY-MM-DDTHH:mm[:ss], and the same T-separated date-time with Z or a +HH:mm/-HH:mm offset. Zoned strings may include 1-3 millisecond digits.

    Structured strings are parsed into numeric components and validated strictly. Invalid calendar dates such as "2020-02-30" are rejected instead of being normalized into another date.

    Usage:

    const ret1 = isValidDate(1577877720000);
    const ret2 = isValidDate("2020-01-01 11:22");
    const ret3 = isValidDate("2020-02-30");
    const ret4 = isValidDate(new Date("invalid"));
    console.log(ret1, ret2, ret3, ret4);

    Output:

    true true false false
    

    Check whether a date has the current local year, month, and day.

    isToday(new Date());
    

    Output: true

    Check whether a date is in the current local calendar year.

    isThisYear(new Date());
    

    Output: true

    Check whether a date is in the current local calendar month and year.

    isThisMonth(new Date());
    

    Output: true

    Check whether a date is in the current local Monday-first week. The week ends before the following Monday.

    isThisWeek(new Date());
    

    Output: true

    Check whether a date has the current local year, month, day, and hour.

    isThisHour(new Date());
    

    Output: true

    Format the absolute distance from a date to now without adding ago or in. Past and future dates use the same approximate English wording.

    formatDistanceToNow(new Date(Date.now() - 60 * 60 * 1000));
    

    Output: about 1 hour

    Generate a local-time Calendar Versioning string using the conceptual format yyyy.MMdd.HHmmss. Leading zeroes are removed from each numeric segment for Semantic Versioning compatibility.

    Versions increase with the supplied local date and time under normal clock progression. Because the function intentionally follows local time, a manual clock rollback or daylight-saving fallback can produce a value lower than one generated earlier.

    Usage:

    const version = generateCalendarVersion(
    new Date(2026, 6, 11, 7, 40, 35)
    );
    console.log(version);

    Output:

    2026.711.74035
    

    Format a duration in milliseconds using the largest applicable unit: seconds, minutes, hours, or days. Values are rounded to at most one decimal place; negative and non-finite durations produce "0 seconds".

    Usage:

    const ret1 = formatDurationFromMs(500);
    const ret2 = formatDurationFromMs(90000);
    const ret3 = formatDurationFromMs(3600000);
    const ret4 = formatDurationFromMs(129600000);
    console.log(ret1);
    console.log(ret2);
    console.log(ret3);
    console.log(ret4);

    Output:

    0.5 seconds
    1.5 minutes
    1 hour
    1.5 days
    

    Format a non-negative byte count using 1024-based units and one fractional digit by default. Decimal scaling, precision, and the invalid-input fallback are configurable. The former getFileSize name is a deprecated alias.

    formatByteSize(0);
    formatByteSize(1536);
    formatByteSize(1500000, { base: 1000, fractionDigits: 2 });

    Output:

    0 B
    1.5 KB
    1.50 MB
    

    Copy/Clone Object deeply.

    Usage:

    const ret1 = deepCopy(["a", "b", "c"]);
    const ret2 = deepCopy("abc");
    console.log(ret1);
    console.log(ret2);

    Output:

    ["a", "b", "c"]
    abc
    

    Recursively freeze an object and its nested enumerable values. Primitive values and objects that are already frozen are returned unchanged.

    Usage:

    const config = deepFreeze({
    api: {
    timeout: 5000,
    },
    });

    console.log(Object.isFrozen(config));
    console.log(Object.isFrozen(config.api));

    Output:

    true
    true
    

    Shallowly mutate a target with defined properties from later sources. The helper skips only undefined, so null, empty strings, 0, and false remain valid overrides.

    const options = assignDefined(
    { retries: 3, verbose: true },
    { retries: undefined, verbose: false }
    );
    console.log(options);

    Output:

    { retries: 3, verbose: false }
    

    Debounce

    Usage:

    const foo = debounce(() => {
    console.log("The debounced function will only be invoked in 1000 milliseconds, the other invoking will disappear during the wait time.");
    }, 1000, true);

    Throttle

    Usage:

    const foo = throttle(() => {
    console.log("The function will be invoked at most once per every wait 1000 milliseconds.");
    }, 1000, { leading: true });

    Reference: Lodash

    Transfer CamelCase to KebabCase.

    Usage:

    const ret1 = convertCamelToKebab("ABC");
    const ret2 = convertCamelToKebab("aBC");
    console.log(ret1);
    console.log(ret2);

    Output:

    a-b-c
    a-b-c
    

    Transfer CamelCase to Underscore.

    Usage:

    const ret1 = convertCamelToUnder("ABC");
    const ret2 = convertCamelToUnder("aBC");
    console.log(ret1);
    console.log(ret2);

    Output:

    a_b_c
    a_b_c
    

    Convert text to a deterministic uppercase ASCII identifier suitable for an IIFE global name. Invalid identifier characters become underscores, and a leading digit is prefixed with an underscore.

    const globalName = toJavaScriptGlobalName("@scope/my-library");
    console.log(globalName);

    Output:

    _SCOPE_MY_LIBRARY
    

    Get the query param's value of the current Web URL(location.search).

    Usage:

    // http://example.com/?t1=1&t2=2&t3=3&t4=4#2333
    // ?t1=1&t2=2&t3=3&t4=4
    const p1 = getQueryParam("t3");
    const p2 = getQueryParam("t4");
    console.log(p1, p2);

    Output:

    3 4
    

    Returns the value of the specified query parameter in the input URL.

    Usage:

    const p1 = getUrlParam("https://example.com/?t1=1&t2=2&t3=3&t4=4", "t3");
    const p2 = getUrlParam("https://example.com/?t1=1&t2=2&t3=3&t4=4", "t4");
    console.log(p1, p2);

    Output:

    3 4
    

    Get the hash query param's value of the current Web URL(location.hash).

    Usage:

    // http://example.com/?#2333?t1=1&t2=2&t3=3&t4=4
    // #2333?t1=1&t2=2&t3=3&t4=4
    const p1 = getHashQueryParam("t3");
    const p2 = getHashQueryParam("t4");
    console.log(p1, p2);

    Output:

    3 4
    

    Get the domain of URL, and other params.

    Usage:

    const ret1 = getDomain("http://example.com/?t1=1&t2=2&t3=3&t4=4");
    const ret2 = getDomain("http://example.com/test/thanks?t1=1&t2=2&t3=3&t4=4", ["hostname", "pathname"]);
    const ret3 = getDomain("http://example.com:7890/test/thanks", ["hostname"]);
    const ret4 = getDomain("http://example.com:7890/test/thanks", ["host"]); // With Port
    const ret5 = getDomain("http://example.com:7890/test/thanks", ["origin"]);
    const ret6 = getDomain("http://example.com:7890/test/thanks?id=1", ["origin", "pathname", "search"]);
    console.log(ret1);
    console.log(ret2);
    console.log(ret3);
    console.log(ret4);
    console.log(ret5);
    console.log(ret6);

    Output:

    example.com
    example.com/test/thanks
    example.com
    example.com:7890
    http://example.com:7890
    http://example.com:7890/test/thanks?id=1
    

    Update the query param's value of the input URL.

    Usage:

    const ret1 = updateQueryParam("http://example.com/?t1=1&t2=2&t3=3&t4=4", "t3", "three");
    const ret2 = updateQueryParam("http://example.com/?t1=1&t2=2&t3=3&t4=4", "t4", "four");
    console.log(ret1);
    console.log(ret2);

    Output:

    http://example.com/?t1=1&t2=2&t3=three&t4=4
    http://example.com/?t1=1&t2=2&t3=3&t4=four
    

    Checks if the given string is a valid URL, including scheme URLs.

    Usage:

    const ret1 = isValidUrl("https://www.example.com");
    const ret2 = isValidUrl("http://example.com/path/exx/ss");
    const ret3 = isValidUrl("https://www.example.com/?q=hello&age=24#world");
    const ret4 = isValidUrl("http://www.example.com/#world?id=9");
    const ret5 = isValidUrl("ftp://example.com");
    console.log(ret1, ret2, ret3, ret4, ret5);

    Output:

    true true true true true
    

    If you are specifically checking for HTTP/HTTPS URLs, it is recommended to use the isValidHttpUrl function instead. The isValidUrl function matches all scheme URLs, including FTP and other non-HTTP schemes.

    Check if the given string is a valid HTTP/HTTPS URL.

    Usage:

    const ret1 = isValidHttpUrl("https://www.example.com");
    const ret2 = isValidHttpUrl("http://example.com/path/exx/ss");
    const ret3 = isValidHttpUrl("https://www.example.com/?q=hello&age=24#world");
    const ret4 = isValidHttpUrl("http://www.example.com/#world?id=9");
    const ret5 = isValidHttpUrl("ftp://example.com");
    console.log(ret1, ret2, ret3, ret4, ret5);

    Output:

    true true true true false
    

    Parse a GitHub repository shorthand, SCP form, or supported Git transport URL into canonical identity fields.

    const repository = parseGitHubRepository("git@github.com:acme/widget.git");
    console.log(JSON.stringify(repository));

    Output:

    {"owner":"acme","name":"widget","slug":"acme/widget","url":"https://github.com/acme/widget"}
    

    Handle Cookie.

    Usage:

    setCookie("test", "123", 30, "example.com"); // key value day domain
    const ret = getCookie("test");
    console.log(ret);

    Output:

    123
    

    Handle Storage (Keep fit for JSON, it can transfer format automatically).

    Usage:

    setSessionStorage("test", "123");
    const ret1 = getSessionStorage("test");
    setLocalStorage("test", "123");
    const ret2 = getLocalStorage("test");
    console.log(ret1, ret2);

    // or package in usage
    const projectName = "mazey";
    function mSetLocalStorage (key, value) {
    return setLocalStorage(`${projectName}_${key}`, value);
    }

    function mGetLocalStorage (key) {
    return getLocalStorage(`${projectName}_${key}`);
    }

    Output:

    123 123
    

    Modify class.

    Usage:

    const dom = document.querySelector("#box");

    // Determine `class`
    hasClass(dom, "test");
    // Add `class`
    addClass(dom, "test");
    // Remove `class`
    removeClass(dom, "test");

    Check whether a value is a CSS selector supported by the supplied query root. Invalid selector syntax returns false instead of throwing.

    isValidCssSelector(".message > img"); // true
    isValidCssSelector("["); // false
    isValidCssSelector("", { allowEmpty: true }); // true

    Extract normalized text from a cloned element without modifying the original DOM. Images can contribute their alt text, and matching descendants can be excluded.

    const message = document.querySelector(".message");
    const text = extractElementText(message, {
    excludeSelector: ".message-actions",
    });

    Add <style> in <head>.

    Usage:

    Example 1: Add the <style> with id, and repeated invoking will update the content instead of adding a new one.

    import { addStyle } from "mazey";

    addStyle(
    "body { background-color: #333; }",
    { id: "test" }
    );

    Output:

    <style id="test">body { background-color: #333; }</style>
    

    Example 2: Add the <style> without id, and repeated invoking will add a new one.

    import { addStyle } from "mazey";

    addStyle("body { background-color: #444; }");

    Output:

    <style>body { background-color: #444; }</style>
    

    Example 3: Combine genStyleString and addStyle to add multiple styles at once.

    import { genStyleString, addStyle } from "mazey";

    const xStyle = genStyleString(
    ".footer>.x-wish>a:first-child" +
    ",div.wish-flex>a[href^='https://github.com/chengchuu']" +
    ",.m-hide",
    [ "display: none" ]
    );
    const yStyle = genStyleString(
    ".footer>.y-wish:before",
    [
    `content: 'Copyright (c) chengchuu'`,
    "color: inherit",
    "padding-inline-start: var(--y-wish-1_5)",
    "padding-inline-end: var(--y-wish-1_5)",
    "padding-top: var(--y-wish-1)",
    "padding-bottom: var(--y-wish-1)",
    ]
    );
    addStyle(xStyle + yStyle, { id: "z-style" });

    Output:

    <style id="z-style">.footer>.x-wish>a:first-child,div.wish-flex>a[href^='https://github.com/chengchuu'],.m-hide{display: none;}.footer>.y-wish:before{content: 'Copyright (c) chengchuu';color: inherit;padding-inline-start: var(--y-wish-1_5);padding-inline-end: var(--y-wish-1_5);padding-top: var(--y-wish-1);padding-bottom: var(--y-wish-1);}</style>
    

    Generate the inline style string from the given parameters. The first parameter is the query selector, and the second parameter is the style array.

    Usage:

    const ret1 = genStyleString(".a", [ "color:red" ]);
    const ret2 = genStyleString("#b", [ "color:red", "font-size:12px" ]);
    console.log(ret1);
    console.log(ret2);

    Output:

    .a{color:red;}
    #b{color:red;font-size:12px;}
    

    Example: Combine genStyleString and addStyle to add multiple styles at once.

    import { genStyleString, addStyle } from "mazey";

    const xStyle = genStyleString(
    ".footer>.x-wish>a:first-child" +
    ",div.wish-flex>a[href^='https://github.com/chengchuu']" +
    ",.m-hide",
    [ "display: none" ]
    );
    const yStyle = genStyleString(
    ".footer>.y-wish:before",
    [
    `content: 'Copyright (c) chengchuu'`,
    "color: inherit",
    "padding-inline-start: var(--y-wish-1_5)",
    "padding-inline-end: var(--y-wish-1_5)",
    "padding-top: var(--y-wish-1)",
    "padding-bottom: var(--y-wish-1)",
    ]
    );
    addStyle(xStyle + yStyle, { id: "z-style" });

    Output:

    <style id="z-style">.footer>.x-wish>a:first-child,div.wish-flex>a[href^='https://github.com/chengchuu'],.m-hide{display: none;}.footer>.y-wish:before{content: 'Copyright (c) chengchuu';color: inherit;padding-inline-start: var(--y-wish-1_5);padding-inline-end: var(--y-wish-1_5);padding-top: var(--y-wish-1);padding-bottom: var(--y-wish-1);}</style>
    

    Make a new line of HTML.

    Usage:

    const ret1 = newLine("a\nb\nc");
    const ret2 = newLine("a\n\nbc");
    console.log(ret1);
    console.log(ret2);

    Output:

    a<br />b<br />c
    a<br /><br />bc
    

    Calculate an investment's Compound Annual Growth Rate (CAGR) from its start date, end date, and total return over the complete period.

    CAGR = (1 + totalReturnRate)^(365 / durationInDays) - 1
    

    The dates may be supported structured date strings, millisecond timestamps, or Date instances. The calculation uses the exact elapsed milliseconds, including time-of-day components, and a fixed 365-day financial year.

    Number input is a decimal ratio, so 0.202 represents 20.2%. String input is a percentage value, so "20.2%" and "20.2" both represent 20.2%; strict scientific notation such as "2.02e1%" is also accepted. The returned CAGR is an unrounded decimal ratio.

    import { calculateCAGR, floatToPercent } from "mazey";

    const cagr = calculateCAGR(
    "2022-04-01",
    "2025-10-01",
    "20.2%"
    );

    console.log({
    cagr,
    percentage: floatToPercent(cagr, 2),
    });

    Possible output:

    {
      cagr: 0.053908...,
      percentage: "5.39%"
    }
    

    The equivalent decimal-number call is:

    calculateCAGR(
    "2022-04-01",
    "2025-10-01",
    0.202
    );

    Date strings are validated using Mazey's strict date rules. Invalid dates, malformed or non-finite returns, and non-increasing date ranges throw errors. The parsed total return must be greater than -1, because -1 represents a complete loss for which CAGR is undefined.

    Hit probability (1% ~ 100%).

    Usage:

    const ret = inRate(0.5); // 0.01 ~ 1 true/false
    console.log(ret);

    Output:

    true
    

    Example: Test the precision.

    // Test
    let trueCount = 0;
    let falseCount = 0;
    new Array(1000000).fill(0).forEach(() => {
    if (inRate(0.5)) {
    trueCount++;
    } else {
    falseCount++;
    }
    });
    console.log(trueCount, falseCount); // 499994 500006

    Computes the longest common substring of two strings.

    Usage:

    const ret = longestComSubstring("fish", "finish");
    console.log(ret);

    Output:

    3
    

    Computes the longest common subsequence of two strings.

    Usage:

    const ret = longestComSubsequence("fish", "finish");
    console.log(ret);

    Output:

    4
    

    Resolve a project-specific website theme without applying it to the page. Resolution checks the fixed theme URL query, the supplied local-storage key, the current system color scheme, and finally the fixed light fallback.

    const theme = resolveThemePreference(
    "MY_WEBSITE_THEME"
    );

    console.log(theme);

    Output:

    {
      value: "dark",
      label: "System"
    }
    

    value is always the concrete light or dark theme. label identifies the preference that selected it: System, Light, or Dark. Only light and dark are accepted from ?theme= and are persisted under the supplied storage key when browser storage is available; stored values may also be system. The resolver is safe during SSR, tolerates unavailable browser storage and media queries, and does not mutate the DOM.

    Persist an exact system, light, or dark preference under a project-specific storage key. The function returns false when storage is unavailable or rejects the write; it does not apply the theme to the page.

    const stored = setThemePreference(
    "MY_WEBSITE_THEME",
    "dark"
    );

    Output: true

    Resolve one current UI language without applying it to the page. Resolution checks the fixed lang URL query, the supplied local-storage key, navigator.language, and finally the fixed en fallback.

    const language =
    resolveLanguagePreference(
    "MY_WEBSITE_LANGUAGE"
    );

    console.log(language);

    Possible output:

    {
      value: "ja-JP",
      label: "日本語(日本)"
    }
    

    Language tags are trimmed, treat _ as -, and are canonicalized. The label is generated with Intl.DisplayNames when available, so its exact wording may vary by runtime; otherwise the canonical language tag is used. Only the browser's single navigator.language value is read—navigator.languages is ignored. The resolver is SSR-safe and never writes storage, applies a language, loads translations, or mutates the DOM.

    Canonicalize and persist the language selected by the user. The function returns false when storage is unavailable or rejects the write.

    const stored = setLanguagePreference(
    "MY_WEBSITE_LANGUAGE",
    "ja-JP"
    );

    Output: true

    Conservatively classify a visitor as "crawler", "automation", or "unknown". The function first checks a focused list of recognizable crawler, indexing, SEO, AI-fetcher, and link-preview user-agent tokens. It then checks explicit automation user-agent tokens and navigator.webdriver === true.

    When no argument is provided, the function safely reads navigator.userAgent. An explicit user-agent string can be supplied for captured-user-agent analysis, deterministic tests, or server-side use. During SSR or in Node.js without navigator, the default result is "unknown"; explicit user-agent classification still works.

    const visitorType = detectVisitorType();

    console.log(visitorType);

    Possible output:

    unknown
    

    Explicit crawler example:

    const visitorType = detectVisitorType(
    "Mozilla/5.0 (compatible; Googlebot/2.1)"
    );

    console.log(visitorType);

    Output:

    crawler
    

    "unknown" means that no supported crawler or browser-automation signal was detected. User-agent values can be spoofed, and WebDriver signals can be hidden or changed, so false positives and false negatives are possible.

    unknown does not mean that the visitor has been verified as human. This function uses browser-side heuristics and must not be used as a security boundary or by itself for authentication, authorization, payments, rate limiting, fraud prevention, or access control. Genuine crawler verification generally requires server-side request information and provider-specific validation.

    Browser Information

    Usage:

    const ret = getBrowserInfo();
    console.log(ret);

    Output:

    {"engine":"webkit","engineVs":"537.36","platform":"desktop","supporter":"chrome","supporterVs":"85.0.4183.121","system":"windows","systemVs":"10"}
    

    Results:

    Attribute Description Type Values
    system System string android, ios, windows, macos, linux
    systemVs System version string Windows: 2000, xp, 2003, vista, 7, 8, 8.1, 10 macOS: ...
    platform Platform string desktop, mobile
    engine Engine string webkit, gecko, presto, trident
    engineVs Engine version string -
    supporter Supporter string edge, opera, chrome, safari, firefox, iexplore
    supporterVs Supporter version string -
    shell Shell string (Optional) wechat, qq_browser, qq_app, uc, 360, 2345, sougou, liebao, maxthon, bilibili
    shellVs Shell version string (Optional) 20/...
    appleType Apple device type string (Optional) ipad, iphone, ipod, iwatch

    Example: Determine the environment of the mobile QQ.

    const { system, shell } = getBrowserInfo();
    const isMobileQQ = ["android", "ios"].includes(system) && ["qq_browser", "qq_app"].includes(shell);

    Detect whether the current browser document provides the minimum prerequisites for PWA functionality that synchronous JavaScript can identify: a secure context, Service Worker API support, and, by default, a web app manifest link with a non-empty href. Pass { requireManifest: false } when only secure Service Worker eligibility is needed, or { scope: "/app/" } to require the current page to be inside a same-origin path scope.

    This check does not validate or request the manifest, verify service worker registration, determine whether the app is installed, or guarantee that an installation prompt is available. Browser-specific installation policies may impose additional requirements.

    Usage:

    const ret = isSafePWAEnv();
    console.log(ret);

    Output:

    true
    

    Detect standard standalone display mode with the iOS Safari navigator.standalone fallback. This is a presentation hint, not proof that the app is installed or controlled by a service worker.

    if (isStandalonePWA()) {
    document.querySelector("[data-install-help]")?.remove();
    }

    Get page load time(PerformanceNavigationTiming).

    This function uses the PerformanceNavigationTiming API to get page load time data. The PerformanceNavigationTiming API provides more accurate and detailed information about page load time than the deprecated PerformanceTiming API.

    Usage:

    // `camelCase:false` (Default) Return underline(`a_b`) data.
    // `camelCase:true` Return hump(`aB`) data.
    getPerformance()
    .then(res => {
    console.log(JSON.stringify(res));
    })
    .catch(console.error);

    Output:

    {"source":"PerformanceNavigationTiming","os":"others","os_version":"","device_type":"pc","network":"4g","screen_direction":"","unload_time":0,"redirect_time":0,"dns_time":0,"tcp_time":0,"ssl_time":0,"response_time":2,"download_time":2,"first_paint_time":288,"first_contentful_paint_time":288,"dom_ready_time":0,"onload_time":0,"white_time":0,"render_time":0,"decoded_body_size":718,"encoded_body_size":718}
    

    Results:

    Attribute Description Type Values
    dns_time DNS Lookup number domainLookupEnd - domainLookupStart
    tcp_time Connection Negotiation number connectEnd - connectStart
    response_time Requests and Responses number responseStart - requestStart
    white_time White Screen number responseStart - navigationStart
    dom_ready_time Dom Ready number domContentLoadedEventStart - navigationStart
    onload_time Onload number loadEventStart - navigationStart
    render_time EventEnd number loadEventEnd -navigationStart
    unload_time Unload number (Optional) unloadEventEnd - unloadEventStart
    redirect_time Redirect number (Optional) redirectEnd - redirectStart
    ssl_time SSL number (Optional) connectEnd - secureConnectionStart
    download_time Download number (Optional) responseEnd - responseStart

    Custom console printing (console).

    Usage:

    const myConsole = genCustomConsole("MazeyLog:");
    myConsole.log("I am string.");
    myConsole.info("I am boolean.", true);
    myConsole.info("I am number.", 123, 456);
    myConsole.info("I am object.", { a: 123, b: 456});

    Output:

    MazeyLog: I am string.
    MazeyLog: I am boolean. true
    MazeyLog: I am number. 123 456
    MazeyLog: I am object. {a: 123, b: 456}
    
    Dependency Version
    Node.js v22.21.1
    TypeScript v5.1.6
    Command Purpose
    npm install Install development dependencies.
    npm run dev Start the website and playground development server.
    npm run build Build the publishable package files.
    npm test Run the Jest test suite.
    npm run docs Build and validate the complete GitHub Pages artifact.
    npm run preview Run the full type, lint, build, test, and documentation checks.
    npm run pwa:preview Serve the production Pages artifact at the /mazey/ base path.
    Values Description Type
    ok The operation was successful. string
    loaded Some assets have been loaded. string
    failed An error occurred. string
    defined The value is defined. string
    undefined The value is undefined. string
    timeout The operation timed out. string
    true The value is true. boolean
    false The value is false. boolean

    This software is released under the terms of the MIT license.