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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<td align="center"><b>🌐 Free APIs</b><br><code>102</code></td>
<td align="center"><b>🤖 AI & LLMs</b><br><code>90</code></td>
<td align="center"><b>⚡ CLI Tools</b><br><code>119</code></td>
<td align="center"><b>🧪 Testing & QA</b><br><code>62</code></td>
<td align="center"><b>🧪 Testing & QA</b><br><code>63</code></td>
<td align="center"><b>☁️ Free Cloud</b><br><code>71</code></td>
<td align="center"><b>🤝 Up for Grabs</b><br><code>21</code></td>
<td align="center"><b>🎁 Dev Perks</b><br><code>30</code></td>
Expand All @@ -47,7 +47,7 @@
### 🎯 The Race to 1,000 Verified Tools (Hacktoberfest Milestone)

```text
[███████████░░░░░░░░░] 536 / 1,000 Tools Verified (54% • 464 to go!)
[███████████░░░░░░░░░] 537 / 1,000 Tools Verified (54% • 463 to go!)
```

*Help us curate the definitive zero-paywall index! [Submit your favorite developer tool, API, or AI framework →](#-how-to-submit-your-project-or-api)*
Expand All @@ -66,7 +66,7 @@ DevShelf isn't a static markdown list. It runs directly inside your terminal, in
┌─────────────────────────────────────────────────────────────────────────────────┐
│ $ npx devshelf search "postgres" │
│ │
│ 📚 DevShelf CLI v1.1.0 — 536 Curated Tools (Live CI Audited) │
│ 📚 DevShelf CLI v1.1.0 — 537 Curated Tools (Live CI Audited) │
│ │
│ [1] Neon (Database / Serverless) │
│ Serverless Postgres with autoscaling, branching, and generous free tier. │
Expand Down Expand Up @@ -181,14 +181,14 @@ npx devshelf stats

## 📂 Browse Catalog by Category

Explore our curated collections of **536+ zero-paywall developer tools**, categorized into dedicated guides with subcategory indexing:
Explore our curated collections of **537+ zero-paywall developer tools**, categorized into dedicated guides with subcategory indexing:

| Category | Resources | Description & Subcategories | Guide |
| :--- | :---: | :--- | :---: |
| 🌐 **Free & Public APIs** | **102** | Weather, Finance, Mock/Dev APIs, Geocoding, AI/ML, Media, Entertainment | [**Browse APIs →**](docs/apis.md) |
| 🤖 **AI Agents & Local LLMs** | **90** | Local LLM Runtimes, Autonomous Agents, Coding Assistants, Orchestration | [**Browse AI Tools →**](docs/ai-tools.md) |
| ⚡ **CLI & Productivity Tools** | **119** | Terminal Utilities, Git Power Tools, Docker & DevOps, Benchmarking, DBs | [**Browse CLI Tools →**](docs/cli-tools.md) |
| 🧪 **Testing & QA Reliability** | **62** | E2E Testing, Mock Servers, Contract Testing, Security Auditing, Performance | [**Browse Testing Tools →**](docs/testing-qa.md) |
| 🧪 **Testing & QA Reliability** | **63** | E2E Testing, Mock Servers, Contract Testing, Security Auditing, Performance | [**Browse Testing Tools →**](docs/testing-qa.md) |
| ☁️ **Free Cloud & Developer Tiers** | **71** | Databases, Auth & Identity, Serverless Compute, Object Storage, Email, APM | [**Browse Cloud Tiers →**](docs/free-cloud.md) |
| 🤝 **Contributors Wanted** | **21** | Active open-source repos with curated Good First Issues and starter tasks | [**Browse Projects →**](docs/contributors-wanted.md) |
| 🎁 **Developer Discounts & Perks** | **30** | Cloud credits, free IDE licenses, student packs, open-source sponsorships | [**Browse Perks →**](docs/perks.md) |
Expand Down
12 changes: 6 additions & 6 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -806,8 +806,8 @@ async function main() {
allIssues: nlData.issues,
},
null,
2
)
2,
),
);
return;
}
Expand All @@ -821,7 +821,7 @@ async function main() {

if (latest.sponsor) {
console.log(
` ${c.amber}⚡ Issue Sponsor: ${c.bold}${latest.sponsor.name}${c.reset} ${c.gray}— ${latest.sponsor.tagline}${c.reset}`
` ${c.amber}⚡ Issue Sponsor: ${c.bold}${latest.sponsor.name}${c.reset} ${c.gray}— ${latest.sponsor.tagline}${c.reset}`,
);
console.log(` Perk: ${latest.sponsor.perk}`);
console.log(` URL: ${c.underline}${c.blue}${latest.sponsor.url}${c.reset}\n`);
Expand All @@ -831,7 +831,7 @@ async function main() {
(latest.featuredTools || []).slice(0, 5).forEach((tool, idx) => {
const badge = tool.badge ? ` ${c.cyan}[${tool.badge}]${c.reset}` : "";
console.log(
` ${idx + 1}. ${c.bold}${tool.name}${c.reset}${badge} ${c.gray}(${tool.category})${c.reset}`
` ${idx + 1}. ${c.bold}${tool.name}${c.reset}${badge} ${c.gray}(${tool.category})${c.reset}`,
);
console.log(` ${tool.description}`);
console.log(` ${c.underline}${c.blue}${tool.url}${c.reset}`);
Expand All @@ -840,14 +840,14 @@ async function main() {

if (latest.perkOfTheWeek) {
console.log(
` 🎁 ${c.green}${c.bold}Perk of the Week:${c.reset} ${latest.perkOfTheWeek.title}`
` 🎁 ${c.green}${c.bold}Perk of the Week:${c.reset} ${latest.perkOfTheWeek.title}`,
);
console.log(` ${latest.perkOfTheWeek.description}`);
console.log(` ${c.underline}${c.blue}${latest.perkOfTheWeek.url}${c.reset}\n`);
}

console.log(
` ${c.gray}Active Subscribers: ${c.bold}${nlData.stats?.activeSubscribers?.toLocaleString() || "2,800+"}${c.reset} engineers`
` ${c.gray}Active Subscribers: ${c.bold}${nlData.stats?.activeSubscribers?.toLocaleString() || "2,800+"}${c.reset} engineers`,
);
console.log(` 📡 W3C RSS Feed: ${c.underline}${c.blue}${nlData.feedUrl}${c.reset}`);
console.log(` 🌐 Web Archive: ${c.underline}${c.blue}${nlData.website}${c.reset}\n`);
Expand Down
10 changes: 5 additions & 5 deletions data/counts.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"totalCount": 536,
"totalCount": 537,
"milestone": "530+",
"exactCount": 536,
"exactCount": 537,
"shelfCounts": {
"ai-tools.json": 90,
"apis.json": 102,
Expand All @@ -10,8 +10,8 @@
"contributors-wanted.json": 21,
"free-cloud.json": 71,
"perks.json": 30,
"testing-qa.json": 62
"testing-qa.json": 63
},
"reposCount": 333,
"updatedAt": "2026-10-19T22:29:09.787Z"
"reposCount": 334,
"updatedAt": "2026-10-20T19:43:20.474Z"
}
10 changes: 8 additions & 2 deletions docs/testing-qa.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

[← Back to Main Directory](../README.md) • [🌐 Live Search App](https://devshelf.ritualdev.in) • [➕ Submit New Resource](../README.md#-how-to-submit-your-project-or-api)

[![Total Testing Tools](https://img.shields.io/badge/Testing_Tools-62_Curated-blueviolet?style=for-the-badge)](https://devshelf.ritualdev.in)
[![Total Testing Tools](https://img.shields.io/badge/Testing_Tools-63_Curated-blueviolet?style=for-the-badge)](https://devshelf.ritualdev.in)

**Jump to Subcategory:**
[API Mocking & Sandboxes](#api-mocking-sandboxes) • [API Testing & Debugging](#api-testing-debugging) • [Browser & E2E Testing](#browser-e2e-testing) • [Contract & Schema Testing](#contract-schema-testing) • [Performance & Load Testing](#performance-load-testing) • [Security & Vulnerability Scanners](#security-vulnerability-scanners) • [Test Data Generation](#test-data-generation) • [Unit & Integration Testing](#unit-integration-testing)
[API Mocking & Sandboxes](#api-mocking-sandboxes) • [API Testing & Debugging](#api-testing-debugging) • [Browser & E2E Testing](#browser-e2e-testing) • [Contract & Schema Testing](#contract-schema-testing) • [Performance & Load Testing](#performance-load-testing) • [Security & Vulnerability Scanners](#security-vulnerability-scanners) • [Test Data Generation](#test-data-generation) • [Testing & QA Reliability](#testing-qa-reliability) • [Unit & Integration Testing](#unit-integration-testing)

---

Expand Down Expand Up @@ -104,6 +104,12 @@
| [**Mimesis**](https://github.com/lk-geimfari/mimesis) | `Python` | `MIT` | High-performance Python library for generating realistic synthetic data in a variety of locales. | [GitHub](https://github.com/lk-geimfari/mimesis) |
| [**Bogus**](https://github.com/bchavez/Bogus) | `C#` | `MIT` | A simple and sane fake data generator for .NET languages, ported from Faker.js with fluent syntax. | [GitHub](https://github.com/bchavez/Bogus) |

### <a id="testing-qa-reliability"></a>Testing & QA Reliability (1)

| Tool | Language | License | Description | Links |
| :--- | :---: | :---: | :--- | :---: |
| [**Clockshift**](https://github.com/brodyga45/clockshift-dst-check) | `JavaScript / Node.js and browser Intl` | `MIT` | Find missing or repeated local clock times in daily and weekly schedules, with CSV export and a weekday filter. Includes a browser UI and a dependency-free Node.js CLI; scheduler execution policy must be checked separately. | [GitHub](https://github.com/brodyga45/clockshift-dst-check) |

### <a id="unit-integration-testing"></a>Unit & Integration Testing (4)

| Tool | Language | License | Description | Links |
Expand Down
79 changes: 34 additions & 45 deletions scripts/activate-sponsor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,7 @@ const ROOT_DIR = path.resolve(__dirname, "..");
const SHELF_DIR = path.join(ROOT_DIR, "shelf");
const DATA_DIR = path.join(ROOT_DIR, "data");

export type ShelfCategory =
| "ai"
| "cli"
| "apis"
| "cloud"
| "testing"
| "boilerplates"
| "perks";
export type ShelfCategory = "ai" | "cli" | "apis" | "cloud" | "testing" | "boilerplates" | "perks";

export type SponsorTier = "starter" | "mcpPro" | "enterprise";

Expand Down Expand Up @@ -98,7 +91,10 @@ function normalizeUrl(u: string): string {
const parsed = new URL(u);
return `${parsed.hostname.replace(/^www\./, "").toLowerCase()}${parsed.pathname.replace(/\/$/, "").toLowerCase()}`;
} catch {
return String(u || "").toLowerCase().trim().replace(/\/$/, "");
return String(u || "")
.toLowerCase()
.trim()
.replace(/\/$/, "");
}
}

Expand All @@ -109,9 +105,7 @@ function normalizeUrl(u: string): string {
* 3. Appends/updates the sponsor ledger in data/sponsors.json with patron details & telemetry
* 4. Triggers catalog & badge rebuild to maintain 100% sync
*/
export async function activateSponsor(
options: ActivateSponsorOptions,
): Promise<ActivationResult> {
export async function activateSponsor(options: ActivateSponsorOptions): Promise<ActivationResult> {
const toolName = (options.name || "").trim();
const toolUrl = (options.url || "").trim();

Expand All @@ -122,18 +116,16 @@ export async function activateSponsor(
throw new Error("Missing required option: --url <tool-url>");
}

const category: ShelfCategory = options.category && CATEGORY_MAP[options.category]
? options.category
: "cli";
const tier: SponsorTier = options.tier && TIER_MAP[options.tier]
? options.tier
: "mcpPro";
const category: ShelfCategory =
options.category && CATEGORY_MAP[options.category] ? options.category : "cli";
const tier: SponsorTier = options.tier && TIER_MAP[options.tier] ? options.tier : "mcpPro";

const categoryConfig = CATEGORY_MAP[category];
const tierConfig = TIER_MAP[tier];
const amountUSD = typeof options.amount === "number" && options.amount > 0
? options.amount
: tierConfig.defaultUSD;
const amountUSD =
typeof options.amount === "number" && options.amount > 0
? options.amount
: tierConfig.defaultUSD;

const targetNormUrl = normalizeUrl(toolUrl);
const targetNormName = toolName.toLowerCase();
Expand Down Expand Up @@ -204,9 +196,8 @@ export async function activateSponsor(
}

const defaultPitch = `${toolName} - Verified zero-paywall developer tooling and AI context integration.`;
const pitch = options.pitch && options.pitch.trim().length >= 10
? options.pitch.trim()
: defaultPitch;
const pitch =
options.pitch && options.pitch.trim().length >= 10 ? options.pitch.trim() : defaultPitch;

if (category === "apis") {
finalItem = {
Expand Down Expand Up @@ -322,25 +313,25 @@ export async function activateSponsor(
rank: 1,
name: patronName,
github: cleanGithub || "ghost",
avatar: cleanGithub
? `https://github.com/${cleanGithub}.png`
: "https://github.com/ghost.png",
avatar: cleanGithub ? `https://github.com/${cleanGithub}.png` : "https://github.com/ghost.png",
url: toolUrl,
amountUSD,
amountINR: Math.round(amountUSD * 84),
tier: tierConfig.patronTier,
date: new Date().toISOString().split("T")[0],
comment: (options.comment || "").trim() ||
comment:
(options.comment || "").trim() ||
`Sponsoring DevShelf to feature ${toolName} across MCP coding queries and developer dossiers.`,
badgeUrl: `https://devshelf.ritualdev.in/api/v1/badges/${tierConfig.patronTier}.svg`,
toolName,
};

const existingPatronIdx = Array.isArray(sponsorsData.patrons)
? sponsorsData.patrons.findIndex((p: any) =>
p.id === patronId ||
(cleanGithub && p.github && p.github.toLowerCase() === cleanGithub.toLowerCase()) ||
p.name.toLowerCase() === patronName.toLowerCase()
? sponsorsData.patrons.findIndex(
(p: any) =>
p.id === patronId ||
(cleanGithub && p.github && p.github.toLowerCase() === cleanGithub.toLowerCase()) ||
p.name.toLowerCase() === patronName.toLowerCase(),
)
: -1;

Expand Down Expand Up @@ -406,16 +397,8 @@ export async function activateSponsor(
}

// Write changes to disk
await fs.writeFile(
targetShelfPath,
`${JSON.stringify(foundShelfData, null, 2)}\n`,
"utf8",
);
await fs.writeFile(
sponsorsJsonPath,
`${JSON.stringify(sponsorsData, null, 2)}\n`,
"utf8",
);
await fs.writeFile(targetShelfPath, `${JSON.stringify(foundShelfData, null, 2)}\n`, "utf8");
await fs.writeFile(sponsorsJsonPath, `${JSON.stringify(sponsorsData, null, 2)}\n`, "utf8");

// Synchronize site, README, counts, badges, and SEO pages
if (!options.skipBuild) {
Expand Down Expand Up @@ -510,14 +493,20 @@ Examples:
console.log("\n=======================================================");
console.log(`🎉 SUCCESS: ${result.toolName} Activated as ${result.tier} Sponsor!`);
console.log("=======================================================");
console.log(`• Target Shelf File: shelf/${result.shelfFile} (${result.isNewTool ? "New Tool Created" : "Existing Tool Promoted"})`);
console.log(
`• Target Shelf File: shelf/${result.shelfFile} (${result.isNewTool ? "New Tool Created" : "Existing Tool Promoted"})`,
);
console.log(`• Featured Flag: true (Tagged as: "${result.item.sponsorTier}")`);
console.log(`• MCP AI Telemetry: Injected into npx devshelf-mcp server recommendations`);
console.log(`• Wall of Patrons: Ranked in data/sponsors.json & site/sponsors.html`);
console.log(`• Dry-Run Mode: ${result.dryRun ? "YES (No files modified)" : "NO (Files synchronized)"}`);
console.log(
`• Dry-Run Mode: ${result.dryRun ? "YES (No files modified)" : "NO (Files synchronized)"}`,
);
console.log("\nEmbeddable README Badge Snippet:");
const handle = (result.patron.github as string) || "verified";
console.log(`[![DevShelf Sponsor](https://devshelf.ritualdev.in/api/v1/badges/${encodeURIComponent(handle)}.svg)](https://devshelf.ritualdev.in/sponsors.html)`);
console.log(
`[![DevShelf Sponsor](https://devshelf.ritualdev.in/api/v1/badges/${encodeURIComponent(handle)}.svg)](https://devshelf.ritualdev.in/sponsors.html)`,
);
console.log("=======================================================\n");
} catch (err) {
console.error("❌ Activation failed:", err);
Expand Down
33 changes: 26 additions & 7 deletions scripts/add-affiliate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,11 @@ export async function addOrUpdateAffiliate(
await fs.mkdir(DATA_DIR, { recursive: true });
await fs.mkdir(GO_DIR, { recursive: true });

let rawData = { version: "1.0.0", updatedAt: new Date().toISOString(), partners: [] as AffiliatePartner[] };
let rawData = {
version: "1.0.0",
updatedAt: new Date().toISOString(),
partners: [] as AffiliatePartner[],
};
try {
const raw = await fs.readFile(AFFILIATES_JSON_PATH, "utf8");
rawData = JSON.parse(raw);
Expand All @@ -165,15 +169,24 @@ export async function addOrUpdateAffiliate(
toolName,
url,
vanityPath,
category: options.category || (existingIdx !== -1 ? rawData.partners[existingIdx].category : "cloud"),
perkTitle: options.perk?.trim() || (existingIdx !== -1 ? rawData.partners[existingIdx].perkTitle : "Developer Free Tier & Credits"),
category:
options.category || (existingIdx !== -1 ? rawData.partners[existingIdx].category : "cloud"),
perkTitle:
options.perk?.trim() ||
(existingIdx !== -1
? rawData.partners[existingIdx].perkTitle
: "Developer Free Tier & Credits"),
perkDescription:
options.description?.trim() ||
(existingIdx !== -1
? rawData.partners[existingIdx].perkDescription
: `Claim exclusive developer credits and perpetual free tier allowances with ${toolName}.`),
ctaText: options.cta?.trim() || (existingIdx !== -1 ? rawData.partners[existingIdx].ctaText : "Claim Offer →"),
badge: options.badge?.trim() || (existingIdx !== -1 ? rawData.partners[existingIdx].badge : "🎁 Dev Perk"),
ctaText:
options.cta?.trim() ||
(existingIdx !== -1 ? rawData.partners[existingIdx].ctaText : "Claim Offer →"),
badge:
options.badge?.trim() ||
(existingIdx !== -1 ? rawData.partners[existingIdx].badge : "🎁 Dev Perk"),
active: true,
};

Expand All @@ -194,7 +207,11 @@ export async function addOrUpdateAffiliate(
// 3. Write site/api/v1/affiliates.json
const apiV1Dir = path.join(SITE_DIR, "api", "v1");
await fs.mkdir(apiV1Dir, { recursive: true });
await fs.writeFile(path.join(apiV1Dir, "affiliates.json"), `${JSON.stringify(rawData, null, 2)}\n`, "utf8");
await fs.writeFile(
path.join(apiV1Dir, "affiliates.json"),
`${JSON.stringify(rawData, null, 2)}\n`,
"utf8",
);

// 4. Synchronize site if not skipped
if (!options.skipBuild) {
Expand Down Expand Up @@ -277,7 +294,9 @@ Examples:
});

console.log("\n=======================================================");
console.log(`🎉 SUCCESS: ${partner.toolName} Affiliate Partner ${isNew ? "Created" : "Updated"}!`);
console.log(
`🎉 SUCCESS: ${partner.toolName} Affiliate Partner ${isNew ? "Created" : "Updated"}!`,
);
console.log("=======================================================");
console.log(`• Destination URL: ${partner.url}`);
console.log(`• Outbound Redirect: devshelf.ritualdev.in${partner.vanityPath}`);
Expand Down
9 changes: 9 additions & 0 deletions shelf/testing-qa.json
Original file line number Diff line number Diff line change
Expand Up @@ -618,5 +618,14 @@
"license": "MIT",
"featured": true,
"goodFirstIssues": "https://github.com/testcontainers/testcontainers-java/issues"
},
{
"name": "Clockshift",
"repo": "https://github.com/brodyga45/clockshift-dst-check",
"category": "Testing & QA Reliability",
"description": "Find missing or repeated local clock times in daily and weekly schedules, with CSV export and a weekday filter. Includes a browser UI and a dependency-free Node.js CLI; scheduler execution policy must be checked separately.",
"language": "JavaScript / Node.js and browser Intl",
"license": "MIT",
"featured": false
}
]
4 changes: 2 additions & 2 deletions site/api/v1/categories.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": "1.1.2",
"updatedAt": "2026-10-19T22:29:04.667Z",
"updatedAt": "2026-10-20T19:43:12.167Z",
"totalCategories": 8,
"categories": [
{
Expand Down Expand Up @@ -30,7 +30,7 @@
{
"slug": "testing",
"name": "Testing & QA Automation",
"count": 62,
"count": 63,
"endpoint": "https://devshelf.ritualdev.in/api/v1/categories/testing.json"
},
{
Expand Down
2 changes: 1 addition & 1 deletion site/api/v1/categories/ai.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": "1.1.2",
"updatedAt": "2026-10-19T22:29:04.667Z",
"updatedAt": "2026-10-20T19:43:12.167Z",
"slug": "ai",
"name": "AI Agents & Local LLMs",
"count": 90,
Expand Down
Loading
Loading