@adityanair98/api-oracle 0.5.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/LICENSE +21 -0
- package/README.md +216 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +74 -0
- package/dist/dashboard/public/app.js +1004 -0
- package/dist/dashboard/public/index.html +142 -0
- package/dist/dashboard/public/public/app.js +1004 -0
- package/dist/dashboard/public/public/index.html +142 -0
- package/dist/dashboard/public/public/styles.css +1464 -0
- package/dist/dashboard/public/styles.css +1464 -0
- package/dist/dashboard/routes/api.d.ts +7 -0
- package/dist/dashboard/routes/api.js +245 -0
- package/dist/dashboard/server.d.ts +9 -0
- package/dist/dashboard/server.js +45 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +23 -0
- package/dist/knowledge/db.d.ts +22 -0
- package/dist/knowledge/db.js +182 -0
- package/dist/knowledge/schema.d.ts +275 -0
- package/dist/knowledge/schema.js +135 -0
- package/dist/knowledge/scorer.d.ts +63 -0
- package/dist/knowledge/scorer.js +314 -0
- package/dist/knowledge/search.d.ts +37 -0
- package/dist/knowledge/search.js +111 -0
- package/dist/knowledge/synonyms.d.ts +36 -0
- package/dist/knowledge/synonyms.js +523 -0
- package/dist/knowledge/tfidf.d.ts +42 -0
- package/dist/knowledge/tfidf.js +138 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.js +40 -0
- package/dist/tools/check-freshness.d.ts +9 -0
- package/dist/tools/check-freshness.js +95 -0
- package/dist/tools/compare-apis.d.ts +8 -0
- package/dist/tools/compare-apis.js +149 -0
- package/dist/tools/find-api.d.ts +9 -0
- package/dist/tools/find-api.js +120 -0
- package/dist/tools/get-setup-guide.d.ts +8 -0
- package/dist/tools/get-setup-guide.js +127 -0
- package/dist/updater/linter.d.ts +31 -0
- package/dist/updater/linter.js +219 -0
- package/dist/updater/report.d.ts +29 -0
- package/dist/updater/report.js +96 -0
- package/dist/updater/staleness.d.ts +39 -0
- package/dist/updater/staleness.js +66 -0
- package/dist/updater/version-tracker.d.ts +28 -0
- package/dist/updater/version-tracker.js +50 -0
- package/dist/utils/config.d.ts +11 -0
- package/dist/utils/config.js +13 -0
- package/dist/utils/logger.d.ts +20 -0
- package/dist/utils/logger.js +32 -0
- package/package.json +56 -0
- package/src/entries/ai/anthropic.json +95 -0
- package/src/entries/ai/eleven-labs.json +90 -0
- package/src/entries/ai/openai.json +95 -0
- package/src/entries/ai/replicate.json +87 -0
- package/src/entries/ai/resemble-ai.json +88 -0
- package/src/entries/ai/stability-ai.json +89 -0
- package/src/entries/analytics/posthog.json +88 -0
- package/src/entries/analytics/sentry.json +84 -0
- package/src/entries/auth/auth0.json +90 -0
- package/src/entries/auth/clerk.json +95 -0
- package/src/entries/cms/contentful.json +92 -0
- package/src/entries/cms/sanity.json +92 -0
- package/src/entries/cms/strapi.json +93 -0
- package/src/entries/commerce/medusa.json +91 -0
- package/src/entries/commerce/shopify-api.json +91 -0
- package/src/entries/communication/sendbird.json +85 -0
- package/src/entries/communication/stream-chat.json +94 -0
- package/src/entries/database/firebase.json +88 -0
- package/src/entries/database/neon.json +94 -0
- package/src/entries/database/planetscale.json +95 -0
- package/src/entries/database/supabase.json +94 -0
- package/src/entries/database/upstash.json +94 -0
- package/src/entries/devops/fly-io.json +90 -0
- package/src/entries/devops/netlify.json +90 -0
- package/src/entries/devops/railway.json +90 -0
- package/src/entries/devops/vercel.json +90 -0
- package/src/entries/email/mailgun.json +91 -0
- package/src/entries/email/postmark.json +91 -0
- package/src/entries/email/resend.json +89 -0
- package/src/entries/email/sendgrid.json +90 -0
- package/src/entries/forms/formspark.json +85 -0
- package/src/entries/forms/typeform.json +98 -0
- package/src/entries/infrastructure/aws-s3.json +104 -0
- package/src/entries/infrastructure/cloudflare-r2.json +92 -0
- package/src/entries/infrastructure/cloudflare-workers.json +92 -0
- package/src/entries/infrastructure/digital-ocean-spaces.json +87 -0
- package/src/entries/integration/nango.json +90 -0
- package/src/entries/integration/zapier.json +92 -0
- package/src/entries/maps/google-maps.json +89 -0
- package/src/entries/maps/mapbox.json +87 -0
- package/src/entries/media/deepgram.json +84 -0
- package/src/entries/media/imgix.json +84 -0
- package/src/entries/media/mux.json +94 -0
- package/src/entries/messaging/ably.json +94 -0
- package/src/entries/messaging/pusher.json +94 -0
- package/src/entries/messaging/twilio.json +94 -0
- package/src/entries/messaging/vonage.json +89 -0
- package/src/entries/notifications/knock.json +84 -0
- package/src/entries/notifications/novu.json +84 -0
- package/src/entries/notifications/onesignal.json +84 -0
- package/src/entries/payments/lemonsqueezy.json +91 -0
- package/src/entries/payments/paddle.json +90 -0
- package/src/entries/payments/paypal.json +91 -0
- package/src/entries/payments/razorpay.json +85 -0
- package/src/entries/payments/square.json +91 -0
- package/src/entries/payments/stripe.json +96 -0
- package/src/entries/scheduling/cal-com.json +90 -0
- package/src/entries/scheduling/calendly.json +90 -0
- package/src/entries/search/algolia.json +96 -0
- package/src/entries/security/arcjet.json +89 -0
- package/src/entries/security/snyk.json +90 -0
- package/src/entries/storage/cloudinary.json +93 -0
- package/src/entries/storage/uploadthing.json +90 -0
- package/src/entries/testing/browserstack.json +86 -0
- package/src/entries/testing/checkly.json +89 -0
- package/src/entries/workflow/inngest.json +88 -0
- package/src/entries/workflow/temporal.json +90 -0
- package/src/entries/workflow/trigger-dev.json +89 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Cloudflare Workers",
|
|
3
|
+
"slug": "cloudflare-workers",
|
|
4
|
+
"category": "infrastructure",
|
|
5
|
+
"subcategory": "edge-compute",
|
|
6
|
+
"website": "https://workers.cloudflare.com",
|
|
7
|
+
"description": "Cloudflare Workers is a serverless JavaScript/TypeScript platform that runs at the edge in 300+ global locations with sub-millisecond cold starts, powered by V8 isolates instead of containers.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Run TypeScript/JavaScript logic at the edge closest to users",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Build API middleware (auth, rate limiting, routing) at CDN level",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Transform responses before they reach the client",
|
|
19
|
+
"fit": "perfect"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Run lightweight background tasks triggered by Cloudflare queues",
|
|
23
|
+
"fit": "good"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth": {
|
|
27
|
+
"method": "api_key",
|
|
28
|
+
"setupSteps": [
|
|
29
|
+
"Create a Cloudflare account at cloudflare.com",
|
|
30
|
+
"Navigate to Workers & Pages in the dashboard",
|
|
31
|
+
"Install the Wrangler CLI: npm install -g wrangler",
|
|
32
|
+
"Run wrangler login to authenticate via browser OAuth",
|
|
33
|
+
"Create a new Worker project: wrangler init my-worker",
|
|
34
|
+
"Deploy with wrangler deploy — no manual API token needed for CLI deployments",
|
|
35
|
+
"For CI/CD, create an API token at dash.cloudflare.com/profile/api-tokens with Workers Scripts Edit permission"
|
|
36
|
+
],
|
|
37
|
+
"envVarName": "CLOUDFLARE_API_TOKEN",
|
|
38
|
+
"codeSnippet": "// Minimal Cloudflare Worker handler (TypeScript)\nexport default {\n async fetch(request: Request, env: Env): Promise<Response> {\n return new Response('Hello from the edge!', { status: 200 });\n },\n};\n\n// Env interface — bindings declared in wrangler.toml\ninterface Env {\n MY_KV: KVNamespace;\n MY_BUCKET: R2Bucket;\n MY_SECRET: string;\n}"
|
|
39
|
+
},
|
|
40
|
+
"pricing": {
|
|
41
|
+
"model": "freemium",
|
|
42
|
+
"freeTier": "100,000 requests/day, 10ms CPU time per request, unlimited Workers",
|
|
43
|
+
"startingPrice": "$5/month (Workers Paid) for 10M requests + 30M CPU milliseconds",
|
|
44
|
+
"costPer": "$0.50/million requests after 10M included, $0.02/million CPU-ms after 30M included",
|
|
45
|
+
"pricingUrl": "https://developers.cloudflare.com/workers/platform/pricing/"
|
|
46
|
+
},
|
|
47
|
+
"rateLimits": {
|
|
48
|
+
"tier": "free tier",
|
|
49
|
+
"limit": "100K req/day (free), 10ms CPU time/request (free). Paid: 10M req/month, 30s max CPU duration per request (Unbound Workers)",
|
|
50
|
+
"notes": "The 10ms CPU limit on the free plan is CPU execution time, not wall-clock time. I/O (fetch calls, KV reads) does not count toward this limit. Paid Workers Standard gets 30ms CPU; Unbound Workers can run up to 15 minutes.",
|
|
51
|
+
"retryStrategy": "Workers execute synchronously — implement circuit breakers in worker code. Use Durable Objects for stateful retry logic."
|
|
52
|
+
},
|
|
53
|
+
"sdk": {
|
|
54
|
+
"primaryLanguage": "typescript",
|
|
55
|
+
"installCommand": "npm install --save-exact wrangler @cloudflare/workers-types --save-dev",
|
|
56
|
+
"importStatement": "export default { async fetch(request: Request, env: Env): Promise<Response> {",
|
|
57
|
+
"otherLanguages": ["javascript", "rust", "python"]
|
|
58
|
+
},
|
|
59
|
+
"codeExamples": [
|
|
60
|
+
{
|
|
61
|
+
"title": "Basic Worker with routing",
|
|
62
|
+
"language": "typescript",
|
|
63
|
+
"code": "interface Env {\n API_SECRET: string;\n}\n\nfunction jsonResponse(data: unknown, status = 200): Response {\n return new Response(JSON.stringify(data), {\n status,\n headers: { 'Content-Type': 'application/json' },\n });\n}\n\nexport default {\n async fetch(request: Request, env: Env): Promise<Response> {\n const url = new URL(request.url);\n const { pathname } = url;\n\n // Simple router\n if (pathname === '/api/health' && request.method === 'GET') {\n return jsonResponse({ status: 'ok', region: request.cf?.colo });\n }\n\n if (pathname === '/api/echo' && request.method === 'POST') {\n const body = await request.json();\n return jsonResponse({ echo: body });\n }\n\n if (pathname.startsWith('/api/')) {\n return jsonResponse({ error: 'Not found' }, 404);\n }\n\n // Pass non-API requests through to origin\n return fetch(request);\n },\n};",
|
|
64
|
+
"notes": "Use new URL(request.url) to parse the URL — the global URL constructor is available in Workers. request.cf contains Cloudflare metadata like the datacenter (colo), country, and ASN. Workers run on every incoming request without a cold start penalty."
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"title": "Worker with R2 storage integration",
|
|
68
|
+
"language": "typescript",
|
|
69
|
+
"code": "interface Env {\n MEDIA_BUCKET: R2Bucket;\n}\n\nexport default {\n async fetch(request: Request, env: Env): Promise<Response> {\n const url = new URL(request.url);\n // Expected path: /media/<object-key>\n const key = url.pathname.replace('/media/', '');\n\n if (!key) {\n return new Response('Missing key', { status: 400 });\n }\n\n if (request.method === 'GET') {\n // Serve file from R2\n const object = await env.MEDIA_BUCKET.get(key);\n\n if (!object) {\n return new Response('Object not found', { status: 404 });\n }\n\n const headers = new Headers();\n object.writeHttpMetadata(headers);\n headers.set('etag', object.httpEtag);\n headers.set('Cache-Control', 'public, max-age=31536000');\n\n return new Response(object.body, { headers });\n }\n\n if (request.method === 'PUT') {\n // Upload file to R2\n await env.MEDIA_BUCKET.put(key, request.body, {\n httpMetadata: {\n contentType: request.headers.get('Content-Type') ?? 'application/octet-stream',\n },\n });\n\n return new Response(JSON.stringify({ key, uploaded: true }), {\n status: 201,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n return new Response('Method not allowed', { status: 405 });\n },\n};",
|
|
70
|
+
"notes": "R2 bindings are declared in wrangler.toml: [[r2_buckets]] binding = 'MEDIA_BUCKET' bucket_name = 'my-bucket'. The env.MEDIA_BUCKET object provides get(), put(), delete(), and list() methods directly — no SDK needed inside a Worker."
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"gotchas": [
|
|
74
|
+
"The Workers runtime is NOT Node.js. Many Node.js APIs (fs, path, net, Node's built-in crypto) are not available. Use the Web Crypto API (crypto.subtle) instead of Node's crypto module. Check the Workers compatibility list at developers.cloudflare.com before assuming a Node.js package will work.",
|
|
75
|
+
"The CPU time limit is 10ms on the free plan per request. This is CPU execution time, not wall-clock time (network I/O and waiting on fetch calls does not count). CPU-intensive operations like image processing, complex regex on large strings, or parsing large JSON payloads will hit this limit and throw an error.",
|
|
76
|
+
"Workers use V8 isolates, not VMs or containers. There is NO persistent memory between requests. Any module-level variables are reset between requests (or shared unpredictably within the same isolate). Use KV, Durable Objects, or R2 for any state that must persist.",
|
|
77
|
+
"wrangler dev runs a local simulation that is NOT 100% identical to the production edge environment. Edge cases with headers, TLS fingerprinting, Cloudflare-specific request properties (request.cf), and some Workers APIs behave differently locally. Always test with wrangler dev --remote for critical behavior before deploying."
|
|
78
|
+
],
|
|
79
|
+
"reliability": {
|
|
80
|
+
"uptimeGuarantee": "99.9% uptime SLA (Workers Standard), globally redundant across 300+ PoPs",
|
|
81
|
+
"statusPageUrl": "https://www.cloudflarestatus.com",
|
|
82
|
+
"notes": "Requests automatically route to the nearest available Cloudflare datacenter. If one PoP is degraded, traffic is rerouted with automatic failover. Workers deployments are globally propagated within seconds."
|
|
83
|
+
},
|
|
84
|
+
"qualityScore": 9,
|
|
85
|
+
"qualityJustification": "Sub-millisecond cold starts (V8 isolates vs containers) make it the fastest serverless platform available. The global network means code runs within milliseconds of any user. The 100K free daily requests is genuinely useful for production traffic. Main limitation is the constrained runtime (not Node.js).",
|
|
86
|
+
"alternatives": ["vercel", "netlify", "fly-io"],
|
|
87
|
+
"complementary": ["cloudflare-r2", "upstash", "neon", "supabase"],
|
|
88
|
+
"bestFor": "Low-latency edge logic: API routing, auth middleware, A/B testing, content transformation — runs in 300+ global locations with near-zero cold starts",
|
|
89
|
+
"lastVerified": "2026-02-25",
|
|
90
|
+
"entryVersion": 1,
|
|
91
|
+
"addedBy": "claude-code-session-4"
|
|
92
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "DigitalOcean Spaces",
|
|
3
|
+
"slug": "digital-ocean-spaces",
|
|
4
|
+
"category": "infrastructure",
|
|
5
|
+
"subcategory": "object-storage",
|
|
6
|
+
"website": "https://www.digitalocean.com/products/spaces",
|
|
7
|
+
"description": "DigitalOcean Spaces is S3-compatible object storage with a built-in CDN, flat predictable pricing, and seamless integration for teams already running apps on DigitalOcean.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Store and serve user-uploaded files with built-in CDN",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Simple object storage for a DigitalOcean-hosted application",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Migrate from S3 to a simpler, flat-rate pricing model",
|
|
19
|
+
"fit": "good"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"auth": {
|
|
23
|
+
"method": "api_key",
|
|
24
|
+
"setupSteps": [
|
|
25
|
+
"Log in to your DigitalOcean account at cloud.digitalocean.com",
|
|
26
|
+
"Navigate to Spaces Object Storage and click Create a Space",
|
|
27
|
+
"Choose a region and bucket name, then click Create Space",
|
|
28
|
+
"Go to API → Spaces Keys → Generate New Key",
|
|
29
|
+
"Name the key and copy the Access Key and Secret Key — the secret is shown only once",
|
|
30
|
+
"Set DO_SPACES_KEY, DO_SPACES_SECRET, DO_SPACES_REGION, and DO_SPACES_BUCKET environment variables"
|
|
31
|
+
],
|
|
32
|
+
"envVarName": "DO_SPACES_KEY",
|
|
33
|
+
"codeSnippet": "import { S3Client } from '@aws-sdk/client-s3';\n\nconst spacesClient = new S3Client({\n region: process.env.DO_SPACES_REGION!,\n endpoint: `https://${process.env.DO_SPACES_REGION}.digitaloceanspaces.com`,\n credentials: {\n accessKeyId: process.env.DO_SPACES_KEY!,\n secretAccessKey: process.env.DO_SPACES_SECRET!,\n },\n});"
|
|
34
|
+
},
|
|
35
|
+
"pricing": {
|
|
36
|
+
"model": "paid",
|
|
37
|
+
"freeTier": null,
|
|
38
|
+
"startingPrice": "$5/month for 250GB storage + 1TB outbound transfer",
|
|
39
|
+
"costPer": "$0.02/GB additional storage, $0.01/GB additional transfer, $0.004/10K PUT requests, $0.004/10K GET requests after 10K included per month",
|
|
40
|
+
"pricingUrl": "https://www.digitalocean.com/pricing/spaces-object-storage"
|
|
41
|
+
},
|
|
42
|
+
"rateLimits": {
|
|
43
|
+
"tier": "standard tier",
|
|
44
|
+
"limit": "No published request rate limits. 1TB transfer/month included. CDN bandwidth is separate from Spaces bandwidth.",
|
|
45
|
+
"notes": "DigitalOcean does not publish specific per-bucket request rate limits for Spaces. Transfer limits apply to data out from Spaces directly; CDN transfer is metered separately if CDN is enabled.",
|
|
46
|
+
"retryStrategy": "Use exponential backoff on errors. The S3-compatible API uses standard S3 error codes and retry patterns."
|
|
47
|
+
},
|
|
48
|
+
"sdk": {
|
|
49
|
+
"primaryLanguage": "typescript",
|
|
50
|
+
"installCommand": "npm install --save-exact @aws-sdk/client-s3",
|
|
51
|
+
"importStatement": "import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';",
|
|
52
|
+
"otherLanguages": ["python", "go", "ruby", "php"]
|
|
53
|
+
},
|
|
54
|
+
"codeExamples": [
|
|
55
|
+
{
|
|
56
|
+
"title": "Upload to DigitalOcean Spaces",
|
|
57
|
+
"language": "typescript",
|
|
58
|
+
"code": "import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';\n\nconst spacesClient = new S3Client({\n region: process.env.DO_SPACES_REGION!,\n endpoint: `https://${process.env.DO_SPACES_REGION}.digitaloceanspaces.com`,\n credentials: {\n accessKeyId: process.env.DO_SPACES_KEY!,\n secretAccessKey: process.env.DO_SPACES_SECRET!,\n },\n});\n\nasync function uploadToSpaces(\n key: string,\n body: Buffer | string,\n contentType: string,\n isPublic = false\n): Promise<string> {\n const command = new PutObjectCommand({\n Bucket: process.env.DO_SPACES_BUCKET!,\n Key: key,\n Body: body,\n ContentType: contentType,\n ACL: isPublic ? 'public-read' : 'private',\n });\n\n await spacesClient.send(command);\n\n // Public URL format for Spaces\n const region = process.env.DO_SPACES_REGION!;\n const bucket = process.env.DO_SPACES_BUCKET!;\n return `https://${bucket}.${region}.digitaloceanspaces.com/${key}`;\n}\n\n// Usage: upload a publicly readable image\nconst publicUrl = await uploadToSpaces(\n 'images/product-hero.jpg',\n imageBuffer,\n 'image/jpeg',\n true\n);\nconsole.log('Uploaded to Spaces:', publicUrl);",
|
|
59
|
+
"notes": "Unlike S3, Spaces supports ACL (Access Control List) at the object level with public-read. The endpoint URL format is {region}.digitaloceanspaces.com. The bucket name is included in the path, not the subdomain, when constructing the endpoint for the S3 client."
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"title": "Enable CDN for a Spaces bucket and get CDN URL",
|
|
63
|
+
"language": "typescript",
|
|
64
|
+
"code": "import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';\n\nconst spacesClient = new S3Client({\n region: process.env.DO_SPACES_REGION!,\n endpoint: `https://${process.env.DO_SPACES_REGION}.digitaloceanspaces.com`,\n credentials: {\n accessKeyId: process.env.DO_SPACES_KEY!,\n secretAccessKey: process.env.DO_SPACES_SECRET!,\n },\n});\n\n// CDN must be enabled on the Space via the DigitalOcean dashboard first.\n// Once enabled, the CDN endpoint follows this pattern:\nfunction getCdnUrl(key: string): string {\n const bucket = process.env.DO_SPACES_BUCKET!;\n const region = process.env.DO_SPACES_REGION!;\n // Default CDN endpoint: {bucket}.{region}.cdn.digitaloceanspaces.com\n return `https://${bucket}.${region}.cdn.digitaloceanspaces.com/${key}`;\n}\n\nasync function uploadAndGetCdnUrl(\n key: string,\n body: Buffer,\n contentType: string\n): Promise<{ originUrl: string; cdnUrl: string }> {\n const command = new PutObjectCommand({\n Bucket: process.env.DO_SPACES_BUCKET!,\n Key: key,\n Body: body,\n ContentType: contentType,\n ACL: 'public-read',\n // Set cache headers for CDN\n CacheControl: 'public, max-age=31536000',\n });\n\n await spacesClient.send(command);\n\n const bucket = process.env.DO_SPACES_BUCKET!;\n const region = process.env.DO_SPACES_REGION!;\n\n return {\n originUrl: `https://${bucket}.${region}.digitaloceanspaces.com/${key}`,\n cdnUrl: getCdnUrl(key),\n };\n}\n\n// Usage\nconst { originUrl, cdnUrl } = await uploadAndGetCdnUrl(\n 'assets/logo.png',\n logoBuffer,\n 'image/png'\n);\nconsole.log('Origin URL:', originUrl);\nconsole.log('CDN URL:', cdnUrl);",
|
|
65
|
+
"notes": "CDN must be enabled on the Space in the DigitalOcean dashboard before CDN URLs will work. The CDN endpoint is {bucket}.{region}.cdn.digitaloceanspaces.com. Set CacheControl headers at upload time to control how long the CDN caches objects."
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"gotchas": [
|
|
69
|
+
"Spaces CDN uses DigitalOcean's CDN network (powered by Cloudflare in some regions, other providers in others). It does NOT automatically integrate with your own Cloudflare DNS — routing traffic through both Spaces CDN and Cloudflare's proxy can cause caching conflicts and unexpected behavior.",
|
|
70
|
+
"The $5/month flat rate includes 250GB + 1TB transfer per Space (bucket). If you create multiple Spaces, each Space is billed separately at $5/month minimum. There is no account-level pooling of storage or transfer across multiple Spaces.",
|
|
71
|
+
"Spaces is only available in select DigitalOcean regions: NYC3, SFO3, AMS3, SGP1, FRA1. You cannot create a Space in every DigitalOcean region. Choose your Space region to be geographically close to your Droplets or App Platform apps to avoid inter-region transfer costs.",
|
|
72
|
+
"Spaces does not support all S3 API features: no S3 Select, no Object Lock, no S3 Batch Operations. Object versioning must be enabled at Space creation time — it cannot be enabled on an existing Space. Review the S3 compatibility guide at docs.digitalocean.com before migrating from S3."
|
|
73
|
+
],
|
|
74
|
+
"reliability": {
|
|
75
|
+
"uptimeGuarantee": "99.9% uptime SLA",
|
|
76
|
+
"statusPageUrl": "https://status.digitalocean.com",
|
|
77
|
+
"notes": "Spaces data is replicated across multiple availability zones within the selected region. No cross-region replication is available."
|
|
78
|
+
},
|
|
79
|
+
"qualityScore": 7,
|
|
80
|
+
"qualityJustification": "Predictable flat pricing ($5/month for 250GB + 1TB) is its strongest selling point for teams that hate surprise bills. S3-compatible API means existing code works with minimal changes. However, Cloudflare R2 has a better free tier and zero egress fees, making Spaces most compelling for teams already invested in the DigitalOcean ecosystem.",
|
|
81
|
+
"alternatives": ["aws-s3", "cloudflare-r2", "cloudinary"],
|
|
82
|
+
"complementary": ["railway"],
|
|
83
|
+
"bestFor": "Simple object storage with predictable flat pricing for teams already using DigitalOcean infrastructure",
|
|
84
|
+
"lastVerified": "2026-02-25",
|
|
85
|
+
"entryVersion": 1,
|
|
86
|
+
"addedBy": "claude-code-session-4"
|
|
87
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Nango",
|
|
3
|
+
"slug": "nango",
|
|
4
|
+
"category": "integration",
|
|
5
|
+
"subcategory": "oauth-integrations",
|
|
6
|
+
"website": "https://www.nango.dev",
|
|
7
|
+
"description": "Nango is an open-source platform for building and managing OAuth integrations with 200+ APIs. It handles the OAuth flow, token refresh, credential storage, and provides a unified API to make authenticated requests to third-party services on behalf of your users.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Add 'Connect your GitHub/Salesforce/HubSpot' integration to your app",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Store and auto-refresh OAuth tokens for users' connected accounts",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Sync data from third-party APIs into your database on a schedule",
|
|
19
|
+
"fit": "good"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Build a white-label integration marketplace for your SaaS product",
|
|
23
|
+
"fit": "good"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth": {
|
|
27
|
+
"method": "api_key",
|
|
28
|
+
"setupSteps": [
|
|
29
|
+
"Create an account at app.nango.dev",
|
|
30
|
+
"Create a new environment (dev or prod) in the Nango dashboard",
|
|
31
|
+
"Copy the secret key from Settings → Secret Key",
|
|
32
|
+
"Set the NANGO_SECRET_KEY environment variable in your backend",
|
|
33
|
+
"Configure integrations in the dashboard: add each OAuth provider (e.g., GitHub, Salesforce) with its client ID and client secret obtained from that provider's developer portal",
|
|
34
|
+
"Install the Nango Node SDK: npm install --save-exact @nangohq/node"
|
|
35
|
+
],
|
|
36
|
+
"envVarName": "NANGO_SECRET_KEY",
|
|
37
|
+
"codeSnippet": "import Nango from '@nangohq/node';\n\nconst nango = new Nango({ secretKey: process.env.NANGO_SECRET_KEY });\n\n// Retrieve a connection's access token to make API calls on behalf of a user\nconst connection = await nango.getConnection('github', 'user-123');\nconst accessToken = connection.credentials.access_token;"
|
|
38
|
+
},
|
|
39
|
+
"pricing": {
|
|
40
|
+
"model": "freemium",
|
|
41
|
+
"freeTier": "Free: unlimited OAuth connections, 100 syncs/month, community support",
|
|
42
|
+
"startingPrice": "$250/month (Scale) for unlimited syncs, SLAs, and priority support",
|
|
43
|
+
"costPer": null,
|
|
44
|
+
"pricingUrl": "https://www.nango.dev/pricing"
|
|
45
|
+
},
|
|
46
|
+
"rateLimits": {
|
|
47
|
+
"tier": "free tier",
|
|
48
|
+
"limit": "Unlimited OAuth connections on all plans. Syncs (scheduled data pulls from third-party APIs) limited to 100/month on the free tier.",
|
|
49
|
+
"notes": "Nango proxies API requests through its infrastructure, so rate limits of the underlying third-party API still apply. Nango itself does not impose additional rate limits on proxy API calls. Token refresh is automatic and does not count against limits.",
|
|
50
|
+
"retryStrategy": "Nango handles OAuth token refresh automatically on every request. For sync failures, configure retry logic in the nango.yaml sync definition. For proxy calls, implement retry with exponential backoff in your application code since Nango passes through API errors."
|
|
51
|
+
},
|
|
52
|
+
"sdk": {
|
|
53
|
+
"primaryLanguage": "typescript",
|
|
54
|
+
"installCommand": "npm install --save-exact @nangohq/node",
|
|
55
|
+
"importStatement": "import Nango from '@nangohq/node';",
|
|
56
|
+
"otherLanguages": ["javascript", "python"]
|
|
57
|
+
},
|
|
58
|
+
"codeExamples": [
|
|
59
|
+
{
|
|
60
|
+
"title": "Initiate OAuth flow and retrieve access token",
|
|
61
|
+
"language": "typescript",
|
|
62
|
+
"code": "// --- Frontend: initiate the OAuth connection for a user ---\n// Install the frontend SDK: npm install --save-exact @nangohq/frontend\nimport Nango from '@nangohq/frontend';\n\nconst nango = new Nango();\n\nasync function connectGitHub(userId: string): Promise<void> {\n // Your backend endpoint generates a session token for this user\n const response = await fetch('/api/nango/session', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ userId }),\n });\n const { sessionToken } = await response.json() as { sessionToken: string };\n\n // Opens the OAuth popup — Nango handles the full OAuth flow\n await nango.auth('github', sessionToken);\n console.log('GitHub connected successfully!');\n}\n\n// --- Backend: generate a session token and use the connection ---\nimport Nango from '@nangohq/node';\n\nconst nango = new Nango({ secretKey: process.env.NANGO_SECRET_KEY });\n\n// Generate a session token (call this from your /api/nango/session endpoint)\nasync function createNangoSession(userId: string): Promise<string> {\n const session = await nango.createConnectSession({\n end_user: { id: userId },\n // Optionally restrict which integrations the user can connect\n allowed_integrations: ['github'],\n });\n return session.data.token;\n}\n\n// After the user connects, retrieve their access token to make API calls\nasync function getGitHubAccessToken(userId: string): Promise<string> {\n const connection = await nango.getConnection('github', userId);\n // Nango automatically refreshes the token if it has expired\n const accessToken = (connection.credentials as { access_token: string }).access_token;\n return accessToken;\n}\n\n// Use the token to call the GitHub API directly\nconst token = await getGitHubAccessToken('user-123');\nconst ghResponse = await fetch('https://api.github.com/user', {\n headers: { Authorization: `Bearer ${token}` },\n});\nconst githubUser = await ghResponse.json();\nconsole.log('GitHub user:', githubUser);",
|
|
63
|
+
"notes": "The connection_id (second argument to getConnection) should be your own user's ID — this is how Nango maps stored tokens back to your users. Use consistent IDs (e.g., your database user UUID) so you can always retrieve the right token. Nango automatically refreshes expired tokens on every getConnection() call."
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"title": "Make a proxied API call on behalf of a user",
|
|
67
|
+
"language": "typescript",
|
|
68
|
+
"code": "import Nango from '@nangohq/node';\n\nconst nango = new Nango({ secretKey: process.env.NANGO_SECRET_KEY });\n\ninterface GitHubRepo {\n id: number;\n name: string;\n full_name: string;\n private: boolean;\n html_url: string;\n stargazers_count: number;\n}\n\n// Use nango.proxy() to make authenticated API calls without managing tokens\nasync function getUserRepos(userId: string): Promise<GitHubRepo[]> {\n const response = await nango.proxy<GitHubRepo[]>({\n providerConfigKey: 'github', // The integration name in your Nango dashboard\n connectionId: userId, // Your user's ID (maps to their stored token)\n method: 'GET',\n endpoint: '/user/repos',\n params: {\n sort: 'updated',\n per_page: '30',\n },\n });\n\n return response.data;\n}\n\n// Example: list repos for a connected GitHub user\nconst repos = await getUserRepos('user-123');\nconsole.log(`Found ${repos.length} repositories:`);\nfor (const repo of repos) {\n console.log(` - ${repo.full_name} (${repo.stargazers_count} stars)`);\n}\n\n// You can also make POST requests via proxy\nasync function createIssue(\n userId: string,\n owner: string,\n repoName: string,\n title: string,\n body: string\n): Promise<void> {\n await nango.proxy({\n providerConfigKey: 'github',\n connectionId: userId,\n method: 'POST',\n endpoint: `/repos/${owner}/${repoName}/issues`,\n data: { title, body },\n });\n}",
|
|
69
|
+
"notes": "nango.proxy() automatically injects the correct Authorization header using the stored and refreshed token for that connection. The endpoint is relative to the base URL configured for the integration in Nango. This approach keeps token handling entirely in Nango — your application code never needs to handle token refresh logic."
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"gotchas": [
|
|
73
|
+
"Nango does NOT provide pre-configured OAuth credentials. You must register your own OAuth app with each third-party provider (GitHub, Salesforce, HubSpot, etc.) and supply the client ID and client secret to Nango. Integrating 10 providers means registering 10 separate OAuth apps across 10 developer portals — budget time for this setup work.",
|
|
74
|
+
"The open-source self-hosted version of Nango has fewer features than the cloud offering. Scheduled sync orchestration, the pre-built integration templates marketplace, and some advanced proxy features are cloud-only. Review the feature comparison at docs.nango.dev before committing to self-hosting.",
|
|
75
|
+
"Nango stores OAuth access tokens and refresh tokens on their servers (or your self-hosted instance). You are trusting Nango with credentials that grant access to your users' third-party accounts. Review Nango's security documentation, encryption at rest policies, and ensure this arrangement complies with your security requirements and terms of service with end users."
|
|
76
|
+
],
|
|
77
|
+
"reliability": {
|
|
78
|
+
"uptimeGuarantee": "99.9% SLA (Scale tier and above)",
|
|
79
|
+
"statusPageUrl": "https://www.nangostatus.dev",
|
|
80
|
+
"notes": "Open-source self-hosted option available for full control. Cloud version uses isolated credential storage per customer environment. Token refresh happens automatically in Nango's infrastructure, decoupled from your application availability."
|
|
81
|
+
},
|
|
82
|
+
"qualityScore": 8,
|
|
83
|
+
"qualityJustification": "Solves the hardest part of third-party integrations — OAuth token lifecycle management and refresh — elegantly. 200+ pre-built integration configurations save significant OAuth boilerplate. The proxy API and connection model are well-designed. For teams building product integrations, Nango is substantially faster than implementing OAuth yourself for each provider.",
|
|
84
|
+
"alternatives": [],
|
|
85
|
+
"complementary": ["supabase", "neon", "clerk", "auth0"],
|
|
86
|
+
"bestFor": "Building product integrations that let users connect their third-party accounts (GitHub, Salesforce, HubSpot) via OAuth, without managing token storage and refresh yourself",
|
|
87
|
+
"lastVerified": "2026-02-25",
|
|
88
|
+
"entryVersion": 1,
|
|
89
|
+
"addedBy": "claude-code-session-4"
|
|
90
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Zapier",
|
|
3
|
+
"slug": "zapier",
|
|
4
|
+
"category": "integration",
|
|
5
|
+
"subcategory": "no-code-automation",
|
|
6
|
+
"website": "https://zapier.com",
|
|
7
|
+
"description": "Zapier is the dominant no-code automation platform connecting 6,000+ apps with trigger-action workflows (\"Zaps\"). For developers, Zapier offers Webhooks for triggering Zaps programmatically or sending data from custom apps into any of 6,000+ connected services.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Trigger actions in 6,000+ apps from a webhook or API call",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Connect two SaaS tools without writing any code",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Forward form submissions or payments to CRM and email",
|
|
19
|
+
"fit": "good"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Build a custom Zapier integration for your own product",
|
|
23
|
+
"fit": "good"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth": {
|
|
27
|
+
"method": "api_key",
|
|
28
|
+
"setupSteps": [
|
|
29
|
+
"Create an account at zapier.com",
|
|
30
|
+
"Create a new Zap and search for 'Webhooks by Zapier' as the trigger",
|
|
31
|
+
"Select 'Catch Hook' as the trigger event to get an instant webhook URL",
|
|
32
|
+
"Copy the webhook URL shown — this is your ZAPIER_WEBHOOK_URL endpoint",
|
|
33
|
+
"Send a test POST request to the webhook URL to confirm the trigger fires",
|
|
34
|
+
"Add action steps in the Zap editor (e.g., add row to Google Sheets, post to Slack)",
|
|
35
|
+
"Publish the Zap to activate it"
|
|
36
|
+
],
|
|
37
|
+
"envVarName": "ZAPIER_WEBHOOK_URL",
|
|
38
|
+
"codeSnippet": "const response = await fetch(process.env.ZAPIER_WEBHOOK_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ event: 'user.signed_up', email: 'user@example.com' }),\n});\nif (!response.ok) {\n throw new Error(`Zapier webhook failed: ${response.status}`);\n}\n// Zapier returns 200 with 'Accepted' on success"
|
|
39
|
+
},
|
|
40
|
+
"pricing": {
|
|
41
|
+
"model": "freemium",
|
|
42
|
+
"freeTier": "Free: 100 tasks/month, 5 Zaps, 15-minute polling interval",
|
|
43
|
+
"startingPrice": "$19.99/month (Starter) for 750 tasks/month, 20 Zaps, 15-minute polling",
|
|
44
|
+
"costPer": null,
|
|
45
|
+
"pricingUrl": "https://zapier.com/pricing"
|
|
46
|
+
},
|
|
47
|
+
"rateLimits": {
|
|
48
|
+
"tier": "free tier",
|
|
49
|
+
"limit": "100 tasks/month on free plan; tasks are counted per action step (a 3-step Zap consumes 3 tasks per run)",
|
|
50
|
+
"notes": "Webhook triggers (Catch Hook) are real-time and instant on all plans. Polling triggers on the free plan check every 15 minutes; paid plans support 1-minute polling. Task count resets monthly.",
|
|
51
|
+
"retryStrategy": "Zapier automatically retries failed tasks up to 3 times before marking them errored. Failed tasks appear in Task History and can be manually replayed from the Zapier dashboard. Implement idempotency in your receiving endpoint to handle replays safely."
|
|
52
|
+
},
|
|
53
|
+
"sdk": {
|
|
54
|
+
"primaryLanguage": "typescript",
|
|
55
|
+
"installCommand": "npm install --save-exact node-fetch",
|
|
56
|
+
"importStatement": "import fetch from 'node-fetch';",
|
|
57
|
+
"otherLanguages": ["javascript", "python", "ruby"]
|
|
58
|
+
},
|
|
59
|
+
"codeExamples": [
|
|
60
|
+
{
|
|
61
|
+
"title": "Send data to a Zapier webhook",
|
|
62
|
+
"language": "typescript",
|
|
63
|
+
"code": "interface ZapierWebhookPayload {\n [key: string]: string | number | boolean | null;\n}\n\nasync function triggerZap(payload: ZapierWebhookPayload): Promise<void> {\n const webhookUrl = process.env.ZAPIER_WEBHOOK_URL;\n if (!webhookUrl) {\n throw new Error('ZAPIER_WEBHOOK_URL environment variable is not set');\n }\n\n const response = await fetch(webhookUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n throw new Error(`Zapier webhook request failed: ${response.status} ${response.statusText}`);\n }\n\n // Zapier responds with plain text 'Accepted' on success\n const body = await response.text();\n console.log('Zap triggered:', body);\n}\n\n// Example: trigger a Zap when a user signs up\nawait triggerZap({\n event: 'user.signed_up',\n email: 'jane@example.com',\n name: 'Jane Smith',\n plan: 'free',\n signedUpAt: new Date().toISOString(),\n});\n// Zapier will now execute all action steps in the Zap:\n// e.g., add row to Google Sheets, send Slack notification, create HubSpot contact",
|
|
64
|
+
"notes": "The webhook URL is specific to each Zap — copy it from the 'Catch Hook' trigger step in the Zap editor. Any JSON-serializable fields you send become available as variables in Zap action steps. Field names become the variable names visible in the Zapier editor."
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"title": "Receive a webhook FROM Zapier in your app",
|
|
68
|
+
"language": "typescript",
|
|
69
|
+
"code": "import express, { Request, Response } from 'express';\n\ninterface ZapierWebhookBody {\n event?: string;\n [key: string]: unknown;\n}\n\nconst app = express();\napp.use(express.json());\n\n// Zapier sends data to your app using the 'Webhooks by Zapier' action\n// Configure the Zap to POST to your endpoint URL\napp.post('/webhooks/zapier', (req: Request, res: Response): void => {\n const body = req.body as ZapierWebhookBody;\n\n console.log('Received Zapier webhook:', body);\n\n // Zapier checks for a 2xx status to consider the action successful\n // If you return 4xx/5xx, Zapier will retry and eventually mark the task errored\n const event = body.event ?? 'unknown';\n\n switch (event) {\n case 'new_lead':\n // Handle new CRM lead forwarded from HubSpot via Zapier\n console.log('New lead received from Zapier:', body);\n break;\n case 'payment_received':\n // Handle payment notification forwarded from Stripe via Zapier\n console.log('Payment notification from Zapier:', body);\n break;\n default:\n console.log('Unhandled Zapier event:', event);\n }\n\n // Always return 200 quickly — Zapier has a short timeout (~10s)\n res.status(200).json({ received: true });\n});\n\napp.listen(3000, () => console.log('Listening for Zapier webhooks on port 3000'));",
|
|
70
|
+
"notes": "Zapier expects a 2xx response within roughly 10 seconds. If your processing takes longer, immediately return 200 and process asynchronously (queue the job). Zapier does not sign its webhook requests by default — if you need to verify the source, use a secret in the URL path or a shared header value configured in the Zap's webhook action settings."
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"gotchas": [
|
|
74
|
+
"Zapier's free plan uses 15-minute polling for most app triggers — this is NOT real-time automation. For instant reactions (e.g., new Stripe payment triggers an email), you need a paid plan or must use 'Webhooks by Zapier' as the trigger, which IS instant on all plans.",
|
|
75
|
+
"Tasks are counted per action step, not per Zap run. A Zap with 4 action steps consumes 4 tasks every time it runs. An apparently simple automation can drain your monthly quota surprisingly fast — audit your multi-step Zaps before hitting task limits.",
|
|
76
|
+
"Zapier is optimized for non-developers. When you need complex logic (loops, conditional branches, data transformation beyond basic formatting), the built-in tools (Formatter, Filter, Paths) become limiting quickly. For code-heavy workflows with branching logic, dedicated workflow engines are more appropriate.",
|
|
77
|
+
"Data sent through Zapier passes through Zapier's servers. Do NOT send sensitive PII, credentials, or HIPAA-covered data through Zapier unless your plan includes a Business Associate Agreement (BAA) and you have reviewed their data handling and retention policies."
|
|
78
|
+
],
|
|
79
|
+
"reliability": {
|
|
80
|
+
"uptimeGuarantee": "99.9% SLA (Business and Company plans)",
|
|
81
|
+
"statusPageUrl": "https://status.zapier.com",
|
|
82
|
+
"notes": "Zapier's core infrastructure is mature and reliable. The primary failure mode is third-party API changes breaking individual Zaps — Zapier cannot control external API stability. Monitor Task History for errored tasks and set up Zapier error notifications."
|
|
83
|
+
},
|
|
84
|
+
"qualityScore": 7,
|
|
85
|
+
"qualityJustification": "Unmatched breadth with 6,000+ integrations — if you need to connect two SaaS tools with no code, nothing beats it. For developers, the webhook trigger is simple and genuinely useful. Main drawbacks: task-based pricing gets expensive at scale, 15-minute polling on the free tier is frustrating, and it is not designed for complex programmatic workflows with conditional logic.",
|
|
86
|
+
"alternatives": [],
|
|
87
|
+
"complementary": ["stripe", "resend", "typeform", "cal-com", "shopify-api"],
|
|
88
|
+
"bestFor": "No-code automation between SaaS tools, or programmatically triggering actions across 6,000+ apps via webhooks without building direct API integrations",
|
|
89
|
+
"lastVerified": "2026-02-25",
|
|
90
|
+
"entryVersion": 1,
|
|
91
|
+
"addedBy": "claude-code-session-4"
|
|
92
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Google Maps Platform",
|
|
3
|
+
"slug": "google-maps",
|
|
4
|
+
"category": "maps",
|
|
5
|
+
"subcategory": "maps-and-navigation",
|
|
6
|
+
"website": "https://developers.google.com/maps",
|
|
7
|
+
"description": "Google Maps Platform is the world's most comprehensive mapping service, providing Maps, Places, Routes, and Geolocation APIs backed by Google's unmatched global map data. It is the default choice when place data accuracy, POI coverage, and user familiarity are the top priorities.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Add a Google Maps embed to a webpage",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Autocomplete address input fields with real-time suggestions",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Validate and geocode user addresses",
|
|
19
|
+
"fit": "perfect"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Calculate distance and travel time between locations",
|
|
23
|
+
"fit": "perfect"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"task": "Find nearby places (restaurants, stores) by category",
|
|
27
|
+
"fit": "perfect"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"auth": {
|
|
31
|
+
"method": "api_key",
|
|
32
|
+
"setupSteps": [
|
|
33
|
+
"Go to console.cloud.google.com",
|
|
34
|
+
"Create or select a project",
|
|
35
|
+
"Go to APIs & Services > Enable APIs and enable the specific APIs you need (Maps JS, Places, Geocoding, etc.)",
|
|
36
|
+
"Go to APIs & Services > Credentials and create an API Key",
|
|
37
|
+
"Restrict the API key to specific APIs and HTTP referrers/IP addresses",
|
|
38
|
+
"Set GOOGLE_MAPS_API_KEY (and NEXT_PUBLIC_GOOGLE_MAPS_API_KEY for browser use)"
|
|
39
|
+
],
|
|
40
|
+
"envVarName": "GOOGLE_MAPS_API_KEY",
|
|
41
|
+
"codeSnippet": "// Browser: load via script tag\n// <script src=\"https://maps.googleapis.com/maps/api/js?key=API_KEY&libraries=places\"></script>\n// Server: use @googlemaps/google-maps-services-js\nimport { Client } from '@googlemaps/google-maps-services-js';\nconst client = new Client({});"
|
|
42
|
+
},
|
|
43
|
+
"pricing": {
|
|
44
|
+
"model": "freemium",
|
|
45
|
+
"freeTier": "$200/month free credit (resets monthly)",
|
|
46
|
+
"startingPrice": "$200 free credit covers ~28,000 map loads or 40,000 geocoding requests",
|
|
47
|
+
"costPer": "Maps: $7/1,000 loads; Geocoding: $5/1,000 requests; Places: $17-32/1,000 requests",
|
|
48
|
+
"pricingUrl": "https://developers.google.com/maps/billing-and-pricing/pricing"
|
|
49
|
+
},
|
|
50
|
+
"rateLimits": {
|
|
51
|
+
"tier": "default",
|
|
52
|
+
"limit": "50 requests/second (Geocoding); 100 requests/second (Places); varies by API",
|
|
53
|
+
"notes": "Rate limits are per API key. QPS limits can be increased via the Google Cloud Console.",
|
|
54
|
+
"retryStrategy": "Respect Retry-After headers and implement exponential backoff for OVER_QUERY_LIMIT responses"
|
|
55
|
+
},
|
|
56
|
+
"sdk": {
|
|
57
|
+
"primaryLanguage": "typescript",
|
|
58
|
+
"installCommand": "npm install --save-exact @googlemaps/google-maps-services-js @types/google.maps",
|
|
59
|
+
"importStatement": "import { Client } from '@googlemaps/google-maps-services-js';",
|
|
60
|
+
"otherLanguages": ["python", "java", "go", "ruby", "node"]
|
|
61
|
+
},
|
|
62
|
+
"codeExamples": [
|
|
63
|
+
{
|
|
64
|
+
"title": "Geocode an address (server-side)",
|
|
65
|
+
"language": "typescript",
|
|
66
|
+
"code": "import { Client } from '@googlemaps/google-maps-services-js';\n\nconst client = new Client({});\n\nconst response = await client.geocode({\n params: {\n address: '1600 Amphitheatre Parkway, Mountain View, CA',\n key: process.env.GOOGLE_MAPS_API_KEY!,\n },\n});\n\nconst result = response.data.results[0];\nif (!result) throw new Error('Address not found');\n\nconst { lat, lng } = result.geometry.location;\nconsole.log(`Lat: ${lat}, Lng: ${lng}`);\nconsole.log('Formatted:', result.formatted_address);",
|
|
67
|
+
"notes": "Server-side geocoding uses your unrestricted API key. For browser use, add the Maps JavaScript API with Places library. Always restrict your browser API key to specific domains."
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"gotchas": [
|
|
71
|
+
"The $200/month free credit sounds generous, but the Places API (New) can cost $17-32 per 1,000 requests, meaning it's exhausted in ~6,000-11,000 requests. Caching results is essential.",
|
|
72
|
+
"You need to enable EACH API separately in the Google Cloud Console — Maps JavaScript API, Geocoding API, Places API, and Directions API are all separate products with separate billing.",
|
|
73
|
+
"API keys must be restricted. An unrestricted key leaked in your frontend code can be used by anyone and run up charges. Restrict browser keys to your domain and server keys to specific APIs.",
|
|
74
|
+
"The Places Autocomplete API has a minimum character threshold and the widget UI is hard to customize compared to Mapbox. If you need full design control over the autocomplete dropdown, Mapbox's Geocoding API is more flexible."
|
|
75
|
+
],
|
|
76
|
+
"reliability": {
|
|
77
|
+
"uptimeGuarantee": "99.9% uptime SLA",
|
|
78
|
+
"statusPageUrl": "https://status.cloud.google.com",
|
|
79
|
+
"notes": "Google Maps has the most comprehensive global coverage and is the most reliable mapping platform. Infrastructure is backed by Google Cloud."
|
|
80
|
+
},
|
|
81
|
+
"qualityScore": 8,
|
|
82
|
+
"qualityJustification": "Unmatched data quality and global coverage, especially for POI data and place information. The $200/month free credit covers many use cases. Billing complexity, Places API cost, and harder API key management are the main drawbacks compared to Mapbox.",
|
|
83
|
+
"alternatives": ["mapbox"],
|
|
84
|
+
"complementary": ["supabase", "stripe", "clerk"],
|
|
85
|
+
"bestFor": "Address autocomplete, geocoding, and place search where Google's superior data coverage and user familiarity are the top priorities",
|
|
86
|
+
"lastVerified": "2026-02-25",
|
|
87
|
+
"entryVersion": 1,
|
|
88
|
+
"addedBy": "claude-code-session-2"
|
|
89
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Mapbox",
|
|
3
|
+
"slug": "mapbox",
|
|
4
|
+
"category": "maps",
|
|
5
|
+
"subcategory": "maps-and-navigation",
|
|
6
|
+
"website": "https://www.mapbox.com",
|
|
7
|
+
"description": "Mapbox is a developer-focused mapping platform providing interactive maps, geocoding, routing, navigation, and spatial data visualization. It is the preferred choice for applications needing highly customizable maps, offline navigation, or custom map styles — used by Snap, Instacart, and many data visualization tools.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Add interactive, customizable maps to a web or mobile app",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Geocode addresses and search for places",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Build turn-by-turn navigation in a mobile app",
|
|
19
|
+
"fit": "perfect"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Display data visualizations on a map (heatmaps, clusters)",
|
|
23
|
+
"fit": "perfect"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"task": "Simple embedded Google-style map on a webpage",
|
|
27
|
+
"fit": "good"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"auth": {
|
|
31
|
+
"method": "api_key",
|
|
32
|
+
"setupSteps": [
|
|
33
|
+
"Sign up at mapbox.com",
|
|
34
|
+
"Go to your Account page to find your default public access token",
|
|
35
|
+
"For server-side use, create a secret token with appropriate scopes",
|
|
36
|
+
"Set MAPBOX_ACCESS_TOKEN environment variable (or NEXT_PUBLIC_MAPBOX_TOKEN for browser)"
|
|
37
|
+
],
|
|
38
|
+
"envVarName": "MAPBOX_ACCESS_TOKEN",
|
|
39
|
+
"codeSnippet": "import mapboxgl from 'mapbox-gl';\nmapboxgl.accessToken = process.env.NEXT_PUBLIC_MAPBOX_TOKEN!;"
|
|
40
|
+
},
|
|
41
|
+
"pricing": {
|
|
42
|
+
"model": "freemium",
|
|
43
|
+
"freeTier": "50,000 map loads/month, 100,000 geocoding/month",
|
|
44
|
+
"startingPrice": "$50/month for higher usage (pay-as-you-go above free tier)",
|
|
45
|
+
"costPer": "$5 per 1,000 map loads above free tier; $0.75 per 1,000 geocoding requests",
|
|
46
|
+
"pricingUrl": "https://www.mapbox.com/pricing"
|
|
47
|
+
},
|
|
48
|
+
"rateLimits": {
|
|
49
|
+
"tier": "all tiers",
|
|
50
|
+
"limit": "600 requests/minute for Geocoding API (default)",
|
|
51
|
+
"notes": "Map loads are counted per session (not per tile). Higher rate limits available on paid plans.",
|
|
52
|
+
"retryStrategy": "Implement exponential backoff for 429 responses. Cache geocoding results to avoid redundant API calls."
|
|
53
|
+
},
|
|
54
|
+
"sdk": {
|
|
55
|
+
"primaryLanguage": "typescript",
|
|
56
|
+
"installCommand": "npm install --save-exact mapbox-gl @types/mapbox-gl",
|
|
57
|
+
"importStatement": "import mapboxgl from 'mapbox-gl';\nimport 'mapbox-gl/dist/mapbox-gl.css';",
|
|
58
|
+
"otherLanguages": ["swift", "android", "react-native", "python"]
|
|
59
|
+
},
|
|
60
|
+
"codeExamples": [
|
|
61
|
+
{
|
|
62
|
+
"title": "Render an interactive map in React",
|
|
63
|
+
"language": "typescript",
|
|
64
|
+
"code": "import { useRef, useEffect } from 'react';\nimport mapboxgl from 'mapbox-gl';\nimport 'mapbox-gl/dist/mapbox-gl.css';\n\nmapboxgl.accessToken = process.env.NEXT_PUBLIC_MAPBOX_TOKEN!;\n\nexport function Map() {\n const mapContainer = useRef<HTMLDivElement>(null);\n const map = useRef<mapboxgl.Map | null>(null);\n\n useEffect(() => {\n if (map.current || !mapContainer.current) return;\n\n map.current = new mapboxgl.Map({\n container: mapContainer.current,\n style: 'mapbox://styles/mapbox/streets-v12',\n center: [-74.0060, 40.7128], // NYC\n zoom: 12,\n });\n\n // Add a marker\n new mapboxgl.Marker()\n .setLngLat([-74.0060, 40.7128])\n .addTo(map.current);\n\n return () => map.current?.remove();\n }, []);\n\n return <div ref={mapContainer} style={{ height: '400px', width: '100%' }} />;\n}",
|
|
65
|
+
"notes": "Remember to import 'mapbox-gl/dist/mapbox-gl.css' — without it, the map UI controls won't render. In Next.js, add this to your layout or global CSS."
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"gotchas": [
|
|
69
|
+
"Mapbox GL JS requires WebGL. It does not work in environments without WebGL support (some headless browsers, server-side rendering). Use dynamic imports in Next.js to prevent SSR issues.",
|
|
70
|
+
"The Mapbox access token is public-facing (must be in client-side code). Always restrict your public token to specific URLs in the Mapbox dashboard to prevent unauthorized usage from stealing your quota.",
|
|
71
|
+
"Map loads are counted per web session, not per page view. A single user session that initializes the map once counts as one load. But if your SPA reinitializes the map on every route change, you'll burn through quota quickly.",
|
|
72
|
+
"Custom map styles using Mapbox Studio look great but can be complex to maintain. For most apps, the built-in styles (streets-v12, satellite-streets-v12) are sufficient and require no maintenance."
|
|
73
|
+
],
|
|
74
|
+
"reliability": {
|
|
75
|
+
"uptimeGuarantee": "99.9% uptime SLA",
|
|
76
|
+
"statusPageUrl": "https://status.mapbox.com",
|
|
77
|
+
"notes": "Mapbox serves tiles from a global CDN. Core map rendering is client-side (WebGL), so partial API outages rarely affect the user experience."
|
|
78
|
+
},
|
|
79
|
+
"qualityScore": 8,
|
|
80
|
+
"qualityJustification": "Best choice for custom map styling and data visualization on maps. More developer-friendly than Google Maps with better pricing for most use cases. The 50k free map loads/month is sufficient for most apps. Requires WebGL and has a steeper initial learning curve than Google Maps.",
|
|
81
|
+
"alternatives": ["google-maps"],
|
|
82
|
+
"complementary": ["supabase", "stripe"],
|
|
83
|
+
"bestFor": "Custom, interactive maps with data visualization, heatmaps, and highly styled cartography for web and mobile apps",
|
|
84
|
+
"lastVerified": "2026-02-25",
|
|
85
|
+
"entryVersion": 1,
|
|
86
|
+
"addedBy": "claude-code-session-2"
|
|
87
|
+
}
|