English | 简体中文
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.
unknowndoes 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.