Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
run: bun run build:package

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v6
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
use_oidc: true
files: ./packages/astro-gravatar/coverage/lcov.info
Expand Down Expand Up @@ -102,6 +102,8 @@ jobs:
security:
name: Security Scan
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout repository
Expand All @@ -121,13 +123,7 @@ jobs:
run: bun install --frozen-lockfile

- name: Run security audit
# Ignore currently unpatched transitive advisories from latest Astro/eslint dependency chains.
run: >
bun audit --audit-level high
--ignore=GHSA-25h7-pfq9-p65f
--ignore=GHSA-rf6f-7fwh-wjgh
--ignore=GHSA-c2c7-rcm5-vvqj
--ignore=GHSA-mw96-cpmx-2vgc
run: bun run security:check

pack-test:
name: Test Package Pack
Expand Down
4 changes: 2 additions & 2 deletions apps/astro-gravatar.and.guide/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/starlight": "^0.39.2",
"@astrojs/starlight": "^0.40.0",
"astro-gravatar": "workspace:*",
"astro": "catalog:",
"sharp": "^0.34.2"
"sharp": "^0.35.1"
},
"devDependencies": {
"astro": "catalog:",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ While basic avatar display works without authentication, an API key unlocks powe
<p style="margin: 0;">Show verified social media accounts and professional networks</p>
</Card>
<Card title="Higher Rate Limits" icon="zap">
<p style="margin: 0;">Increased API quotas for profile fetching (1000 requests/hour)</p>
<p style="margin: 0;">Increased profile API quotas (1000/hour vs 100/hour unauthenticated)</p>
</Card>
<Card title="Advanced Features" icon="shield">
<p style="margin: 0;">Access QR code generation and profile management features</p>
<p style="margin: 0;">Access additional profile fields and profile management features</p>
</Card>
</CardGrid>

Expand All @@ -47,7 +47,7 @@ While basic avatar display works without authentication, an API key unlocks powe

- **Bearer Token**: Standard API key for server-side requests
- **OAuth 2.0**: For applications that need user authorization
- **Public Access**: Limited functionality without authentication
- **Public Access**: Limited profile data and lower profile API limits without authentication

## Basic Authentication

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ async function getProfileWithFallback(email: string) {
return {
email,
display_name: email.split('@')[0],
avatar_url: `https://www.gravatar.com/avatar/${hashEmail(email)}?d=identicon&s=80`,
avatar_url: `https://0.gravatar.com/avatar/${hashEmail(email)}?d=identicon&s=80`,
description: null,
};
}
Expand Down Expand Up @@ -169,14 +169,14 @@ function safeGetAvatarUrl(email: string, options = {}) {
if (!isValidEmail(email)) {
console.warn('Invalid email provided:', email);
// Return default avatar URL
return 'https://www.gravatar.com/avatar/default?s=80&d=mp';
return 'https://0.gravatar.com/avatar/default?s=80&d=mp';
}

try {
return buildAvatarUrl(email, options);
} catch (error) {
console.error('Failed to build avatar URL:', error);
return 'https://www.gravatar.com/avatar/default?s=80&d=mp';
return 'https://0.gravatar.com/avatar/default?s=80&d=mp';
}
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Slow loading or excessive API calls.
**Solutions**:

- Implement client-side caching
- Use API key for higher limits (1000/hour vs limited)
- Use an API key for higher profile API limits (1000/hour vs 100/hour unauthenticated)
- Apply for increased limits at [gravatar.com/developers](https://gravatar.com/developers)
- Use exponential backoff for retries

Expand Down Expand Up @@ -284,7 +284,7 @@ const avatarProps: GravatarAvatarProps = {
size={80}
onError={(e) => {
// Fallback to identicon
const fallbackUrl = `https://www.gravatar.com/avatar/${hashEmail(e.target.dataset.email)}?d=identicon&s=80`;
const fallbackUrl = `https://0.gravatar.com/avatar/${hashEmail(e.target.dataset.email)}?d=identicon&s=80`;
e.target.src = fallbackUrl;
}}
data-email="user@example.com"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ https://api.gravatar.com/v3

## Authentication

Use Bearer token authentication for all API requests:
Use Bearer token authentication for richer profile data and higher profile API limits:

```http
Authorization: Bearer YOUR_API_KEY
Expand All @@ -36,6 +36,10 @@ Retrieve a user's profile using their email hash or profile URL slug.

- `profileIdentifier` (required): SHA256 hash of email or profile URL slug

:::note
Profile requests only resolve for the hash of the primary email address on a Gravatar account. A user can have multiple email addresses, so an avatar image request for a hash may succeed even when the profile endpoint for that same hash returns `404`.
:::

**Response Codes**:

- `200 OK`: Successfully retrieved profile
Expand Down Expand Up @@ -84,6 +88,7 @@ Generate a QR code for a user's profile.
**Query Parameters**:

- `size` (optional): Size of QR code in pixels (default: 80)
- `s` (optional): Alias for `size`
- `version` (optional): QR code style (1: standard, 3: modern dots)
- `utm_medium` (optional): UTM medium parameter
- `utm_campaign` (optional): UTM campaign parameter
Expand All @@ -108,7 +113,7 @@ While not API endpoints, avatar URLs follow a predictable pattern:
### Basic Avatar URL

```
https://www.gravatar.com/avatar/{hash}?parameters
https://0.gravatar.com/avatar/{hash}?parameters
```

### URL Parameters
Expand All @@ -135,13 +140,31 @@ https://www.gravatar.com/avatar/{hash}?parameters

```bash
# Basic avatar
https://www.gravatar.com/avatar/27205e5c51cb03f862138b22bcb5dc20f94a342e744ff6df1b8dc8af3c865109
https://0.gravatar.com/avatar/27205e5c51cb03f862138b22bcb5dc20f94a342e744ff6df1b8dc8af3c865109

# With parameters
https://www.gravatar.com/avatar/27205e5c51cb03f862138b22bcb5dc20f94a342e744ff6df1b8dc8af3c865109?s=200&r=pg&d=identicon
https://0.gravatar.com/avatar/27205e5c51cb03f862138b22bcb5dc20f94a342e744ff6df1b8dc8af3c865109?s=200&r=pg&d=identicon

# Force default
https://www.gravatar.com/avatar/27205e5c51cb03f862138b22bcb5dc20f94a342e744ff6df1b8dc8af3c865109?f=y
https://0.gravatar.com/avatar/27205e5c51cb03f862138b22bcb5dc20f94a342e744ff6df1b8dc8af3c865109?f=y
```

## Profile Card Embeds

### oEmbed Profile Card

Embed a Gravatar profile card through the oEmbed endpoint.

**Endpoint**: `GET /oembed`

**Parameters**:

- `url` (required): Gravatar profile URL, such as `https://gravatar.com/{username}`

#### Example Request

```bash
curl "https://api.gravatar.com/v3/oembed?url=https%3A%2F%2Fgravatar.com%2Fmatt"
```

## Data Formats
Expand Down Expand Up @@ -198,10 +221,12 @@ https://gravatar.com/99511d6010af8c574c31f94e1b327bba5e25086dd7b92a4b6f3e132b579

### Default Rate Limits

| Authentication | Requests per Hour |
| -------------- | ----------------- |
| API Key | 1,000 |
| Public | Limited |
| Authentication | Profile Requests per Hour |
| --------------- | ------------------------- |
| API Key | 1,000 |
| Unauthenticated | 100 |

Avatar image requests do not count toward these profile endpoint limits.

### Rate Limit Headers

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ import GravatarQR from 'astro-gravatar/GravatarQR';
- **Range**: 1-1000 pixels
- **Default**: 80px
- **Recommendation**: 80-200px for optimal scanning
- **Direct URL alias**: Gravatar accepts both `size` and `s`; the `GravatarQR` component uses `size`.

```astro
<!-- Small QR for tight spaces -->
Expand Down
Loading