@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": "Contentful",
|
|
3
|
+
"slug": "contentful",
|
|
4
|
+
"category": "cms",
|
|
5
|
+
"subcategory": "headless-cms",
|
|
6
|
+
"website": "https://contentful.com",
|
|
7
|
+
"description": "Contentful is an enterprise-grade headless CMS that stores structured content and delivers it via REST and GraphQL APIs. Content editors use the Contentful web app; developers fetch content in any framework. Strong for large teams needing workflow approvals, localization, and rich media management. The content model is flexible — define your own content types.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Fetch blog posts, marketing pages, or product content for a web app",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Build a multi-language website with locale-specific content",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Enable non-technical content editors to manage website content",
|
|
19
|
+
"fit": "good"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Integrate structured content into a mobile app",
|
|
23
|
+
"fit": "good"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth": {
|
|
27
|
+
"method": "api_key",
|
|
28
|
+
"setupSteps": [
|
|
29
|
+
"Create a Contentful account at contentful.com",
|
|
30
|
+
"Create a new Space (a Space is your content repository)",
|
|
31
|
+
"Define your Content Types (the schema for your content)",
|
|
32
|
+
"Navigate to Settings → API Keys → Add API Key",
|
|
33
|
+
"Copy the Space ID and Content Delivery API access token",
|
|
34
|
+
"For write access, generate a Content Management API token under Settings → API Keys → Content Management Tokens",
|
|
35
|
+
"Set CONTENTFUL_DELIVERY_TOKEN, CONTENTFUL_SPACE_ID, and CONTENTFUL_ENVIRONMENT_ID environment variables"
|
|
36
|
+
],
|
|
37
|
+
"envVarName": "CONTENTFUL_DELIVERY_TOKEN",
|
|
38
|
+
"codeSnippet": "import { createClient } from 'contentful';\n\nconst client = createClient({\n space: process.env.CONTENTFUL_SPACE_ID!,\n environment: process.env.CONTENTFUL_ENVIRONMENT_ID ?? 'master',\n accessToken: process.env.CONTENTFUL_DELIVERY_TOKEN!,\n});"
|
|
39
|
+
},
|
|
40
|
+
"pricing": {
|
|
41
|
+
"model": "freemium",
|
|
42
|
+
"freeTier": "Free Community plan: 1 space, 25K API calls/month, 500MB assets, 2 roles, 5 users",
|
|
43
|
+
"startingPrice": "$300/month (Basic) for 25 users, 2M API calls, 5 spaces",
|
|
44
|
+
"costPer": null,
|
|
45
|
+
"pricingUrl": "https://www.contentful.com/pricing/"
|
|
46
|
+
},
|
|
47
|
+
"rateLimits": {
|
|
48
|
+
"tier": "free tier",
|
|
49
|
+
"limit": "25,000 API calls/month (Community), no per-second limit documented — burst throttling at 55 requests/second on Delivery API",
|
|
50
|
+
"notes": "Content Delivery API responses are cached at Contentful's CDN globally. Cache invalidation happens on publish — unpublished content may be served from cache for up to 15 minutes.",
|
|
51
|
+
"retryStrategy": "Implement retry with exponential backoff on 429 responses. Use the GraphQL API for complex queries to reduce call count (fetch multiple content types in one request)."
|
|
52
|
+
},
|
|
53
|
+
"sdk": {
|
|
54
|
+
"primaryLanguage": "typescript",
|
|
55
|
+
"installCommand": "npm install --save-exact contentful contentful-management",
|
|
56
|
+
"importStatement": "import { createClient } from 'contentful';",
|
|
57
|
+
"otherLanguages": ["python", "java", "ruby", "php"]
|
|
58
|
+
},
|
|
59
|
+
"codeExamples": [
|
|
60
|
+
{
|
|
61
|
+
"title": "Fetch blog posts from Contentful",
|
|
62
|
+
"language": "typescript",
|
|
63
|
+
"code": "import { createClient, EntryCollection } from 'contentful';\n\ninterface BlogPostFields {\n title: string;\n slug: string;\n body: string;\n publishedAt: string;\n author: {\n fields: {\n name: string;\n };\n };\n}\n\nconst client = createClient({\n space: process.env.CONTENTFUL_SPACE_ID!,\n environment: process.env.CONTENTFUL_ENVIRONMENT_ID ?? 'master',\n accessToken: process.env.CONTENTFUL_DELIVERY_TOKEN!,\n});\n\nasync function getBlogPosts(limit = 10) {\n const entries: EntryCollection<BlogPostFields> = await client.getEntries<BlogPostFields>({\n content_type: 'blogPost',\n order: ['-fields.publishedAt'],\n limit,\n include: 2, // resolve linked entries up to 2 levels deep\n });\n\n return entries.items.map((entry) => ({\n id: entry.sys.id,\n title: entry.fields.title,\n slug: entry.fields.slug,\n body: entry.fields.body,\n publishedAt: entry.fields.publishedAt,\n authorName: entry.fields.author?.fields?.name ?? 'Unknown',\n }));\n}\n\nconst posts = await getBlogPosts(10);\nconsole.log('Blog posts:', posts);",
|
|
64
|
+
"notes": "Replace 'blogPost' with your Contentful content type ID. The `include` parameter resolves linked entries (e.g., nested author fields) up to N levels deep. Avoid setting include too high — it increases response size significantly."
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"title": "Fetch a single entry by ID",
|
|
68
|
+
"language": "typescript",
|
|
69
|
+
"code": "import { createClient } from 'contentful';\n\ninterface PageFields {\n title: string;\n slug: string;\n hero: {\n fields: {\n title: string;\n file: {\n url: string;\n details: { size: number; image: { width: number; height: number } };\n };\n };\n };\n body: unknown; // Rich Text — use @contentful/rich-text-html-renderer to render\n}\n\nconst client = createClient({\n space: process.env.CONTENTFUL_SPACE_ID!,\n environment: process.env.CONTENTFUL_ENVIRONMENT_ID ?? 'master',\n accessToken: process.env.CONTENTFUL_DELIVERY_TOKEN!,\n});\n\nasync function getPageById(entryId: string) {\n const entry = await client.getEntry<PageFields>(entryId, {\n include: 2,\n });\n\n return {\n id: entry.sys.id,\n title: entry.fields.title,\n slug: entry.fields.slug,\n heroImageUrl: entry.fields.hero?.fields?.file?.url\n ? `https:${entry.fields.hero.fields.file.url}`\n : null,\n body: entry.fields.body, // pass to documentToHtmlString() for rendering\n };\n}\n\nconst page = await getPageById('5KsDBWseXY6QegucYAoacS');\nconsole.log('Page:', page);",
|
|
70
|
+
"notes": "Contentful image URLs are protocol-relative (start with //). Prefix with https: before using them in img tags or passing to image optimization tools. The body field for Rich Text must be rendered with @contentful/rich-text-html-renderer or @contentful/rich-text-react-renderer."
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"gotchas": [
|
|
74
|
+
"Contentful's free plan has a hard cap of 25,000 API calls/month. A Next.js site that revalidates content frequently (ISR with low revalidation intervals) can easily exceed this. Always enable the CDN caching layer and set ISR revalidation to at least 60 seconds.",
|
|
75
|
+
"Rich Text content is stored in Contentful's own JSON format (not HTML or Markdown). To render it, you must use @contentful/rich-text-html-renderer or @contentful/rich-text-react-renderer. Trying to render the raw JSON as HTML will output [object Object].",
|
|
76
|
+
"The Content Management API (write access) and Content Delivery API (read access) use different tokens. The Management token has full write access — never expose it client-side or commit it to git. Use it server-side only.",
|
|
77
|
+
"Content models cannot be changed once they have content entries without migration scripts. Adding a new required field to an existing content type with 500 existing entries requires either a migration (run via @contentful/cli) or making the field optional."
|
|
78
|
+
],
|
|
79
|
+
"reliability": {
|
|
80
|
+
"uptimeGuarantee": "99.9% uptime SLA on paid plans",
|
|
81
|
+
"statusPageUrl": "https://www.contentstatus.com",
|
|
82
|
+
"notes": "CDN-distributed with global edge caching. Content Delivery API responses are served from Fastly CDN nodes worldwide, providing low-latency reads for end users globally."
|
|
83
|
+
},
|
|
84
|
+
"qualityScore": 8,
|
|
85
|
+
"qualityJustification": "Industry standard enterprise headless CMS with the most mature ecosystem and plugin library. Excellent content modeling, localization, and workflow features. Rich Text handling and steep pricing cliff ($0 → $300/month) are the main friction points for smaller projects.",
|
|
86
|
+
"alternatives": ["sanity", "strapi"],
|
|
87
|
+
"complementary": ["vercel", "netlify", "algolia", "cloudinary"],
|
|
88
|
+
"bestFor": "Enterprise and mid-size teams needing a robust headless CMS with content workflows, localization, and a rich editor for non-technical content managers",
|
|
89
|
+
"lastVerified": "2026-02-25",
|
|
90
|
+
"entryVersion": 1,
|
|
91
|
+
"addedBy": "claude-code-session-4"
|
|
92
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Sanity",
|
|
3
|
+
"slug": "sanity",
|
|
4
|
+
"category": "cms",
|
|
5
|
+
"subcategory": "headless-cms",
|
|
6
|
+
"website": "https://www.sanity.io",
|
|
7
|
+
"description": "Sanity is a developer-first headless CMS with a real-time content API (GROQ) and a customizable React-based editor (Sanity Studio). Content is stored as portable text and JSON documents. Unlike WordPress or Contentful, the Sanity Studio is code you own and deploy, making it infinitely customizable. Strong TypeScript support with schema-to-type generation.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Build a content-driven website or blog with a custom editor",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Fetch structured content (blog, docs, product info) via API",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Build a fully custom CMS UI for client content management",
|
|
19
|
+
"fit": "good"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Manage content across multiple front-end platforms from one source",
|
|
23
|
+
"fit": "good"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth": {
|
|
27
|
+
"method": "api_key",
|
|
28
|
+
"setupSteps": [
|
|
29
|
+
"Run `npm create sanity@latest` to scaffold a new Sanity project",
|
|
30
|
+
"Log in with a Sanity account (GitHub, Google, or email)",
|
|
31
|
+
"A project is created automatically — note the Project ID printed in the terminal",
|
|
32
|
+
"Find your Project ID at sanity.io/manage under your project",
|
|
33
|
+
"For private datasets or write access, go to sanity.io/manage → API → Tokens → Add API Token",
|
|
34
|
+
"Choose token permissions (Viewer for read-only, Editor or higher for mutations)",
|
|
35
|
+
"Set SANITY_PROJECT_ID, SANITY_DATASET, and SANITY_API_TOKEN environment variables"
|
|
36
|
+
],
|
|
37
|
+
"envVarName": "SANITY_API_TOKEN",
|
|
38
|
+
"codeSnippet": "import { createClient } from '@sanity/client';\n\nconst client = createClient({\n projectId: process.env.SANITY_PROJECT_ID!,\n dataset: process.env.SANITY_DATASET ?? 'production',\n apiVersion: '2024-01-01', // use today's date or a fixed date\n useCdn: true, // true for reads (CDN-cached), false for fresh data\n token: process.env.SANITY_API_TOKEN, // only required for private datasets or writes\n});"
|
|
39
|
+
},
|
|
40
|
+
"pricing": {
|
|
41
|
+
"model": "freemium",
|
|
42
|
+
"freeTier": "Free: 2 users, 10K documents, 1M API CDN requests/month, 20GB CDN bandwidth",
|
|
43
|
+
"startingPrice": "$15/month (Growth) for 10 users, 25K documents, 10M API requests",
|
|
44
|
+
"costPer": "$1/additional user/month, $0.00001/CDN request above included",
|
|
45
|
+
"pricingUrl": "https://www.sanity.io/pricing"
|
|
46
|
+
},
|
|
47
|
+
"rateLimits": {
|
|
48
|
+
"tier": "free tier",
|
|
49
|
+
"limit": "1M CDN API requests/month, 1,000 mutations/hour (write operations) on free tier",
|
|
50
|
+
"notes": "Sanity uses GROQ (Graph-Relational Object Queries) — its own query language. CDN requests are cached; non-CDN requests (mutations, fresh data) have lower limits. Use .withConfig({ useCdn: true }) for reads.",
|
|
51
|
+
"retryStrategy": "Implement retry on 429 responses. Use withConfig({ useCdn: true }) to route reads through CDN and dramatically reduce API usage."
|
|
52
|
+
},
|
|
53
|
+
"sdk": {
|
|
54
|
+
"primaryLanguage": "typescript",
|
|
55
|
+
"installCommand": "npm install --save-exact @sanity/client",
|
|
56
|
+
"importStatement": "import { createClient } from '@sanity/client';",
|
|
57
|
+
"otherLanguages": ["javascript", "python"]
|
|
58
|
+
},
|
|
59
|
+
"codeExamples": [
|
|
60
|
+
{
|
|
61
|
+
"title": "Fetch posts with GROQ query",
|
|
62
|
+
"language": "typescript",
|
|
63
|
+
"code": "import { createClient } from '@sanity/client';\n\ninterface Post {\n _id: string;\n title: string;\n slug: { current: string };\n publishedAt: string;\n excerpt: string;\n author: {\n name: string;\n imageUrl: string | null;\n };\n}\n\nconst client = createClient({\n projectId: process.env.SANITY_PROJECT_ID!,\n dataset: process.env.SANITY_DATASET ?? 'production',\n apiVersion: '2024-01-01',\n useCdn: true,\n});\n\nasync function getPosts(limit = 10): Promise<Post[]> {\n const query = `\n *[_type == \"post\" && defined(publishedAt)] | order(publishedAt desc) [0...$limit] {\n _id,\n title,\n slug,\n publishedAt,\n excerpt,\n author-> {\n name,\n \"imageUrl\": image.asset->url\n }\n }\n `;\n\n const posts = await client.fetch<Post[]>(query, { limit: limit - 1 });\n return posts;\n}\n\nconst posts = await getPosts(10);\nconsole.log('Posts:', posts);",
|
|
64
|
+
"notes": "GROQ array slices are inclusive on both ends: [0...9] returns 10 items (indices 0 through 9). Use the `->` operator to dereference linked documents (e.g., author->). The `defined()` filter skips documents where the field is null or missing."
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"title": "Create a document via Sanity mutation",
|
|
68
|
+
"language": "typescript",
|
|
69
|
+
"code": "import { createClient } from '@sanity/client';\n\ninterface NewPost {\n title: string;\n slug: string;\n body: string;\n authorId: string;\n}\n\nconst client = createClient({\n projectId: process.env.SANITY_PROJECT_ID!,\n dataset: process.env.SANITY_DATASET ?? 'production',\n apiVersion: '2024-01-01',\n useCdn: false, // must be false for write operations\n token: process.env.SANITY_API_TOKEN!, // write token required\n});\n\nasync function createPost(data: NewPost) {\n const doc = await client.create({\n _type: 'post',\n title: data.title,\n slug: {\n _type: 'slug',\n current: data.slug,\n },\n body: [\n {\n _type: 'block',\n _key: crypto.randomUUID(),\n children: [\n {\n _type: 'span',\n _key: crypto.randomUUID(),\n text: data.body,\n marks: [],\n },\n ],\n markDefs: [],\n style: 'normal',\n },\n ],\n author: {\n _type: 'reference',\n _ref: data.authorId,\n },\n publishedAt: new Date().toISOString(),\n });\n\n console.log('Created document with ID:', doc._id);\n return doc;\n}\n\nawait createPost({\n title: 'Hello World',\n slug: 'hello-world',\n body: 'This is the first paragraph of my post.',\n authorId: 'author-document-id-here',\n});",
|
|
70
|
+
"notes": "Write operations require useCdn: false and a valid API token with Editor permissions or higher. The body field uses Sanity's Portable Text format — an array of block objects. Each block and span requires a unique _key. Use crypto.randomUUID() or nanoid to generate keys."
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"gotchas": [
|
|
74
|
+
"GROQ is not GraphQL or SQL — it's Sanity's own query language. The syntax is powerful but requires learning: `*[_type == 'post' && published == true] | order(publishedAt desc) [0..9]`. Bookmark the GROQ cheat sheet; autocomplete is only available in Sanity Studio, not in your code editor.",
|
|
75
|
+
"Sanity's portable text format (for rich content) requires the @portabletext/react or @portabletext/to-html package to render. The raw format is an array of block objects — do not try to render it directly.",
|
|
76
|
+
"The Sanity Studio (your CMS editor) is a React app you deploy separately from your main website. It requires its own hosting (sanity.io provides free hosting for Studio, or you can self-host). Forgetting to redeploy the Studio after schema changes results in editors seeing a mismatch between the UI and the data.",
|
|
77
|
+
"Sanity real-time live preview requires setting up a listener with `client.listen()` — it's not automatic. The subscription returns a ReadableStream that needs to be properly closed when done to avoid memory leaks and connection buildup."
|
|
78
|
+
],
|
|
79
|
+
"reliability": {
|
|
80
|
+
"uptimeGuarantee": "99.9% uptime SLA (Growth+)",
|
|
81
|
+
"statusPageUrl": "https://status.sanity.io",
|
|
82
|
+
"notes": "Globally distributed CDN with edge caching for read queries. The content API is hosted on Sanity's managed infrastructure with automatic failover. Real-time collaboration features use WebSocket connections."
|
|
83
|
+
},
|
|
84
|
+
"qualityScore": 9,
|
|
85
|
+
"qualityJustification": "Best developer experience of any headless CMS — TypeScript schema generation, GROQ query language with type inference, real-time previews, and a fully customizable Studio. The free tier is genuinely useful for small projects. Sanity is the go-to CMS for teams using Next.js or Astro who want a modern, code-first CMS.",
|
|
86
|
+
"alternatives": ["contentful", "strapi"],
|
|
87
|
+
"complementary": ["vercel", "netlify", "algolia", "cloudinary", "resend"],
|
|
88
|
+
"bestFor": "Developer-first headless CMS with a customizable React editor, real-time collaboration, and type-safe content APIs — ideal for Next.js and Astro projects",
|
|
89
|
+
"lastVerified": "2026-02-25",
|
|
90
|
+
"entryVersion": 1,
|
|
91
|
+
"addedBy": "claude-code-session-4"
|
|
92
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Strapi",
|
|
3
|
+
"slug": "strapi",
|
|
4
|
+
"category": "cms",
|
|
5
|
+
"subcategory": "headless-cms",
|
|
6
|
+
"website": "https://strapi.io",
|
|
7
|
+
"description": "Strapi is the leading open source headless CMS built with Node.js. Self-hosted on your own infrastructure, Strapi generates a REST and GraphQL API automatically from your content types. The admin panel is a React app included with the server. No vendor lock-in, full ownership of data, and a large plugin ecosystem. Strapi v5 (2024) brings improved TypeScript support.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Build a self-hosted headless CMS with auto-generated REST/GraphQL API",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Give a client a custom admin panel for managing website content",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Migrate from WordPress to a headless CMS with API access",
|
|
19
|
+
"fit": "good"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Build a multi-tenant CMS with role-based access control",
|
|
23
|
+
"fit": "good"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth": {
|
|
27
|
+
"method": "api_key",
|
|
28
|
+
"setupSteps": [
|
|
29
|
+
"Run `npx create-strapi@latest my-project` to scaffold a new Strapi project",
|
|
30
|
+
"Choose a database (SQLite for local dev, PostgreSQL for production)",
|
|
31
|
+
"Start the server with `npm run develop` and open http://localhost:1337/admin",
|
|
32
|
+
"Create an admin account on first launch",
|
|
33
|
+
"Navigate to Settings → API Tokens → Create new API Token",
|
|
34
|
+
"Choose token type (Read-only, Full access, or Custom) and set an expiry",
|
|
35
|
+
"Copy the generated token — it is shown only once",
|
|
36
|
+
"Set STRAPI_API_TOKEN and STRAPI_URL environment variables in your client application"
|
|
37
|
+
],
|
|
38
|
+
"envVarName": "STRAPI_API_TOKEN",
|
|
39
|
+
"codeSnippet": "const STRAPI_URL = process.env.STRAPI_URL ?? 'http://localhost:1337';\nconst STRAPI_TOKEN = process.env.STRAPI_API_TOKEN!;\n\nconst response = await fetch(`${STRAPI_URL}/api/articles?populate=*`, {\n headers: {\n Authorization: `Bearer ${STRAPI_TOKEN}`,\n 'Content-Type': 'application/json',\n },\n});\n\nconst data = await response.json();"
|
|
40
|
+
},
|
|
41
|
+
"pricing": {
|
|
42
|
+
"model": "open_source",
|
|
43
|
+
"freeTier": "Self-hosted: free forever. Strapi Cloud starts at $29/month for managed hosting.",
|
|
44
|
+
"startingPrice": "Self-hosted: your infrastructure costs (Railway from $5/month). Strapi Cloud: $29/month (Developer)",
|
|
45
|
+
"costPer": null,
|
|
46
|
+
"pricingUrl": "https://strapi.io/pricing"
|
|
47
|
+
},
|
|
48
|
+
"rateLimits": {
|
|
49
|
+
"tier": "self-hosted",
|
|
50
|
+
"limit": "No built-in rate limits — determined by your server. Add koa-ratelimit or similar middleware for production.",
|
|
51
|
+
"notes": "Strapi does not implement rate limiting out of the box. In production, add rate limiting at the reverse proxy (nginx) or middleware level. Strapi Cloud has built-in rate limiting.",
|
|
52
|
+
"retryStrategy": "Standard HTTP retry with exponential backoff. For self-hosted, configure your own rate limiting middleware."
|
|
53
|
+
},
|
|
54
|
+
"sdk": {
|
|
55
|
+
"primaryLanguage": "typescript",
|
|
56
|
+
"installCommand": "npm install --save-exact @strapi/sdk-js",
|
|
57
|
+
"importStatement": "import { createStrapiClient } from '@strapi/sdk-js';",
|
|
58
|
+
"otherLanguages": ["javascript", "python", "php", "ruby"]
|
|
59
|
+
},
|
|
60
|
+
"codeExamples": [
|
|
61
|
+
{
|
|
62
|
+
"title": "Fetch content from Strapi REST API",
|
|
63
|
+
"language": "typescript",
|
|
64
|
+
"code": "const STRAPI_URL = process.env.STRAPI_URL ?? 'http://localhost:1337';\nconst STRAPI_TOKEN = process.env.STRAPI_API_TOKEN!;\n\ninterface StrapiArticle {\n id: number;\n documentId: string;\n title: string;\n slug: string;\n content: string;\n publishedAt: string | null;\n cover: {\n url: string;\n alternativeText: string | null;\n } | null;\n}\n\ninterface StrapiListResponse<T> {\n data: T[];\n meta: {\n pagination: {\n page: number;\n pageSize: number;\n pageCount: number;\n total: number;\n };\n };\n}\n\nasync function getArticles(page = 1, pageSize = 10): Promise<StrapiArticle[]> {\n const params = new URLSearchParams({\n 'pagination[page]': String(page),\n 'pagination[pageSize]': String(pageSize),\n 'populate[cover][fields][0]': 'url',\n 'populate[cover][fields][1]': 'alternativeText',\n 'sort[0]': 'publishedAt:desc',\n });\n\n const response = await fetch(`${STRAPI_URL}/api/articles?${params}`, {\n headers: {\n Authorization: `Bearer ${STRAPI_TOKEN}`,\n 'Content-Type': 'application/json',\n },\n next: { revalidate: 60 }, // Next.js ISR cache hint\n });\n\n if (!response.ok) {\n throw new Error(`Strapi fetch failed: ${response.status} ${response.statusText}`);\n }\n\n const json: StrapiListResponse<StrapiArticle> = await response.json();\n return json.data;\n}\n\nconst articles = await getArticles(1, 10);\nconsole.log('Articles:', articles);",
|
|
65
|
+
"notes": "Strapi v5 uses a flat response format — data is returned directly without the `attributes` wrapper used in v4. The `populate` parameter controls which relations are included. Use `populate=*` for all relations or specify fields explicitly for better performance."
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"title": "Create an entry via REST API",
|
|
69
|
+
"language": "typescript",
|
|
70
|
+
"code": "const STRAPI_URL = process.env.STRAPI_URL ?? 'http://localhost:1337';\nconst STRAPI_TOKEN = process.env.STRAPI_API_TOKEN!;\n\ninterface CreateArticleInput {\n title: string;\n slug: string;\n content: string;\n publishedAt?: string; // set to null to create as draft\n}\n\ninterface StrapiCreateResponse {\n data: {\n id: number;\n documentId: string;\n title: string;\n slug: string;\n content: string;\n publishedAt: string | null;\n createdAt: string;\n updatedAt: string;\n };\n}\n\nasync function createArticle(input: CreateArticleInput): Promise<StrapiCreateResponse['data']> {\n const response = await fetch(`${STRAPI_URL}/api/articles`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${STRAPI_TOKEN}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n data: {\n title: input.title,\n slug: input.slug,\n content: input.content,\n publishedAt: input.publishedAt ?? null, // null = draft, ISO string = published\n },\n }),\n });\n\n if (!response.ok) {\n const error = await response.json();\n throw new Error(`Failed to create article: ${JSON.stringify(error)}`);\n }\n\n const json: StrapiCreateResponse = await response.json();\n console.log('Created article with ID:', json.data.id, 'documentId:', json.data.documentId);\n return json.data;\n}\n\nawait createArticle({\n title: 'My First Article',\n slug: 'my-first-article',\n content: 'This is the body of the article.',\n publishedAt: new Date().toISOString(), // publish immediately\n});",
|
|
71
|
+
"notes": "The POST body must be wrapped in a `data` key — this is required by Strapi's REST API. Omit `publishedAt` or set it to null to save as a draft. The `documentId` field (Strapi v5) is a stable UUID used for referencing documents across locales; the `id` is a numeric database row ID."
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"gotchas": [
|
|
75
|
+
"Strapi's content types and plugins are defined in JavaScript/TypeScript config files that live in your project. Every time you change a content type schema in the admin panel, it modifies files on disk and requires a server restart (and redeploy in production). Strapi is NOT a stateless API — schema changes are code changes.",
|
|
76
|
+
"Using SQLite in production is strongly discouraged by Strapi — it doesn't support concurrent writes and can corrupt under load. Always use PostgreSQL for production. SQLite is only for local development.",
|
|
77
|
+
"Strapi v4 and v5 have different API response formats. v4 wraps responses in `{ data: { id, attributes: {...} } }`. v5 changed this to a flat structure. Tutorials and plugins written for v4 will break on v5. Pin your Strapi version or audit plugins before upgrading.",
|
|
78
|
+
"The Strapi admin panel is served from the same process as the API. Under heavy API traffic, the admin panel can become slow or unresponsive. For production, consider running admin and API as separate Strapi instances."
|
|
79
|
+
],
|
|
80
|
+
"reliability": {
|
|
81
|
+
"uptimeGuarantee": "Self-hosted — your responsibility; Strapi Cloud: 99.9% SLA",
|
|
82
|
+
"statusPageUrl": null,
|
|
83
|
+
"notes": "Use Railway or Fly.io with a managed Postgres database. Strapi Cloud provides managed hosting with automatic backups."
|
|
84
|
+
},
|
|
85
|
+
"qualityScore": 7,
|
|
86
|
+
"qualityJustification": "Most popular open source headless CMS — battle-tested in production with a huge ecosystem. Auto-generated API is genuinely magical for rapid prototyping. Main friction: schema changes are code changes requiring redeploys, SQLite-only in dev mode, and v4/v5 migration is breaking. Better for backend developers than Sanity; worse DX for frontend-first teams.",
|
|
87
|
+
"alternatives": ["contentful", "sanity"],
|
|
88
|
+
"complementary": ["vercel", "railway", "neon", "supabase", "algolia", "cloudinary"],
|
|
89
|
+
"bestFor": "Self-hosted headless CMS for full data ownership — teams that want Contentful-style content management without the SaaS pricing or vendor lock-in",
|
|
90
|
+
"lastVerified": "2026-02-25",
|
|
91
|
+
"entryVersion": 1,
|
|
92
|
+
"addedBy": "claude-code-session-4"
|
|
93
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Medusa",
|
|
3
|
+
"slug": "medusa",
|
|
4
|
+
"category": "commerce",
|
|
5
|
+
"subcategory": "headless-commerce",
|
|
6
|
+
"website": "https://medusajs.com",
|
|
7
|
+
"description": "Medusa is an open source Node.js headless commerce platform — a self-hosted Shopify alternative. Provides a REST API for products, orders, carts, customers, and payments, plus a plugin system for payment processors (Stripe, PayPal), fulfilment, and CMS. Run on your own server (Railway, Fly.io) or use Medusa Cloud. Full control over data and customization.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Build a custom ecommerce store with full control over data and infrastructure",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Create a headless commerce backend for a custom frontend",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Migrate off Shopify to own your ecommerce data",
|
|
19
|
+
"fit": "good"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Build a marketplace with multi-vendor support",
|
|
23
|
+
"fit": "good"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth": {
|
|
27
|
+
"method": "api_key",
|
|
28
|
+
"setupSteps": [
|
|
29
|
+
"Run 'npx create-medusa-app@latest' to scaffold a new Medusa project",
|
|
30
|
+
"Provision a PostgreSQL database and Redis instance (local or managed)",
|
|
31
|
+
"Configure DATABASE_URL and REDIS_URL in your .env file",
|
|
32
|
+
"Start the server with 'npx medusa develop' and complete the admin account setup",
|
|
33
|
+
"In the admin dashboard, navigate to Settings > API Keys to create a publishable key",
|
|
34
|
+
"Set MEDUSA_ADMIN_API_KEY (secret) and NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY (storefront) as environment variables"
|
|
35
|
+
],
|
|
36
|
+
"envVarName": "MEDUSA_ADMIN_API_KEY",
|
|
37
|
+
"codeSnippet": "import Medusa from '@medusajs/js-sdk';\n\nconst medusa = new Medusa({\n baseUrl: process.env.MEDUSA_BACKEND_URL ?? 'http://localhost:9000',\n publishableKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY!,\n});"
|
|
38
|
+
},
|
|
39
|
+
"pricing": {
|
|
40
|
+
"model": "open_source",
|
|
41
|
+
"freeTier": "Self-hosted: free forever (pay for your own infrastructure). Medusa Cloud plans for managed hosting start at $0 (Starter).",
|
|
42
|
+
"startingPrice": "Self-hosted: your infrastructure costs only (Railway from $5/month, Fly.io from ~$5/month). Medusa Cloud: TBD pricing.",
|
|
43
|
+
"costPer": null,
|
|
44
|
+
"pricingUrl": "https://medusajs.com/pricing/"
|
|
45
|
+
},
|
|
46
|
+
"rateLimits": {
|
|
47
|
+
"tier": "self-hosted",
|
|
48
|
+
"limit": "No built-in rate limits — determined by your server capacity and any rate limiting middleware you add",
|
|
49
|
+
"notes": "For production deployments, add rate limiting via middleware or a reverse proxy (nginx, Cloudflare). Medusa does not include rate limiting out of the box.",
|
|
50
|
+
"retryStrategy": "Standard HTTP retry patterns. Consider adding express-rate-limit middleware for your self-hosted instance."
|
|
51
|
+
},
|
|
52
|
+
"sdk": {
|
|
53
|
+
"primaryLanguage": "typescript",
|
|
54
|
+
"installCommand": "npm install --save-exact @medusajs/js-sdk",
|
|
55
|
+
"importStatement": "import Medusa from '@medusajs/js-sdk';",
|
|
56
|
+
"otherLanguages": ["javascript", "python"]
|
|
57
|
+
},
|
|
58
|
+
"codeExamples": [
|
|
59
|
+
{
|
|
60
|
+
"title": "List products from Medusa storefront",
|
|
61
|
+
"language": "typescript",
|
|
62
|
+
"code": "import Medusa from '@medusajs/js-sdk';\n\nconst medusa = new Medusa({\n baseUrl: process.env.MEDUSA_BACKEND_URL ?? 'http://localhost:9000',\n publishableKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY!,\n});\n\n// Fetch the first page of products with their variants and images\nconst { products, count, offset, limit } = await medusa.store.product.list({\n limit: 20,\n offset: 0,\n fields: '+variants,+images,+thumbnail',\n});\n\nconsole.log(`Found ${count} total products, showing ${products.length}`);\n\nfor (const product of products) {\n console.log(`- ${product.title} (${product.variants?.length ?? 0} variants)`);\n const prices = product.variants?.map((v) =>\n v.calculated_price?.calculated_amount\n );\n console.log(` Price range: ${Math.min(...(prices ?? [0]))} – ${Math.max(...(prices ?? [0]))}`);\n}",
|
|
63
|
+
"notes": "The publishable key is safe to use in browser/client code. Use 'fields' to select only the data you need — fetching all fields on large catalogs is slow. Paginate with limit/offset for catalogs larger than 20 products."
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"title": "Create a cart and add an item",
|
|
67
|
+
"language": "typescript",
|
|
68
|
+
"code": "import Medusa from '@medusajs/js-sdk';\n\nconst medusa = new Medusa({\n baseUrl: process.env.MEDUSA_BACKEND_URL ?? 'http://localhost:9000',\n publishableKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY!,\n});\n\n// Step 1: Retrieve available regions\nconst { regions } = await medusa.store.region.list();\nconst region = regions[0]; // Use the first region (e.g., United States)\n\n// Step 2: Create an empty cart for the region\nconst { cart } = await medusa.store.cart.create({\n region_id: region.id,\n currency_code: region.currency_code,\n});\n\nconsole.log('Created cart:', cart.id);\n\n// Step 3: Add a line item (requires a valid variant ID from your store)\nconst variantId = 'variant_01JEXAMPLE'; // Replace with a real variant ID\n\nconst { cart: updatedCart } = await medusa.store.cart.createLineItem(cart.id, {\n variant_id: variantId,\n quantity: 1,\n});\n\nconsole.log(\n `Cart now has ${updatedCart.items?.length} item(s)`,\n `Total: ${updatedCart.total} ${updatedCart.currency_code?.toUpperCase()}`\n);",
|
|
69
|
+
"notes": "Cart IDs should be persisted in localStorage or a cookie so returning users can resume their cart. Medusa v2 uses a new cart API — this code is not compatible with Medusa v1. Always look up the region first; currency and tax rates are region-scoped."
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"gotchas": [
|
|
73
|
+
"Medusa requires a PostgreSQL database and Redis for session/queue management. This is two additional services to provision and maintain. With Vercel + Neon + Upstash, you can get a fully serverless Medusa deployment, but the setup is non-trivial compared to hosted solutions.",
|
|
74
|
+
"Medusa v2 (released 2024) is a major rewrite with breaking API changes. Plugins built for v1 don't work with v2. Check that any community plugins you want are v2-compatible before starting — some popular ones (specific payment providers, fulfilment integrations) may lag behind.",
|
|
75
|
+
"Self-hosting means you're responsible for uptime, database backups, security patches, and SSL certificates. Medusa does not provide a managed hosting option with SLAs — if your server goes down, your store goes down. Budget for ops time or use a PaaS like Railway or Fly.io with auto-restart.",
|
|
76
|
+
"Medusa's admin dashboard is a separate application that must be built and deployed separately from the API. Running both on the same server is possible but not recommended for production. Plan for two deployments: API server and Admin dashboard."
|
|
77
|
+
],
|
|
78
|
+
"reliability": {
|
|
79
|
+
"uptimeGuarantee": "Self-hosted — uptime is your responsibility; Medusa Cloud: not yet publicly available with SLA",
|
|
80
|
+
"statusPageUrl": null,
|
|
81
|
+
"notes": "Deploy on Railway or Fly.io with auto-restart for best reliability. Use Neon or Supabase for managed Postgres with auto-failover."
|
|
82
|
+
},
|
|
83
|
+
"qualityScore": 7,
|
|
84
|
+
"qualityJustification": "Best open source headless commerce platform for developers who want Shopify-level features with full data ownership. Active community, good documentation, and v2 is a significant improvement. Loses points for operational complexity (Postgres + Redis required) and the ecosystem lag in plugin compatibility between v1 and v2.",
|
|
85
|
+
"alternatives": ["shopify-api"],
|
|
86
|
+
"complementary": ["stripe", "railway", "fly-io", "neon", "supabase", "algolia", "cloudinary", "resend"],
|
|
87
|
+
"bestFor": "Building a custom ecommerce store with full ownership of data and infrastructure — the open source alternative to Shopify with no vendor lock-in",
|
|
88
|
+
"lastVerified": "2026-02-25",
|
|
89
|
+
"entryVersion": 1,
|
|
90
|
+
"addedBy": "claude-code-session-4"
|
|
91
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Shopify API",
|
|
3
|
+
"slug": "shopify-api",
|
|
4
|
+
"category": "commerce",
|
|
5
|
+
"subcategory": "ecommerce-platform",
|
|
6
|
+
"website": "https://shopify.dev",
|
|
7
|
+
"description": "Shopify provides a REST and GraphQL API for building custom storefronts, apps, and integrations on top of the world's largest ecommerce platform. The Storefront API enables headless commerce (fetch products, manage carts, process checkouts) while the Admin API allows full management of orders, products, and customers. Over 1.7M merchants run on Shopify.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Build a headless storefront that fetches products from Shopify",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Create a Shopify app that extends merchant functionality",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Sync order data from Shopify to an external system",
|
|
19
|
+
"fit": "good"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Add a custom checkout flow to an existing Shopify store",
|
|
23
|
+
"fit": "good"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth": {
|
|
27
|
+
"method": "oauth2",
|
|
28
|
+
"setupSteps": [
|
|
29
|
+
"Create a Shopify Partner account at partners.shopify.com",
|
|
30
|
+
"Create a new app in the Partner Dashboard and configure scopes",
|
|
31
|
+
"Install the app on a development store to initiate the OAuth flow",
|
|
32
|
+
"After OAuth, store the Admin API access token securely on your server",
|
|
33
|
+
"For the Storefront API, enable it in the app settings and copy the Storefront access token",
|
|
34
|
+
"Set SHOPIFY_ADMIN_API_TOKEN and SHOPIFY_STOREFRONT_ACCESS_TOKEN as environment variables"
|
|
35
|
+
],
|
|
36
|
+
"envVarName": "SHOPIFY_STOREFRONT_ACCESS_TOKEN",
|
|
37
|
+
"codeSnippet": "import '@shopify/shopify-api/adapters/node';\nimport { shopifyApi, ApiVersion } from '@shopify/shopify-api';\n\nconst shopify = shopifyApi({\n apiKey: process.env.SHOPIFY_API_KEY!,\n apiSecretKey: process.env.SHOPIFY_API_SECRET!,\n adminApiAccessToken: process.env.SHOPIFY_ADMIN_API_TOKEN!,\n hostName: process.env.SHOPIFY_SHOP_DOMAIN!,\n apiVersion: ApiVersion.January25,\n isEmbeddedApp: false,\n});"
|
|
38
|
+
},
|
|
39
|
+
"pricing": {
|
|
40
|
+
"model": "usage_based",
|
|
41
|
+
"freeTier": "Development stores are free; merchant plans from $29/month (not charged to developer)",
|
|
42
|
+
"startingPrice": "API access is free; Shopify Partner apps charged on usage beyond free API call quotas",
|
|
43
|
+
"costPer": "Storefront API: free. Admin API: 2 request/second (REST) or 50 points/second (GraphQL) rate limits apply; over-limit costs nothing but responses are throttled",
|
|
44
|
+
"pricingUrl": "https://shopify.dev/docs/api/usage/rate-limits"
|
|
45
|
+
},
|
|
46
|
+
"rateLimits": {
|
|
47
|
+
"tier": "standard",
|
|
48
|
+
"limit": "REST Admin: 2 calls/second; GraphQL Admin: 50 points/second query cost budget; Storefront: 100 calls/minute per storefront",
|
|
49
|
+
"notes": "GraphQL Admin API uses cost-based rate limiting. Each field has a cost; complex queries with many nested fields cost more points. Check X-GraphQL-Cost-Include-Fields response header.",
|
|
50
|
+
"retryStrategy": "Check Retry-After header on 429 responses. GraphQL responses include extensions.cost with throttle status. Implement exponential backoff starting at 1 second."
|
|
51
|
+
},
|
|
52
|
+
"sdk": {
|
|
53
|
+
"primaryLanguage": "typescript",
|
|
54
|
+
"installCommand": "npm install --save-exact @shopify/shopify-api",
|
|
55
|
+
"importStatement": "import '@shopify/shopify-api/adapters/node';\nimport { shopifyApi, ApiVersion } from '@shopify/shopify-api';",
|
|
56
|
+
"otherLanguages": ["python", "ruby", "php"]
|
|
57
|
+
},
|
|
58
|
+
"codeExamples": [
|
|
59
|
+
{
|
|
60
|
+
"title": "Fetch products with Storefront API (GraphQL)",
|
|
61
|
+
"language": "typescript",
|
|
62
|
+
"code": "const STOREFRONT_QUERY = `\n query GetProducts($first: Int!) {\n products(first: $first) {\n edges {\n node {\n id\n title\n handle\n priceRange {\n minVariantPrice {\n amount\n currencyCode\n }\n }\n images(first: 1) {\n edges {\n node {\n url\n altText\n }\n }\n }\n }\n }\n }\n }\n`;\n\nconst response = await fetch(\n `https://${process.env.SHOPIFY_SHOP_DOMAIN}/api/2025-01/graphql.json`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Shopify-Storefront-Access-Token': process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN!,\n },\n body: JSON.stringify({\n query: STOREFRONT_QUERY,\n variables: { first: 20 },\n }),\n }\n);\n\nconst { data } = await response.json();\nconst products = data.products.edges.map((edge: any) => edge.node);\nconsole.log('Products:', products);",
|
|
63
|
+
"notes": "The Storefront API access token is safe to use in client-side code. Always paginate with a reasonable 'first' value (20-50) rather than fetching hundreds of products at once to avoid hitting query cost limits."
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"title": "Create an order via Admin API",
|
|
67
|
+
"language": "typescript",
|
|
68
|
+
"code": "import '@shopify/shopify-api/adapters/node';\nimport { shopifyApi, ApiVersion } from '@shopify/shopify-api';\n\nconst shopify = shopifyApi({\n apiKey: process.env.SHOPIFY_API_KEY!,\n apiSecretKey: process.env.SHOPIFY_API_SECRET!,\n adminApiAccessToken: process.env.SHOPIFY_ADMIN_API_TOKEN!,\n hostName: process.env.SHOPIFY_SHOP_DOMAIN!,\n apiVersion: ApiVersion.January25,\n isEmbeddedApp: false,\n});\n\nconst client = new shopify.clients.Rest({\n session: {\n shop: process.env.SHOPIFY_SHOP_DOMAIN!,\n accessToken: process.env.SHOPIFY_ADMIN_API_TOKEN!,\n } as any,\n});\n\nconst response = await client.post({\n path: 'orders',\n data: {\n order: {\n email: 'customer@example.com',\n financial_status: 'paid',\n line_items: [\n {\n title: 'Custom T-Shirt',\n price: '29.99',\n quantity: 2,\n requires_shipping: true,\n },\n ],\n billing_address: {\n first_name: 'Jane',\n last_name: 'Doe',\n address1: '123 Main St',\n city: 'San Francisco',\n province: 'California',\n country: 'United States',\n zip: '94101',\n },\n },\n },\n});\n\nconst order = response.body as any;\nconsole.log('Created order ID:', order.order.id);",
|
|
69
|
+
"notes": "Admin API calls must be made server-side only — never expose your Admin API token in client code. The REST Admin API processes orders synchronously; for high-volume scenarios, use the GraphQL Bulk Operations API instead."
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"gotchas": [
|
|
73
|
+
"Shopify has TWO separate APIs with different authentication: the Storefront API (public-facing, uses a Storefront access token, safe to expose in client code) and the Admin API (private, uses OAuth or Admin API token, NEVER expose in client code). Using the Admin token in a frontend app is a critical security vulnerability.",
|
|
74
|
+
"GraphQL API cost is based on complexity, not just count. A query for 250 products with 10 fields each might cost 2,500 points — hitting the 50,000 point/second limit with just 20 concurrent users. Always request only needed fields and use pagination (first: 50) instead of fetching everything at once.",
|
|
75
|
+
"Shopify's API versioning is date-based (e.g., 2024-01). Versions are supported for 12 months after release, then deprecated. Running an app on an old API version will suddenly break when Shopify removes it. Implement API version upgrade as part of your maintenance routine.",
|
|
76
|
+
"Webhooks from Shopify must be verified using the HMAC-SHA256 signature in the X-Shopify-Hmac-SHA256 header. Accepting webhooks without verification allows any actor to fake Shopify events — a security vulnerability. Always verify before processing."
|
|
77
|
+
],
|
|
78
|
+
"reliability": {
|
|
79
|
+
"uptimeGuarantee": "99.98% uptime SLA for Shopify platform",
|
|
80
|
+
"statusPageUrl": "https://www.shopifystatus.com",
|
|
81
|
+
"notes": "Globally distributed on Google Cloud infrastructure. Shopify CDN serves storefront assets with high availability. Peak traffic (Black Friday/Cyber Monday) is handled at scale — Shopify processes millions of requests per minute during peak events."
|
|
82
|
+
},
|
|
83
|
+
"qualityScore": 8,
|
|
84
|
+
"qualityJustification": "Access to 1.7M+ merchant stores makes the Shopify API uniquely powerful for building apps and integrations. The Storefront API is well-designed for headless commerce. GraphQL Admin API is flexible but complex. Main friction: the Storefront API lacks some commerce capabilities (subscriptions require apps), and the versioning cadence requires ongoing maintenance.",
|
|
85
|
+
"alternatives": ["medusa"],
|
|
86
|
+
"complementary": ["stripe", "algolia", "cloudinary", "resend"],
|
|
87
|
+
"bestFor": "Building headless storefronts, custom checkout experiences, or apps that integrate with existing Shopify merchant stores",
|
|
88
|
+
"lastVerified": "2026-02-25",
|
|
89
|
+
"entryVersion": 1,
|
|
90
|
+
"addedBy": "claude-code-session-4"
|
|
91
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Sendbird",
|
|
3
|
+
"slug": "sendbird",
|
|
4
|
+
"category": "communication",
|
|
5
|
+
"subcategory": "in-app-chat",
|
|
6
|
+
"website": "https://sendbird.com",
|
|
7
|
+
"description": "Sendbird is an enterprise-grade in-app messaging and chat platform with SDKs for iOS, Android, React, and React Native. It provides a complete chat infrastructure including message persistence, push notifications, moderation, file sharing, and AI-powered features for healthcare, fintech, and marketplace applications.",
|
|
8
|
+
"useCases": [
|
|
9
|
+
{
|
|
10
|
+
"task": "Build HIPAA-compliant in-app messaging for healthcare",
|
|
11
|
+
"fit": "perfect"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"task": "Add in-app chat to a mobile marketplace (buyer/seller messaging)",
|
|
15
|
+
"fit": "perfect"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"task": "Build customer support chat with agent handoff",
|
|
19
|
+
"fit": "perfect"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"task": "Add group messaging to a mobile social app",
|
|
23
|
+
"fit": "perfect"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth": {
|
|
27
|
+
"method": "api_key",
|
|
28
|
+
"setupSteps": [
|
|
29
|
+
"Sign up at sendbird.com",
|
|
30
|
+
"Create an application in the Sendbird Dashboard",
|
|
31
|
+
"Copy your App ID from the dashboard",
|
|
32
|
+
"Generate an API token under Settings > Application > API Tokens",
|
|
33
|
+
"Set SENDBIRD_APP_ID and SENDBIRD_API_TOKEN environment variables",
|
|
34
|
+
"Generate user session tokens server-side for client authentication"
|
|
35
|
+
],
|
|
36
|
+
"envVarName": "SENDBIRD_API_TOKEN",
|
|
37
|
+
"codeSnippet": "// Server-side API calls use API token in header\nconst response = await fetch(`https://api-${process.env.SENDBIRD_APP_ID}.sendbird.com/v3/users`, {\n headers: { 'Api-Token': process.env.SENDBIRD_API_TOKEN! },\n});"
|
|
38
|
+
},
|
|
39
|
+
"pricing": {
|
|
40
|
+
"model": "freemium",
|
|
41
|
+
"freeTier": "Up to 1,000 MAU, 5GB storage, core features",
|
|
42
|
+
"startingPrice": "$399/month for Starter plan (higher MAU limits)",
|
|
43
|
+
"costPer": "Custom enterprise pricing for large deployments; $0.05+ per MAU on standard plans",
|
|
44
|
+
"pricingUrl": "https://sendbird.com/pricing"
|
|
45
|
+
},
|
|
46
|
+
"rateLimits": {
|
|
47
|
+
"tier": "all tiers",
|
|
48
|
+
"limit": "Platform API: 20 requests/second (default); can be increased",
|
|
49
|
+
"notes": "Sendbird has separate rate limits for the Platform API (server-side) and client SDK. High-volume use cases should request increased limits.",
|
|
50
|
+
"retryStrategy": "Client SDKs handle reconnection automatically. Platform API calls should use exponential backoff on 429 responses."
|
|
51
|
+
},
|
|
52
|
+
"sdk": {
|
|
53
|
+
"primaryLanguage": "typescript",
|
|
54
|
+
"installCommand": "npm install --save-exact @sendbird/chat",
|
|
55
|
+
"importStatement": "import SendbirdChat from '@sendbird/chat';\nimport { GroupChannelModule } from '@sendbird/chat/groupChannel';",
|
|
56
|
+
"otherLanguages": ["swift", "android", "react-native", "flutter", "unity"]
|
|
57
|
+
},
|
|
58
|
+
"codeExamples": [
|
|
59
|
+
{
|
|
60
|
+
"title": "Initialize Sendbird and connect user",
|
|
61
|
+
"language": "typescript",
|
|
62
|
+
"code": "import SendbirdChat from '@sendbird/chat';\nimport { GroupChannelModule } from '@sendbird/chat/groupChannel';\n\nconst sb = SendbirdChat.init({\n appId: process.env.NEXT_PUBLIC_SENDBIRD_APP_ID!,\n modules: [new GroupChannelModule()],\n});\n\n// accessToken generated server-side\nawait sb.connect('user-123', accessToken);\n\nconsole.log('Connected as:', sb.currentUser?.nickname);\n\n// Create a group channel\nconst { groupChannel } = sb.groupChannel;\nconst channel = await groupChannel.createChannel({\n invitedUserIds: ['user-123', 'user-456'],\n isDistinct: true, // Reuse same channel for same pair of users\n name: 'Support Chat',\n});",
|
|
63
|
+
"notes": "User access tokens must be generated server-side using the Platform API or SDK. isDistinct: true means Sendbird reuses the same channel URL for the same set of members."
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"gotchas": [
|
|
67
|
+
"Sendbird's pricing tier jumps sharply from free (1k MAU) to paid ($399/month). There is no intermediate tier. This makes it difficult to test with real users before committing to a paid plan.",
|
|
68
|
+
"The mobile SDKs (iOS/Android) are mature and well-maintained, but the web JavaScript SDK has historically lagged. Check the changelog for the @sendbird/chat package before upgrading.",
|
|
69
|
+
"Push notifications require setting up both APNs (iOS) and FCM (Android) credentials in the Sendbird dashboard — two separate integration steps that often get overlooked.",
|
|
70
|
+
"Sendbird's compliance features (HIPAA BAA, GDPR DPA) are only available on Enterprise plans. If you need these for healthcare or EU data, factor the enterprise cost into your planning."
|
|
71
|
+
],
|
|
72
|
+
"reliability": {
|
|
73
|
+
"uptimeGuarantee": "99.99% uptime SLA on paid plans",
|
|
74
|
+
"statusPageUrl": "https://status.sendbird.com",
|
|
75
|
+
"notes": "Sendbird processes over 8 billion messages per month for enterprises. Dedicated instances available for Enterprise customers with data residency requirements."
|
|
76
|
+
},
|
|
77
|
+
"qualityScore": 8,
|
|
78
|
+
"qualityJustification": "Enterprise-grade chat platform with excellent mobile SDK quality and compliance features. Strong for healthcare and fintech. More setup complexity than Stream Chat and the pricing cliff from free to paid is steep. Best choice when mobile-first chat with compliance requirements is the priority.",
|
|
79
|
+
"alternatives": ["stream-chat"],
|
|
80
|
+
"complementary": ["clerk", "onesignal", "twilio"],
|
|
81
|
+
"bestFor": "Enterprise in-app messaging for mobile apps, especially healthcare, fintech, and marketplaces requiring compliance (HIPAA, GDPR)",
|
|
82
|
+
"lastVerified": "2026-02-25",
|
|
83
|
+
"entryVersion": 1,
|
|
84
|
+
"addedBy": "claude-code-session-2"
|
|
85
|
+
}
|