@repodeckhz/core 0.6.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 +174 -0
- package/dist/index.cjs +1096 -0
- package/dist/index.d.cts +616 -0
- package/dist/index.d.ts +616 -0
- package/dist/index.js +1029 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# @repodeckhz/core
|
|
2
|
+
|
|
3
|
+
> Framework-free core for **repodeck**: fetch, parse, and build GitHub repo card data. Zero DOM, zero dependencies.
|
|
4
|
+
|
|
5
|
+
This is the headless heart of the repodeck package. It talks to the GitHub REST API, parses the response, and returns a normalized `CardData` object. No UI, no framework: use it in Node, Deno, Bun, the browser, or any server-side template engine.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @repodeckhz/core
|
|
11
|
+
# or
|
|
12
|
+
bun add @repodeckhz/core
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { buildCardData } from '@repodeckhz/core';
|
|
19
|
+
|
|
20
|
+
const card = await buildCardData('repodeck', 'taskflow', {
|
|
21
|
+
include: { readme: true, resume: true, screenshots: true },
|
|
22
|
+
branch: 'main',
|
|
23
|
+
configPath: 'config-repodeck',
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// card.resume → { text, truncated } | { error: RepoDeckError }
|
|
27
|
+
// card.readme → { html, raw, frontmatter? } | { error: RepoDeckError }
|
|
28
|
+
// card.screenshots → Screenshot[] | { error: RepoDeckError }
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The target repo must contain a `config-repodeck/` folder (configurable
|
|
32
|
+
via `options.configPath`):
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
config-repodeck/
|
|
36
|
+
├── README.md # expanded content (shown in the modal)
|
|
37
|
+
├── RESUME.txt # short plain-text summary (shown on the card)
|
|
38
|
+
└── screenshots/ # project images, sorted alphabetically
|
|
39
|
+
├── 01-home.png
|
|
40
|
+
└── 02-dashboard.png
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Public API
|
|
44
|
+
|
|
45
|
+
### `buildCardData(owner, repo, options?) → Promise<CardData>`
|
|
46
|
+
|
|
47
|
+
The orchestrator. Fires only the fetches you asked for (via `options.include`) in parallel, and assembles a single `CardData` object.
|
|
48
|
+
|
|
49
|
+
**Per-field error model** (closed decision, never all-or-nothing): if `RESUME.txt` is missing but `README.md` exists, the card still builds; `resume` carries its own `RepoDeckError`. You always know exactly which file failed.
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
interface CardData {
|
|
53
|
+
meta: { owner, repo, url, branch, configPath, fetchedAt };
|
|
54
|
+
resume: FieldResult<ResumeData> | null;
|
|
55
|
+
readme: FieldResult<ReadmeData> | null;
|
|
56
|
+
screenshots: FieldResult<Screenshot[]> | null;
|
|
57
|
+
stats?: FieldResult<RepoStats> | null;
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`FieldResult<T>` is either `T` or `{ error: RepoDeckError }`.
|
|
62
|
+
|
|
63
|
+
### `FetchOptions`
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
interface FetchOptions {
|
|
67
|
+
token?: string; // GitHub PAT - bumps rate limit from 60 to 5000 req/h
|
|
68
|
+
branch?: string; // default "main"
|
|
69
|
+
timeoutMs?: number; // per-request timeout
|
|
70
|
+
retries?: number; // retries on 5xx/network (never on 404/401)
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### `BuildOptions`
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
interface BuildOptions extends FetchOptions {
|
|
78
|
+
include?: {
|
|
79
|
+
readme?: boolean;
|
|
80
|
+
resume?: boolean;
|
|
81
|
+
screenshots?: boolean;
|
|
82
|
+
stats?: boolean; // fetches /repos/{owner}/{repo} for stars/forks
|
|
83
|
+
};
|
|
84
|
+
configPath?: string; // default "config-repodeck"
|
|
85
|
+
resumeMaxChars?: number; // default 280
|
|
86
|
+
locale?: string; // tries RESUME.<locale>.txt before RESUME.txt
|
|
87
|
+
debug?: boolean; // verbose [repodeck:…] console logs (or REPODECK_DEBUG=1 env)
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### GitHub client functions
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
fetchFileContent(owner, repo, path, options?) // 404 → null (not an error)
|
|
95
|
+
fetchDirectoryListing(owner, repo, path, options?) // 404 → []
|
|
96
|
+
fetchRepoStats(owner, repo, options?) // stars, forks, watchers
|
|
97
|
+
checkRateLimit(options?) // { remaining, limit, resetAt }
|
|
98
|
+
buildRawUrl(owner, repo, branch, path) // raw.githubusercontent.com URL
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Parsers
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
parseResume(rawText, { maxChars? }) // → { text, truncated, locale? }
|
|
105
|
+
parseReadme(rawMarkdown) // → { html, raw, frontmatter? } (sanitized)
|
|
106
|
+
parseReadmeFrontmatter(rawMarkdown) // → { metadata, content }
|
|
107
|
+
resolveScreenshots(entries, owner, repo, branch) // → Screenshot[]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Presets
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { defaultPresets, registerPreset, getPreset, mergePresetWithUserConfig } from '@repodeckhz/core';
|
|
114
|
+
|
|
115
|
+
defaultPresets.minimal // title + 1 cover
|
|
116
|
+
defaultPresets.standard // title + resume + screenshot cover
|
|
117
|
+
defaultPresets.detailed // everything + README preview line
|
|
118
|
+
|
|
119
|
+
registerPreset('my-preset', { include: {...}, readmePreview: true, ... });
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Layout & radius helpers
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
resolveScreenshotLayout(screenshots, context, options?) // → { mode, items, total, hidden }
|
|
126
|
+
assignBentoSpans(count) // deterministic bento spans
|
|
127
|
+
resolveRadiusTokens('soft') // → { card, button, modal }
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### `RepoDeckError`
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
class RepoDeckError extends Error {
|
|
134
|
+
code: 'NOT_FOUND' | 'RATE_LIMITED' | 'UNAUTHORIZED' | 'NETWORK_ERROR' | 'INVALID_CONFIG';
|
|
135
|
+
status?: number;
|
|
136
|
+
field?: string;
|
|
137
|
+
toJSON(): { name, code, message, status, field };
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Also exported as `repodeckError` for backwards compatibility (same class).
|
|
142
|
+
|
|
143
|
+
## Frontmatter (README.md)
|
|
144
|
+
|
|
145
|
+
Add YAML-like frontmatter to the top of `README.md` for per-project customization:
|
|
146
|
+
|
|
147
|
+
```markdown
|
|
148
|
+
---
|
|
149
|
+
title: My Project
|
|
150
|
+
accent: "#0891b2"
|
|
151
|
+
order: 2
|
|
152
|
+
tags: library, charts
|
|
153
|
+
---
|
|
154
|
+
# My Project
|
|
155
|
+
...
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Supported fields: `title`, `accent` (hex color), `order` (number), `description`, `tags`, `author`.
|
|
159
|
+
|
|
160
|
+
## Localized RESUME
|
|
161
|
+
|
|
162
|
+
Pass `locale: 'pt'` and the builder tries `RESUME.pt.txt` before `RESUME.txt`, returning `{ text, truncated, locale: 'pt' }`.
|
|
163
|
+
|
|
164
|
+
## Caching
|
|
165
|
+
|
|
166
|
+
In-memory singleton cache (Map) with TTL (5 min default):
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { getCached, setCached, clearCache, buildCacheKey } from '@repodeckhz/core';
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT
|