Skip to content

Conversation

@adityaoberai
Copy link
Member

@adityaoberai adityaoberai commented Nov 27, 2025

What does this PR do?

Create a Cursor Rules Generator

Test Plan

Visit the preview deployment

Related PRs and Issues

No

Have you read the Contributing Guidelines on issues?

Yes

Summary by CodeRabbit

  • New Features

    • Interactive Rules Generator UI with SDK/framework selection, feature toggles, live preview, copy and download as Markdown
    • Server endpoints to list SDKs and generate/download rules; many language/framework templates added and automatic SDK version lookup
  • Documentation

    • Added comprehensive README describing the project, usage, and examples
  • Chores

    • Project tooling configured (Prettier, ESLint, TypeScript, Vite, package scripts, workspace, npm engine-strict)
    • Ignore patterns and robots.txt added; LICENSE content removed

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 27, 2025

Warning

Rate limit exceeded

@adityaoberai has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 2 minutes and 43 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 404442e and 2cfc254.

📒 Files selected for processing (3)
  • src/lib/languages/common/products.js (1 hunks)
  • src/lib/rules-generator.js (1 hunks)
  • src/routes/api/sdks/+server.js (1 hunks)

Walkthrough

Adds a SvelteKit application scaffold (routes, layout, static assets, UI page) and Appwrite client wiring. Introduces a central rules generator (src/lib/rules-generator.js), a large set of language/framework template modules under src/lib/languages, SDK version utilities with caching and fallback (src/lib/utils/versions.js), server API endpoints (src/routes/api/*), helper scripts, and many tooling/config files (package.json, pnpm-workspace.yaml, eslint.config.js, Prettier, TypeScript, Vite, svelte.config.js, .npmrc, ignore files). The LICENSE file content was removed.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Areas to focus during review:

  • src/lib/rules-generator.js — public API shapes (SDK_OPTIONS, generateRules), concurrency, dynamic imports, markdown composition, and error paths
  • src/lib/utils/versions.js — network/error handling, caching semantics, and the correctness of the fallback map
  • Consistency across src/lib/languages/* — async version fetching patterns, createFrameworkTemplate usage, and uniform output formatting
  • src/routes/api/rules/+server.js and src/routes/api/sdks/+server.js — input validation, feature normalization, response formats (JSON vs text), and error handling
  • src/routes/+page.svelte — state management, async flows, clipboard/download logic, and UX error feedback
  • scripts/lib-loader.js — ESM resolver hook correctness and file URL resolution
  • Build/tooling config files — eslint.config.js, vite.config.ts, svelte.config.js, tsconfig.json, package.json, pnpm-workspace.yaml, .npmrc, .prettierrc/.prettierignore, and .gitignore
  • LICENSE file removal — confirm intended licensing/legal implications

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title "Create app" is vague and generic, providing no meaningful information about the specific changes or the main purpose of the pull request. Provide a more descriptive title that captures the primary change, such as "Add Appwrite Cursor Rules Generator app" or "Implement rules generator UI and API."
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 93.10% which is sufficient. The required threshold is 80.00%.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@appwrite
Copy link

appwrite bot commented Nov 27, 2025

Cursor Rules Generator

Project ID: cursor-rules-generator

Sites (1)
Site Status Logs Preview QR
 rules
69286b200030c76206be
Ready Ready View Logs Preview URL QR Code

Tip

SSR frameworks are fully supported with configurable build runtimes

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (21)
README.md (1)

1-38: Replace generic README with project-specific documentation.

The current README is SvelteKit scaffolding boilerplate and lacks any context about the Appwrite Cursor Rules Generator. Users need to understand the project's purpose, core features, and how to use the rules generator.

Consider adding sections covering:

  • Project description and purpose
  • Quick-start guide for the rules generator
  • Appwrite integration details
  • Configuration and environment setup
  • Example workflows
  • Build and deployment instructions
  • Links to relevant Appwrite documentation
src/lib/appwrite.js (2)

2-2: Consider removing @ts-ignore in favor of proper TypeScript configuration.

SvelteKit's $env/static/public should be recognized by TypeScript if tsconfig.json extends .svelte-kit/tsconfig.json. The @ts-ignore may hide legitimate type errors.


5-10: Empty projectId fallback could cause confusing runtime errors.

If PUBLIC_APPWRITE_PROJECT_ID is not set, the client initializes with an empty string. Appwrite will fail at runtime with an unclear error. Consider validating or throwing early:

 const endpoint = PUBLIC_APPWRITE_ENDPOINT || 'https://cloud.appwrite.io/v1';
-const projectId = PUBLIC_APPWRITE_PROJECT_ID || '';
+const projectId = PUBLIC_APPWRITE_PROJECT_ID;
+
+if (!projectId) {
+	throw new Error('PUBLIC_APPWRITE_PROJECT_ID environment variable is required');
+}
src/lib/languages/python/flask.js (1)

3-7: Consider expanding Flask security guidance.

The current security notes are minimal (2 bullet points) compared to server-side templates which provide more comprehensive guidance (3-4 bullet points with specifics about API keys and admin access).

Consider adding Flask-specific security best practices such as:

  • Secret key management (Flask's SECRET_KEY configuration)
  • Disabling debug mode in production
  • CORS configuration if building APIs
  • Session security settings
src/lib/languages/js/vue.js (1)

5-8: Consider using .env.local instead of .env for Vue.

Vue.js projects (using Vite) conventionally use .env.local for local environment variables that should not be committed to version control. The .env file is typically committed and contains non-sensitive defaults.

Note that the clientSecurityWithEnv helper defaults to .env.local, suggesting this is the preferred pattern for client-side frameworks.

Apply this diff to align with Vue.js conventions:

 export const vue = createFrameworkTemplate({
 	installation: jsInstall,
-	securityNotes: clientSecurityWithEnv('.env')
+	securityNotes: clientSecurityWithEnv('.env.local')
 });
src/lib/languages/dotnet/vanilla.js (1)

4-7: Consider adding security notes for consistency.

The .NET template uses empty securityNotes, while other server-side SDK templates (e.g., Next.js at line 7 in nextjs.js, Kotlin at line 45 in kotlin/index.js) include serverSecurity notes about API key protection and environment variables. Consider adding appropriate security guidance for .NET developers.

Apply this diff to add security notes:

-export const vanilla = createFrameworkTemplate({
-	installation: dotnetInstall,
-	securityNotes: ''
-});
+import { serverSecurity } from '../common/security.js';
+
+export const vanilla = createFrameworkTemplate({
+	installation: dotnetInstall,
+	securityNotes: serverSecurity
+});
src/lib/languages/react-native/vanilla.js (1)

4-10: Consider extracting security notes to a shared constant.

The inline securityNotes string duplicates content that exists in src/lib/languages/common/security.js (e.g., clientSecurity). For consistency with other modules like js/vanilla.js that reference shared security constants, consider importing and reusing from the common security module.

This is a minor consistency suggestion and the current implementation works correctly.

src/lib/languages/swift/index.js (1)

31-35: Consider adding security notes for the Swift client SDK.

The securityNotes parameter is an empty string, which will result in no security guidance in the generated template. Other client SDK templates (e.g., react-native/vanilla.js, js/vanilla.js) include best practices about environment variables, API key handling, and singleton initialization.

For consistency and user guidance, consider adding appropriate client-side security notes:

 export const vanilla = async () => {
 	const version = await getSDKVersion('client-apple');
 	const installation = generateInstallationTemplate(version);
-	return createFrameworkTemplate({ installation, securityNotes: '' });
+	return createFrameworkTemplate({ 
+		installation, 
+		securityNotes: `**Best Practices:**
+- Store endpoint and project ID in configuration
+- Never commit API keys to version control
+- Initialize the Appwrite client once and reuse`
+	});
 };
src/lib/utils/versions.js (1)

39-42: Consider using getCachedVersions() to avoid redundant API calls.

getSDKVersion calls fetchSDKVersions() directly, bypassing the cache. If multiple SDK versions are fetched in sequence (e.g., when generating rules for multiple languages), each call triggers a separate API request.

 export async function getSDKVersion(sdkKey) {
-	const versions = await fetchSDKVersions();
+	const versions = await getCachedVersions();
 	return versions[sdkKey] || 'latest';
 }
src/routes/+page.svelte (5)

21-26: Framework selection not updated on initial load.

updateFrameworks() is only called on SDK change events, but not during component initialization. If the default selectedSDK ('javascript') doesn't have 'nextjs' as its first framework, the initial selectedFramework value could be invalid.

Consider calling updateFrameworks() on mount or using a reactive statement:

+	import { onMount } from 'svelte';
+	
+	onMount(() => {
+		updateFrameworks();
+	});
+	
 	function updateFrameworks() {
 		const sdk = SDK_OPTIONS[selectedSDK];
 		if (sdk && sdk.frameworks.length > 0) {
 			selectedFramework = sdk.frameworks[0];
 		}
 	}

Or use Svelte's reactive statement:

$: if (SDK_OPTIONS[selectedSDK]) {
    const sdk = SDK_OPTIONS[selectedSDK];
    if (sdk.frameworks.length > 0 && !sdk.frameworks.includes(selectedFramework)) {
        selectedFramework = sdk.frameworks[0];
    }
}

28-35: Missing error handling for generateRules.

The generate function doesn't handle potential errors from generateRules(). If the async call fails, the user won't receive feedback.

 	async function generate() {
+		try {
 			generatedRules = await generateRules({
 				sdk: selectedSDK,
 				framework: selectedFramework,
 				features: selectedFeatures
 			});
 			previewVisible = true;
+		} catch (err) {
+			console.error('Failed to generate rules:', err);
+			// Consider showing user feedback
+		}
 	}

100-114: Allow at least one feature to be selected.

Users can deselect all features, which may produce empty or invalid rules output. Consider enforcing a minimum selection.

 	function toggleFeature(featureId) {
 		if (selectedFeatures.includes(featureId)) {
+			if (selectedFeatures.length === 1) {
+				return; // Prevent deselecting the last feature
+			}
 			selectedFeatures = selectedFeatures.filter(f => f !== featureId);
 		} else {
 			selectedFeatures = [...selectedFeatures, featureId];
 		}
 	}

150-153: Global style resets may cause unintended side effects.

Using :global(*) to disable tap-highlight affects all elements across the entire application. This could override styles in other components.

Consider scoping this more narrowly or applying it only to interactive elements within this component:

.main-layout :global(*) {
    -webkit-tap-highlight-color: transparent;
}

232-242: Potential accessibility issue with fixed viewport height.

Using max-height: 100vh and min-height: 100vh with overflow: hidden on .content-area may cause content to be inaccessible on desktop if it exceeds viewport height and scrolling is disabled.

The responsive styles do adjust this for smaller screens, but verify that content remains accessible on all desktop viewport sizes.

src/lib/languages/common/security.js (1)

48-61: Consider extracting duplicated best practices.

The frameworkNotes.angular and frameworkNotes.nodejs entries duplicate the base best practices text from clientSecurity. This creates maintenance overhead if the base guidance changes.

Consider composing from the base constants:

export const frameworkNotes = {
    angular: `${clientSecurity}
- Use Angular services for dependency injection

${authNote}`,
    
    nodejs: `${clientSecurity}
- Use environment variables for configuration
- API keys grant admin access - use with extreme caution`
};
src/lib/languages/common/install.js (1)

5-11: Consider removing unused single-line install constants.

The npmInstall, yarnInstall, pnpmInstall, and bunInstall constants appear to be unused, as jsInstall() generates a complete multi-package-manager installation block that is used throughout the codebase.

If these are exported for potential future use or external consumption, consider documenting that intent. Otherwise, removing dead code improves maintainability.

src/lib/rules-generator.js (5)

5-11: Unused SDKConfig properties: importSyntax, exportSyntax, asyncSyntax.

These properties are defined in the SDKConfig typedef and populated for each SDK but never referenced elsewhere in the codebase. If intended for future use, consider adding a TODO comment; otherwise, remove them to reduce maintenance burden.

Also applies to: 19-91


104-124: Filter empty sections before joining to avoid extraneous blank lines.

When features are not selected, empty strings in sections are joined with \n\n, producing consecutive blank lines in the output.

-${sections.join('\n\n')}
+${sections.filter(Boolean).join('\n\n')}

152-169: Consider extracting the template resolution logic to reduce duplication.

The "check if function and await" pattern is duplicated for both the framework-specific and vanilla fallback cases.

+async function resolveTemplate(template) {
+	if (typeof template === 'function') {
+		return await template();
+	}
+	return template;
+}
+
 async function generateSDKInitialization(sdk, framework) {
 	// ...templates definition...
 
 	const sdkTemplates = templates[sdk];
 	if (sdkTemplates && sdkTemplates[framework]) {
-		const template = sdkTemplates[framework];
-		if (typeof template === 'function') {
-			return await template();
-		}
-		return template;
+		return await resolveTemplate(sdkTemplates[framework]);
 	}
 	
 	if (sdkTemplates && sdkTemplates.vanilla) {
-		const template = sdkTemplates.vanilla;
-		if (typeof template === 'function') {
-			return await template();
-		}
-		return template;
+		return await resolveTemplate(sdkTemplates.vanilla);
 	}
 	// ...fallback...
 }

182-197: Unused sdk and framework parameters across all section generators.

The sdk and framework parameters are declared in all section generator functions (auth, database, storage, functions, messaging, sites, realtime) but never used. The generated content is identical regardless of SDK/framework. If SDK/framework-specific content is planned, consider adding a TODO; otherwise, remove the unused parameters.


183-183: Repeated dynamic imports of the same module could be consolidated.

Each section generator dynamically imports ./languages/common/products.js. Since these run in parallel via Promise.all, this causes redundant module resolution. Consider either:

  1. A single static import at the top of the file (simpler, no code-splitting benefit lost since all sections may be used)
  2. A shared cached import if code-splitting is intentional
+import {
+	authProductLinks,
+	databaseProductLinks,
+	storageProductLinks,
+	functionsProductLinks,
+	messagingProductLinks,
+	sitesProductLinks,
+	realtimeProductLinks
+} from './languages/common/products.js';

-async function generateAuthSection(sdk, framework) {
-	const { authProductLinks } = await import('./languages/common/products.js');
+function generateAuthSection() {
 	return `## Authentication & Teams
 // ... similar changes for other section generators

Also applies to: 205-205, 226-226, 246-246, 267-267, 288-288, 308-308

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 31f668d and d71c4ba.

⛔ Files ignored due to path filters (2)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • src/lib/assets/favicon.svg is excluded by !**/*.svg
📒 Files selected for processing (58)
  • .cursor/rules/APPWRITE.mdc (1 hunks)
  • .gitignore (1 hunks)
  • .npmrc (1 hunks)
  • .prettierignore (1 hunks)
  • .prettierrc (1 hunks)
  • LICENSE (0 hunks)
  • README.md (1 hunks)
  • eslint.config.js (1 hunks)
  • package.json (1 hunks)
  • pnpm-workspace.yaml (1 hunks)
  • src/app.d.ts (1 hunks)
  • src/app.html (1 hunks)
  • src/lib/appwrite.js (1 hunks)
  • src/lib/languages/common/install.js (1 hunks)
  • src/lib/languages/common/mcp.js (1 hunks)
  • src/lib/languages/common/products.js (1 hunks)
  • src/lib/languages/common/security.js (1 hunks)
  • src/lib/languages/common/utils.js (1 hunks)
  • src/lib/languages/dart/index.js (1 hunks)
  • src/lib/languages/dart/server.js (1 hunks)
  • src/lib/languages/dotnet/index.js (1 hunks)
  • src/lib/languages/dotnet/server.js (1 hunks)
  • src/lib/languages/dotnet/vanilla.js (1 hunks)
  • src/lib/languages/go/index.js (1 hunks)
  • src/lib/languages/go/server.js (1 hunks)
  • src/lib/languages/index.js (1 hunks)
  • src/lib/languages/js/angular.js (1 hunks)
  • src/lib/languages/js/astro.js (1 hunks)
  • src/lib/languages/js/index.js (1 hunks)
  • src/lib/languages/js/nextjs.js (1 hunks)
  • src/lib/languages/js/nodejs.js (1 hunks)
  • src/lib/languages/js/nuxt.js (1 hunks)
  • src/lib/languages/js/qwik.js (1 hunks)
  • src/lib/languages/js/react.js (1 hunks)
  • src/lib/languages/js/solid.js (1 hunks)
  • src/lib/languages/js/svelte.js (1 hunks)
  • src/lib/languages/js/tanstack.js (1 hunks)
  • src/lib/languages/js/vanilla.js (1 hunks)
  • src/lib/languages/js/vue.js (1 hunks)
  • src/lib/languages/kotlin/index.js (1 hunks)
  • src/lib/languages/php/index.js (1 hunks)
  • src/lib/languages/php/server.js (1 hunks)
  • src/lib/languages/python/flask.js (1 hunks)
  • src/lib/languages/python/index.js (1 hunks)
  • src/lib/languages/python/server.js (1 hunks)
  • src/lib/languages/react-native/index.js (1 hunks)
  • src/lib/languages/react-native/vanilla.js (1 hunks)
  • src/lib/languages/ruby/index.js (1 hunks)
  • src/lib/languages/ruby/server.js (1 hunks)
  • src/lib/languages/swift/index.js (1 hunks)
  • src/lib/rules-generator.js (1 hunks)
  • src/lib/utils/versions.js (1 hunks)
  • src/routes/+layout.svelte (1 hunks)
  • src/routes/+page.svelte (1 hunks)
  • static/robots.txt (1 hunks)
  • svelte.config.js (1 hunks)
  • tsconfig.json (1 hunks)
  • vite.config.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • LICENSE
🧰 Additional context used
🧬 Code graph analysis (27)
src/lib/languages/python/server.js (7)
src/lib/languages/dotnet/server.js (2)
  • server (5-8)
  • server (5-8)
src/lib/languages/go/server.js (2)
  • server (5-8)
  • server (5-8)
src/lib/languages/php/server.js (2)
  • server (5-8)
  • server (5-8)
src/lib/languages/ruby/server.js (2)
  • server (5-8)
  • server (5-8)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (2)
  • pythonInstall (54-66)
  • pythonInstall (54-66)
src/lib/languages/common/security.js (2)
  • serverSecurity (25-28)
  • serverSecurity (25-28)
src/lib/languages/dart/server.js (4)
src/lib/utils/versions.js (1)
  • getSDKVersion (39-42)
src/lib/languages/common/install.js (2)
  • dartInstall (129-147)
  • dartInstall (129-147)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/security.js (2)
  • serverSecurity (25-28)
  • serverSecurity (25-28)
src/lib/languages/js/vue.js (3)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (1)
  • jsInstall (18-44)
src/lib/languages/common/security.js (2)
  • clientSecurityWithEnv (17-20)
  • clientSecurityWithEnv (17-20)
src/lib/languages/react-native/vanilla.js (3)
src/lib/languages/js/vanilla.js (2)
  • vanilla (5-8)
  • vanilla (5-8)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (1)
  • jsInstall (18-44)
src/lib/languages/js/angular.js (3)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (1)
  • jsInstall (18-44)
src/lib/languages/common/security.js (2)
  • frameworkNotes (48-61)
  • frameworkNotes (48-61)
src/lib/languages/python/flask.js (1)
src/lib/languages/common/utils.js (1)
  • createSecuritySection (12-17)
src/lib/languages/ruby/server.js (3)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (2)
  • rubyInstall (93-105)
  • rubyInstall (93-105)
src/lib/languages/common/security.js (2)
  • serverSecurityWithConfig (34-37)
  • serverSecurityWithConfig (34-37)
src/lib/languages/dart/index.js (4)
src/lib/languages/dart/server.js (2)
  • version (11-11)
  • installation (12-12)
src/lib/utils/versions.js (1)
  • getSDKVersion (39-42)
src/lib/languages/common/install.js (2)
  • dartInstall (129-147)
  • dartInstall (129-147)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/js/solid.js (3)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (1)
  • jsInstall (18-44)
src/lib/languages/common/security.js (4)
  • clientSecurityWithEnv (17-20)
  • clientSecurityWithEnv (17-20)
  • authNote (42-43)
  • authNote (42-43)
src/lib/languages/go/server.js (6)
src/lib/languages/dart/server.js (2)
  • server (10-14)
  • server (10-14)
src/lib/languages/php/server.js (2)
  • server (5-8)
  • server (5-8)
src/lib/languages/python/server.js (2)
  • server (5-8)
  • server (5-8)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (2)
  • goInstall (82-88)
  • goInstall (82-88)
src/lib/languages/common/security.js (2)
  • serverSecurity (25-28)
  • serverSecurity (25-28)
src/lib/languages/js/nuxt.js (3)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (1)
  • jsInstall (18-44)
src/lib/languages/common/security.js (2)
  • authNote (42-43)
  • authNote (42-43)
svelte.config.js (1)
src/lib/rules-generator.js (1)
  • config (98-98)
src/lib/languages/js/react.js (3)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (1)
  • jsInstall (18-44)
src/lib/languages/common/security.js (2)
  • clientSecurity (8-11)
  • clientSecurity (8-11)
src/lib/languages/js/tanstack.js (3)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (1)
  • jsInstall (18-44)
src/lib/languages/common/security.js (2)
  • authNote (42-43)
  • authNote (42-43)
src/lib/languages/js/svelte.js (3)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (1)
  • jsInstall (18-44)
src/lib/languages/common/security.js (4)
  • clientSecurityWithEnv (17-20)
  • clientSecurityWithEnv (17-20)
  • authNote (42-43)
  • authNote (42-43)
src/lib/languages/js/vanilla.js (4)
src/lib/languages/react-native/vanilla.js (2)
  • vanilla (4-10)
  • vanilla (4-10)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (1)
  • jsInstall (18-44)
src/lib/languages/common/security.js (2)
  • clientSecurity (8-11)
  • clientSecurity (8-11)
src/lib/languages/js/nodejs.js (3)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (1)
  • jsInstall (18-44)
src/lib/languages/common/security.js (2)
  • serverSecurity (25-28)
  • serverSecurity (25-28)
src/lib/languages/swift/index.js (2)
src/lib/utils/versions.js (1)
  • getSDKVersion (39-42)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
eslint.config.js (1)
src/lib/languages/js/svelte.js (2)
  • svelte (5-9)
  • svelte (5-9)
src/lib/languages/common/utils.js (4)
src/lib/languages/dart/index.js (1)
  • installation (12-12)
src/lib/languages/dart/server.js (1)
  • installation (12-12)
src/lib/languages/kotlin/index.js (1)
  • installation (44-44)
src/lib/languages/swift/index.js (1)
  • installation (33-33)
src/lib/languages/js/nextjs.js (3)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (1)
  • jsInstall (18-44)
src/lib/languages/common/security.js (4)
  • serverSecurity (25-28)
  • serverSecurity (25-28)
  • authNote (42-43)
  • authNote (42-43)
src/lib/languages/common/install.js (4)
src/lib/languages/dart/index.js (1)
  • version (11-11)
src/lib/languages/dart/server.js (1)
  • version (11-11)
src/lib/languages/kotlin/index.js (1)
  • version (43-43)
src/lib/languages/swift/index.js (1)
  • version (32-32)
src/lib/rules-generator.js (2)
src/lib/languages/common/mcp.js (1)
  • generateMCPRecommendation (10-54)
src/lib/languages/common/products.js (14)
  • authProductLinks (16-28)
  • authProductLinks (16-28)
  • databaseProductLinks (33-41)
  • databaseProductLinks (33-41)
  • storageProductLinks (46-50)
  • storageProductLinks (46-50)
  • functionsProductLinks (55-61)
  • functionsProductLinks (55-61)
  • messagingProductLinks (66-74)
  • messagingProductLinks (66-74)
  • sitesProductLinks (79-103)
  • sitesProductLinks (79-103)
  • realtimeProductLinks (108-118)
  • realtimeProductLinks (108-118)
src/lib/languages/dotnet/server.js (5)
src/lib/languages/go/server.js (2)
  • server (5-8)
  • server (5-8)
src/lib/languages/ruby/server.js (2)
  • server (5-8)
  • server (5-8)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (2)
  • dotnetInstall (110-122)
  • dotnetInstall (110-122)
src/lib/languages/common/security.js (2)
  • serverSecurityWithConfig (34-37)
  • serverSecurityWithConfig (34-37)
src/lib/languages/dotnet/vanilla.js (3)
src/lib/languages/js/vanilla.js (2)
  • vanilla (5-8)
  • vanilla (5-8)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (2)
  • dotnetInstall (110-122)
  • dotnetInstall (110-122)
src/lib/languages/php/server.js (3)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (2)
  • phpInstall (71-77)
  • phpInstall (71-77)
src/lib/languages/common/security.js (2)
  • serverSecurity (25-28)
  • serverSecurity (25-28)
src/lib/languages/js/astro.js (3)
src/lib/languages/common/utils.js (1)
  • createFrameworkTemplate (27-32)
src/lib/languages/common/install.js (1)
  • jsInstall (18-44)
src/lib/languages/common/security.js (4)
  • clientSecurityWithEnv (17-20)
  • clientSecurityWithEnv (17-20)
  • authNote (42-43)
  • authNote (42-43)
🔇 Additional comments (55)
static/robots.txt (1)

1-3: robots.txt configuration looks good.

The file correctly allows all crawlers to access all paths by default, which is the appropriate policy for a new public project. Syntax is valid per the robots.txt standard.

.npmrc (1)

1-1: Configuration is appropriate.

Enforcing strict engine versions is a best practice for ensuring consistent environments across development and CI/CD pipelines.

.prettierrc (1)

1-17: Prettier configuration is well-structured.

The config properly enables Svelte-aware formatting and establishes consistent conventions for the project. Parser override for .svelte files is correctly configured.

pnpm-workspace.yaml (1)

1-2: Verify monorepo intent for workspace configuration.

The pnpm-workspace.yaml file indicates a monorepo setup, but only a single package.json is shown in this PR. Clarify whether the project is intended as a multi-package workspace or if this file can be removed to simplify the single-package configuration.

.prettierignore (1)

1-9: Ignore patterns are comprehensive.

Lock files and static assets are correctly excluded from formatting, preventing unnecessary changes to generated or dependency-managed files.

package.json (1)

1-37: Package configuration is well-structured with comprehensive tooling.

Scripts cover all essential workflows (dev, build, test, format, lint). Dependency selection is appropriate for a SvelteKit + TypeScript + ESLint + Prettier stack.

Verify that @appwrite.io/[email protected] is the intended stable version. If this is a new or frequently-updated package, confirm it's not pinned to an outdated release.

src/app.html (1)

1-12: HTML template is properly structured for SvelteKit.

The template correctly implements SvelteKit placeholders, includes appropriate meta tags for viewport and theme configuration, and uses display: contents wrapper appropriately. The dark theme styling aligns with the Appwrite design system mentioned in package.json (@appwrite.io/pink).

.gitignore (1)

1-23: Gitignore patterns are comprehensive and appropriate.

Coverage includes standard Node.js artifacts, SvelteKit build output, deployment platform directories, environment files with appropriate exceptions, and OS-specific metadata. The .env exclusion with .env.example and .env.test exceptions follows best practices for environment management.

src/app.d.ts (1)

1-13: LGTM!

Standard SvelteKit type declaration scaffolding with placeholder interfaces for future augmentation.

eslint.config.js (1)

1-40: LGTM!

Well-structured ESLint flat configuration with proper TypeScript and Svelte integration. Good practice including the justification comment for disabling no-undef.

src/lib/languages/go/index.js (1)

1-2: LGTM!

Clean barrel export consistent with other language module patterns in the project.

src/lib/languages/ruby/index.js (1)

1-1: LGTM!

Clean barrel export following the consistent pattern used across language modules.

svelte.config.js (1)

1-18: LGTM!

Standard SvelteKit configuration with adapter-auto and vitePreprocess. The inline comments appropriately document the adapter limitations and link to official docs for future reference.

src/lib/languages/python/index.js (1)

1-2: LGTM!

Clean barrel exports exposing both Flask-specific and generic server templates for Python.

src/lib/languages/php/index.js (1)

1-1: LGTM!

Clean barrel export consistent with the pattern used across language modules.

vite.config.ts (1)

1-6: LGTM!

Minimal and correct Vite configuration for SvelteKit. The sveltekit() plugin handles all framework-specific build requirements.

src/lib/languages/php/server.js (1)

1-8: LGTM!

The PHP server template follows the established pattern consistently, using shared utilities for installation instructions and security notes.

src/routes/+layout.svelte (1)

1-13: LGTM!

The layout component is clean and properly structured, using Svelte 5 runes syntax and correctly handling the favicon and theme imports.

src/lib/languages/go/server.js (1)

1-8: LGTM!

The Go server template maintains consistency with other language server implementations, correctly composing shared utilities for installation and security guidance.

src/lib/languages/dotnet/index.js (1)

1-2: LGTM!

Clean re-export pattern for aggregating .NET language modules.

src/lib/languages/python/server.js (1)

1-8: LGTM!

The Python server template is consistent with other language server implementations, properly utilizing shared utilities for installation instructions and security notes.

src/lib/languages/common/mcp.js (1)

10-54: Documentation link verified as accessible and correct.

The URL https://appwrite.io/docs/tooling/mcp/cursor returns HTTP 200, confirming the documentation link is valid and functional. The MCP recommendation content is comprehensive and well-structured with clear installation steps, configuration examples, and use cases.

src/lib/languages/react-native/index.js (1)

1-1: LGTM!

The re-export follows the established pattern used across other language modules in this PR.

tsconfig.json (1)

1-20: LGTM!

The TypeScript configuration is well-structured for a SvelteKit project with strict type checking enabled and proper JS/TS interop to support the mixed .js and .ts modules throughout the codebase.

src/lib/languages/js/astro.js (1)

1-11: LGTM!

The Astro template correctly composes installation instructions with appropriate security notes. The guidance to use separate clients for client-side and server-side operations is particularly relevant for Astro's hybrid rendering model.

src/lib/languages/js/angular.js (1)

1-8: LGTM!

The Angular template follows the established pattern and uses framework-specific security notes that appropriately reference Angular services for dependency injection.

src/lib/languages/js/nextjs.js (1)

1-9: LGTM!

The Next.js template correctly uses serverSecurity notes, which is appropriate given Next.js's server-first architecture and the need to emphasize API key protection.

src/lib/languages/ruby/server.js (1)

1-8: LGTM!

The Ruby server template correctly follows the established pattern for server-side SDK templates, using shared utilities for installation instructions and security notes. The inclusion of "Rails credentials" as an alternative to environment variables is appropriate for the Ruby ecosystem.

src/lib/languages/js/svelte.js (1)

1-9: LGTM!

The Svelte template correctly uses the shared framework template pattern. The .env file reference and SSR auth note are appropriate for SvelteKit's conventions and SSR capabilities.

src/lib/languages/js/react.js (1)

1-8: LGTM!

The React template appropriately uses the generic clientSecurity notes without the SSR auth recommendation, which is correct since vanilla React is primarily client-side. SSR-specific guidance is correctly reserved for Next.js and similar frameworks.

src/lib/languages/dotnet/server.js (1)

1-8: LGTM!

The .NET server template follows the established pattern correctly. The "configuration files or environment variables" phrasing is appropriate for .NET's configuration patterns (e.g., appsettings.json, IConfiguration).

src/lib/languages/js/solid.js (1)

1-9: LGTM!

The Solid template correctly mirrors the Svelte template structure, which is appropriate since both SolidStart and SvelteKit share similar SSR paradigms. The .env file reference and SSR auth note are well-suited for Solid's conventions.

src/lib/languages/dart/server.js (1)

1-14: LGTM!

Clean implementation that correctly:

  • Fetches the server-dart SDK version asynchronously
  • Passes isServer=true to dartInstall to generate the correct pub command (dart pub get)
  • Uses serverSecurity notes appropriate for server-side SDK usage
src/lib/languages/js/nuxt.js (2)

5-6: Ensure jsInstall is called, not passed as a reference.

Comparing to other framework templates (e.g., tanstack.js at line 6), jsInstall(...) is called with arguments to produce an installation string. Here, jsInstall appears to be passed directly without invocation.

If jsInstallDefault is meant to be a pre-computed string constant (different from the jsInstall function), this is fine. Otherwise, you may need:

 export const nuxt = createFrameworkTemplate({
-	installation: jsInstall,
+	installation: jsInstall(),
 	securityNotes: `**Best Practices:**

1-1: The review comment is incorrect—jsInstallDefault is a valid export.

The verification confirms that jsInstallDefault is properly exported from src/lib/languages/common/install.js (line 49) as the pre-computed result of calling jsInstall(). The import in nuxt.js is correct and functional. No action needed.

Likely an incorrect or invalid review comment.

src/lib/languages/swift/index.js (1)

9-24: LGTM on the installation template.

The generateInstallationTemplate function provides clear instructions for both Swift Package Manager and Xcode integration, with proper version interpolation.

src/lib/languages/js/tanstack.js (1)

1-16: LGTM!

Well-structured TanStack Query integration template that:

  • Installs both required packages (appwrite and @tanstack/react-query) together
  • Provides TanStack-specific best practices (query keys, invalidation, enabled option)
  • Links to official documentation for further guidance
  • Includes the shared authNote for SSR authentication recommendations
src/lib/languages/js/nodejs.js (1)

1-9: LGTM!

Clean implementation following the established pattern for JS framework templates. The additional security note about never logging API keys in error messages is a good server-specific practice.

src/lib/languages/dart/index.js (1)

1-25: LGTM!

Well-structured module with proper async handling for version fetching. The vanilla alias for backwards compatibility is a thoughtful addition, and the re-export pattern for server keeps the public API clean.

src/lib/utils/versions.js (2)

5-32: LGTM!

Good defensive coding with fallback versions when the API is unavailable. The error logging provides visibility into failures.


44-60: Cache implementation looks good, but it's currently unused.

The caching mechanism is well-implemented. Once getSDKVersion is updated to use getCachedVersions(), this will prevent redundant API calls across the application.

src/lib/languages/js/vanilla.js (2)

1-1: I'll help you verify this review comment. Let me start by checking if jsInstallDefault is actually exported from the install.js module and how jsInstall is being used.
<function_calls>

#!/bin/bash

Check for jsInstallDefault export in install.js

rg -n 'export.*jsInstallDefault' src/lib/languages/common/install.js


</function_calls>
<function_calls>

#!/bin/bash

Check all exports in install.js to understand what's available

rg -n '^export' src/lib/languages/common/install.js


</function_calls>
<function_calls>

#!/bin/bash

Check the usage of jsInstall in vanilla.js

cat -n src/lib/languages/js/vanilla.js


</function_calls>
<function_calls>

#!/bin/bash

Check how jsInstall is used in react-native/vanilla.js for comparison

cat -n src/lib/languages/js/react-native/vanilla.js


</function_calls>


5-8: The code is correct. jsInstall is an alias for the pre-computed string jsInstallDefault.

The import at line 1 shows import { jsInstallDefault as jsInstall }, so jsInstall in this file is actually the result of calling the jsInstall() function with default arguments (line 49 in install.js). It's a string constant, not a function reference, so no invocation is needed.

src/routes/+page.svelte (3)

37-47: LGTM!

The downloadRules function correctly creates a blob, triggers download, cleans up the anchor element, and revokes the object URL to prevent memory leaks.


49-63: LGTM!

The copyRules function handles both success and error cases with appropriate user feedback and timeout reset.


65-72: LGTM!

The toggleFeature function correctly uses immutable array operations to trigger Svelte reactivity.

src/lib/languages/common/utils.js (2)

12-17: LGTM!

Clean utility function with proper JSDoc documentation and sensible default value.


27-32: LGTM!

The createFrameworkTemplate function correctly composes installation and security sections with proper separation.

src/lib/languages/js/index.js (1)

1-13: LGTM!

Clean barrel file pattern for aggregating JavaScript framework modules. The named re-exports provide a convenient single import point.

src/lib/languages/common/security.js (4)

8-11: LGTM!

Clear and actionable client-side security best practices.


17-20: LGTM!

Good use of a parameterized function to customize the environment file reference.


25-28: LGTM!

Server security notes appropriately emphasize the critical nature of API key protection.


34-37: LGTM!

Flexible template function for server security with configurable configuration method.

src/lib/languages/common/install.js (1)

18-44: LGTM!

The jsInstall function provides good flexibility with sensible defaults and generates comprehensive multi-package-manager installation instructions.

src/lib/languages/index.js (1)

1-10: Clean barrel file for language module consolidation.

The re-export pattern is clean and idiomatic for ES modules. The reactNative camelCase naming appropriately maps the hyphenated folder name to a valid JavaScript identifier.

Comment on lines +1 to +46
import { getSDKVersion } from '$lib/utils/versions.js';
import { createFrameworkTemplate } from '../common/utils.js';
import { serverSecurity } from '../common/security.js';

/**
* Generates the Kotlin SDK installation template with the latest version
* @param {string} version - The SDK version to use
* @returns {string}
*/
function generateInstallationTemplate(version) {
return `## SDK Installation

Add the Appwrite Kotlin SDK to your \`build.gradle.kts\`:

**Recommended: Specify exact version for stability**

\`\`\`kotlin
dependencies {
implementation("io.appwrite:sdk-for-kotlin:${version}")
}
\`\`\`

Or for Maven, add to \`pom.xml\`:

**Recommended: Specify exact version**

\`\`\`xml
<dependency>
<groupId>io.appwrite</groupId>
<artifactId>sdk-for-kotlin</artifactId>
<version>${version}</version>
</dependency>
\`\`\`
`;
}

/**
* Gets the Kotlin SDK installation template with the latest version from Appwrite's API
* This is the main export used by the rules generator
* @returns {Promise<string>}
*/
export const vanilla = async () => {
const version = await getSDKVersion('server-kotlin');
const installation = generateInstallationTemplate(version);
return createFrameworkTemplate({ installation, securityNotes: serverSecurity });
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, locate the rules-generator file to confirm it exists
fd -type f -name "rules-generator.js" src/

# Then examine its contents, especially around template invocation
if [ -f "src/lib/rules-generator.js" ]; then
  wc -l src/lib/rules-generator.js
fi

Repository: appwrite/rules

Length of output: 276


🏁 Script executed:

#!/bin/bash
# Read the full rules-generator.js file to inspect error handling
cat -n src/lib/rules-generator.js

Repository: appwrite/rules

Length of output: 13367


Error handling for async template invocation is missing and should be added.

The concern in the original review is valid. The generateRules() function at line 97-128 calls generateSDKInitialization() at line 101 without any try-catch or error handling. When generateSDKInitialization() invokes async template functions (lines 156, 166) like the Kotlin vanilla() export, any errors from getSDKVersion('server-kotlin') or network failures will propagate unhandled, causing the entire rule generation to fail.

Wrap the async template invocations and the generateRules() call in appropriate error handling (try-catch blocks or Promise error handlers) to gracefully handle network failures, API unavailability, and other failures during version fetching. This will improve resilience and provide better error diagnostics.

🤖 Prompt for AI Agents
In src/lib/languages/kotlin/index.js lines 1-46, the exported async vanilla()
calls getSDKVersion and can propagate network/async errors to callers; update
vanilla() to wrap the await getSDKVersion('server-kotlin') call in a try-catch,
handle failures by either returning a clear fallback installation template
(e.g., a template using a pinned or placeholder version and a note about version
retrieval failure) or rethrowing a new error with contextual message, and ensure
any caught errors are logged or annotated so callers can detect and handle the
failure gracefully.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/lib/rules-generator.js (2)

131-175: SDK initialization lookup and fallbacks are well‑designed (optional micro‑refactor)

The template resolution logic (framework → vanilla → generic text) is a nice, safe fallback chain and should behave well even when a new framework lacks a specific snippet.

If you expect generateRules to be called frequently, you might consider hoisting the templates object to module scope so it isn’t reallocated on every generateSDKInitialization call, but this is a micro‑optimization and not required for correctness:

-async function generateSDKInitialization(sdk, framework) {
-	/** @type {Record<string, Record<string, string | (() => Promise<string>)>>} */
-	const templates = {
+/** @type {Record<string, Record<string, string | (() => Promise<string>)>>} */
+const TEMPLATES = {
 		javascript: codeExamples.js,
 		'react-native': codeExamples.reactNative,
 		python: codeExamples.python,
 		php: codeExamples.php,
 		go: codeExamples.go,
 		flutter: codeExamples.dart,
 		swift: codeExamples.swift,
 		kotlin: codeExamples.kotlin,
 		ruby: codeExamples.ruby,
 		dotnet: codeExamples.dotnet
-	};
-
-	const sdkTemplates = templates[sdk];
+	};
+
+async function generateSDKInitialization(sdk, framework) {
+	const sdkTemplates = TEMPLATES[sdk];

177-326: Section generators are consistent; consider sharing the products import + boilerplate

All feature section functions follow a consistent pattern and read well. The only noticeable repetition is:

  • The identical (sdk, framework) signature (currently unused in bodies).
  • Repeated dynamic imports of ./languages/common/products.js.
  • Repeated “Best Practices” section scaffolding.

If this starts to grow, you could DRY it up with a small helper that takes { heading, linksKey, bullets } and returns the markdown, and a single cached dynamic import for product links. For now, this is perfectly acceptable and clear as is.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d71c4ba and 4181a43.

📒 Files selected for processing (1)
  • src/lib/rules-generator.js (1 hunks)
🔇 Additional comments (2)
src/lib/rules-generator.js (2)

1-17: Imports and JSDoc typedefs look solid

Module imports are clear, and the JSDoc typedefs for SDKConfig and GeneratorConfig give good editor/TS tooling support without adding runtime overhead. No changes needed here.


19-91: SDK_OPTIONS structure is clear and extensible

The SDK_OPTIONS map is well‑structured and gives you a single source of truth for SDK labels, supported frameworks, and syntax hints. This should work well for driving both the UI and the generator. Just keep this in sync with the templates in languages/index.js when adding new SDKs/frameworks; the runtime fallbacks in generateSDKInitialization will protect you in the meantime.

Comment on lines 93 to 128
/**
* @param {GeneratorConfig} config
* @returns {Promise<string>}
*/
export async function generateRules(config) {
const { sdk, framework, features } = config;
const sdkInfo = SDK_OPTIONS[sdk];

const sdkInit = await generateSDKInitialization(sdk, framework);

// Generate all sections in parallel
const sections = await Promise.all([
features.includes('auth') ? generateAuthSection(sdk, framework) : Promise.resolve(''),
features.includes('database') ? generateDatabaseSection(sdk, framework) : Promise.resolve(''),
features.includes('storage') ? generateStorageSection(sdk, framework) : Promise.resolve(''),
features.includes('functions') ? generateFunctionsSection(sdk, framework) : Promise.resolve(''),
features.includes('messaging') ? generateMessagingSection(sdk, framework) : Promise.resolve(''),
features.includes('sites') ? generateSitesSection(sdk, framework) : Promise.resolve(''),
features.includes('realtime') ? generateRealtimeSection(sdk, framework) : Promise.resolve('')
]);

let rules = `---
description: You are an expert developer focused on building apps with Appwrite's ${sdkInfo?.name || sdk} SDK.
alwaysApply: false
---

# Appwrite Development Rules

${generateMCPRecommendation()}

${sdkInit}
${sections.join('\n\n')}
`;

return rules;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Harden features handling and simplify section generation

There’s a small robustness risk if config.features is ever undefined/non‑array: features.includes(...) will throw at runtime. Easy to guard inside generateRules:

-export async function generateRules(config) {
-	const { sdk, framework, features } = config;
+export async function generateRules(config) {
+	const { sdk, framework } = config;
+	const features = Array.isArray(config.features) ? config.features : [];

This keeps the public API forgiving and avoids accidental crashes if the caller omits features or passes something unexpected.

If you want to reduce a bit of duplication in the section list, you could also consider a small feature→generator map and filter on features.includes(feature) instead of embedding Promise.resolve('') placeholders, but that’s optional.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* @param {GeneratorConfig} config
* @returns {Promise<string>}
*/
export async function generateRules(config) {
const { sdk, framework, features } = config;
const sdkInfo = SDK_OPTIONS[sdk];
const sdkInit = await generateSDKInitialization(sdk, framework);
// Generate all sections in parallel
const sections = await Promise.all([
features.includes('auth') ? generateAuthSection(sdk, framework) : Promise.resolve(''),
features.includes('database') ? generateDatabaseSection(sdk, framework) : Promise.resolve(''),
features.includes('storage') ? generateStorageSection(sdk, framework) : Promise.resolve(''),
features.includes('functions') ? generateFunctionsSection(sdk, framework) : Promise.resolve(''),
features.includes('messaging') ? generateMessagingSection(sdk, framework) : Promise.resolve(''),
features.includes('sites') ? generateSitesSection(sdk, framework) : Promise.resolve(''),
features.includes('realtime') ? generateRealtimeSection(sdk, framework) : Promise.resolve('')
]);
let rules = `---
description: You are an expert developer focused on building apps with Appwrite's ${sdkInfo?.name || sdk} SDK.
alwaysApply: false
---
# Appwrite Development Rules
${generateMCPRecommendation()}
${sdkInit}
${sections.join('\n\n')}
`;
return rules;
}
/**
* @param {GeneratorConfig} config
* @returns {Promise<string>}
*/
export async function generateRules(config) {
const { sdk, framework } = config;
const features = Array.isArray(config.features) ? config.features : [];
const sdkInfo = SDK_OPTIONS[sdk];
const sdkInit = await generateSDKInitialization(sdk, framework);
// Generate all sections in parallel
const sections = await Promise.all([
features.includes('auth') ? generateAuthSection(sdk, framework) : Promise.resolve(''),
features.includes('database') ? generateDatabaseSection(sdk, framework) : Promise.resolve(''),
features.includes('storage') ? generateStorageSection(sdk, framework) : Promise.resolve(''),
features.includes('functions') ? generateFunctionsSection(sdk, framework) : Promise.resolve(''),
features.includes('messaging') ? generateMessagingSection(sdk, framework) : Promise.resolve(''),
features.includes('sites') ? generateSitesSection(sdk, framework) : Promise.resolve(''),
features.includes('realtime') ? generateRealtimeSection(sdk, framework) : Promise.resolve('')
]);
let rules = `---
description: You are an expert developer focused on building apps with Appwrite's ${sdkInfo?.name || sdk} SDK.
alwaysApply: false
---
# Appwrite Development Rules
${generateMCPRecommendation()}
${sdkInit}
${sections.join('\n\n')}
`;
return rules;
}
🤖 Prompt for AI Agents
In src/lib/rules-generator.js around lines 93 to 128, features is accessed with
features.includes(...) which will throw if config.features is undefined or not
an array; normalize features to a safe array (e.g. const featuresList =
Array.isArray(features) ? features : []) at the top of the function and use that
for checks. While updating, simplify section generation by creating a small
feature→generator map (e.g. [{ key: 'auth', fn: generateAuthSection }, ...]),
filter that map by featuresList.includes(key), then Promise.all over the
selected generator calls to produce sections (no Promise.resolve('')
placeholders).

Copy link
Member

@eldadfux eldadfux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to improve the readme, explaining the file structure and inheritance mechanism between the different instructions, encouraging contribution, adding a template for issues and PRs.

I would add a test that runs on a few PRs and generate demo apps to verify the quality of the instructions. Could be phase 2 as well.

Maybe we should also educate the LLM about some common mistakes like not whitelisting your domain if you get CORS issues. We can check our stats around the most viewed Discord threads to see what come up most often.

I miss some general description of what Appwrite is at the start. Maybe using this also to have links to our different channels for human based support (Discord, X).

I would also print a version of this repo in the generated file for tracking and debugging user issues.

Do we need to generate this file a bit differently depending on the SDK? I think most follow a standard, so maybe we can just use that as instructions to how to actually use this generated file.


### Installation Steps

1. **Open Cursor Settings**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how helpful it is to recommend this to the agent. I find it hard to see in what context it will use it to suggest it back to the end-user.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of making this an opening recommendation simply because it helps to have access to exact examples. But we can leave this out and keep it as a recommendation in the docs

export const clientSecurityWithEnv = (envFile = '.env.local') => `**Best Practices:**
- Store endpoint and project ID in environment variables (${envFile})
- Never commit API keys to version control
- Initialize services once and export as singletons`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe same for the client. I also think maybe some examples on how to handle a sever and client instance of the SDKs can be helpful. I think one more crucial thing for the setup of the SDK is to explore or recommend on how to communicate between client and server SDK for SSR apps. Maybe how to generate a JWT, how refresh it etc.


\`\`\`kotlin
dependencies {
implementation("io.appwrite:sdk-for-android:${version}")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking of this again, should we just try to push to latest version? assuming the docs links we share also relevant for latest version all the time

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For most SDKs, this isn't an issue. Some of them expect a version number though.

/**
* Functions product documentation
*/
export const functionsProductLinks = `For detailed serverless function execution, see the [Functions Execution Documentation](https://appwrite.io/docs/products/functions/execute).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Develop page is really important for functions. Including links to some of our starter templates per language have been really crucial for me in getting functions to build and execute well after a single prompt generation. I think maybe we should also encourage the LLM to go this path only on specific use cases such as scheduled tasks, event driven tasks etc.


For server-side rendering (SSR) authentication, see the [SSR Login Guide](https://appwrite.io/docs/products/auth/server-side-rendering).

For Teams management, team invitations, and team-based permissions, see the [Teams Documentation](https://appwrite.io/docs/products/auth/teams).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multi-tenancy should be a big topic, maybe we should cover it under permissions. It's really important and we don't cover it enough even in our own docs. Its crucial the LLM prefer team/member based roles of specific user based roles and then understand how to do member management from scratch.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
src/lib/rules-generator.js (1)

112-145: Harden features parameter handling

If config.features is undefined or not an array, the features.includes(...) calls will throw a runtime error. Consider normalizing at the start of the function for robustness.

Apply this diff:

 export async function generateRules(config) {
-	const { sdk, framework, features, includeMCP = false } = config;
+	const { sdk, framework, includeMCP = false } = config;
+	const features = Array.isArray(config.features) ? config.features : [];
 	const sdkInfo = SDK_OPTIONS[sdk];
src/lib/languages/common/products.js (2)

6-11: Address duplicate documentation links

The rows documentation link (line 9) appears again at line 33, and the storage link (line 11) reappears at lines 46 and 48. Consider removing these from commonProductLinks since they're already covered in their respective product sections.


16-18: Remove duplicate Quick Start Guide link

The Authentication Quick Start Guide link appears on both line 16 and line 18. Keep only one reference to avoid duplication.

🧹 Nitpick comments (3)
scripts/lib-loader.js (1)

10-18: Consider adding existence check for clearer error messages.

While Node.js will error if the resolved file doesn't exist, adding an explicit check could provide clearer diagnostics during development.

 	if (specifier.startsWith('$lib/')) {
 		const relativePath = specifier.replace('$lib/', '');
 		const absolutePath = resolvePath(projectRoot, 'src', 'lib', relativePath);
+		// Optional: Add existence check using fs.existsSync for better error messages
 		const fileUrl = pathToFileURL(absolutePath).href;
 		return {
 			url: fileUrl,
 			format: 'module',
 			shortCircuit: true
 		};
 	}
src/routes/+page.svelte (1)

86-88: Add keys to each blocks for better performance

Svelte recommends adding keys to each blocks to optimize rendering and prevent potential issues when lists change.

Apply these diffs:

-{#each Object.entries(SDK_OPTIONS) as [key, value]}
+{#each Object.entries(SDK_OPTIONS) as [key, value] (key)}
 	<option value={key}>{value.name}</option>
 {/each}
-{#each SDK_OPTIONS[selectedSDK]?.frameworks || [] as framework}
+{#each SDK_OPTIONS[selectedSDK]?.frameworks || [] as framework (framework)}
 	<option value={framework}>{framework.charAt(0).toUpperCase() + framework.slice(1)}</option>
 {/each}
-{#each features as feature}
+{#each features as feature (feature.id)}
 	<label class="checkbox">
 		<input
 			type="checkbox"
 			checked={selectedFeatures.includes(feature.id)}
 			on:change={() => toggleFeature(feature.id)}
 		/>
 		<span>{feature.label}</span>
 	</label>
 {/each}

Also applies to: 95-97, 104-113

src/lib/rules-generator.js (1)

201-201: Consider prefixing unused parameters with underscore

Several section generator functions have sdk and framework parameters that aren't currently used. If these are reserved for future framework-specific customization, prefix them with underscores to indicate intentional non-use and silence linter warnings.

Example:

-async function generateAuthSection(sdk, framework) {
+async function generateAuthSection(_sdk, _framework) {

Note: generateFunctionsSection does use the sdk parameter (line 719), so it should not be changed.

Also applies to: 234-234, 622-622, 648-648, 755-755, 776-776, 796-796

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50a1829 and 0d05102.

⛔ Files ignored due to path filters (1)
  • src/lib/assets/favicon.svg is excluded by !**/*.svg
📒 Files selected for processing (7)
  • package.json (1 hunks)
  • scripts/generate-nextjs-rules.js (1 hunks)
  • scripts/lib-loader.js (1 hunks)
  • src/lib/languages/common/mcp.js (1 hunks)
  • src/lib/languages/common/products.js (1 hunks)
  • src/lib/rules-generator.js (1 hunks)
  • src/routes/+page.svelte (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🧰 Additional context used
🧬 Code graph analysis (2)
scripts/lib-loader.js (1)
scripts/generate-nextjs-rules.js (1)
  • __dirname (7-7)
scripts/generate-nextjs-rules.js (2)
scripts/lib-loader.js (1)
  • __dirname (6-6)
src/lib/rules-generator.js (2)
  • rules (133-142)
  • generateRules (112-145)
🪛 ESLint
src/lib/rules-generator.js

[error] 201-201: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 201-201: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 234-234: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 234-234: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 622-622: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 622-622: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 648-648: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 648-648: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 717-717: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 755-755: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 755-755: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 776-776: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 776-776: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 796-796: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 796-796: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)

src/routes/+page.svelte

[error] 86-88: Each block should have a key

(svelte/require-each-key)


[error] 95-97: Each block should have a key

(svelte/require-each-key)


[error] 104-113: Each block should have a key

(svelte/require-each-key)

🔇 Additional comments (12)
scripts/lib-loader.js (2)

1-7: LGTM! Clean ESM-compatible path setup.

The imports and path resolution are appropriate for a custom ESM loader. The use of import.meta.url to derive __dirname is the correct approach for ES modules.


9-21: I'll help you verify the review comment about $lib imports and file extensions in the loader. Let me search the codebase for actual usage patterns.
<function_calls>


#!/bin/bash

Find all files that import from $lib/

rg -n "$lib/" --type=js --type=ts --type=mjs --type=cjs -A 2 -B 2 | head -100


</function_calls>

Let me also check the repository structure to better understand the project:
<function_calls>


#!/bin/bash

Get overview of repository structure

git ls-files | head -30


</function_calls>

Let me search more specifically for imports with the $lib alias:
<function_calls>


#!/bin/bash

Search for any import or require statements using $lib

echo "=== Looking for $lib imports in various file types ==="
rg "from ['"]?\$lib|require(['\"]\$lib" --type=js --type=ts --type=mjs -n | head -50

echo ""
echo "=== Checking if lib-loader is being used ==="
rg "lib-loader|--experimental-loader" . --type=js --type=json --type=mjs -n | head -20


</function_calls>

Let me check the loader file itself and its context:
<function_calls>


#!/bin/bash

Read the lib-loader.js file to understand its purpose

echo "=== Contents of scripts/lib-loader.js ==="
cat -n scripts/lib-loader.js

echo ""
echo "=== Check for package.json or similar configuration ==="
cat -n package.json 2>/dev/null | grep -A 5 -B 5 "loader|exports" || echo "No relevant package.json config found"

echo ""
echo "=== Look for any test or example files using the loader ==="
find . -type f ( -name ".md" -o -name ".mjs" -o -name "*.json" ) | xargs grep -l "$lib|lib-loader" 2>/dev/null | head -10


</function_calls>

Let me take a more targeted approach:
<function_calls>


#!/bin/bash

First, verify the file exists and show its content

ls -lah scripts/lib-loader.js 2>/dev/null && echo "File found" || echo "File not found"

echo ""

Show the file

head -30 scripts/lib-loader.js

echo ""

Search for any reference to lib-loader or $lib in the entire repo

echo "=== References to lib-loader ==="
rg "lib-loader" . -n 2>/dev/null || echo "No references to lib-loader found"

echo ""
echo "=== Any Node.js loader configuration ==="
rg "node.--loader|node.--experimental-loader" . -n -t js -t json 2>/dev/null || echo "No loader configuration found"


</function_calls>

scripts/generate-nextjs-rules.js (1)

1-32: LGTM!

The script is well-structured with proper error handling, clear console output, and comprehensive feature generation. The output path to the parent directory appears intentional for a generator script that produces distribution files.

src/lib/languages/common/mcp.js (1)

10-54: LGTM!

The MCP recommendation content is comprehensive and well-structured. The installation steps are clear, and the benefits section provides good examples of use cases.

src/routes/+page.svelte (2)

50-64: LGTM!

Good error handling for clipboard operations with clear user feedback via the button text state.


151-452: LGTM!

Comprehensive responsive design with good mobile and touch device support. The styles are well-organized with appropriate breakpoints.

src/lib/rules-generator.js (6)

153-194: LGTM!

The SDK initialization logic has proper fallbacks (framework-specific → vanilla → generic) and correctly handles both synchronous and asynchronous templates.


201-227: LGTM!

The authentication section provides comprehensive best practices with strong emphasis on team-based architecture and multi-tenancy, addressing the need for robust member management patterns.


234-615: Excellent multi-tenancy guidance!

This section provides exceptional depth on multi-tenancy patterns, team-based permissions, and member management. The step-by-step implementation patterns and code examples will be highly valuable for developers building secure, scalable applications.


672-710: LGTM!

The function template helpers provide direct links to official starter templates, which addresses the need for developers to have access to properly configured function scaffolds.


717-748: LGTM!

The functions section appropriately emphasizes when to use starter templates, particularly for scheduled tasks and event-driven functions, which ensures developers get the correct project structure and configuration.


796-814: LGTM!

The realtime section provides comprehensive best practices for subscription management, including proper cleanup patterns and connection handling.

Comment on lines +29 to +36
async function generate() {
generatedRules = await generateRules({
sdk: selectedSDK,
framework: selectedFramework,
features: selectedFeatures
});
previewVisible = true;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

MCP feature selection not working

The generate() function doesn't pass the includeMCP parameter to generateRules(). When users check the MCP checkbox, it adds 'mcp' to selectedFeatures, but this isn't converted to the includeMCP boolean that generateRules() expects.

Apply this diff to fix the issue:

 async function generate() {
+	const includeMCP = selectedFeatures.includes('mcp');
+	const productFeatures = selectedFeatures.filter(f => f !== 'mcp');
+
 	generatedRules = await generateRules({
 		sdk: selectedSDK,
 		framework: selectedFramework,
-		features: selectedFeatures
+		features: productFeatures,
+		includeMCP
 	});
 	previewVisible = true;
 }
🤖 Prompt for AI Agents
In src/routes/+page.svelte around lines 29 to 36, the generate() call fails to
provide the includeMCP boolean to generateRules; compute includeMCP as
selectedFeatures.includes('mcp') and call generateRules with includeMCP set to
that value, and pass features as selectedFeatures without the 'mcp' token (e.g.,
features: selectedFeatures.filter(f => f !== 'mcp')) so the MCP flag is conveyed
correctly and the features list remains valid.

…rite Cursor Rules Generator; add .mdc file extension to .gitignore
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d05102 and d2ef717.

📒 Files selected for processing (2)
  • .gitignore (1 hunks)
  • README.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .gitignore
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
README.md

89-89: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (3)
README.md (3)

1-36: Documentation is comprehensive and well-structured.

The README clearly describes the Cursor Rules Generator's features, supported SDKs/frameworks, and provides a well-organized table summarizing SDK-to-framework mappings. The introductory section accurately reflects the PR objectives.


38-86: Getting Started and Development sections are clear and actionable.

Installation steps, development scripts, and usage flow are well-documented and include appropriate prerequisites. The available scripts and their purposes are clearly listed for developer reference.


109-130: Extension guidelines are helpful for contributors.

The instructions for adding new SDKs, frameworks, and features provide clear steps and reference the relevant files, making it easy for future contributors to extend the tool.

Comment on lines 89 to 107
```
appwrite-cursor-rules/
├── src/
│ ├── lib/
│ │ ├── languages/ # SDK and framework-specific code examples
│ │ │ ├── js/ # JavaScript/TypeScript frameworks
│ │ │ ├── python/ # Python frameworks
│ │ │ ├── common/ # Shared rules (products, MCP, etc.)
│ │ │ └── ... # Other SDKs
│ │ ├── rules-generator.js # Main rules generation logic
│ │ └── utils/ # Utility functions
│ └── routes/
│ ├── +page.svelte # Main application page
│ └── +layout.svelte # Layout component
├── scripts/
│ ├── generate-nextjs-rules.js # Example script for generating rules
│ └── lib-loader.js # Module loader for scripts
└── static/ # Static assets
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Specify a language for the fenced code block.

The project structure code block at line 89 should include a language identifier for proper markdown linting compliance.

Apply this diff to add a language specifier:

-```
+```
 appwrite-cursor-rules/
 ├── src/
 │   ├── lib/
 │   │   ├── languages/          # SDK and framework-specific code examples
 │   │   │   ├── js/             # JavaScript/TypeScript frameworks
 │   │   │   ├── python/         # Python frameworks
 │   │   │   ├── common/         # Shared rules (products, MCP, etc.)
 │   │   │   └── ...             # Other SDKs
 │   │   ├── rules-generator.js  # Main rules generation logic
 │   │   └── utils/              # Utility functions
 │   └── routes/
 │       ├── +page.svelte        # Main application page
 │       └── +layout.svelte      # Layout component
 ├── scripts/
 │   ├── generate-nextjs-rules.js  # Example script for generating rules
 │   └── lib-loader.js             # Module loader for scripts
 └── static/                        # Static assets

Since the content is a directory tree rather than executable code, you may alternatively use a backtick fence without a language identifier if your markdown configuration permits it, or use txt as the language.

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

89-89: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
README.md around lines 89 to 107: the fenced code block containing the project
directory tree lacks a language identifier which fails markdown linting; update
the opening fence from ``` to ```txt (or another appropriate identifier such as
text) so the block is explicitly marked as plain text, leaving the content
unchanged and keeping the closing ``` intact.

…ance code snippets for multi-tenancy best practices and member management flows.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/lib/rules-generator.js (1)

108-145: Harden features handling to prevent runtime errors.

The past review comment correctly identified that features.includes(...) on lines 121-128 will throw if config.features is undefined or not an array. This issue remains unaddressed.

As suggested in the previous review, normalize features at the beginning of the function:

 export async function generateRules(config) {
-	const { sdk, framework, features, includeMCP = false } = config;
+	const { sdk, framework, includeMCP = false } = config;
+	const features = Array.isArray(config.features) ? config.features : [];
 	const sdkInfo = SDK_OPTIONS[sdk];

This defensive approach keeps the API forgiving and prevents crashes if callers omit or mistype features.

🧹 Nitpick comments (1)
src/lib/rules-generator.js (1)

196-227: Consider prefixing unused parameters with underscores.

ESLint is flagging unused parameters in several section generator functions. While the consistent (sdk, framework) signature across all generators is intentional for the Promise.all call on line 120, you can satisfy the linter by prefixing unused parameters with underscores:

Functions with unused parameters:

  • generateAuthSection (line 201): both sdk and framework unused
  • generatePermissionsSection (line 234): framework unused
  • generateDatabaseSection (line 500): both unused
  • generateStorageSection (line 526): both unused
  • generateFunctionsSection (line 595): framework unused
  • generateMessagingSection (line 633): both unused
  • generateSitesSection (line 654): both unused
  • generateRealtimeSection (line 674): both unused

Example refactor for generateAuthSection:

-async function generateAuthSection(sdk, framework) {
+async function generateAuthSection(_sdk, _framework) {
 	const { authProductLinks } = await import('./languages/common/products.js');

Apply the same pattern to other functions, prefixing only the parameters that remain unused.

Also applies to: 229-469, 495-519, 521-543, 590-626, 628-647, 649-667, 669-692

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d2ef717 and db0f222.

📒 Files selected for processing (1)
  • src/lib/rules-generator.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/lib/rules-generator.js (2)
src/lib/languages/common/mcp.js (1)
  • generateMCPRecommendation (10-54)
src/lib/languages/common/products.js (14)
  • authProductLinks (16-28)
  • authProductLinks (16-28)
  • databaseProductLinks (33-41)
  • databaseProductLinks (33-41)
  • storageProductLinks (46-50)
  • storageProductLinks (46-50)
  • functionsProductLinks (55-61)
  • functionsProductLinks (55-61)
  • messagingProductLinks (66-74)
  • messagingProductLinks (66-74)
  • sitesProductLinks (79-103)
  • sitesProductLinks (79-103)
  • realtimeProductLinks (108-118)
  • realtimeProductLinks (108-118)
🪛 ESLint
src/lib/rules-generator.js

[error] 201-201: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 201-201: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 234-234: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 500-500: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 500-500: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 526-526: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 526-526: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 595-595: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 633-633: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 633-633: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 654-654: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 654-654: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 674-674: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 674-674: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)

@eldadfux
Copy link
Member

@adityaoberai another cool idea would be to make this generator accessible via an API that returns the relevant markdown version

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
README.md (1)

177-200: Add a language identifier to the project-structure code fence.

markdownlint (MD040) flags this block because the fenced code block has no language. Since this is a directory tree, using txt (or similar) satisfies the rule without affecting rendering.

-```
+```txt
 appwrite-cursor-rules/
 ├── src/
 │   ├── lib/
 │   │   ├── languages/          # SDK and framework-specific code examples
 │   │   │   ├── js/             # JavaScript/TypeScript frameworks
 │   │   │   ├── python/         # Python frameworks
 │   │   │   ├── common/         # Shared rules (products, MCP, etc.)
 │   │   │   └── ...             # Other SDKs
 │   │   ├── rules-generator.js  # Main rules generation logic
 │   │   └── utils/              # Utility functions
 │   └── routes/
 │       ├── api/
 │       │   ├── rules/
 │       │   │   └── +server.js   # API endpoint for generating rules
 │       │   └── sdks/
 │       │       └── +server.js   # API endpoint for listing SDKs
 │       ├── +page.svelte        # Main application page
 │       └── +layout.svelte      # Layout component
 ├── scripts/
 │   ├── generate-nextjs-rules.js  # Example script for generating rules
 │   └── lib-loader.js             # Module loader for scripts
 └── static/                        # Static assets
🧹 Nitpick comments (3)
README.md (1)

130-133: Capitalize “Markdown” in prose for consistency with tooling.

LanguageTool flags “markdown text” as a common noun; using “Markdown text” reads better and keeps terminology consistent.

-- Returns the generated rules as markdown text
+- Returns the generated rules as Markdown text
src/routes/api/sdks/+server.js (1)

4-7: Remove or fix the stale JSDoc @param for GET.

The JSDoc documents a Request parameter, but GET currently takes no arguments, which can mislead readers and tooling.

If you don’t need the event/request object, you can drop the JSDoc block:

-/**
- * @param {Request} request
- */
-export async function GET() {
+export async function GET() {
src/routes/api/rules/+server.js (1)

7-17: Harden normalizeFeatures to trim and ignore unknown feature names.

Right now, any unknown features values (e.g. features=foo,bar) pass through and result in no feature sections being generated, without signaling an issue. You can make this more robust by trimming inputs and discarding unsupported names while still honoring the special all alias.

For example:

-/**
- * Normalize features array - replace 'all' with all available features
- * @param {string[]} features
- * @returns {string[]}
- */
-function normalizeFeatures(features) {
-	if (features.includes('all')) {
-		return ALL_FEATURES;
-	}
-	return features;
-}
+/**
+ * Normalize features:
+ * - trims values
+ * - discards unknown feature names
+ * - replaces 'all' with ALL_FEATURES
+ * @param {string[]} features
+ * @returns {string[]}
+ */
+function normalizeFeatures(features) {
+	const cleaned = features
+		.map((feature) => feature.trim())
+		.filter((feature) => ALL_FEATURES.includes(feature) || feature === 'all');
+
+	if (cleaned.includes('all')) {
+		return ALL_FEATURES;
+	}
+
+	return cleaned;
+}

This keeps the API forgiving while avoiding silently ignored typos.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db0f222 and 5d7e367.

📒 Files selected for processing (3)
  • README.md (1 hunks)
  • src/routes/api/rules/+server.js (1 hunks)
  • src/routes/api/sdks/+server.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/routes/api/sdks/+server.js (1)
src/routes/api/rules/+server.js (1)
  • GET (22-84)
src/routes/api/rules/+server.js (2)
src/routes/api/sdks/+server.js (1)
  • GET (7-35)
src/lib/rules-generator.js (1)
  • generateRules (112-145)
🪛 LanguageTool
README.md

[uncategorized] ~132-~132: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...utf-8- Returns the generated rules as markdown text - IncludesContent-Disposition` h...

(MARKDOWN_NNP)

🪛 markdownlint-cli2 (0.18.1)
README.md

177-177: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (2)
src/routes/api/sdks/+server.js (1)

9-30: SDK listing and feature metadata JSON shape looks good.

The transformation of SDK_OPTIONS into { id, name, frameworks, importSyntax, exportSyntax, asyncSyntax } plus the availableFeatures array is straightforward and matches how the README describes this endpoint.

src/routes/api/rules/+server.js (1)

22-83: Query parsing, validation, and response formats are coherent and match the documented API.

The GET handler’s flow—defaulting sdk/framework, validating against SDK_OPTIONS, normalizing features, delegating to generateRules, and switching between JSON vs Markdown attachment based on format—is clear and lines up with the README examples and error codes.

Comment on lines +85 to +101
**Response:**
```json
{
"sdks": [
{
"id": "javascript",
"name": "JavaScript/TypeScript",
"frameworks": ["nextjs", "react", "vue", ...],
"importSyntax": "import",
"exportSyntax": "export",
"asyncSyntax": "async/await"
},
...
],
"availableFeatures": ["auth", "database", "storage", "functions", "messaging", "sites", "realtime"]
}
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Align /api/sdks response example with actual API (availableFeatures includes "all").

src/routes/api/sdks/+server.js returns availableFeatures including the special "all" value, but the README example omits it. This can confuse API consumers about the supported features values.

Consider updating the example to include "all":

-  "availableFeatures": ["auth", "database", "storage", "functions", "messaging", "sites", "realtime"]
+  "availableFeatures": ["auth", "database", "storage", "functions", "messaging", "sites", "realtime", "all"]
🤖 Prompt for AI Agents
In README.md around lines 85 to 101, the example JSON for the /api/sdks response
omits the special "all" value returned by the real API; update the example
response to include "all" in the availableFeatures array (e.g.,
["auth","database","storage","functions","messaging","sites","realtime","all"])
so the docs match src/routes/api/sdks/+server.js.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/lib/rules-generator.js (1)

112-129: Normalize features before calling .includes and consider simplifying section assembly

generateRules assumes config.features is a defined array; if it’s ever undefined or non‑array, every features.includes(...) call will throw at runtime. To make the API more forgiving, normalize features up front and use that for checks. You can also drop the explicit Promise.resolve('') placeholders by driving sections from a small descriptor list.

Example refactor:

-export async function generateRules(config) {
-	const { sdk, framework, features, includeMCP = false } = config;
+export async function generateRules(config) {
+	const { sdk, framework, includeMCP = false } = config;
+	const features =
+		Array.isArray(config.features) ? config.features : [];
@@
-	// Generate all sections in parallel
-	// Permissions section is mandatory for all products
-	const sections = await Promise.all([
-		features.includes('auth') ? generateAuthSection(sdk, framework) : Promise.resolve(''),
-		generatePermissionsSection(sdk, framework),
-		features.includes('database') ? generateDatabaseSection(sdk, framework) : Promise.resolve(''),
-		features.includes('storage') ? generateStorageSection(sdk, framework) : Promise.resolve(''),
-		features.includes('functions') ? generateFunctionsSection(sdk, framework) : Promise.resolve(''),
-		features.includes('messaging') ? generateMessagingSection(sdk, framework) : Promise.resolve(''),
-		features.includes('sites') ? generateSitesSection(sdk, framework) : Promise.resolve(''),
-		features.includes('realtime') ? generateRealtimeSection(sdk, framework) : Promise.resolve('')
-	]);
+	// Generate all sections in parallel
+	const sectionSpecs = [
+		{ key: 'auth', fn: generateAuthSection },
+		{ key: 'permissions', fn: generatePermissionsSection, always: true },
+		{ key: 'database', fn: generateDatabaseSection },
+		{ key: 'storage', fn: generateStorageSection },
+		{ key: 'functions', fn: generateFunctionsSection },
+		{ key: 'messaging', fn: generateMessagingSection },
+		{ key: 'sites', fn: generateSitesSection },
+		{ key: 'realtime', fn: generateRealtimeSection }
+	];
+
+	const sections = await Promise.all(
+		sectionSpecs
+			.filter(({ key, always }) => always || features.includes(key))
+			.map(({ fn }) => fn(sdk, framework))
+	);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5d7e367 and 9c347b5.

📒 Files selected for processing (1)
  • src/lib/rules-generator.js (1 hunks)
🧰 Additional context used
🪛 ESLint
src/lib/rules-generator.js

[error] 201-201: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 201-201: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 234-234: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 500-500: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 500-500: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 526-526: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 526-526: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 595-595: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 633-633: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 633-633: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 654-654: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 654-654: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 674-674: 'sdk' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 674-674: 'framework' is defined but never used.

(@typescript-eslint/no-unused-vars)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants