github-pinned-repo-sdk 1.0.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 ADDED
@@ -0,0 +1,84 @@
1
+ # GitHub Pinned Repository SDK
2
+
3
+ [![npm version](https://img.shields.io/npm/v/github-pinned-repo-sdk)](https://npmjs.com/package/github-pinned-repo-sdk)
4
+ [![npm downloads](https://img.shields.io/npm/dm/github-pinned-repo-sdk)](https://npmjs.com/package/github-pinned-repo-sdk)
5
+ [![License](https://img.shields.io/npm/l/github-pinned-repo-sdk)](https://github.com/luisoos/github-pinned-repo-sdk/blob/main/LICENSE)
6
+
7
+ Fetch GitHub user profile + pinned repositories with full TypeScript support.
8
+
9
+ **Based on** [better-github-api](https://github.com/luisoos/better-github-api)
10
+
11
+ ## ๐Ÿš€ Installation
12
+ ```bash
13
+ npm i github-pinned-repo-sdk
14
+
15
+ // OR using yarn
16
+
17
+ yarn add github-pinned-repo-sdk
18
+ ```
19
+
20
+ ## ๐Ÿ“– Usage
21
+ ```ts
22
+ import { getPinnedRepos } from 'github-pinned-repo-sdk';
23
+
24
+ const data = await getPinnedRepos('sindresorhus');
25
+ ```
26
+
27
+ #### TypeScript
28
+ Define types:
29
+ ```ts
30
+ import { getPinnedRepos } from 'github-pinned-repo-sdk';
31
+
32
+ type ApiResponse = {
33
+ user: GithubUser;
34
+ pinned_repos: PinnedRepo[];
35
+ pinned_repos_total_stars: number;
36
+ };
37
+
38
+ const data: ApiResponse = await getPinnedRepos('sindresorhus');
39
+ ```
40
+
41
+ ## ๐Ÿงช Testing
42
+ Run tests using vitest:
43
+ ```bash
44
+ npm test
45
+ ```
46
+
47
+ ### In node console
48
+ ```bash
49
+ node -e "import('./dist/index.js').then(async m=>{const {JSDOM}=await import('jsdom');global.DOMParser=new JSDOM().window.DOMParser;const data=await m.getPinnedRepos('luisoos');console.log(data)})"
50
+ ```
51
+
52
+ ## ๐ŸŒ Astro Example
53
+
54
+ ```astro
55
+ ---
56
+ import { getPinnedRepos } from 'github-pinned-repo-sdk';
57
+ const { user, pinned_repos } = await getPinnedRepos('torvalds');
58
+ ***
59
+ <h1>{user.login}</h1>
60
+ <ul>
61
+ {pinned_repos.map(repo => (
62
+ <li>
63
+ <a href={repo.link}>{repo.repo}</a>
64
+ <span>โญ {repo.stars.toLocaleString()}</span>
65
+ </li>
66
+ ))}
67
+ </ul>
68
+ ```
69
+
70
+ ## ๐Ÿ“ฆ Features
71
+
72
+ - โœ… **No dependencies** (pure `fetch` + `DOMParser`)
73
+ - โœ… **Full TypeScript** (IntelliSense ready)
74
+ - โœ… **Browser + Node** compatible
75
+ - โœ… **GitHub API** + HTML scraping hybrid
76
+ - โœ… **Rate-limit safe** (User-Agent headers)
77
+
78
+ ## ๐Ÿ™Œ Credits
79
+
80
+ Inspired by [better-github-api](https://github.com/luisoos/better-github-api)
81
+
82
+ ## ๐Ÿ“„ License
83
+
84
+ MIT ยฉ [luisoos](https://github.com/luisoos)
@@ -0,0 +1,27 @@
1
+ type GithubUser = {
2
+ login: string;
3
+ id: number;
4
+ avatar_url: string;
5
+ html_url: string;
6
+ public_repos: number;
7
+ followers: number;
8
+ following: number;
9
+ };
10
+ type PinnedRepo = {
11
+ owner: string;
12
+ repo: string;
13
+ internal_link?: string;
14
+ link?: string;
15
+ description?: string;
16
+ language?: string;
17
+ languageColor?: string;
18
+ stars: number;
19
+ forks: number;
20
+ };
21
+ export declare function getPinnedRepos(username: string): Promise<{
22
+ user: GithubUser;
23
+ pinned_repos: PinnedRepo[];
24
+ pinned_repos_total_stars: number;
25
+ }>;
26
+ export {};
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,KAAK,UAAU,GAAG;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAMF,KAAK,UAAU,GAAG;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9D,IAAI,EAAE,UAAU,CAAC;IACjB,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,wBAAwB,EAAE,MAAM,CAAC;CAClC,CAAC,CA8ED"}
package/dist/index.js ADDED
@@ -0,0 +1,66 @@
1
+ export async function getPinnedRepos(username) {
2
+ // 1. Official GitHub API for user data
3
+ const apiUrl = `https://api.github.com/users/${username}`;
4
+ const apiResponse = await fetch(apiUrl, {
5
+ headers: { 'User-Agent': 'github-pinned-sdk/1.0.0' }
6
+ });
7
+ if (!apiResponse.ok) {
8
+ throw new Error(`GitHub API failed: ${apiResponse.status}`);
9
+ }
10
+ const user = await apiResponse.json();
11
+ // 2. Scrape page for pinned repos (no official endpoint)
12
+ const pageUrl = `https://github.com/${username}`;
13
+ const pageResponse = await fetch(pageUrl, {
14
+ headers: { 'User-Agent': 'github-pinned-sdk/1.0.0' }
15
+ });
16
+ if (!pageResponse.ok) {
17
+ throw new Error(`GitHub page fetch failed: ${pageResponse.status}`);
18
+ }
19
+ const html = await pageResponse.text();
20
+ const parser = new DOMParser();
21
+ const doc = parser.parseFromString(html, 'text/html');
22
+ const pinnedItems = doc.querySelectorAll('.js-pinned-items-reorder-container > ol > li');
23
+ const pinnedRepositories = [];
24
+ let pinnedRepositoriesStars = 0;
25
+ pinnedItems.forEach((elem) => {
26
+ const ownerEl = elem.querySelector('.owner');
27
+ const owner = ownerEl ? ownerEl.textContent?.trim() || username : username;
28
+ const repoEl = elem.querySelector('.repo');
29
+ const repo = repoEl ? repoEl.textContent?.trim() || '' : '';
30
+ const linkEl = elem.querySelector('a');
31
+ const internal_link = linkEl?.getAttribute('href') || undefined;
32
+ const link = internal_link ? `https://github.com${internal_link}` : undefined;
33
+ const descEl = elem.querySelector('.pinned-item-desc');
34
+ let description = descEl ? descEl.textContent?.trim() || undefined : undefined;
35
+ if (description) {
36
+ description = description.slice(9, -7).trim();
37
+ }
38
+ const langEl = elem.querySelector('[itemprop="programmingLanguage"]');
39
+ const language = langEl ? langEl.textContent?.trim() || undefined : undefined;
40
+ const langColorEl = elem.querySelector('.repo-language-color');
41
+ const languageColor = langColorEl ? langColorEl.getAttribute('style')?.match(/background-color:\s*(.+?);/)?.[1] || undefined : undefined;
42
+ const starsEl = elem.querySelector('a[href$="/stargazers"]');
43
+ const stars = starsEl ? parseInt(starsEl.textContent?.trim() || '0', 10) : 0;
44
+ const forksEl = elem.querySelector('a[href$="/forks"]');
45
+ const forks = forksEl ? parseInt(forksEl.textContent?.trim() || '0', 10) : 0;
46
+ const repoData = {
47
+ owner,
48
+ repo,
49
+ ...(internal_link !== undefined && { internal_link }),
50
+ ...(link !== undefined && { link }),
51
+ ...(description !== undefined && { description }),
52
+ ...(language !== undefined && { language }),
53
+ ...(languageColor !== undefined && { languageColor }),
54
+ stars,
55
+ forks,
56
+ };
57
+ pinnedRepositories.push(repoData);
58
+ pinnedRepositoriesStars += stars;
59
+ });
60
+ return {
61
+ user,
62
+ pinned_repos: pinnedRepositories,
63
+ pinned_repos_total_stars: pinnedRepositoriesStars,
64
+ };
65
+ }
66
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA0BA,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB;IAKnD,uCAAuC;IACvC,MAAM,MAAM,GAAG,gCAAgC,QAAQ,EAAE,CAAC;IAC1D,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,MAAM,EAAE;QACtC,OAAO,EAAE,EAAE,YAAY,EAAE,yBAAyB,EAAE;KACrD,CAAC,CAAC;IACH,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,sBAAsB,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,MAAM,IAAI,GAAe,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;IAElD,yDAAyD;IACzD,MAAM,OAAO,GAAG,sBAAsB,QAAQ,EAAE,CAAC;IACjD,MAAM,YAAY,GAAG,MAAM,KAAK,CAAC,OAAO,EAAE;QACxC,OAAO,EAAE,EAAE,YAAY,EAAE,yBAAyB,EAAE;KACrD,CAAC,CAAC;IACH,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,6BAA6B,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;IAC/B,MAAM,GAAG,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAEtD,MAAM,WAAW,GAAG,GAAG,CAAC,gBAAgB,CAAC,8CAA8C,CAAC,CAAC;IACzF,MAAM,kBAAkB,GAAiB,EAAE,CAAC;IAC5C,IAAI,uBAAuB,GAAG,CAAC,CAAC;IAEhC,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;QAE3E,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAE5D,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,aAAa,GAAG,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;QAChE,MAAM,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,qBAAqB,aAAa,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAE9E,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAAC,CAAC;QACvD,IAAI,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QAC/E,IAAI,WAAW,EAAE,CAAC;YAChB,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAChD,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,kCAAkC,CAAC,CAAC;QACtE,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QAE9E,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;QAC/D,MAAM,aAAa,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,4BAA4B,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QAEzI,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,wBAAwB,CAAC,CAAC;QAC7D,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7E,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7E,MAAM,QAAQ,GAAe;YAC3B,KAAK;YACL,IAAI;YACJ,GAAG,CAAC,aAAa,KAAK,SAAS,IAAI,EAAE,aAAa,EAAE,CAAC;YACrD,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,EAAE,IAAI,EAAE,CAAC;YACnC,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,CAAC;YACjD,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,CAAC;YAC3C,GAAG,CAAC,aAAa,KAAK,SAAS,IAAI,EAAE,aAAa,EAAE,CAAC;YACrD,KAAK;YACL,KAAK;SACN,CAAC;QAEF,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClC,uBAAuB,IAAI,KAAK,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,IAAI;QACJ,YAAY,EAAE,kBAAkB;QAChC,wBAAwB,EAAE,uBAAuB;KAClD,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "github-pinned-repo-sdk",
3
+ "version": "1.0.0",
4
+ "description": "SDK to simply fetch a GitHub user's pinned repositories and general data.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "test": "vitest",
13
+ "test:ui": "vitest --ui",
14
+ "prepublishOnly": "npm run build && npm test"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "github.com/luisoos/github-pinned-repo-sdk"
19
+ },
20
+ "keywords": [
21
+ "github",
22
+ "api",
23
+ "github-api",
24
+ "github-sdk",
25
+ "pinned-repositories",
26
+ "pinned-repos"
27
+ ],
28
+ "type": "module",
29
+ "author": "luisoos",
30
+ "license": "MIT",
31
+ "devDependencies": {
32
+ "@types/node": "^25.0.3",
33
+ "@vitest/ui": "^4.0.16",
34
+ "jsdom": "^27.4.0",
35
+ "typescript": "^5.9.3",
36
+ "vitest": "^4.0.16"
37
+ }
38
+ }