@eventuras/core 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -0
- package/dist/currency/format-price.d.ts +8 -0
- package/dist/currency/format-price.d.ts.map +1 -0
- package/dist/currency/index.d.ts +2 -0
- package/dist/currency/index.d.ts.map +1 -0
- package/dist/currency/index.js +19 -0
- package/dist/currency/index.js.map +1 -0
- package/dist/datetime/formatDate.d.ts +20 -0
- package/dist/datetime/formatDate.d.ts.map +1 -0
- package/dist/datetime/index.d.ts +7 -0
- package/dist/datetime/index.d.ts.map +1 -0
- package/dist/datetime/index.js +80 -0
- package/dist/datetime/index.js.map +1 -0
- package/dist/errors/formatApiError.d.ts +18 -0
- package/dist/errors/formatApiError.d.ts.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +36 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/regex/index.d.ts +30 -0
- package/dist/regex/index.d.ts.map +1 -0
- package/dist/regex/index.js +34 -0
- package/dist/regex/index.js.map +1 -0
- package/dist/url/index.d.ts +9 -0
- package/dist/url/index.d.ts.map +1 -0
- package/dist/url/index.js +15 -0
- package/dist/url/index.js.map +1 -0
- package/dist/useragents/index.d.ts +2 -0
- package/dist/useragents/index.d.ts.map +1 -0
- package/dist/useragents/index.js +195 -0
- package/dist/useragents/index.js.map +1 -0
- package/dist/useragents/isBot.d.ts +2 -0
- package/dist/useragents/isBot.d.ts.map +1 -0
- package/dist/useragents/patterns.json.d.ts +188 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# @eventuras/core
|
|
2
|
+
|
|
3
|
+
Core utilities for Eventuras applications.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
### Regex Patterns
|
|
8
|
+
|
|
9
|
+
Common validation regex patterns for form validation and data processing.
|
|
10
|
+
|
|
11
|
+
#### Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
// Import specific patterns from @eventuras/core/regex
|
|
15
|
+
import { internationalPhoneNumber, lettersSpaceAndHyphen } from '@eventuras/core/regex';
|
|
16
|
+
|
|
17
|
+
// Use in validation
|
|
18
|
+
const isValidPhone = internationalPhoneNumber.test('+4712345678');
|
|
19
|
+
const isValidName = lettersSpaceAndHyphen.test('Jean-Pierre');
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
#### Available Patterns
|
|
23
|
+
|
|
24
|
+
- `internationalPhoneNumber` - International phone numbers in E.164 format
|
|
25
|
+
- `letters` - Unicode letters only
|
|
26
|
+
- `lettersAndSpace` - Unicode letters and spaces
|
|
27
|
+
- `lettersSpaceAndHyphen` - Unicode letters, spaces, and hyphens
|
|
28
|
+
|
|
29
|
+
### DateTime Utilities
|
|
30
|
+
|
|
31
|
+
Utilities for formatting dates and date ranges.
|
|
32
|
+
|
|
33
|
+
#### Usage Examples
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// Import specific utilities from @eventuras/core/datetime
|
|
37
|
+
import { formatDate, formatDateSpan } from '@eventuras/core/datetime';
|
|
38
|
+
|
|
39
|
+
// Format a single date
|
|
40
|
+
const formatted = formatDate(new Date(), { locale: 'en-US', showTime: true });
|
|
41
|
+
|
|
42
|
+
// Format a date range
|
|
43
|
+
const dateSpan = formatDateSpan('2025-01-01', '2025-01-31', { locale: 'nb-NO' });
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
#### Available Functions
|
|
47
|
+
|
|
48
|
+
- `formatDate(date, options?)` - Format a single date with locale and time options
|
|
49
|
+
- `formatDateSpan(startDate, endDate?, options?)` - Format a date range
|
|
50
|
+
|
|
51
|
+
## Development
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Build the library
|
|
55
|
+
pnpm build
|
|
56
|
+
|
|
57
|
+
# Watch mode for development
|
|
58
|
+
pnpm dev
|
|
59
|
+
```
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format price with proper locale formatting
|
|
3
|
+
* @param amount - Price amount (already in kr, not cents)
|
|
4
|
+
* @param currency - Currency code (default: 'NOK')
|
|
5
|
+
* @param locale - Locale for formatting (default: 'no')
|
|
6
|
+
*/
|
|
7
|
+
export declare function formatPrice(amount: number, currency?: string, locale?: string): string;
|
|
8
|
+
//# sourceMappingURL=format-price.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-price.d.ts","sourceRoot":"","sources":["../../src/currency/format-price.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAAc,EACxB,MAAM,GAAE,MAAa,GACpB,MAAM,CAOR"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/currency/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/currency/format-price.ts
|
|
2
|
+
/**
|
|
3
|
+
* Format price with proper locale formatting
|
|
4
|
+
* @param amount - Price amount (already in kr, not cents)
|
|
5
|
+
* @param currency - Currency code (default: 'NOK')
|
|
6
|
+
* @param locale - Locale for formatting (default: 'no')
|
|
7
|
+
*/
|
|
8
|
+
function formatPrice(amount, currency = "NOK", locale = "no") {
|
|
9
|
+
return new Intl.NumberFormat(locale, {
|
|
10
|
+
style: "currency",
|
|
11
|
+
currency,
|
|
12
|
+
minimumFractionDigits: 0,
|
|
13
|
+
maximumFractionDigits: 2
|
|
14
|
+
}).format(amount);
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { formatPrice };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/currency/format-price.ts"],"sourcesContent":["/**\n * Format price with proper locale formatting\n * @param amount - Price amount (already in kr, not cents)\n * @param currency - Currency code (default: 'NOK')\n * @param locale - Locale for formatting (default: 'no')\n */\nexport function formatPrice(\n amount: number,\n currency: string = 'NOK',\n locale: string = 'no',\n): string {\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: currency,\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n }).format(amount);\n}\n"],"mappings":";;;;;;;AAMA,SAAgB,YACd,QACA,WAAmB,OACnB,SAAiB,MACT;CACR,OAAO,IAAI,KAAK,aAAa,QAAQ;EACnC,OAAO;EACG;EACV,uBAAuB;EACvB,uBAAuB;CACzB,CAAC,CAAC,CAAC,OAAO,MAAM;AAClB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface FormatDateOptions {
|
|
2
|
+
locale?: string;
|
|
3
|
+
showTime?: boolean;
|
|
4
|
+
timeZone?: string;
|
|
5
|
+
}
|
|
6
|
+
declare const formatDate: (date: string | Date, { locale, showTime, timeZone }?: FormatDateOptions) => string;
|
|
7
|
+
declare const formatDateSpan: (startDate: string | Date, endDate?: string | Date | null, options?: FormatDateOptions) => string;
|
|
8
|
+
/**
|
|
9
|
+
* Compact date range formatter for dense listings — produces strings like
|
|
10
|
+
* `"14. SEP"`, `"14.–16. SEP"`, `"30. AUG–2. SEP"`, or
|
|
11
|
+
* `"30. DEC 2026–2. JAN 2027"` depending on whether the range crosses
|
|
12
|
+
* months or years. Output is uppercased to read as a label / pill.
|
|
13
|
+
*
|
|
14
|
+
* Returns an empty string when no start date is supplied. Pair with the
|
|
15
|
+
* mono caps tile pattern in `EventTile` and similar dense displays.
|
|
16
|
+
*/
|
|
17
|
+
declare const formatCompactDateRange: (startDate: string | Date | null | undefined, endDate: string | Date | null | undefined, locale?: string, timeZone?: string) => string;
|
|
18
|
+
export { formatDate, formatDateSpan, formatCompactDateRange };
|
|
19
|
+
export type { FormatDateOptions };
|
|
20
|
+
//# sourceMappingURL=formatDate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatDate.d.ts","sourceRoot":"","sources":["../../src/datetime/formatDate.ts"],"names":[],"mappings":"AAAA,UAAU,iBAAiB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAQD,QAAA,MAAM,UAAU,GACd,MAAM,MAAM,GAAG,IAAI,EACnB,iCAAsE,iBAAsB,KAC3F,MA0BF,CAAC;AAEF,QAAA,MAAM,cAAc,GAClB,WAAW,MAAM,GAAG,IAAI,EACxB,UAAS,MAAM,GAAG,IAAI,GAAG,IAAW,EACpC,UAAS,iBAAsB,KAC9B,MAcF,CAAC;AAEF;;;;;;;;GAQG;AACH,QAAA,MAAM,sBAAsB,GAC1B,WAAW,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,EAC3C,SAAS,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,EACzC,eAAgB,EAChB,WAAU,MAA0B,KACnC,MAqDF,CAAC;AAEF,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,sBAAsB,EAAE,CAAC;AAC9D,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/datetime/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACrF,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
//#region src/datetime/formatDate.ts
|
|
2
|
+
var DEFAULT_TIME_ZONE = "Europe/Oslo";
|
|
3
|
+
var formatDate = (date, { locale = "en-US", showTime = false, timeZone = DEFAULT_TIME_ZONE } = {}) => {
|
|
4
|
+
if (!date) return "";
|
|
5
|
+
const dateOptions = {
|
|
6
|
+
year: "numeric",
|
|
7
|
+
month: "numeric",
|
|
8
|
+
day: "numeric",
|
|
9
|
+
timeZone
|
|
10
|
+
};
|
|
11
|
+
const timeOptions = {
|
|
12
|
+
hour: "2-digit",
|
|
13
|
+
minute: "2-digit",
|
|
14
|
+
timeZone
|
|
15
|
+
};
|
|
16
|
+
const parsedDate = new Date(date);
|
|
17
|
+
let formattedDate = parsedDate.toLocaleDateString(locale, dateOptions);
|
|
18
|
+
if (showTime) formattedDate += " " + parsedDate.toLocaleTimeString(locale, timeOptions);
|
|
19
|
+
return formattedDate;
|
|
20
|
+
};
|
|
21
|
+
var formatDateSpan = (startDate, endDate = null, options = {}) => {
|
|
22
|
+
if (!startDate) return "";
|
|
23
|
+
const formattedStartDate = formatDate(startDate, options);
|
|
24
|
+
if (!endDate || startDate === endDate) return formattedStartDate;
|
|
25
|
+
return `${formattedStartDate} - ${formatDate(endDate, options)}`;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Compact date range formatter for dense listings — produces strings like
|
|
29
|
+
* `"14. SEP"`, `"14.–16. SEP"`, `"30. AUG–2. SEP"`, or
|
|
30
|
+
* `"30. DEC 2026–2. JAN 2027"` depending on whether the range crosses
|
|
31
|
+
* months or years. Output is uppercased to read as a label / pill.
|
|
32
|
+
*
|
|
33
|
+
* Returns an empty string when no start date is supplied. Pair with the
|
|
34
|
+
* mono caps tile pattern in `EventTile` and similar dense displays.
|
|
35
|
+
*/
|
|
36
|
+
var formatCompactDateRange = (startDate, endDate, locale = "en-US", timeZone = DEFAULT_TIME_ZONE) => {
|
|
37
|
+
if (!startDate) return "";
|
|
38
|
+
const start = new Date(startDate);
|
|
39
|
+
const end = endDate ? new Date(endDate) : null;
|
|
40
|
+
const dayMonthFmt = new Intl.DateTimeFormat(locale, {
|
|
41
|
+
day: "numeric",
|
|
42
|
+
month: "short",
|
|
43
|
+
timeZone
|
|
44
|
+
});
|
|
45
|
+
const dayFmt = new Intl.DateTimeFormat(locale, {
|
|
46
|
+
day: "numeric",
|
|
47
|
+
timeZone
|
|
48
|
+
});
|
|
49
|
+
const yearFmt = new Intl.DateTimeFormat(locale, {
|
|
50
|
+
year: "numeric",
|
|
51
|
+
timeZone
|
|
52
|
+
});
|
|
53
|
+
const dayPart = (date) => dayFmt.formatToParts(date).find((p) => p.type === "day")?.value ?? String(date.getDate());
|
|
54
|
+
const startLabel = dayMonthFmt.format(start).toUpperCase();
|
|
55
|
+
if (!end || +start === +end) return startLabel;
|
|
56
|
+
const ymdInZoneFmt = new Intl.DateTimeFormat("en-US", {
|
|
57
|
+
year: "numeric",
|
|
58
|
+
month: "numeric",
|
|
59
|
+
day: "numeric",
|
|
60
|
+
timeZone
|
|
61
|
+
});
|
|
62
|
+
const partsInZone = (date) => {
|
|
63
|
+
const lookup = Object.fromEntries(ymdInZoneFmt.formatToParts(date).map((p) => [p.type, p.value]));
|
|
64
|
+
return {
|
|
65
|
+
year: Number(lookup.year),
|
|
66
|
+
month: Number(lookup.month)
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
const startParts = partsInZone(start);
|
|
70
|
+
const endParts = partsInZone(end);
|
|
71
|
+
const sameMonth = startParts.year === endParts.year && startParts.month === endParts.month;
|
|
72
|
+
const sameYear = startParts.year === endParts.year;
|
|
73
|
+
if (sameMonth) return `${dayPart(start)}.–${dayMonthFmt.format(end)}`.toUpperCase();
|
|
74
|
+
if (sameYear) return `${dayMonthFmt.format(start)}–${dayMonthFmt.format(end)}`.toUpperCase();
|
|
75
|
+
return `${dayMonthFmt.format(start)} ${yearFmt.format(start)}–${dayMonthFmt.format(end)} ${yearFmt.format(end)}`.toUpperCase();
|
|
76
|
+
};
|
|
77
|
+
//#endregion
|
|
78
|
+
export { formatCompactDateRange, formatDate, formatDateSpan };
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/datetime/formatDate.ts"],"sourcesContent":["interface FormatDateOptions {\n locale?: string;\n showTime?: boolean;\n timeZone?: string;\n}\n\n// Default IANA time zone for formatted dates. Hardcoded to the project's\n// operational time zone so SSR (server clock, typically UTC) and client\n// hydration (user device) produce identical strings. Override via\n// FormatDateOptions.timeZone where needed.\nconst DEFAULT_TIME_ZONE = 'Europe/Oslo';\n\nconst formatDate = (\n date: string | Date,\n { locale = 'en-US', showTime = false, timeZone = DEFAULT_TIME_ZONE }: FormatDateOptions = {}\n): string => {\n if (!date) {\n return '';\n }\n\n const dateOptions: Intl.DateTimeFormatOptions = {\n year: 'numeric',\n month: 'numeric',\n day: 'numeric',\n timeZone,\n };\n\n const timeOptions: Intl.DateTimeFormatOptions = {\n hour: '2-digit',\n minute: '2-digit',\n timeZone,\n };\n\n const parsedDate = new Date(date);\n let formattedDate = parsedDate.toLocaleDateString(locale, dateOptions);\n\n if (showTime) {\n formattedDate += ' ' + parsedDate.toLocaleTimeString(locale, timeOptions);\n }\n\n return formattedDate;\n};\n\nconst formatDateSpan = (\n startDate: string | Date,\n endDate: string | Date | null = null,\n options: FormatDateOptions = {}\n): string => {\n if (!startDate) {\n return '';\n }\n\n const formattedStartDate = formatDate(startDate, options);\n\n if (!endDate || startDate === endDate) {\n return formattedStartDate;\n }\n\n const formattedEndDate = formatDate(endDate, options);\n\n return `${formattedStartDate} - ${formattedEndDate}`;\n};\n\n/**\n * Compact date range formatter for dense listings — produces strings like\n * `\"14. SEP\"`, `\"14.–16. SEP\"`, `\"30. AUG–2. SEP\"`, or\n * `\"30. DEC 2026–2. JAN 2027\"` depending on whether the range crosses\n * months or years. Output is uppercased to read as a label / pill.\n *\n * Returns an empty string when no start date is supplied. Pair with the\n * mono caps tile pattern in `EventTile` and similar dense displays.\n */\nconst formatCompactDateRange = (\n startDate: string | Date | null | undefined,\n endDate: string | Date | null | undefined,\n locale = 'en-US',\n timeZone: string = DEFAULT_TIME_ZONE\n): string => {\n if (!startDate) return '';\n\n const start = new Date(startDate);\n const end = endDate ? new Date(endDate) : null;\n\n const dayMonthFmt = new Intl.DateTimeFormat(locale, { day: 'numeric', month: 'short', timeZone });\n const dayFmt = new Intl.DateTimeFormat(locale, { day: 'numeric', timeZone });\n const yearFmt = new Intl.DateTimeFormat(locale, { year: 'numeric', timeZone });\n\n // Pull the locale-formatted day number without any trailing punctuation\n // (some locales — e.g. nb-NO — append \".\" after the day; we add our own\n // literal `.` below and don't want a doubled period).\n const dayPart = (date: Date): string =>\n dayFmt.formatToParts(date).find(p => p.type === 'day')?.value ?? String(date.getDate());\n\n const startLabel = dayMonthFmt.format(start).toUpperCase();\n\n if (!end || +start === +end) {\n return startLabel;\n }\n\n // Compare year/month/day in the configured time zone, not the runtime's\n // local zone — otherwise an event that starts late on day N in Europe/Oslo\n // can be classified as same-month/same-year against day N+1 in UTC.\n const ymdInZoneFmt = new Intl.DateTimeFormat('en-US', {\n year: 'numeric',\n month: 'numeric',\n day: 'numeric',\n timeZone,\n });\n const partsInZone = (date: Date) => {\n const lookup = Object.fromEntries(\n ymdInZoneFmt.formatToParts(date).map(p => [p.type, p.value])\n );\n return {\n year: Number(lookup.year),\n month: Number(lookup.month),\n };\n };\n\n const startParts = partsInZone(start);\n const endParts = partsInZone(end);\n const sameMonth = startParts.year === endParts.year && startParts.month === endParts.month;\n const sameYear = startParts.year === endParts.year;\n\n if (sameMonth) {\n return `${dayPart(start)}.–${dayMonthFmt.format(end)}`.toUpperCase();\n }\n if (sameYear) {\n return `${dayMonthFmt.format(start)}–${dayMonthFmt.format(end)}`.toUpperCase();\n }\n return `${dayMonthFmt.format(start)} ${yearFmt.format(start)}–${dayMonthFmt.format(end)} ${yearFmt.format(end)}`.toUpperCase();\n};\n\nexport { formatDate, formatDateSpan, formatCompactDateRange };\nexport type { FormatDateOptions };\n"],"mappings":";AAUA,IAAM,oBAAoB;AAE1B,IAAM,cACJ,MACA,EAAE,SAAS,SAAS,WAAW,OAAO,WAAW,sBAAyC,CAAC,MAChF;CACX,IAAI,CAAC,MACH,OAAO;CAGT,MAAM,cAA0C;EAC9C,MAAM;EACN,OAAO;EACP,KAAK;EACL;CACF;CAEA,MAAM,cAA0C;EAC9C,MAAM;EACN,QAAQ;EACR;CACF;CAEA,MAAM,aAAa,IAAI,KAAK,IAAI;CAChC,IAAI,gBAAgB,WAAW,mBAAmB,QAAQ,WAAW;CAErE,IAAI,UACF,iBAAiB,MAAM,WAAW,mBAAmB,QAAQ,WAAW;CAG1E,OAAO;AACT;AAEA,IAAM,kBACJ,WACA,UAAgC,MAChC,UAA6B,CAAC,MACnB;CACX,IAAI,CAAC,WACH,OAAO;CAGT,MAAM,qBAAqB,WAAW,WAAW,OAAO;CAExD,IAAI,CAAC,WAAW,cAAc,SAC5B,OAAO;CAKT,OAAO,GAAG,mBAAmB,KAFJ,WAAW,SAAS,OAEX;AACpC;;;;;;;;;;AAWA,IAAM,0BACJ,WACA,SACA,SAAS,SACT,WAAmB,sBACR;CACX,IAAI,CAAC,WAAW,OAAO;CAEvB,MAAM,QAAQ,IAAI,KAAK,SAAS;CAChC,MAAM,MAAM,UAAU,IAAI,KAAK,OAAO,IAAI;CAE1C,MAAM,cAAc,IAAI,KAAK,eAAe,QAAQ;EAAE,KAAK;EAAW,OAAO;EAAS;CAAS,CAAC;CAChG,MAAM,SAAS,IAAI,KAAK,eAAe,QAAQ;EAAE,KAAK;EAAW;CAAS,CAAC;CAC3E,MAAM,UAAU,IAAI,KAAK,eAAe,QAAQ;EAAE,MAAM;EAAW;CAAS,CAAC;CAK7E,MAAM,WAAW,SACf,OAAO,cAAc,IAAI,CAAC,CAAC,MAAK,MAAK,EAAE,SAAS,KAAK,CAAC,EAAE,SAAS,OAAO,KAAK,QAAQ,CAAC;CAExF,MAAM,aAAa,YAAY,OAAO,KAAK,CAAC,CAAC,YAAY;CAEzD,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KACtB,OAAO;CAMT,MAAM,eAAe,IAAI,KAAK,eAAe,SAAS;EACpD,MAAM;EACN,OAAO;EACP,KAAK;EACL;CACF,CAAC;CACD,MAAM,eAAe,SAAe;EAClC,MAAM,SAAS,OAAO,YACpB,aAAa,cAAc,IAAI,CAAC,CAAC,KAAI,MAAK,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAC7D;EACA,OAAO;GACL,MAAM,OAAO,OAAO,IAAI;GACxB,OAAO,OAAO,OAAO,KAAK;EAC5B;CACF;CAEA,MAAM,aAAa,YAAY,KAAK;CACpC,MAAM,WAAW,YAAY,GAAG;CAChC,MAAM,YAAY,WAAW,SAAS,SAAS,QAAQ,WAAW,UAAU,SAAS;CACrF,MAAM,WAAW,WAAW,SAAS,SAAS;CAE9C,IAAI,WACF,OAAO,GAAG,QAAQ,KAAK,EAAE,IAAI,YAAY,OAAO,GAAG,IAAI,YAAY;CAErE,IAAI,UACF,OAAO,GAAG,YAAY,OAAO,KAAK,EAAE,GAAG,YAAY,OAAO,GAAG,IAAI,YAAY;CAE/E,OAAO,GAAG,YAAY,OAAO,KAAK,EAAE,GAAG,QAAQ,OAAO,KAAK,EAAE,GAAG,YAAY,OAAO,GAAG,EAAE,GAAG,QAAQ,OAAO,GAAG,IAAI,YAAY;AAC/H"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract a human-readable message from an SDK error payload.
|
|
3
|
+
*
|
|
4
|
+
* Handles:
|
|
5
|
+
* - Plain string bodies (the SDK's fallback when a response isn't JSON)
|
|
6
|
+
* - ASP.NET Problem Details (RFC 7807) with `errors: { Field: [msgs] }`
|
|
7
|
+
* — surfaced per-field so validation feedback makes it to the caller
|
|
8
|
+
* - Problem Details with `detail` or `title`
|
|
9
|
+
* - Legacy shapes with `body.message`, `message`, or `statusText`
|
|
10
|
+
*
|
|
11
|
+
* When nothing readable can be extracted, falls back to a status-aware
|
|
12
|
+
* synthetic message for 5xx responses — servers often return an empty body
|
|
13
|
+
* on unhandled exceptions, and "Failed to update X" hides that it's a
|
|
14
|
+
* server problem, not the caller's. Falls back to the caller-supplied
|
|
15
|
+
* `fallback` otherwise.
|
|
16
|
+
*/
|
|
17
|
+
export declare function formatApiError(raw: unknown, fallback: string, statusCode?: number, correlationId?: string | null): string;
|
|
18
|
+
//# sourceMappingURL=formatApiError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatApiError.d.ts","sourceRoot":"","sources":["../../src/errors/formatApiError.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,EACnB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,GAC5B,MAAM,CA+CR"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/errors/formatApiError.ts
|
|
2
|
+
/**
|
|
3
|
+
* Extract a human-readable message from an SDK error payload.
|
|
4
|
+
*
|
|
5
|
+
* Handles:
|
|
6
|
+
* - Plain string bodies (the SDK's fallback when a response isn't JSON)
|
|
7
|
+
* - ASP.NET Problem Details (RFC 7807) with `errors: { Field: [msgs] }`
|
|
8
|
+
* — surfaced per-field so validation feedback makes it to the caller
|
|
9
|
+
* - Problem Details with `detail` or `title`
|
|
10
|
+
* - Legacy shapes with `body.message`, `message`, or `statusText`
|
|
11
|
+
*
|
|
12
|
+
* When nothing readable can be extracted, falls back to a status-aware
|
|
13
|
+
* synthetic message for 5xx responses — servers often return an empty body
|
|
14
|
+
* on unhandled exceptions, and "Failed to update X" hides that it's a
|
|
15
|
+
* server problem, not the caller's. Falls back to the caller-supplied
|
|
16
|
+
* `fallback` otherwise.
|
|
17
|
+
*/
|
|
18
|
+
function formatApiError(raw, fallback, statusCode, correlationId) {
|
|
19
|
+
const reference = correlationId ? `Reference ${correlationId}. ` : "";
|
|
20
|
+
const serverFallback = statusCode != null && statusCode >= 500 ? `Server error (${statusCode}). ${reference}Please try again or contact support if the problem persists.` : null;
|
|
21
|
+
if (typeof raw === "string") return raw.trim() || serverFallback || fallback;
|
|
22
|
+
if (!raw || typeof raw !== "object") return serverFallback || fallback;
|
|
23
|
+
const err = raw;
|
|
24
|
+
if (err.errors && typeof err.errors === "object") {
|
|
25
|
+
const parts = Object.entries(err.errors).map(([field, msgs]) => {
|
|
26
|
+
const text = Array.isArray(msgs) ? msgs.join(", ") : msgs;
|
|
27
|
+
return text ? `${field}: ${text}` : field;
|
|
28
|
+
}).filter(Boolean);
|
|
29
|
+
if (parts.length > 0) return `${err.title ? `${err.title} — ` : ""}${parts.join("; ")}`;
|
|
30
|
+
}
|
|
31
|
+
return err.detail || err.title || err.body?.message || err.message || err.statusText || serverFallback || fallback;
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { formatApiError };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/errors/formatApiError.ts"],"sourcesContent":["/**\n * Extract a human-readable message from an SDK error payload.\n *\n * Handles:\n * - Plain string bodies (the SDK's fallback when a response isn't JSON)\n * - ASP.NET Problem Details (RFC 7807) with `errors: { Field: [msgs] }`\n * — surfaced per-field so validation feedback makes it to the caller\n * - Problem Details with `detail` or `title`\n * - Legacy shapes with `body.message`, `message`, or `statusText`\n *\n * When nothing readable can be extracted, falls back to a status-aware\n * synthetic message for 5xx responses — servers often return an empty body\n * on unhandled exceptions, and \"Failed to update X\" hides that it's a\n * server problem, not the caller's. Falls back to the caller-supplied\n * `fallback` otherwise.\n */\nexport function formatApiError(\n raw: unknown,\n fallback: string,\n statusCode?: number,\n correlationId?: string | null\n): string {\n const reference = correlationId ? `Reference ${correlationId}. ` : '';\n const serverFallback =\n statusCode != null && statusCode >= 500\n ? `Server error (${statusCode}). ${reference}Please try again or contact support if the problem persists.`\n : null;\n\n if (typeof raw === 'string') {\n const trimmed = raw.trim();\n return trimmed || serverFallback || fallback;\n }\n\n if (!raw || typeof raw !== 'object') {\n return serverFallback || fallback;\n }\n\n const err = raw as {\n errors?: Record<string, string[] | string | undefined>;\n title?: string;\n detail?: string;\n body?: { message?: string };\n message?: string;\n statusText?: string;\n };\n\n if (err.errors && typeof err.errors === 'object') {\n const parts = Object.entries(err.errors)\n .map(([field, msgs]) => {\n const text = Array.isArray(msgs) ? msgs.join(', ') : msgs;\n return text ? `${field}: ${text}` : field;\n })\n .filter(Boolean);\n if (parts.length > 0) {\n const prefix = err.title ? `${err.title} — ` : '';\n return `${prefix}${parts.join('; ')}`;\n }\n }\n\n return (\n err.detail ||\n err.title ||\n err.body?.message ||\n err.message ||\n err.statusText ||\n serverFallback ||\n fallback\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAgBA,SAAgB,eACd,KACA,UACA,YACA,eACQ;CACR,MAAM,YAAY,gBAAgB,aAAa,cAAc,MAAM;CACnE,MAAM,iBACJ,cAAc,QAAQ,cAAc,MAChC,iBAAiB,WAAW,KAAK,UAAU,gEAC3C;CAEN,IAAI,OAAO,QAAQ,UAEjB,OADgB,IAAI,KACb,KAAW,kBAAkB;CAGtC,IAAI,CAAC,OAAO,OAAO,QAAQ,UACzB,OAAO,kBAAkB;CAG3B,MAAM,MAAM;CASZ,IAAI,IAAI,UAAU,OAAO,IAAI,WAAW,UAAU;EAChD,MAAM,QAAQ,OAAO,QAAQ,IAAI,MAAM,CAAC,CACrC,KAAK,CAAC,OAAO,UAAU;GACtB,MAAM,OAAO,MAAM,QAAQ,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI;GACrD,OAAO,OAAO,GAAG,MAAM,IAAI,SAAS;EACtC,CAAC,CAAC,CACD,OAAO,OAAO;EACjB,IAAI,MAAM,SAAS,GAEjB,OAAO,GADQ,IAAI,QAAQ,GAAG,IAAI,MAAM,OAAO,KAC5B,MAAM,KAAK,IAAI;CAEtC;CAEA,OACE,IAAI,UACJ,IAAI,SACJ,IAAI,MAAM,WACV,IAAI,WACJ,IAAI,cACJ,kBACA;AAEJ"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regular expressions for common validation patterns.
|
|
3
|
+
* @module regex
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Validates international phone numbers in E.164 format.
|
|
7
|
+
* Format: +[country code][number] (1-15 digits total after +)
|
|
8
|
+
* @example "+4712345678", "+14155552671"
|
|
9
|
+
*/
|
|
10
|
+
export declare const internationalPhoneNumber: RegExp;
|
|
11
|
+
/**
|
|
12
|
+
* Validates strings containing only letters (Unicode-aware).
|
|
13
|
+
* Supports all Unicode letter characters including diacritics.
|
|
14
|
+
* @example "Hello", "Bjørn", "José"
|
|
15
|
+
*/
|
|
16
|
+
export declare const letters: RegExp;
|
|
17
|
+
/**
|
|
18
|
+
* Validates strings containing only letters and spaces (Unicode-aware).
|
|
19
|
+
* Supports all Unicode letter characters including diacritics.
|
|
20
|
+
* @example "Hello World", "Bjørn Hansen", "María José"
|
|
21
|
+
*/
|
|
22
|
+
export declare const lettersAndSpace: RegExp;
|
|
23
|
+
/**
|
|
24
|
+
* Validates strings containing letters, spaces, and hyphens (Unicode-aware).
|
|
25
|
+
* Supports all Unicode letter characters including diacritics.
|
|
26
|
+
* Useful for names with hyphenation.
|
|
27
|
+
* @example "Jean-Pierre", "Mary-Anne Smith", "Müller-Schmidt"
|
|
28
|
+
*/
|
|
29
|
+
export declare const lettersSpaceAndHyphen: RegExp;
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/regex/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,QAAsB,CAAC;AAE5D;;;;GAIG;AACH,eAAO,MAAM,OAAO,QAAgB,CAAC;AAErC;;;;GAIG;AACH,eAAO,MAAM,eAAe,QAAiB,CAAC;AAE9C;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAkB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region src/regex/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Regular expressions for common validation patterns.
|
|
4
|
+
* @module regex
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Validates international phone numbers in E.164 format.
|
|
8
|
+
* Format: +[country code][number] (1-15 digits total after +)
|
|
9
|
+
* @example "+4712345678", "+14155552671"
|
|
10
|
+
*/
|
|
11
|
+
var internationalPhoneNumber = /^\+[1-9]\d{1,14}$/;
|
|
12
|
+
/**
|
|
13
|
+
* Validates strings containing only letters (Unicode-aware).
|
|
14
|
+
* Supports all Unicode letter characters including diacritics.
|
|
15
|
+
* @example "Hello", "Bjørn", "José"
|
|
16
|
+
*/
|
|
17
|
+
var letters = /^[\p{L}]+$/u;
|
|
18
|
+
/**
|
|
19
|
+
* Validates strings containing only letters and spaces (Unicode-aware).
|
|
20
|
+
* Supports all Unicode letter characters including diacritics.
|
|
21
|
+
* @example "Hello World", "Bjørn Hansen", "María José"
|
|
22
|
+
*/
|
|
23
|
+
var lettersAndSpace = /^[\p{L} ]+$/u;
|
|
24
|
+
/**
|
|
25
|
+
* Validates strings containing letters, spaces, and hyphens (Unicode-aware).
|
|
26
|
+
* Supports all Unicode letter characters including diacritics.
|
|
27
|
+
* Useful for names with hyphenation.
|
|
28
|
+
* @example "Jean-Pierre", "Mary-Anne Smith", "Müller-Schmidt"
|
|
29
|
+
*/
|
|
30
|
+
var lettersSpaceAndHyphen = /^[\p{L} -]+$/u;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { internationalPhoneNumber, letters, lettersAndSpace, lettersSpaceAndHyphen };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/regex/index.ts"],"sourcesContent":["/**\n * Regular expressions for common validation patterns.\n * @module regex\n */\n\n/**\n * Validates international phone numbers in E.164 format.\n * Format: +[country code][number] (1-15 digits total after +)\n * @example \"+4712345678\", \"+14155552671\"\n */\nexport const internationalPhoneNumber = /^\\+[1-9]\\d{1,14}$/;\n\n/**\n * Validates strings containing only letters (Unicode-aware).\n * Supports all Unicode letter characters including diacritics.\n * @example \"Hello\", \"Bjørn\", \"José\"\n */\nexport const letters = /^[\\p{L}]+$/u;\n\n/**\n * Validates strings containing only letters and spaces (Unicode-aware).\n * Supports all Unicode letter characters including diacritics.\n * @example \"Hello World\", \"Bjørn Hansen\", \"María José\"\n */\nexport const lettersAndSpace = /^[\\p{L} ]+$/u;\n\n/**\n * Validates strings containing letters, spaces, and hyphens (Unicode-aware).\n * Supports all Unicode letter characters including diacritics.\n * Useful for names with hyphenation.\n * @example \"Jean-Pierre\", \"Mary-Anne Smith\", \"Müller-Schmidt\"\n */\nexport const lettersSpaceAndHyphen = /^[\\p{L} -]+$/u;\n"],"mappings":";;;;;;;;;;AAUA,IAAa,2BAA2B;;;;;;AAOxC,IAAa,UAAU;;;;;;AAOvB,IAAa,kBAAkB;;;;;;;AAQ/B,IAAa,wBAAwB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Join a base URL with path segments, handling slashes correctly.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* joinUrl('https://example.com/', '/api', '/v1') // 'https://example.com/api/v1'
|
|
6
|
+
* joinUrl('https://example.com', 'api', 'v1') // 'https://example.com/api/v1'
|
|
7
|
+
*/
|
|
8
|
+
export declare function joinUrl(base: string, ...segments: string[]): string;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/url/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAKnE"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/url/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Join a base URL with path segments, handling slashes correctly.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* joinUrl('https://example.com/', '/api', '/v1') // 'https://example.com/api/v1'
|
|
7
|
+
* joinUrl('https://example.com', 'api', 'v1') // 'https://example.com/api/v1'
|
|
8
|
+
*/
|
|
9
|
+
function joinUrl(base, ...segments) {
|
|
10
|
+
return segments.reduce((url, segment) => url.replace(/\/+$/, "") + "/" + segment.replace(/^\/+/, ""), base);
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { joinUrl };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/url/index.ts"],"sourcesContent":["/**\n * Join a base URL with path segments, handling slashes correctly.\n *\n * @example\n * joinUrl('https://example.com/', '/api', '/v1') // 'https://example.com/api/v1'\n * joinUrl('https://example.com', 'api', 'v1') // 'https://example.com/api/v1'\n */\nexport function joinUrl(base: string, ...segments: string[]): string {\n return segments.reduce(\n (url, segment) => url.replace(/\\/+$/, '') + '/' + segment.replace(/^\\/+/, ''),\n base\n );\n}\n"],"mappings":";;;;;;;;AAOA,SAAgB,QAAQ,MAAc,GAAG,UAA4B;CACnE,OAAO,SAAS,QACb,KAAK,YAAY,IAAI,QAAQ,QAAQ,EAAE,IAAI,MAAM,QAAQ,QAAQ,QAAQ,EAAE,GAC5E,IACF;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/useragents/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
//#endregion
|
|
2
|
+
//#region src/useragents/isBot.ts
|
|
3
|
+
var botPattern = new RegExp([
|
|
4
|
+
" daum[ /]",
|
|
5
|
+
" deusu/",
|
|
6
|
+
"(?:^|[^g])news(?!sapphire)",
|
|
7
|
+
"(?<! (?:channel/|google/))google(?!(app|/google| pixel))",
|
|
8
|
+
"(?<! cu)bots?(?:\\b|_)",
|
|
9
|
+
"(?<!(?:lib))http",
|
|
10
|
+
"(?<!cam)scan",
|
|
11
|
+
"24x7",
|
|
12
|
+
"@[a-z][\\w-]+\\.",
|
|
13
|
+
"\\(\\)",
|
|
14
|
+
"\\.com\\b",
|
|
15
|
+
"\\b\\w+\\.ai",
|
|
16
|
+
"\\bcursor/",
|
|
17
|
+
"\\bmanus-user/",
|
|
18
|
+
"\\bort/",
|
|
19
|
+
"\\bperl\\b",
|
|
20
|
+
"\\bplaywright\\b",
|
|
21
|
+
"\\bsecurityheaders\\b",
|
|
22
|
+
"\\bselenium\\b",
|
|
23
|
+
"\\btime/",
|
|
24
|
+
"\\|",
|
|
25
|
+
"^[\\w \\.\\-\\(?:\\):%]+(?:/v?\\d+(?:\\.\\d+)?(?:\\.\\d{1,10})*?)?(?:,|$)",
|
|
26
|
+
"^[\\w\\-]+/[\\w]+$",
|
|
27
|
+
"^[^ ]{50,}$",
|
|
28
|
+
"^\\d+\\b",
|
|
29
|
+
"^\\W",
|
|
30
|
+
"^\\w*search\\b",
|
|
31
|
+
"^\\w+/[\\w\\(\\)]*$",
|
|
32
|
+
"^\\w+/\\d\\.\\d\\s\\([\\w@]+\\)$",
|
|
33
|
+
"^active",
|
|
34
|
+
"^ad muncher",
|
|
35
|
+
"^amaya",
|
|
36
|
+
"^apache/",
|
|
37
|
+
"^avsdevicesdk/",
|
|
38
|
+
"^azure",
|
|
39
|
+
"^biglotron",
|
|
40
|
+
"^bot",
|
|
41
|
+
"^bw/",
|
|
42
|
+
"^clamav[ /]",
|
|
43
|
+
"^claude-code/",
|
|
44
|
+
"^client/",
|
|
45
|
+
"^cobweb/",
|
|
46
|
+
"^custom",
|
|
47
|
+
"^ddg[_-]android",
|
|
48
|
+
"^discourse",
|
|
49
|
+
"^dispatch/\\d",
|
|
50
|
+
"^downcast/",
|
|
51
|
+
"^duckduckgo",
|
|
52
|
+
"^email",
|
|
53
|
+
"^facebook",
|
|
54
|
+
"^getright/",
|
|
55
|
+
"^gozilla/",
|
|
56
|
+
"^hobbit",
|
|
57
|
+
"^hotzonu",
|
|
58
|
+
"^hwcdn/",
|
|
59
|
+
"^igetter/",
|
|
60
|
+
"^jeode/",
|
|
61
|
+
"^jetty/",
|
|
62
|
+
"^jigsaw",
|
|
63
|
+
"^microsoft bits",
|
|
64
|
+
"^movabletype",
|
|
65
|
+
"^mozilla/\\d\\.\\d\\s[\\w\\.-]+$",
|
|
66
|
+
"^mozilla/\\d\\.\\d\\s\\((?:compatible;)?(?:\\s?[\\w\\d-.]+\\/\\d+\\.\\d+)?\\)$",
|
|
67
|
+
"^navermailapp",
|
|
68
|
+
"^netsurf",
|
|
69
|
+
"^offline",
|
|
70
|
+
"^openai/",
|
|
71
|
+
"^owler",
|
|
72
|
+
"^php",
|
|
73
|
+
"^postman",
|
|
74
|
+
"^python",
|
|
75
|
+
"^rank",
|
|
76
|
+
"^read",
|
|
77
|
+
"^reed",
|
|
78
|
+
"^rest",
|
|
79
|
+
"^rss",
|
|
80
|
+
"^snapchat",
|
|
81
|
+
"^space bison",
|
|
82
|
+
"^svn",
|
|
83
|
+
"^swcd ",
|
|
84
|
+
"^taringa",
|
|
85
|
+
"^thumbor/",
|
|
86
|
+
"^track",
|
|
87
|
+
"^w3c",
|
|
88
|
+
"^webbandit/",
|
|
89
|
+
"^webcopier",
|
|
90
|
+
"^wget",
|
|
91
|
+
"^whatsapp",
|
|
92
|
+
"^wordpress",
|
|
93
|
+
"^xenu link sleuth",
|
|
94
|
+
"^yahoo",
|
|
95
|
+
"^yandex",
|
|
96
|
+
"^zdm/\\d",
|
|
97
|
+
"^zoom marketplace/",
|
|
98
|
+
"advisor",
|
|
99
|
+
"agent\\b",
|
|
100
|
+
"analyzer",
|
|
101
|
+
"archive",
|
|
102
|
+
"ask jeeves/teoma",
|
|
103
|
+
"audit",
|
|
104
|
+
"bit\\.ly/",
|
|
105
|
+
"bluecoat drtr",
|
|
106
|
+
"browsex",
|
|
107
|
+
"burpcollaborator",
|
|
108
|
+
"capture",
|
|
109
|
+
"catch",
|
|
110
|
+
"check\\b",
|
|
111
|
+
"checker",
|
|
112
|
+
"chrome-lighthouse",
|
|
113
|
+
"chromeframe",
|
|
114
|
+
"classifier",
|
|
115
|
+
"cloudflare",
|
|
116
|
+
"convertify",
|
|
117
|
+
"crawl",
|
|
118
|
+
"cypress/",
|
|
119
|
+
"dareboost",
|
|
120
|
+
"datanyze",
|
|
121
|
+
"dejaclick",
|
|
122
|
+
"detect",
|
|
123
|
+
"dmbrowser",
|
|
124
|
+
"download",
|
|
125
|
+
"exaleadcloudview",
|
|
126
|
+
"feed",
|
|
127
|
+
"fetcher",
|
|
128
|
+
"firephp",
|
|
129
|
+
"functionize",
|
|
130
|
+
"grab",
|
|
131
|
+
"headless",
|
|
132
|
+
"httrack",
|
|
133
|
+
"hubspot marketing grader",
|
|
134
|
+
"ibisbrowser",
|
|
135
|
+
"infrawatch",
|
|
136
|
+
"insight",
|
|
137
|
+
"inspect",
|
|
138
|
+
"iplabel",
|
|
139
|
+
"java(?!;)",
|
|
140
|
+
"library",
|
|
141
|
+
"linkcheck",
|
|
142
|
+
"mail\\.ru/",
|
|
143
|
+
"manager",
|
|
144
|
+
"measure",
|
|
145
|
+
"monitor\\b",
|
|
146
|
+
"neustar wpm",
|
|
147
|
+
"node\\b",
|
|
148
|
+
"nutch",
|
|
149
|
+
"offbyone",
|
|
150
|
+
"onetrust",
|
|
151
|
+
"optimize",
|
|
152
|
+
"pageburst",
|
|
153
|
+
"pagespeed",
|
|
154
|
+
"parser",
|
|
155
|
+
"phantomjs",
|
|
156
|
+
"pingdom",
|
|
157
|
+
"powermarks",
|
|
158
|
+
"preview",
|
|
159
|
+
"proxy",
|
|
160
|
+
"ptst[ /]\\d",
|
|
161
|
+
"retriever",
|
|
162
|
+
"rexx;",
|
|
163
|
+
"rigor",
|
|
164
|
+
"rss\\b",
|
|
165
|
+
"scrape",
|
|
166
|
+
"server",
|
|
167
|
+
"sogou",
|
|
168
|
+
"sparkler/",
|
|
169
|
+
"speedcurve",
|
|
170
|
+
"spider",
|
|
171
|
+
"splash",
|
|
172
|
+
"statuscake",
|
|
173
|
+
"supercleaner",
|
|
174
|
+
"synapse",
|
|
175
|
+
"synthetic",
|
|
176
|
+
"tools",
|
|
177
|
+
"torrent",
|
|
178
|
+
"transcoder",
|
|
179
|
+
"url",
|
|
180
|
+
"validator",
|
|
181
|
+
"virtuoso",
|
|
182
|
+
"wappalyzer",
|
|
183
|
+
"webglance",
|
|
184
|
+
"webkit2png",
|
|
185
|
+
"whatcms/",
|
|
186
|
+
"xtate/"
|
|
187
|
+
].join("|"), "i");
|
|
188
|
+
var isBot = (userAgent) => {
|
|
189
|
+
if (!userAgent) return false;
|
|
190
|
+
return botPattern.test(userAgent);
|
|
191
|
+
};
|
|
192
|
+
//#endregion
|
|
193
|
+
export { isBot };
|
|
194
|
+
|
|
195
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/useragents/patterns.json","../../src/useragents/isBot.ts"],"sourcesContent":["[\n \" daum[ /]\",\n \" deusu/\",\n \"(?:^|[^g])news(?!sapphire)\",\n \"(?<! (?:channel/|google/))google(?!(app|/google| pixel))\",\n \"(?<! cu)bots?(?:\\\\b|_)\",\n \"(?<!(?:lib))http\",\n \"(?<!cam)scan\",\n \"24x7\",\n \"@[a-z][\\\\w-]+\\\\.\",\n \"\\\\(\\\\)\",\n \"\\\\.com\\\\b\",\n \"\\\\b\\\\w+\\\\.ai\",\n \"\\\\bcursor/\",\n \"\\\\bmanus-user/\",\n \"\\\\bort/\",\n \"\\\\bperl\\\\b\",\n \"\\\\bplaywright\\\\b\",\n \"\\\\bsecurityheaders\\\\b\",\n \"\\\\bselenium\\\\b\",\n \"\\\\btime/\",\n \"\\\\|\",\n \"^[\\\\w \\\\.\\\\-\\\\(?:\\\\):%]+(?:/v?\\\\d+(?:\\\\.\\\\d+)?(?:\\\\.\\\\d{1,10})*?)?(?:,|$)\",\n \"^[\\\\w\\\\-]+/[\\\\w]+$\",\n \"^[^ ]{50,}$\",\n \"^\\\\d+\\\\b\",\n \"^\\\\W\",\n \"^\\\\w*search\\\\b\",\n \"^\\\\w+/[\\\\w\\\\(\\\\)]*$\",\n \"^\\\\w+/\\\\d\\\\.\\\\d\\\\s\\\\([\\\\w@]+\\\\)$\",\n \"^active\",\n \"^ad muncher\",\n \"^amaya\",\n \"^apache/\",\n \"^avsdevicesdk/\",\n \"^azure\",\n \"^biglotron\",\n \"^bot\",\n \"^bw/\",\n \"^clamav[ /]\",\n \"^claude-code/\",\n \"^client/\",\n \"^cobweb/\",\n \"^custom\",\n \"^ddg[_-]android\",\n \"^discourse\",\n \"^dispatch/\\\\d\",\n \"^downcast/\",\n \"^duckduckgo\",\n \"^email\",\n \"^facebook\",\n \"^getright/\",\n \"^gozilla/\",\n \"^hobbit\",\n \"^hotzonu\",\n \"^hwcdn/\",\n \"^igetter/\",\n \"^jeode/\",\n \"^jetty/\",\n \"^jigsaw\",\n \"^microsoft bits\",\n \"^movabletype\",\n \"^mozilla/\\\\d\\\\.\\\\d\\\\s[\\\\w\\\\.-]+$\",\n \"^mozilla/\\\\d\\\\.\\\\d\\\\s\\\\((?:compatible;)?(?:\\\\s?[\\\\w\\\\d-.]+\\\\/\\\\d+\\\\.\\\\d+)?\\\\)$\",\n \"^navermailapp\",\n \"^netsurf\",\n \"^offline\",\n \"^openai/\",\n \"^owler\",\n \"^php\",\n \"^postman\",\n \"^python\",\n \"^rank\",\n \"^read\",\n \"^reed\",\n \"^rest\",\n \"^rss\",\n \"^snapchat\",\n \"^space bison\",\n \"^svn\",\n \"^swcd \",\n \"^taringa\",\n \"^thumbor/\",\n \"^track\",\n \"^w3c\",\n \"^webbandit/\",\n \"^webcopier\",\n \"^wget\",\n \"^whatsapp\",\n \"^wordpress\",\n \"^xenu link sleuth\",\n \"^yahoo\",\n \"^yandex\",\n \"^zdm/\\\\d\",\n \"^zoom marketplace/\",\n \"advisor\",\n \"agent\\\\b\",\n \"analyzer\",\n \"archive\",\n \"ask jeeves/teoma\",\n \"audit\",\n \"bit\\\\.ly/\",\n \"bluecoat drtr\",\n \"browsex\",\n \"burpcollaborator\",\n \"capture\",\n \"catch\",\n \"check\\\\b\",\n \"checker\",\n \"chrome-lighthouse\",\n \"chromeframe\",\n \"classifier\",\n \"cloudflare\",\n \"convertify\",\n \"crawl\",\n \"cypress/\",\n \"dareboost\",\n \"datanyze\",\n \"dejaclick\",\n \"detect\",\n \"dmbrowser\",\n \"download\",\n \"exaleadcloudview\",\n \"feed\",\n \"fetcher\",\n \"firephp\",\n \"functionize\",\n \"grab\",\n \"headless\",\n \"httrack\",\n \"hubspot marketing grader\",\n \"ibisbrowser\",\n \"infrawatch\",\n \"insight\",\n \"inspect\",\n \"iplabel\",\n \"java(?!;)\",\n \"library\",\n \"linkcheck\",\n \"mail\\\\.ru/\",\n \"manager\",\n \"measure\",\n \"monitor\\\\b\",\n \"neustar wpm\",\n \"node\\\\b\",\n \"nutch\",\n \"offbyone\",\n \"onetrust\",\n \"optimize\",\n \"pageburst\",\n \"pagespeed\",\n \"parser\",\n \"phantomjs\",\n \"pingdom\",\n \"powermarks\",\n \"preview\",\n \"proxy\",\n \"ptst[ /]\\\\d\",\n \"retriever\",\n \"rexx;\",\n \"rigor\",\n \"rss\\\\b\",\n \"scrape\",\n \"server\",\n \"sogou\",\n \"sparkler/\",\n \"speedcurve\",\n \"spider\",\n \"splash\",\n \"statuscake\",\n \"supercleaner\",\n \"synapse\",\n \"synthetic\",\n \"tools\",\n \"torrent\",\n \"transcoder\",\n \"url\",\n \"validator\",\n \"virtuoso\",\n \"wappalyzer\",\n \"webglance\",\n \"webkit2png\",\n \"whatcms/\",\n \"xtate/\"\n]\n","import patterns from './patterns.json';\n\n// Patterns vendored from https://github.com/omrilotan/isbot (Unlicense /\n// public domain) so the same list can be used in browser, edge, and server\n// runtimes without an extra npm dependency. Refresh `patterns.json` from\n// upstream when newly-prevalent crawlers start polluting events.\n//\n// The patterns are designed to be joined into a single case-insensitive\n// regex; building it once at module load avoids paying that cost per call.\nconst botPattern = new RegExp((patterns as readonly string[]).join('|'), 'i');\n\nexport const isBot = (userAgent: string | null | undefined): boolean => {\n if (!userAgent) {\n return false;\n }\n return botPattern.test(userAgent);\n};\n"],"mappings":";;ACSA,IAAM,aAAa,IAAI,OAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,CAAA,CAA+B,KAAK,GAAG,GAAG,GAAG;AAE5E,IAAa,SAAS,cAAkD;CACtE,IAAI,CAAC,WACH,OAAO;CAET,OAAO,WAAW,KAAK,SAAS;AAClC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isBot.d.ts","sourceRoot":"","sources":["../../src/useragents/isBot.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,KAAK,GAAI,WAAW,MAAM,GAAG,IAAI,GAAG,SAAS,KAAG,OAK5D,CAAC"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
declare const _default: [
|
|
2
|
+
" daum[ /]",
|
|
3
|
+
" deusu/",
|
|
4
|
+
"(?:^|[^g])news(?!sapphire)",
|
|
5
|
+
"(?<! (?:channel/|google/))google(?!(app|/google| pixel))",
|
|
6
|
+
"(?<! cu)bots?(?:\\b|_)",
|
|
7
|
+
"(?<!(?:lib))http",
|
|
8
|
+
"(?<!cam)scan",
|
|
9
|
+
"24x7",
|
|
10
|
+
"@[a-z][\\w-]+\\.",
|
|
11
|
+
"\\(\\)",
|
|
12
|
+
"\\.com\\b",
|
|
13
|
+
"\\b\\w+\\.ai",
|
|
14
|
+
"\\bcursor/",
|
|
15
|
+
"\\bmanus-user/",
|
|
16
|
+
"\\bort/",
|
|
17
|
+
"\\bperl\\b",
|
|
18
|
+
"\\bplaywright\\b",
|
|
19
|
+
"\\bsecurityheaders\\b",
|
|
20
|
+
"\\bselenium\\b",
|
|
21
|
+
"\\btime/",
|
|
22
|
+
"\\|",
|
|
23
|
+
"^[\\w \\.\\-\\(?:\\):%]+(?:/v?\\d+(?:\\.\\d+)?(?:\\.\\d{1,10})*?)?(?:,|$)",
|
|
24
|
+
"^[\\w\\-]+/[\\w]+$",
|
|
25
|
+
"^[^ ]{50,}$",
|
|
26
|
+
"^\\d+\\b",
|
|
27
|
+
"^\\W",
|
|
28
|
+
"^\\w*search\\b",
|
|
29
|
+
"^\\w+/[\\w\\(\\)]*$",
|
|
30
|
+
"^\\w+/\\d\\.\\d\\s\\([\\w@]+\\)$",
|
|
31
|
+
"^active",
|
|
32
|
+
"^ad muncher",
|
|
33
|
+
"^amaya",
|
|
34
|
+
"^apache/",
|
|
35
|
+
"^avsdevicesdk/",
|
|
36
|
+
"^azure",
|
|
37
|
+
"^biglotron",
|
|
38
|
+
"^bot",
|
|
39
|
+
"^bw/",
|
|
40
|
+
"^clamav[ /]",
|
|
41
|
+
"^claude-code/",
|
|
42
|
+
"^client/",
|
|
43
|
+
"^cobweb/",
|
|
44
|
+
"^custom",
|
|
45
|
+
"^ddg[_-]android",
|
|
46
|
+
"^discourse",
|
|
47
|
+
"^dispatch/\\d",
|
|
48
|
+
"^downcast/",
|
|
49
|
+
"^duckduckgo",
|
|
50
|
+
"^email",
|
|
51
|
+
"^facebook",
|
|
52
|
+
"^getright/",
|
|
53
|
+
"^gozilla/",
|
|
54
|
+
"^hobbit",
|
|
55
|
+
"^hotzonu",
|
|
56
|
+
"^hwcdn/",
|
|
57
|
+
"^igetter/",
|
|
58
|
+
"^jeode/",
|
|
59
|
+
"^jetty/",
|
|
60
|
+
"^jigsaw",
|
|
61
|
+
"^microsoft bits",
|
|
62
|
+
"^movabletype",
|
|
63
|
+
"^mozilla/\\d\\.\\d\\s[\\w\\.-]+$",
|
|
64
|
+
"^mozilla/\\d\\.\\d\\s\\((?:compatible;)?(?:\\s?[\\w\\d-.]+\\/\\d+\\.\\d+)?\\)$",
|
|
65
|
+
"^navermailapp",
|
|
66
|
+
"^netsurf",
|
|
67
|
+
"^offline",
|
|
68
|
+
"^openai/",
|
|
69
|
+
"^owler",
|
|
70
|
+
"^php",
|
|
71
|
+
"^postman",
|
|
72
|
+
"^python",
|
|
73
|
+
"^rank",
|
|
74
|
+
"^read",
|
|
75
|
+
"^reed",
|
|
76
|
+
"^rest",
|
|
77
|
+
"^rss",
|
|
78
|
+
"^snapchat",
|
|
79
|
+
"^space bison",
|
|
80
|
+
"^svn",
|
|
81
|
+
"^swcd ",
|
|
82
|
+
"^taringa",
|
|
83
|
+
"^thumbor/",
|
|
84
|
+
"^track",
|
|
85
|
+
"^w3c",
|
|
86
|
+
"^webbandit/",
|
|
87
|
+
"^webcopier",
|
|
88
|
+
"^wget",
|
|
89
|
+
"^whatsapp",
|
|
90
|
+
"^wordpress",
|
|
91
|
+
"^xenu link sleuth",
|
|
92
|
+
"^yahoo",
|
|
93
|
+
"^yandex",
|
|
94
|
+
"^zdm/\\d",
|
|
95
|
+
"^zoom marketplace/",
|
|
96
|
+
"advisor",
|
|
97
|
+
"agent\\b",
|
|
98
|
+
"analyzer",
|
|
99
|
+
"archive",
|
|
100
|
+
"ask jeeves/teoma",
|
|
101
|
+
"audit",
|
|
102
|
+
"bit\\.ly/",
|
|
103
|
+
"bluecoat drtr",
|
|
104
|
+
"browsex",
|
|
105
|
+
"burpcollaborator",
|
|
106
|
+
"capture",
|
|
107
|
+
"catch",
|
|
108
|
+
"check\\b",
|
|
109
|
+
"checker",
|
|
110
|
+
"chrome-lighthouse",
|
|
111
|
+
"chromeframe",
|
|
112
|
+
"classifier",
|
|
113
|
+
"cloudflare",
|
|
114
|
+
"convertify",
|
|
115
|
+
"crawl",
|
|
116
|
+
"cypress/",
|
|
117
|
+
"dareboost",
|
|
118
|
+
"datanyze",
|
|
119
|
+
"dejaclick",
|
|
120
|
+
"detect",
|
|
121
|
+
"dmbrowser",
|
|
122
|
+
"download",
|
|
123
|
+
"exaleadcloudview",
|
|
124
|
+
"feed",
|
|
125
|
+
"fetcher",
|
|
126
|
+
"firephp",
|
|
127
|
+
"functionize",
|
|
128
|
+
"grab",
|
|
129
|
+
"headless",
|
|
130
|
+
"httrack",
|
|
131
|
+
"hubspot marketing grader",
|
|
132
|
+
"ibisbrowser",
|
|
133
|
+
"infrawatch",
|
|
134
|
+
"insight",
|
|
135
|
+
"inspect",
|
|
136
|
+
"iplabel",
|
|
137
|
+
"java(?!;)",
|
|
138
|
+
"library",
|
|
139
|
+
"linkcheck",
|
|
140
|
+
"mail\\.ru/",
|
|
141
|
+
"manager",
|
|
142
|
+
"measure",
|
|
143
|
+
"monitor\\b",
|
|
144
|
+
"neustar wpm",
|
|
145
|
+
"node\\b",
|
|
146
|
+
"nutch",
|
|
147
|
+
"offbyone",
|
|
148
|
+
"onetrust",
|
|
149
|
+
"optimize",
|
|
150
|
+
"pageburst",
|
|
151
|
+
"pagespeed",
|
|
152
|
+
"parser",
|
|
153
|
+
"phantomjs",
|
|
154
|
+
"pingdom",
|
|
155
|
+
"powermarks",
|
|
156
|
+
"preview",
|
|
157
|
+
"proxy",
|
|
158
|
+
"ptst[ /]\\d",
|
|
159
|
+
"retriever",
|
|
160
|
+
"rexx;",
|
|
161
|
+
"rigor",
|
|
162
|
+
"rss\\b",
|
|
163
|
+
"scrape",
|
|
164
|
+
"server",
|
|
165
|
+
"sogou",
|
|
166
|
+
"sparkler/",
|
|
167
|
+
"speedcurve",
|
|
168
|
+
"spider",
|
|
169
|
+
"splash",
|
|
170
|
+
"statuscake",
|
|
171
|
+
"supercleaner",
|
|
172
|
+
"synapse",
|
|
173
|
+
"synthetic",
|
|
174
|
+
"tools",
|
|
175
|
+
"torrent",
|
|
176
|
+
"transcoder",
|
|
177
|
+
"url",
|
|
178
|
+
"validator",
|
|
179
|
+
"virtuoso",
|
|
180
|
+
"wappalyzer",
|
|
181
|
+
"webglance",
|
|
182
|
+
"webkit2png",
|
|
183
|
+
"whatcms/",
|
|
184
|
+
"xtate/"
|
|
185
|
+
]
|
|
186
|
+
;
|
|
187
|
+
|
|
188
|
+
export default _default;
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@eventuras/core",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Core utilities for Eventuras",
|
|
5
|
+
"homepage": "https://github.com/losol/origo/tree/main/packages/core#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/losol/origo/issues"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/losol/origo.git",
|
|
12
|
+
"directory": "packages/core"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
"./regex": {
|
|
18
|
+
"types": "./dist/regex/index.d.ts",
|
|
19
|
+
"import": "./dist/regex/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./datetime": {
|
|
22
|
+
"types": "./dist/datetime/index.d.ts",
|
|
23
|
+
"import": "./dist/datetime/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./currency": {
|
|
26
|
+
"types": "./dist/currency/index.d.ts",
|
|
27
|
+
"import": "./dist/currency/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./url": {
|
|
30
|
+
"types": "./dist/url/index.d.ts",
|
|
31
|
+
"import": "./dist/url/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./errors": {
|
|
34
|
+
"types": "./dist/errors/index.d.ts",
|
|
35
|
+
"import": "./dist/errors/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./useragents": {
|
|
38
|
+
"types": "./dist/useragents/index.d.ts",
|
|
39
|
+
"import": "./dist/useragents/index.js"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"dist"
|
|
44
|
+
],
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"vite": "^8.1.0",
|
|
47
|
+
"@eventuras/vite-config": "0.2.2",
|
|
48
|
+
"@eventuras/eslint-config": "1.0.3",
|
|
49
|
+
"@eventuras/typescript-config": "1.0.0"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "vite build",
|
|
53
|
+
"dev": "vite build --watch",
|
|
54
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
55
|
+
}
|
|
56
|
+
}
|