diff --git a/.nvmrc b/.nvmrc
index 25bf17f..2bd5a0a 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-18
\ No newline at end of file
+22
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c1d4d05..02e2e01 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,17 @@
# Changelog
+## [4.0.0](https://github.com/KemingHe/OSU/compare/v3.1.1...v4.0.0) (2024-09-22)
+
+
+### ⚠ BREAKING CHANGES
+
+* **package.json:** due to the sync/async import (bundling) separation, all previously defined import
+will work as normal whilst async must be imported through @keminghe/osu/async
+
+### Bug Fixes
+
+* **package.json:** separated synd and async exports ([3ffb464](https://github.com/KemingHe/OSU/commit/3ffb464c36b6f69fdd2ef8967d2769073c63a681))
+
## [3.1.1](https://github.com/KemingHe/OSU/compare/v3.1.0...v3.1.1) (2024-09-21)
## [3.1.0](https://github.com/KemingHe/OSU/compare/v3.0.0...v3.1.0) (2024-09-21)
diff --git a/README.md b/README.md
index cb35358..b6a3bf1 100644
--- a/README.md
+++ b/README.md
@@ -26,8 +26,8 @@
@@ -42,20 +42,20 @@
> [!IMPORTANT]
>
-> **Now requires Node 18 and up!** Please upgrade your node version.
+> **Async** accessors depend on [`jsdom`](https://github.com/jsdom/jsdom) and are `node`-only. For example: `import { getResearchPostingsAsync } from "@keminghe/osu/async";`
>
-> **Versions 1.1.0 and below are DEPRECATED!** Please upgrade to the latest version.
+> Use import from the **synchronous** `@keminghe/osu` if you are working in a browswer environment.
> [!NOTE]
>
-> Build by students, for students, with :heart:. **NOT** affiliated nor endorsed by official OSU.
+> Build by students, for students, with :heart:. **NOT** affiliated by *official* OSU.
>
-> * Publicly-available data about OSU undergrad majors [here](https://undergrad.osu.edu/majors-and-academics/majors).
-> * Publicly-available data about OSU student organizations [here](https://activities.osu.edu/involvement/student_organizations).
+> * Publicly-available *official* data about OSU undergrad majors [here](https://undergrad.osu.edu/majors-and-academics/majors).
+> * Publicly-available *official* data about OSU student orgs [here](https://activities.osu.edu/involvement/student_organizations).
## :gear: Installation
-Requires [Node.js](https://nodejs.org/en/download/package-manager) >= **18**
+Requires [Node.js](https://nodejs.org/en/download/package-manager) >= **8.1.0** (es2017)
```bash
# Using npm:
@@ -105,28 +105,42 @@ BUCKEYEMAIL_PATTERN.test("buckeyemail.1@buckeyemail.osu.edu"); // true
### Accessing All Undergrad Majors
```typescript
-import { getUndergradMajors, type UndergradMajor } from "@keminghe/osu";
+import {
+ getUndergradMajors,
+ type UndergradMajor,
+ UndergradMajorSchema,
+} from "@keminghe/osu";
const majors: UndergradMajor[] = getUndergradMajors();
+UndergradMajorSchema.array().parse(majors);
console.log(majors);
```
### Accessing All Student Organizations
```typescript
-import { getStudentOrgs, type StudentOrg } from "@keminghe/osu";
+import {
+ getStudentOrgs,
+ type StudentOrg,
+ StudentOrgSchema,
+} from "@keminghe/osu";
const orgs: StudentOrg[] = getStudentOrgs();
+StudentOrgSchema.array().parse(orgs);
console.log(orgs);
```
-### Accessing All Undergrad Research Postings
+### Accessing All Undergrad Research Postings (Async!)
```typescript
-import { getResearchPostingsAsync } from "@keminghe/osu";
+import { ResearchPostingSchema, type ResearchPosting } from "@keminghe/osu";
+
+// IMPORTANT: note the different async import path.
+import { getResearchPostingsAsync } from "@keminghe/osu/async";
getResearchPostingsAsync()
.then((researchPostings) => {
+ ResearchPostingSchema.array().parse(researchPostings);
console.log(researchPostings);
})
.catch((error) => {
diff --git a/package.json b/package.json
index e57e5fe..b15e320 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@keminghe/osu",
- "version": "3.1.1",
+ "version": "4.0.0",
"description": "Unofficial, publicly available data about The Ohio State University.",
"keywords": [
"data",
@@ -15,7 +15,25 @@
],
"main": "dist/index.js",
"module": "dist/index.mjs",
+ "exports": {
+ ".": {
+ "import": "./dist/index.mjs",
+ "require": "./dist/index.js"
+ },
+ "./async": {
+ "import": "./dist/index.async.mjs",
+ "require": "./dist/index.async.js"
+ }
+ },
"types": "dist/index.d.ts",
+ "typesVersions": {
+ "*": {
+ "async": [
+ "./dist/index.async.d.ts"
+ ]
+ }
+ },
+ "sideEffects": false,
"files": [
"dist",
"README.md",
@@ -50,8 +68,9 @@
"build": "tsup",
"postbuild": "echo 'Build complete: src/ -> dist/'"
},
+ "packageManager": "pnpm@9.11.0+sha512.0a203ffaed5a3f63242cd064c8fb5892366c103e328079318f78062f24ea8c9d50bc6a47aa3567cabefd824d170e78fa2745ed1f16b132e16436146b7688f19b",
"dependencies": {
- "jsdom": "^25.0.0",
+ "jsdom": "^25.0.1",
"zod": "^3.23.8"
},
"devDependencies": {
@@ -76,7 +95,7 @@
"vitest": "^2.1.1"
},
"engines": {
- "node": ">=14"
+ "node": ">=8.10.0"
},
"os": [
"linux",
@@ -86,6 +105,5 @@
"cpu": [
"x64",
"arm64"
- ],
- "packageManager": "pnpm@9.11.0+sha512.0a203ffaed5a3f63242cd064c8fb5892366c103e328079318f78062f24ea8c9d50bc6a47aa3567cabefd824d170e78fa2745ed1f16b132e16436146b7688f19b"
+ ]
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 775eb83..4f8d20b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,8 +9,8 @@ importers:
.:
dependencies:
jsdom:
- specifier: ^25.0.0
- version: 25.0.0
+ specifier: ^25.0.1
+ version: 25.0.1
zod:
specifier: ^3.23.8
version: 3.23.8
@@ -35,7 +35,7 @@ importers:
version: 22.5.5
'@vitest/coverage-v8':
specifier: ^2.1.1
- version: 2.1.1(vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.0))
+ version: 2.1.1(vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.1))
commitizen:
specifier: ^4.3.0
version: 4.3.0(@types/node@22.5.5)(typescript@5.6.2)
@@ -71,7 +71,7 @@ importers:
version: 4.3.2(typescript@5.6.2)(vite@5.4.7(@types/node@22.5.5))
vitest:
specifier: ^2.1.1
- version: 2.1.1(@types/node@22.5.5)(jsdom@25.0.0)
+ version: 2.1.1(@types/node@22.5.5)(jsdom@25.0.1)
packages:
@@ -1738,8 +1738,8 @@ packages:
jsbn@1.1.0:
resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==}
- jsdom@25.0.0:
- resolution: {integrity: sha512-OhoFVT59T7aEq75TVw9xxEfkXgacpqAhQaYgP9y/fDqWQCMB/b1H66RfmPm/MaeaAIU9nDwMOVTlPN51+ao6CQ==}
+ jsdom@25.0.1:
+ resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==}
engines: {node: '>=18'}
peerDependencies:
canvas: ^2.11.2
@@ -2171,9 +2171,6 @@ packages:
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
- psl@1.9.0:
- resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
-
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@@ -2182,9 +2179,6 @@ packages:
resolution: {integrity: sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==}
engines: {node: '>=12.20'}
- querystringify@2.2.0:
- resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
-
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -2233,9 +2227,6 @@ packages:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
- requires-port@1.0.0:
- resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
-
resolve-alpn@1.2.1:
resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
@@ -2511,6 +2502,13 @@ packages:
resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
engines: {node: '>=14.0.0'}
+ tldts-core@6.1.47:
+ resolution: {integrity: sha512-6SWyFMnlst1fEt7GQVAAu16EGgFK0cLouH/2Mk6Ftlwhv3Ol40L0dlpGMcnnNiiOMyD2EV/aF3S+U2nKvvLvrA==}
+
+ tldts@6.1.47:
+ resolution: {integrity: sha512-R/K2tZ5MiY+mVrnSkNJkwqYT2vUv1lcT6wJvd2emGaMJ7PHUGRY4e3tUsdFCXgqxi2QgbHjL3yJgXCo40v9Hxw==}
+ hasBin: true
+
tmp@0.0.33:
resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
engines: {node: '>=0.6.0'}
@@ -2523,9 +2521,9 @@ packages:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
- tough-cookie@4.1.4:
- resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
- engines: {node: '>=6'}
+ tough-cookie@5.0.0:
+ resolution: {integrity: sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==}
+ engines: {node: '>=16'}
tr46@1.0.1:
resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
@@ -2628,10 +2626,6 @@ packages:
universal-user-agent@6.0.1:
resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==}
- universalify@0.2.0:
- resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
- engines: {node: '>= 4.0.0'}
-
universalify@2.0.1:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
@@ -2644,9 +2638,6 @@ packages:
resolution: {integrity: sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- url-parse@1.5.10:
- resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
-
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@@ -3335,7 +3326,7 @@ snapshots:
'@types/tough-cookie@4.0.5': {}
- '@vitest/coverage-v8@2.1.1(vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.0))':
+ '@vitest/coverage-v8@2.1.1(vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.1))':
dependencies:
'@ampproject/remapping': 2.3.0
'@bcoe/v8-coverage': 0.2.3
@@ -3349,7 +3340,7 @@ snapshots:
std-env: 3.7.0
test-exclude: 7.0.1
tinyrainbow: 1.2.0
- vitest: 2.1.1(@types/node@22.5.5)(jsdom@25.0.0)
+ vitest: 2.1.1(@types/node@22.5.5)(jsdom@25.0.1)
transitivePeerDependencies:
- supports-color
@@ -4450,7 +4441,7 @@ snapshots:
jsbn@1.1.0: {}
- jsdom@25.0.0:
+ jsdom@25.0.1:
dependencies:
cssstyle: 4.1.0
data-urls: 5.0.0
@@ -4465,7 +4456,7 @@ snapshots:
rrweb-cssom: 0.7.1
saxes: 6.0.0
symbol-tree: 3.2.4
- tough-cookie: 4.1.4
+ tough-cookie: 5.0.0
w3c-xmlserializer: 5.0.0
webidl-conversions: 7.0.0
whatwg-encoding: 3.1.1
@@ -4861,16 +4852,12 @@ snapshots:
proxy-from-env@1.1.0: {}
- psl@1.9.0: {}
-
punycode@2.3.1: {}
pupa@3.1.0:
dependencies:
escape-goat: 4.0.0
- querystringify@2.2.0: {}
-
queue-microtask@1.2.3: {}
quick-lru@5.1.1: {}
@@ -4952,8 +4939,6 @@ snapshots:
require-from-string@2.0.2:
optional: true
- requires-port@1.0.0: {}
-
resolve-alpn@1.2.1: {}
resolve-dir@1.0.1:
@@ -5207,6 +5192,12 @@ snapshots:
tinyspy@3.0.2: {}
+ tldts-core@6.1.47: {}
+
+ tldts@6.1.47:
+ dependencies:
+ tldts-core: 6.1.47
+
tmp@0.0.33:
dependencies:
os-tmpdir: 1.0.2
@@ -5217,12 +5208,9 @@ snapshots:
dependencies:
is-number: 7.0.0
- tough-cookie@4.1.4:
+ tough-cookie@5.0.0:
dependencies:
- psl: 1.9.0
- punycode: 2.3.1
- universalify: 0.2.0
- url-parse: 1.5.10
+ tldts: 6.1.47
tr46@1.0.1:
dependencies:
@@ -5307,8 +5295,6 @@ snapshots:
universal-user-agent@6.0.1: {}
- universalify@0.2.0: {}
-
universalify@2.0.1: {}
update-notifier@7.1.0:
@@ -5328,11 +5314,6 @@ snapshots:
url-join@5.0.0: {}
- url-parse@1.5.10:
- dependencies:
- querystringify: 2.2.0
- requires-port: 1.0.0
-
util-deprecate@1.0.2: {}
validate-npm-package-license@3.0.4:
@@ -5377,7 +5358,7 @@ snapshots:
'@types/node': 22.5.5
fsevents: 2.3.3
- vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.0):
+ vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.1):
dependencies:
'@vitest/expect': 2.1.1
'@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.7(@types/node@22.5.5))
@@ -5400,7 +5381,7 @@ snapshots:
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 22.5.5
- jsdom: 25.0.0
+ jsdom: 25.0.1
transitivePeerDependencies:
- less
- lightningcss
diff --git a/src/autoGenerated/latestAllStudentOrgs.ts b/src/autoGenerated/latestAllStudentOrgs.ts
index 874e4a5..eaf1b78 100644
--- a/src/autoGenerated/latestAllStudentOrgs.ts
+++ b/src/autoGenerated/latestAllStudentOrgs.ts
@@ -1,6 +1,6 @@
// ./src/autoGenerated/latestAllStudentOrgs.ts
//
-// AUTO-GENERATED on 2024-09-21T19:54:50.205Z. DO NOT MODIFY.
+// AUTO-GENERATED on 2024-09-22T19:01:00.679Z. DO NOT MODIFY.
// For details see "@scripts/genStudentOrgs/".
// Type imports.
diff --git a/src/autoGenerated/latestAllUndergradMajors.ts b/src/autoGenerated/latestAllUndergradMajors.ts
index 526b51f..b404164 100644
--- a/src/autoGenerated/latestAllUndergradMajors.ts
+++ b/src/autoGenerated/latestAllUndergradMajors.ts
@@ -1,6 +1,6 @@
// ./src/autoGenerated/latestAllUndergradMajors.ts
//
-// AUTO-GENERATED on 2024-09-21T19:54:50.260Z. DO NOT MODIFY.
+// AUTO-GENERATED on 2024-09-22T19:01:00.754Z. DO NOT MODIFY.
// For details see "./scripts/genUndergradMajors/".
// Type imports.
diff --git a/src/constants/__snapshots__/userAgents.test.ts.snap b/src/constants/__snapshots__/userAgents.test.ts.snap
new file mode 100644
index 0000000..3b3bfb0
--- /dev/null
+++ b/src/constants/__snapshots__/userAgents.test.ts.snap
@@ -0,0 +1,21 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`The UserAgents constant array > matches the snapshot 1`] = `
+[
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.1",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.3",
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.3",
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/25.0 Chrome/121.0.0.0 Safari/537.3",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.3",
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.3",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.3",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Unique/100.7.6266.6",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 OPR/112.0.0.",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.",
+ "Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.3",
+ "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.3",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.",
+]
+`;
diff --git a/src/constants/userAgents.test.ts b/src/constants/userAgents.test.ts
new file mode 100644
index 0000000..e70d9a9
--- /dev/null
+++ b/src/constants/userAgents.test.ts
@@ -0,0 +1,17 @@
+// ./src/constants/userAgents.test.ts
+//
+// Snapshot test for the UserAgents constant array.
+
+// Vitest essential imports.
+import { describe, expect, it } from "vitest";
+
+// Testing target import.
+import UserAgents from "@src/constants/userAgents";
+
+// -----------------------------------------------------------------------------
+// UserAgents constant array snapshot test suite.
+describe("The UserAgents constant array", () => {
+ it("matches the snapshot", () => {
+ expect(UserAgents).toMatchSnapshot();
+ });
+});
diff --git a/src/constants/userAgents.ts b/src/constants/userAgents.ts
new file mode 100644
index 0000000..7333b84
--- /dev/null
+++ b/src/constants/userAgents.ts
@@ -0,0 +1,23 @@
+// ./src/constants/userAgents.ts
+//
+// Const array of user agents for fetching data from OSU websites.
+// Ref: ./data/mostCommonDesktopUserAgents/07/28/2024.json
+
+const UserAgents: string[] = [
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.1",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.3",
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.3",
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/25.0 Chrome/121.0.0.0 Safari/537.3",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.3",
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.3",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.3",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Unique/100.7.6266.6",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 OPR/112.0.0.",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.",
+ "Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.3",
+ "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.3",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.",
+];
+export default UserAgents;
diff --git a/src/index.async.ts b/src/index.async.ts
new file mode 100644
index 0000000..c837f0d
--- /dev/null
+++ b/src/index.async.ts
@@ -0,0 +1,5 @@
+// ./src/index.async.ts
+//
+// OSU package entrypoint, specifically for jsdom (node-only) async utilities.
+
+export * from "@src/researchPostings/getResearchPostingsAsync";
diff --git a/src/index.test.ts b/src/index.test.ts
index 67cd8ba..e8065cc 100644
--- a/src/index.test.ts
+++ b/src/index.test.ts
@@ -1,12 +1,13 @@
// ./src/index.test.ts
//
-// Integration test for the OSU package entrypoint.
+// Integration test for the OSU package entrypoints.
// Vitest essential imports.
import { describe, expect, it } from "vitest";
-// Testing module imports.
+// Testing target imports.
import * as entrypoint from "@src/index";
+import * as asyncEntrypoint from "@src/index.async";
// -----------------------------------------------------------------------------
// Entrypoint integration test suite.
@@ -49,6 +50,6 @@ describe("The OSU package entrypoint", () => {
});
it("exports the getResearchPostingsAsync utility function", () => {
- expect(entrypoint).toHaveProperty("getResearchPostingsAsync");
+ expect(asyncEntrypoint).toHaveProperty("getResearchPostingsAsync");
});
});
diff --git a/src/index.ts b/src/index.ts
index afce1e6..eb1688f 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,6 +1,6 @@
// ./src/index.ts
//
-// OSU package entrypoint, for exporting all and utilities.
+// OSU package entrypoint, specifically for browser-node agnostic utilities.
// OSU name-dot-number and email utility exports
export * from "@src/validators/validators";
@@ -13,4 +13,3 @@ export * from "@src/schemas/UndergradMajor";
export * from "@src/undergradMajors/getUndergradMajors";
export * from "@src/schemas/ResearchPosting";
-export * from "@src/researchPostings/getResearchPostingsAsync";
diff --git a/src/researchPostings/fetchUndergradResearchPostingsOnPageNum.ts b/src/researchPostings/fetchUndergradResearchPostingsOnPageNum.ts
index 7715f0e..7332a4e 100644
--- a/src/researchPostings/fetchUndergradResearchPostingsOnPageNum.ts
+++ b/src/researchPostings/fetchUndergradResearchPostingsOnPageNum.ts
@@ -5,12 +5,13 @@
// jsdom essential imports.
import { JSDOM } from "jsdom";
-import type { ResearchPosting } from "@src/schemas/ResearchPosting";
// Local type and util imports.
+import type { ResearchPosting } from "@src/schemas/ResearchPosting";
import {
getAttributeFromSelector,
getTextContentFromElement,
getTextContentFromSelector,
+ randomUserAgent,
} from "@src/utils/fetchHelpers";
/**
@@ -75,8 +76,7 @@ export async function fetchUndergradResearchPostingsOnPageNum(
"Sec-Fetch-User": "?1",
"Sec-Gpc": "1",
"Upgrade-Insecure-Requests": "1",
- "User-Agent":
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
+ "User-Agent": randomUserAgent(),
},
cache: "no-store",
});
diff --git a/src/utils/fetchHelpers.randomUserAgent.test.ts b/src/utils/fetchHelpers.randomUserAgent.test.ts
new file mode 100644
index 0000000..2cfa823
--- /dev/null
+++ b/src/utils/fetchHelpers.randomUserAgent.test.ts
@@ -0,0 +1,29 @@
+// ./src/utils/fetchHelpers.randomUserAgent.test.ts
+//
+// Unittests for the randomUserAgent function in fetchHelpers.ts.
+
+// Vitest essential imports.
+import { describe, expect, it } from "vitest";
+
+// Local constant import.
+import UserAgents from "@src/constants/userAgents";
+
+// Testing target import.
+import { randomUserAgent } from "@src/utils/fetchHelpers";
+
+// -----------------------------------------------------------------------------
+// Test suite for randomUserAgent function.
+describe("The randomUserAgent fetch helper function", () => {
+ for (let i = 0; i < 10; i++) {
+ it("returns a random user agent string from the UserAgents constant", () => {
+ // Call the randomUserAgent function.
+ const userAgent: string = randomUserAgent();
+
+ // Expect the returned user agent to be a string.
+ expect(typeof userAgent).toBe("string");
+
+ // Expect the returned user agent to be a valid user agent string.
+ expect(UserAgents.includes(userAgent)).toBe(true);
+ });
+ }
+});
diff --git a/src/utils/fetchHelpers.ts b/src/utils/fetchHelpers.ts
index 87fa79d..0a15301 100644
--- a/src/utils/fetchHelpers.ts
+++ b/src/utils/fetchHelpers.ts
@@ -2,6 +2,9 @@
//
// Helper functions for fetching and querying data.
+// Local constant import.
+import UserAgents from "@src/constants/userAgents";
+
// -----------------------------------------------------------------------------
export function getTextContentFromElement(
element: Element,
@@ -127,3 +130,16 @@ export async function randomDelay({
const delay: number = Math.floor(Math.random() * (max - min + 1) + min);
return new Promise((resolve) => setTimeout(resolve, delay));
}
+
+// -----------------------------------------------------------------------------
+export function randomUserAgent(): string {
+ const randomAgent: string | undefined =
+ UserAgents[Math.floor(Math.random() * UserAgents.length)];
+
+ // randomeAgent is always defined, but must be checked for typescript.
+ /* v8 ignore next 3 */
+ if (!randomAgent) {
+ throw new Error("Failed to generate random user agent.");
+ }
+ return randomAgent;
+}
diff --git a/tsup.config.ts b/tsup.config.ts
index 79e059c..1f9c428 100644
--- a/tsup.config.ts
+++ b/tsup.config.ts
@@ -19,10 +19,15 @@ export default defineConfig(
{
// Core. -------------------------------------------------------------------
- entry : ["src/index.ts"], // Source entrypoint.
- format : ["cjs", "esm"], // Output formats: CommonJS and ESM.
- target : "node18", // Max backewards compatibility.
- outDir : "dist", // Output directory.
+ // Source entrypoint, separated for better tree-shaking.
+ entry: [
+ "src/index.ts",
+ "src/index.async.ts",
+ ],
+
+ format: ["cjs", "esm"], // Output formats: CommonJS and ESM.
+ target: "es2017", // Max browser and node (12+) compatibility.
+ outDir: "dist", // Output directory.
dts : true, // Generate declaration files.
sourcemap: true, // Generate source maps, allow reverting to original code.