diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 00000000..6b7eec23
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,3 @@
+# Repository instructions
+
+When adding or updating template dependencies, use constraints that allow compatible patch and minor updates while excluding the next breaking version. Prefer caret ranges where the package manager supports them, avoid unbounded or wildcard constraints, and keep committed lockfiles in sync with their manifests.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index cf866f2a..f31735ed 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -86,7 +86,7 @@ Security and privacy are extremely important to Appwrite, developers, and users
## Dependencies
-Usage of dependencies is welcomed for purpose of simplifying template code. Please only use libraries that are well-known, and popular.
+Usage of dependencies is welcomed for purpose of simplifying template code. Please only use libraries that are well-known and popular. Dependency constraints must allow compatible patch and minor updates while excluding the next breaking version (for example, use caret ranges where the package manager supports them). Keep any committed lockfile in sync with its manifest.
## Introducing New Templates
diff --git a/dart/starter/pubspec.yaml b/dart/starter/pubspec.yaml
index a8d9a1b0..1d83d7e9 100644
--- a/dart/starter/pubspec.yaml
+++ b/dart/starter/pubspec.yaml
@@ -5,7 +5,7 @@ environment:
sdk: ^2.17.0
dependencies:
- dart_appwrite: 19.2.1
+ dart_appwrite: ^19.2.1
dev_dependencies:
lints: ^2.0.0
diff --git a/deno/starter/src/main.ts b/deno/starter/src/main.ts
index 420d8b32..14917011 100644
--- a/deno/starter/src/main.ts
+++ b/deno/starter/src/main.ts
@@ -15,8 +15,8 @@ export default async ({ req, res, log, error }: any) => {
// Log messages and errors to the Appwrite Console
// These logs won't be seen by your end users
log(`Total users: ${response.total}`);
- } catch(err) {
- error("Could not list users: " + err.message);
+ } catch (err) {
+ error("Could not list users: " + String(err));
}
// The req object contains the request data
diff --git a/deno/whatsapp-with-vonage/src/main.ts b/deno/whatsapp-with-vonage/src/main.ts
index 0302884a..f4f077d2 100644
--- a/deno/whatsapp-with-vonage/src/main.ts
+++ b/deno/whatsapp-with-vonage/src/main.ts
@@ -35,7 +35,7 @@ export default async ({ req, res, log, error }: Context) => {
try {
throwIfMissing(payload, ["payload_hash"]);
} catch (err) {
- return res.json({ ok: false, error: err.message }, 400);
+ return res.json({ ok: false, error: String(err) }, 400);
}
const hash = crypto.subtle.digestSync(
@@ -50,7 +50,7 @@ export default async ({ req, res, log, error }: Context) => {
try {
throwIfMissing(req.bodyJson, ["from", "text"]);
} catch (err) {
- return res.json({ ok: false, error: err.message }, 400);
+ return res.json({ ok: false, error: String(err) }, 400);
}
const basicAuthToken: string = btoa(
diff --git a/dotnet/starter/StarterTemplate.csproj b/dotnet/starter/StarterTemplate.csproj
index 7137895f..dc0a8e7e 100644
--- a/dotnet/starter/StarterTemplate.csproj
+++ b/dotnet/starter/StarterTemplate.csproj
@@ -6,6 +6,6 @@
enable
-
+
-
\ No newline at end of file
+
diff --git a/kotlin/sync-with-meilisearch/src/Main.kt b/kotlin/sync-with-meilisearch/src/Main.kt
index 486656aa..b6521b76 100644
--- a/kotlin/sync-with-meilisearch/src/Main.kt
+++ b/kotlin/sync-with-meilisearch/src/Main.kt
@@ -36,7 +36,7 @@ class Main {
val client = AppwriteClient().apply {
setEndpoint(System.getenv("APPWRITE_FUNCTION_API_ENDPOINT"))
setProject(System.getenv("APPWRITE_FUNCTION_PROJECT_ID"))
- setKey(context.res.headers["x-appwrite-key"])
+ setKey(context.req.headers["x-appwrite-key"] ?: "")
}
val databases = Databases(client)
diff --git a/node-typescript/discord-command-bot/src/commands/hello.ts b/node-typescript/discord-command-bot/src/commands/hello.ts
index 4c852415..d8a21441 100644
--- a/node-typescript/discord-command-bot/src/commands/hello.ts
+++ b/node-typescript/discord-command-bot/src/commands/hello.ts
@@ -1,6 +1,6 @@
import { InteractionResponseType } from 'discord-interactions';
-export default function HelloCommand(res) {
+export default function HelloCommand(res: any) {
return res.json(
{
type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
diff --git a/node-typescript/discord-command-bot/src/main.ts b/node-typescript/discord-command-bot/src/main.ts
index 1cced355..e9082445 100644
--- a/node-typescript/discord-command-bot/src/main.ts
+++ b/node-typescript/discord-command-bot/src/main.ts
@@ -7,7 +7,14 @@ import {
import { throwIfMissing } from './utils.js';
import commands from './commands/index.js';
-export default async ({ req, res, error, log }) => {
+type Context = {
+ req: any;
+ res: any;
+ log: (message: string) => void;
+ error: (message: string) => void;
+};
+
+export default async ({ req, res, error, log }: Context) => {
throwIfMissing(process.env, [
'DISCORD_PUBLIC_KEY',
'DISCORD_APPLICATION_ID',
diff --git a/node-typescript/discord-command-bot/tsconfig.json b/node-typescript/discord-command-bot/tsconfig.json
new file mode 100644
index 00000000..c4f98f32
--- /dev/null
+++ b/node-typescript/discord-command-bot/tsconfig.json
@@ -0,0 +1,14 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "NodeNext",
+ "rootDir": "src",
+ "resolveJsonModule": true,
+ "outDir": "dist",
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitAny": true,
+ "skipLibCheck": true
+ }
+}
diff --git a/node-typescript/sync-with-meilisearch/package-lock.json b/node-typescript/sync-with-meilisearch/package-lock.json
index 68a1742e..00f64b8e 100644
--- a/node-typescript/sync-with-meilisearch/package-lock.json
+++ b/node-typescript/sync-with-meilisearch/package-lock.json
@@ -10,7 +10,7 @@
"dependencies": {
"meilisearch": "^0.40.0",
"node-appwrite": "^14.1.0",
- "typescript": "5.4.5"
+ "typescript": "^5.4.5"
},
"devDependencies": {
"@types/node": "^20.12.12",
diff --git a/node-typescript/sync-with-meilisearch/package.json b/node-typescript/sync-with-meilisearch/package.json
index 9e6f3d05..15d9e4fd 100644
--- a/node-typescript/sync-with-meilisearch/package.json
+++ b/node-typescript/sync-with-meilisearch/package.json
@@ -12,7 +12,7 @@
"dependencies": {
"meilisearch": "^0.40.0",
"node-appwrite": "^14.1.0",
- "typescript": "5.4.5"
+ "typescript": "^5.4.5"
},
"devDependencies": {
"prettier": "^3.2.5",
diff --git a/node-typescript/sync-with-qdrant/package-lock.json b/node-typescript/sync-with-qdrant/package-lock.json
index 4deccf7c..b6fadf17 100644
--- a/node-typescript/sync-with-qdrant/package-lock.json
+++ b/node-typescript/sync-with-qdrant/package-lock.json
@@ -11,7 +11,7 @@
"@qdrant/js-client-rest": "^1.9.0",
"node-appwrite": "^14.1.0",
"openai": "^4.47.1",
- "typescript": "5.4.5"
+ "typescript": "^5.4.5"
},
"devDependencies": {
"@types/node": "^20.12.10",
diff --git a/node-typescript/sync-with-qdrant/package.json b/node-typescript/sync-with-qdrant/package.json
index 018b94e0..ed4c9bf2 100644
--- a/node-typescript/sync-with-qdrant/package.json
+++ b/node-typescript/sync-with-qdrant/package.json
@@ -13,7 +13,7 @@
"@qdrant/js-client-rest": "^1.9.0",
"node-appwrite": "^14.1.0",
"openai": "^4.47.1",
- "typescript": "5.4.5"
+ "typescript": "^5.4.5"
},
"devDependencies": {
"@types/node": "^20.12.10",
diff --git a/node-typescript/sync-with-qdrant/src/appwrite.ts b/node-typescript/sync-with-qdrant/src/appwrite.ts
index d113caf2..0a1e0557 100644
--- a/node-typescript/sync-with-qdrant/src/appwrite.ts
+++ b/node-typescript/sync-with-qdrant/src/appwrite.ts
@@ -3,7 +3,7 @@ import { Client, Databases, Query } from 'node-appwrite';
class AppwriteService {
databases: Databases;
- constructor(apiKey) {
+ constructor(apiKey: string) {
const client = new Client();
client
.setEndpoint(process.env.APPWRITE_FUNCTION_API_ENDPOINT)
diff --git a/python-ml/generate_with_tensorflow/requirements.txt b/python-ml/generate_with_tensorflow/requirements.txt
index 95d00589..e5ca81ef 100644
--- a/python-ml/generate_with_tensorflow/requirements.txt
+++ b/python-ml/generate_with_tensorflow/requirements.txt
@@ -1,2 +1,2 @@
-tensorflow
-numpy
\ No newline at end of file
+tensorflow>=2.15.0,<3.0.0
+numpy>=2.0.0,<3.0.0
diff --git a/python-ml/starter/requirements.txt b/python-ml/starter/requirements.txt
index 37e088f6..3cc006dc 100644
--- a/python-ml/starter/requirements.txt
+++ b/python-ml/starter/requirements.txt
@@ -1,2 +1,2 @@
-appwrite==23.0.0
-numpy
\ No newline at end of file
+appwrite>=23.0.0,<24.0.0
+numpy>=2.0.0,<3.0.0
diff --git a/python/censor_with_redact/requirements.txt b/python/censor_with_redact/requirements.txt
index 663bd1f6..d51edac5 100644
--- a/python/censor_with_redact/requirements.txt
+++ b/python/censor_with_redact/requirements.txt
@@ -1 +1 @@
-requests
\ No newline at end of file
+requests>=2.31.0,<3.0.0
diff --git a/python/discord_command_bot/requirements.txt b/python/discord_command_bot/requirements.txt
index 319860cf..4000c0c0 100644
--- a/python/discord_command_bot/requirements.txt
+++ b/python/discord_command_bot/requirements.txt
@@ -1,2 +1,2 @@
-requests
-discord-interactions
\ No newline at end of file
+requests>=2.31.0,<3.0.0
+discord-interactions>=0.4.0,<0.5.0
diff --git a/python/email_contact_form/requirements.txt b/python/email_contact_form/requirements.txt
new file mode 100644
index 00000000..3e1593f0
--- /dev/null
+++ b/python/email_contact_form/requirements.txt
@@ -0,0 +1 @@
+# No third-party dependencies.
diff --git a/python/mcp-server/requirements.txt b/python/mcp-server/requirements.txt
index 321fd1e3..6e6ac958 100644
--- a/python/mcp-server/requirements.txt
+++ b/python/mcp-server/requirements.txt
@@ -1 +1 @@
-mcp==2.0.0
+mcp>=2.0.0,<3.0.0
diff --git a/python/prompt_chatgpt/requirements.txt b/python/prompt_chatgpt/requirements.txt
index f0dd0aec..b16349fc 100644
--- a/python/prompt_chatgpt/requirements.txt
+++ b/python/prompt_chatgpt/requirements.txt
@@ -1 +1 @@
-openai
\ No newline at end of file
+openai>=0.27.8,<0.28.0
diff --git a/python/starter/requirements.txt b/python/starter/requirements.txt
index 0d370b0b..e6a70027 100644
--- a/python/starter/requirements.txt
+++ b/python/starter/requirements.txt
@@ -1 +1 @@
-appwrite==23.0.0
+appwrite>=23.0.0,<24.0.0
diff --git a/python/storage-cleaner/requirements.txt b/python/storage-cleaner/requirements.txt
index b0d9f6db..e6a70027 100644
--- a/python/storage-cleaner/requirements.txt
+++ b/python/storage-cleaner/requirements.txt
@@ -1 +1 @@
-appwrite==23.0.0
\ No newline at end of file
+appwrite>=23.0.0,<24.0.0
diff --git a/python/sync_with_algolia/requirements.txt b/python/sync_with_algolia/requirements.txt
index ad66ca26..c48f316a 100644
--- a/python/sync_with_algolia/requirements.txt
+++ b/python/sync_with_algolia/requirements.txt
@@ -1,2 +1,2 @@
-appwrite==23.0.0
-algoliasearch
\ No newline at end of file
+appwrite>=23.0.0,<24.0.0
+algoliasearch>=3.0.0,<4.0.0
diff --git a/python/sync_with_meilisearch/requirements.txt b/python/sync_with_meilisearch/requirements.txt
index 2ba2bf3b..68c14de2 100644
--- a/python/sync_with_meilisearch/requirements.txt
+++ b/python/sync_with_meilisearch/requirements.txt
@@ -1,2 +1,2 @@
-appwrite==23.0.0
-meilisearch
\ No newline at end of file
+appwrite>=23.0.0,<24.0.0
+meilisearch>=0.30.0,<0.31.0
diff --git a/python/sync_with_qdrant/requirements.txt b/python/sync_with_qdrant/requirements.txt
index 3fb23c0b..39604c17 100644
--- a/python/sync_with_qdrant/requirements.txt
+++ b/python/sync_with_qdrant/requirements.txt
@@ -1,3 +1,3 @@
-appwrite==23.0.0
-qdrant-client
-openai
\ No newline at end of file
+appwrite>=23.0.0,<24.0.0
+qdrant-client>=1.9.0,<2.0.0
+openai>=1.30.0,<2.0.0
diff --git a/python/whatsapp_with_vonage/requirements.txt b/python/whatsapp_with_vonage/requirements.txt
index b126a469..0f287e0a 100644
--- a/python/whatsapp_with_vonage/requirements.txt
+++ b/python/whatsapp_with_vonage/requirements.txt
@@ -1,2 +1,2 @@
-requests
-pyjwt
+requests>=2.31.0,<3.0.0
+pyjwt>=2.8.0,<3.0.0
diff --git a/ruby/starter/Gemfile b/ruby/starter/Gemfile
index a25455c8..5b22aedf 100644
--- a/ruby/starter/Gemfile
+++ b/ruby/starter/Gemfile
@@ -1,3 +1,3 @@
source "https://rubygems.org"
-gem 'appwrite'
\ No newline at end of file
+gem 'appwrite', '>= 27.0.0', '< 28.0.0'
diff --git a/ruby/sync_with_meilisearch/Gemfile b/ruby/sync_with_meilisearch/Gemfile
index cb866cfd..4fd5641e 100644
--- a/ruby/sync_with_meilisearch/Gemfile
+++ b/ruby/sync_with_meilisearch/Gemfile
@@ -1,4 +1,4 @@
source "https://rubygems.org"
-gem 'appwrite'
-gem 'meilisearch'
+gem 'appwrite', '>= 27.0.0', '< 28.0.0'
+gem 'meilisearch', '>= 0.33.0', '< 0.34.0'
diff --git a/ruby/whatsapp-with-vonage/Gemfile b/ruby/whatsapp-with-vonage/Gemfile
index 233ba77a..6e87d751 100644
--- a/ruby/whatsapp-with-vonage/Gemfile
+++ b/ruby/whatsapp-with-vonage/Gemfile
@@ -1,7 +1,7 @@
source "https://rubygems.org"
-gem 'json'
-gem 'dotenv'
-gem 'digest'
-gem 'jwt'
-gem 'httparty'
\ No newline at end of file
+gem 'json', '>= 2.7.6', '< 3.0.0'
+gem 'dotenv', '>= 2.8.1', '< 3.0.0'
+gem 'digest', '>= 3.2.1', '< 4.0.0'
+gem 'jwt', '>= 3.2.0', '< 4.0.0'
+gem 'httparty', '>= 0.24.0', '< 0.25.0'
diff --git a/swift/starter/Package.swift b/swift/starter/Package.swift
index 21826853..5de357c9 100644
--- a/swift/starter/Package.swift
+++ b/swift/starter/Package.swift
@@ -1,4 +1,4 @@
-// swift-tools-version:5.5
+// swift-tools-version:6.2
import PackageDescription
let package = Package(
diff --git a/swift/starter/README.md b/swift/starter/README.md
index b682efba..5991eb04 100644
--- a/swift/starter/README.md
+++ b/swift/starter/README.md
@@ -37,7 +37,7 @@ Sample `200` Response:
| Setting | Value |
| ----------------- | --------------------- |
-| Runtime | Swift (5.5) |
+| Runtime | Swift (6.2) |
| Entrypoint | `Sources/index.swift` |
| Permissions | `any` |
| Timeout (Seconds) | 15 |