diff --git a/README.md b/README.md index 1422c385..55b0a787 100644 --- a/README.md +++ b/README.md @@ -10,23 +10,23 @@ Templates for [Appwrite](https://appwrite.io/) Functions. These templates can be # List of Templates -| Template | Node.js | Python | PHP | Dart | Bun | C++ | Deno | .NET | Java | Kotlin | Node.js (TypeScript) | Ruby | Swift | -| --------------------------- | ------------------------------------- | ------------------------------- | --------------------------- | ---------------------------- | ---------------- | ---------------- | ----------------- | ------------------- | ----------------- | ------------------- | ---------------------------- | ----------------- | ------------------ | -| Starter | [✅](node/starter) | [✅](python/starter) | [✅](php/starter) | [✅](dart/starter) | [✅](bun/starter) | [✅](cpp/starter) | [✅](deno/starter) | [✅](dotnet/starter) | [✅](java/starter) | [✅](kotlin/starter) | [✅](node-typescript/starter) | [✅](ruby/starter) | [✅](swift/starter) | -| Prompt ChatGPT | [✅](node/prompt-chatgpt) | [✅](python/prompt_chatgpt) | [✅](php/prompt-chatgpt) | [✅](dart/prompt_chatgpt) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | -| Censor with Redact | [✅](node/censor-with-redact) | [✅](python/censor_with_redact) | 🏗️ | [✅](dart/censor_with_redact) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | -| Email Contact Form | [✅](node/email-contact-form) | [✅](python/email_contact_form) | [✅](php/email-contact-form) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | -| Sync with Algolia | [✅](node/sync-with-algolia) | [✅](python/sync_with_algolia) | [✅](php/sync-with-algolia) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | -| Discord Command Bot | [✅](node/discord-command-bot) | [✅](python/discord_command_bot) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | -| Analyze with PerspectiveAPI | [✅](node/analyze-with-perspectiveapi) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | -| Generate PDF | [✅](node/generate-pdf) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | -| Github Issue Bot | [✅](node/github-issue-bot) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | -| Payments with Stripe | [✅](node/payments-with-stripe) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | -| Push Notification with FCM | [✅](node/push-notification-with-fcm) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | -| Subscriptions with Stripe | [✅](node/subscriptions-with-stripe) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | -| Sync with Meilisearch | [✅](node/sync-with-meilisearch) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | -| URL Shortener | [✅](node/url-shortener) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | -| WhatsApp with Vonage | [✅](node/whatsapp-with-vonage) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | +| Template | Node.js | Python | PHP | Dart | Deno | Node.js (TypeScript) | Bun | C++ | .NET | Java | Kotlin | Ruby | Swift | +| --------------------------- | ------------------------------------- | -------------------------------- | --------------------------- | ---------------------------- | ------------------------------- | ------------------------------------------ | ---------------- | ---------------- | ------------------- | ----------------- | ------------------- | ----------------- | ------------------ | +| Starter | [✅](node/starter) | [✅](python/starter) | [✅](php/starter) | [✅](dart/starter) | [✅](deno/starter) | [✅](node-typescript/starter) | [✅](bun/starter) | [✅](cpp/starter) | [✅](dotnet/starter) | [✅](java/starter) | [✅](kotlin/starter) | [✅](ruby/starter) | [✅](swift/starter) | +| Prompt ChatGPT | [✅](node/prompt-chatgpt) | [✅](python/prompt_chatgpt) | [✅](php/prompt-chatgpt) | [✅](dart/prompt_chatgpt) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | +| WhatsApp with Vonage | [✅](node/whatsapp-with-vonage) | [✅](python/whatsapp_with_vonage) | 🏗️ | 🏗️ | [✅](deno/whatsapp-with-vonage) | [✅](node-typescript/whatsapp-with-vonage) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | +| Censor with Redact | [✅](node/censor-with-redact) | [✅](python/censor_with_redact) | 🏗️ | [✅](dart/censor_with_redact) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | +| Sync with Meilisearch | [✅](node/sync-with-meilisearch) | 🏗️ | 🏗️ | 🏗️ | [✅](deno/sync-with-meilisearch) | [✅](node-typescript/sync-with-meilisearch) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | +| Email Contact Form | [✅](node/email-contact-form) | [✅](python/email_contact_form) | [✅](php/email-contact-form) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | +| Sync with Algolia | [✅](node/sync-with-algolia) | [✅](python/sync_with_algolia) | [✅](php/sync-with-algolia) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | +| Discord Command Bot | [✅](node/discord-command-bot) | [✅](python/discord_command_bot) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | +| Analyze with PerspectiveAPI | [✅](node/analyze-with-perspectiveapi) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | +| Generate PDF | [✅](node/generate-pdf) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | +| Github Issue Bot | [✅](node/github-issue-bot) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | +| Payments with Stripe | [✅](node/payments-with-stripe) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | +| Push Notification with FCM | [✅](node/push-notification-with-fcm) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | +| Subscriptions with Stripe | [✅](node/subscriptions-with-stripe) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | +| URL Shortener | [✅](node/url-shortener) | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | 🏗️ | ✅ = Done - Function is implemented in this runtime. diff --git a/appwrite.json b/appwrite.json deleted file mode 100644 index bd794ace..00000000 --- a/appwrite.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "projectId": "6524d42869dc1c9786e5", - "projectName": "Personal Project" -} \ No newline at end of file diff --git a/bun/starter/README.md b/bun/starter/README.md index 6d72f925..45f6266e 100644 --- a/bun/starter/README.md +++ b/bun/starter/README.md @@ -26,7 +26,7 @@ Sample `200` Response: ```json { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io" diff --git a/bun/starter/src/main.ts b/bun/starter/src/main.ts index 9f4bcfc0..e7d02daf 100644 --- a/bun/starter/src/main.ts +++ b/bun/starter/src/main.ts @@ -25,7 +25,7 @@ export default async ({ req, res, log, error }: any) => { // `res.json()` is a handy helper for sending JSON return res.json({ - motto: "Build Fast. Scale Big. All in One Place.", + motto: "Build like a team of hundreds_", learn: "https://appwrite.io/docs", connect: "https://appwrite.io/discord", getInspired: "https://builtwith.appwrite.io", diff --git a/cpp/starter/README.md b/cpp/starter/README.md index a74cd8ea..162f2115 100644 --- a/cpp/starter/README.md +++ b/cpp/starter/README.md @@ -26,7 +26,7 @@ Sample `200` Response: ```json { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io" diff --git a/cpp/starter/src/main.cc b/cpp/starter/src/main.cc index ae339489..b1375897 100644 --- a/cpp/starter/src/main.cc +++ b/cpp/starter/src/main.cc @@ -24,7 +24,7 @@ namespace runtime { // `context.res.json()` is a handy helper for sending JSON Json::Value response; - response["motto"] = "Build Fast. Scale Big. All in One Place."; + response["motto"] = "Build like a team of hundreds_"; response["learn"] = "https://appwrite.io/docs"; response["connect"] = "https://appwrite.io/discord"; response["getInspired"] = "https://builtwith.appwrite.io"; diff --git a/dart/starter/README.md b/dart/starter/README.md index f0797d56..f77a225e 100644 --- a/dart/starter/README.md +++ b/dart/starter/README.md @@ -26,7 +26,7 @@ Sample `200` Response: ```json { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io" diff --git a/dart/starter/lib/main.dart b/dart/starter/lib/main.dart index 0b2ff034..a09402e5 100644 --- a/dart/starter/lib/main.dart +++ b/dart/starter/lib/main.dart @@ -26,7 +26,7 @@ Future main(final context) async { // `res.json()` is a handy helper for sending JSON return context.res.json({ - 'motto': 'Build Fast. Scale Big. All in One Place.', + 'motto': 'Build like a team of hundreds_', 'learn': 'https://appwrite.io/docs', 'connect': 'https://appwrite.io/discord', 'getInspired': 'https://builtwith.appwrite.io', diff --git a/deno/starter/README.md b/deno/starter/README.md index 98416f65..dc47465b 100644 --- a/deno/starter/README.md +++ b/deno/starter/README.md @@ -26,7 +26,7 @@ Sample `200` Response: ```json { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io" diff --git a/deno/starter/src/main.ts b/deno/starter/src/main.ts index ca29214d..0b868af7 100644 --- a/deno/starter/src/main.ts +++ b/deno/starter/src/main.ts @@ -25,7 +25,7 @@ export default async ({ req, res, log, error }: any) => { // `res.json()` is a handy helper for sending JSON return res.json({ - motto: "Build Fast. Scale Big. All in One Place.", + motto: "Build like a team of hundreds_", learn: "https://appwrite.io/docs", connect: "https://appwrite.io/discord", getInspired: "https://builtwith.appwrite.io", diff --git a/dotnet/starter/README.md b/dotnet/starter/README.md index 735ca2b0..fdcb2d8b 100644 --- a/dotnet/starter/README.md +++ b/dotnet/starter/README.md @@ -26,7 +26,7 @@ Sample `200` Response: ```json { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io" diff --git a/dotnet/starter/src/Index.cs b/dotnet/starter/src/Index.cs index ab454c7c..1b931b15 100644 --- a/dotnet/starter/src/Index.cs +++ b/dotnet/starter/src/Index.cs @@ -33,7 +33,7 @@ public async Task Main(RuntimeContext Context) // `Context.Res.Json()` is a handy helper for sending JSON return Context.Res.Json(new Dictionary() { - { "motto", "Build Fast. Scale Big. All in One Place." }, + { "motto", "Build like a team of hundreds_" }, { "learn", "https://appwrite.io/docs" }, { "connect", "https://appwrite.io/discord" }, { "getInspired", "https://builtwith.appwrite.io" }, diff --git a/java/starter/README.md b/java/starter/README.md index eb51e0b2..528cbd3c 100644 --- a/java/starter/README.md +++ b/java/starter/README.md @@ -26,7 +26,7 @@ Sample `200` Response: ```json { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io" diff --git a/java/starter/src/Main.java b/java/starter/src/Main.java index e39a23ac..80babe21 100644 --- a/java/starter/src/Main.java +++ b/java/starter/src/Main.java @@ -32,7 +32,7 @@ public RuntimeOutput main(RuntimeContext context) throws Exception { } Map json = new HashMap<>(); - json.put("motto", "Build Fast. Scale Big. All in One Place."); + json.put("motto", "Build like a team of hundreds_"); json.put("learn", "https://appwrite.io/docs"); json.put("connect", "https://appwrite.io/discord"); json.put("getInspired", "https://builtwith.appwrite.io"); diff --git a/kotlin/starter/README.md b/kotlin/starter/README.md index e8f2f635..bb1e8074 100644 --- a/kotlin/starter/README.md +++ b/kotlin/starter/README.md @@ -26,7 +26,7 @@ Sample `200` Response: ```json { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io" diff --git a/kotlin/starter/src/Main.kt b/kotlin/starter/src/Main.kt index c9e65c42..943711d0 100644 --- a/kotlin/starter/src/Main.kt +++ b/kotlin/starter/src/Main.kt @@ -31,7 +31,7 @@ class Main { // `context.res.json()` is a handy helper for sending JSON return context.res.json(mutableMapOf( - "motto" to "Build Fast. Scale Big. All in One Place.", + "motto" to "Build like a team of hundreds_", "learn" to "https://appwrite.io/docs", "connect" to "https://appwrite.io/discord", "getInspired" to "https://builtwith.appwrite.io" diff --git a/node-typescript/starter/README.md b/node-typescript/starter/README.md index da8ed8c9..3a9c64c1 100644 --- a/node-typescript/starter/README.md +++ b/node-typescript/starter/README.md @@ -26,7 +26,7 @@ Sample `200` Response: ```json { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io" diff --git a/node-typescript/starter/src/main.ts b/node-typescript/starter/src/main.ts index 25266fed..77b33853 100644 --- a/node-typescript/starter/src/main.ts +++ b/node-typescript/starter/src/main.ts @@ -32,7 +32,7 @@ export default async ({ req, res, log, error }: Context) => { // `res.json()` is a handy helper for sending JSON return res.json({ - motto: 'Build Fast. Scale Big. All in One Place.', + motto: 'Build like a team of hundreds_', learn: 'https://appwrite.io/docs', connect: 'https://appwrite.io/discord', getInspired: 'https://builtwith.appwrite.io', diff --git a/node/events-to-ga/.prettierrc.json b/node/events-to-ga/.prettierrc.json new file mode 100644 index 00000000..0a725205 --- /dev/null +++ b/node/events-to-ga/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "trailingComma": "es5", + "tabWidth": 2, + "semi": true, + "singleQuote": true +} diff --git a/node/events-to-ga/README.md b/node/events-to-ga/README.md index 3fbd2a96..08426b20 100644 --- a/node/events-to-ga/README.md +++ b/node/events-to-ga/README.md @@ -1,138 +1,86 @@ - - -# ⚡ Template Function - - - -The function will be triggered by configured Appwrite events and report these events to Google Analytics. - -## 🧰 Usage - - - - -### POST / - - - -Gets the event from the header. - -**Parameters** - - - -| Name | Description | Location | Type | Sample Value | -| ------------------ | ------------------------------ | -------- | ------ | --------------------- | -| x-appwrite-user-id | User ID from Appwrite. | Header | String | 642...7cd | -| x-appwrite-event | Describes the triggering event | Header | String | users.65...f19.delete | -| x-appwrite-trigger | Type of trigger for function | Header | String | event | - -**Response** - - - -Sample `200` Response: - -```json -{ - "ok": true, - "message": "event users.653...df19.delete is send to google analytics", -} -``` - - - -Sample `503` Response: - -```json -{ "ok": false, "message": "Response status code when posting event to Google Analytics is 503" } -``` - -Sample `401` Response: - -```json -{ "ok": false, "message": "Error Posting Event to Google Analytics" } -``` -## ⚙️ Configuration - - - -| Setting | Value | -| ----------------- | ---------------- | -| Runtime | Node (18.0) | -| Entrypoint | `src/main.js` | -| Build Commands | `npm install` | -| Permissions | `any` | -| Events | all | - -## 🔒 Environment Variables - - - - - -### APPWRITE_FUNCTION_PROJECT_ID - - - -Project ID in which Appwrite Function is added. - - - - - -| Question | Answer | -| ------------- | -------------------------------------------------------------------------------------------------------------| -| Required | Yes | -| Sample Value | `6524d.....6e5` | -| Documentation | [Appwrite: Getting Started for Server](https://appwrite.io/docs/getting-started-for-server#apiKey) | - - -### GA4_Measurement_Id - - - -API Key to talk to Appwrite backend APIs. - - - - - -| Question | Answer | -| ------------- | --------------------------------------------------------------------------------------------------------------| -| Required | Yes | -| Sample Value | `G-NY5...26R` | -| Documentation | [Google Analytics 4 docs](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference)| - - -### APPWRITE_ENDPOINT - - - -API Key to talk to Appwrite backend APIs. - - - - - -| Question | Answer | -| ------------- | --------------------------------------------------------------------------------------------------------------| -| Required | Yes | -| Sample Value | `https://cloud.appwrite.io/v1` | -| Documentation | [Google Analytics 4 docs](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference)| - -### GA4_API_SECRET - - - -API Key to talk to Appwrite backend APIs. - - - - - -| Question | Answer | -| ------------- | --------------------------------------------------------------------------------------------------------------| -| Required | Yes / No | -| Sample Value | `d1efb...aec35` | -| Documentation | [Google Analytics 4 docs](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference)| +# ⚡ Google Analytics Event Reporter + +The function will be triggered by configured Appwrite events and report these events to Google Analytics. + +## 🧰 Usage + +### POST / + +Gets the event from the header. + +**Parameters** + +| Name | Description | Location | Type | Sample Value | +| ------------------ | ------------------------------ | -------- | ------ | --------------------- | +| x-appwrite-user-id | User ID from Appwrite. | Header | String | 642...7cd | +| x-appwrite-event | Describes the triggering event | Header | String | users.65...f19.delete | +| x-appwrite-trigger | Type of trigger for function | Header | String | event | + +**Response** + +Sample `200` Response: + +```json +{ + "ok": true, + "message": "event users.653...df19.delete is send to google analytics" +} +``` + +Sample `503` Response: +503 response is send when the response status code while sending event to Google Analytics is not within 200-299 range + +```json +{ + "ok": false, + "message": "Response status code when posting event to Google Analytics is 503" +} +``` + +Sample `401` Response: + +```json +{ "ok": false, "message": "Error Posting Event to Google Analytics" } +``` + +## ⚙️ Configuration + +| Setting | Value | +| -------------- | ------------- | +| Runtime | Node (18.0) | +| Entrypoint | `src/main.js` | +| Build Commands | `npm install` | +| Permissions | | +| Events | all | + +## 🔒 Environment Variables + +### APPWRITE_FUNCTION_PROJECT_ID + +Project ID in which Appwrite Function is added. + +| Question | Answer | +| ------------- | -------------------------------------------------------------------------------------------------- | +| Required | Yes | +| Sample Value | `6524d.....6e5` | +| Documentation | [Appwrite: Getting Started for Server](https://appwrite.io/docs/getting-started-for-server#apiKey) | + +### GA4_MEASUREMENT_ID + +API Key to talk to Appwrite backend APIs. + +| Question | Answer | +| ------------- | -------------------------------------------------------------------------------------------------------------- | +| Required | Yes | +| Sample Value | `G-NY5...26R` | +| Documentation | [Google Analytics 4 docs](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference) | + +### GA4_API_SECRET + +API Key to talk to Appwrite backend APIs. + +| Question | Answer | +| ------------- | -------------------------------------------------------------------------------------------------------------- | +| Required | Yes / No | +| Sample Value | `d1efb...aec35` | +| Documentation | [Google Analytics 4 docs](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference) | diff --git a/node/events-to-ga/env.d.ts b/node/events-to-ga/env.d.ts index 4d7567a4..632cfdc1 100644 --- a/node/events-to-ga/env.d.ts +++ b/node/events-to-ga/env.d.ts @@ -1,14 +1,10 @@ declare global { namespace NodeJS { interface ProcessEnv { - APPWRITE_ENDPOINT: string; - APPWRITE_FUNCTION_PROJECT_ID: string; - APPWRITE_API_KEY: string; - GA4_Measurement_Id: string; + GA4_MEASUREMENT_ID: string; GA4_API_SECRET: string; } } } export {}; - diff --git a/node/events-to-ga/package-lock.json b/node/events-to-ga/package-lock.json index 4fc27ac8..3ecee48e 100644 --- a/node/events-to-ga/package-lock.json +++ b/node/events-to-ga/package-lock.json @@ -10,8 +10,18 @@ "license": "ISC", "dependencies": { "node-appwrite": "^11.0.0", - "node-fetch": "^3.3.2", - "prettier": "^3.0.3" + "undici": "^5.27.0" + }, + "devDependencies": { + "prettier": "3.0.3" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz", + "integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==", + "engines": { + "node": ">=14" } }, "node_modules/asynckit": { @@ -53,14 +63,6 @@ "node": ">= 0.8" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "engines": { - "node": ">= 12" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -69,28 +71,6 @@ "node": ">=0.4.0" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, "node_modules/follow-redirects": { "version": "1.15.3", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", @@ -110,17 +90,6 @@ } } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -162,45 +131,11 @@ "node": ">= 6" } }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, "node_modules/prettier": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -216,16 +151,24 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "node_modules/undici": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.0.tgz", + "integrity": "sha512-l3ydWhlhOJzMVOYkymLykcRRXqbUaQriERtR70B9LzNkZ4bX52Fc8wbTDneMiwo8T+AemZXvXaTx+9o5ROxrXg==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, "engines": { - "node": ">= 8" + "node": ">=14.0" } } }, "dependencies": { + "@fastify/busboy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz", + "integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -261,38 +204,16 @@ "delayed-stream": "~1.0.0" } }, - "data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, - "fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "requires": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - } - }, "follow-redirects": { "version": "1.15.3", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==" }, - "formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "requires": { - "fetch-blob": "^3.1.2" - } - }, "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -327,35 +248,24 @@ } } }, - "node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" - }, - "node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "requires": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - } - }, "prettier": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", - "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==" + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true }, "proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, - "web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" + "undici": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.0.tgz", + "integrity": "sha512-l3ydWhlhOJzMVOYkymLykcRRXqbUaQriERtR70B9LzNkZ4bX52Fc8wbTDneMiwo8T+AemZXvXaTx+9o5ROxrXg==", + "requires": { + "@fastify/busboy": "^2.0.0" + } } } } diff --git a/node/events-to-ga/package.json b/node/events-to-ga/package.json index b54fd4b6..59966ae6 100644 --- a/node/events-to-ga/package.json +++ b/node/events-to-ga/package.json @@ -11,7 +11,9 @@ "license": "ISC", "dependencies": { "node-appwrite": "^11.0.0", - "node-fetch": "^3.3.2", - "prettier": "^3.0.3" + "undici": "^5.27.0" + }, + "devDependencies": { + "prettier": "3.0.3" } } diff --git a/node/events-to-ga/src/main.js b/node/events-to-ga/src/main.js index 181e671c..153d9189 100644 --- a/node/events-to-ga/src/main.js +++ b/node/events-to-ga/src/main.js @@ -1,112 +1,74 @@ -import { Client } from "node-appwrite"; -import { throwIfMissing } from "./utils.js"; -import fetch from "node-fetch"; - -throwIfMissing(process.env, [ - "GA4_Measurement_Id", - "APPWRITE_ENDPOINT", - "APPWRITE_FUNCTION_PROJECT_ID", - "GA4_API_SECRET", -]); - -// Initialize the Appwrite SDK -const client = new Client(); -client.setEndpoint(process.env.APPWRITE_ENDPOINT); -client.setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID); -//client.setKey(process.env.APPWRITE_API_KEY); - -// Initialize Google Analytics 4 Measurement ID -const ga4MeasurementId = process.env.GA4_Measurement_Id; -const ga4secret = process.env.GA4_API_SECRET; - -function formatInto_GA_EventString(str) { - const oddElemArray = []; - const wildCardArray = []; - const splitArray = str.split("."); - - for (let i = 0; i < splitArray.length; i++) { - if (i % 2 == 0) oddElemArray.push(splitArray[i]); - else wildCardArray.push([`wildCard_${(i + 1) >> 1}`, splitArray[i]]); - } - const event_name = oddElemArray.join("_"); - return { - event_name: event_name.charAt(0).toUpperCase() + event_name.slice(1), - wildCardObject: Object.fromEntries(wildCardArray), - }; -} - -/* Appwrite function */ - -export default async ({ res, req, log, error }) => { - // Listen for Appwrite events - if (req.headers["x-appwrite-user-id"] == "") { - error(`x-appwrite-trigger value in req.headers is not there`); - return res.json({ ok: false, error: "Invalid Event Header" }, 401); - } - if (req.headers["x-appwrite-trigger"] != "event") { - error(`Not triggered by event but by ${req.headers["x-appwrite-trigger"]}`); - return res.json({ ok: false, error: "Invalid Event Header" }, 401); - } - if (req.headers["x-appwrite-event"] == "") { - error(`x-appwrite-event value in req.headers is null`); - return res.json({ ok: false, error: "Invalid Event Header" }, 401); - } - try { - const { event_name, wildCardObject } = formatInto_GA_EventString( - `${req.headers["x-appwrite-event"]}` - ); - const payload = JSON.stringify({ - client_id: `${req.headers["x-appwrite-user-id"]}`, - user_id: `${req.headers["x-appwrite-user-id"]}`, - events: [ - { - // Event names must start with an alphabetic character and all characters should be alphanumeric. - name: event_name, - params: wildCardObject, - }, - ], - }); - log(payload); - const response = await fetch( - `https://www.google-analytics.com/mp/collect?measurement_id=${ga4MeasurementId}&api_secret=${ga4secret}`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - cors: "no-cors", - body: payload, - } - ); - if (response.ok) { - if (response.status != 204) { - const responseJson = await response.json(); - log(JSON.stringify(responseJson)); - } - log( - `event ${req.headers["x-appwrite-event"]} is send to google analytics` - ); - } else { - error("Response status code is not between 200-299 event to Google Analytics"); - return res.json( - { ok: false, error: `Response status code when posting event to Google Analytics is ${response.status}` }, - 503 - ); - } - } catch (err) { - error("Error reporting event to Google Analytics :"); - return res.json( - { ok: false, error: "Error Posting Event to Google Analytics" }, - 401 - ); - } - - log("Event posted to Google Analytics successfully"); - return res.json( - { - ok: true, - message: `event ${req.headers["x-appwrite-event"]} is send to google analytics`, - }, - 200 - ); -}; +import { fetch } from 'undici'; +import { verifyHeaders, formatIntoGoogleAnalyticsEvent } from './utils.js'; + +export default async ({ res, req, log, error }) => { + try { + verifyHeaders(req); + } catch (err) { + error(err); + return res.json({ ok: false, error: 'Invalid Event Header' }, 401); + } + try { + const { event_name, wildCardObject } = formatIntoGoogleAnalyticsEvent( + `${req.headers['x-appwrite-event']}` + ); + // Documentation on Google Analytics Payload https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference?client_type=gtag#payload + const payload = JSON.stringify({ + client_id: `${req.headers['x-appwrite-user-id']}`, + user_id: `${req.headers['x-appwrite-user-id']}`, + events: [ + { + name: event_name, + params: wildCardObject, + }, + ], + }); + log(payload); + const response = await fetch( + `https://www.google-analytics.com/mp/collect?measurement_id=${process.env.GA4_MEASUREMENT_ID}&api_secret=${process.env.GA4_API_SECRET}`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + cors: 'no-cors', + body: payload, + } + ); + if (response.ok) { + if (response.status != 204) { + const responseJson = await response.json(); + log(JSON.stringify(responseJson)); + } + log( + `event ${req.headers['x-appwrite-event']} is send to google analytics` + ); + } else { + error( + 'Response status code is not between 200-299 event to Google Analytics' + ); + return res.json( + { + ok: false, + error: `Response status code when posting event to Google Analytics is ${response.status}`, + }, + 503 + ); + } + } catch (err) { + error('Error reporting event to Google Analytics :', err); + return res.json( + { ok: false, error: 'Error Posting Event to Google Analytics' }, + 401 + ); + } + + log('Event posted to Google Analytics successfully'); + return res.json( + { + ok: true, + message: `event ${req.headers['x-appwrite-event']} is send to google analytics`, + }, + 200 + ); +}; diff --git a/node/events-to-ga/src/utils.js b/node/events-to-ga/src/utils.js index 45bb30d8..246a8ea2 100644 --- a/node/events-to-ga/src/utils.js +++ b/node/events-to-ga/src/utils.js @@ -1,17 +1,61 @@ -/** - * Throws an error if any of the keys are missing from the object - * @param {*} obj - * @param {string[]} keys - * @throws {Error} - */ -export function throwIfMissing(obj, keys) { - const missing = []; - for (let key of keys) { - if (!(key in obj) || !obj[key]) { - missing.push(key); - } - } - if (missing.length > 0) { - throw new Error(`Missing required fields: ${missing.join(", ")}`); - } -} +/** + * Throws an error if any of the keys are missing from the object + * @param {*} obj + * @param {string[]} keys + * @throws {Error} + */ +export function throwIfMissing(obj, keys) { + const missing = []; + for (let key of keys) { + if (!(key in obj) || !obj[key]) { + missing.push(key); + } + } + if (missing.length > 0) { + throw new Error(`Missing required fields: ${missing.join(', ')}`); + } +} + +/** + * Returns whether the request headers and appropriate message are ok + * @param {*} req + * @returns {} + */ +export function verifyHeaders(req) { + if (req.headers['x-appwrite-user-id'] == '') { + throw new Error(`x-appwrite-user-id value in req.headers is not there`); + } + if (req.headers['x-appwrite-trigger'] != 'event') { + throw new Error( + `Not triggered by event but by ${req.headers['x-appwrite-trigger']}` + ); + } + if (req.headers['x-appwrite-event'] == '') { + throw new Error(`x-appwrite-event value in req.headers is not there`); + } +} + +/** + * Returns object containing a string denoting the formatted event name to Google Analytics and another object containing params + * @param {string} str + * @returns {{event_name:string,wildCardObject:{[key:string]:string}}} + */ +export function formatIntoGoogleAnalyticsEvent(str) { + const oddElemArray = []; + const wildCardArray = []; + const splitArray = str.split('.'); + + for (let i = 0; i < splitArray.length; i++) { + if (i % 2 == 0) oddElemArray.push(splitArray[i]); + else + wildCardArray.push([ + `${oddElemArray[oddElemArray.length - 1]}Id`, + splitArray[i], + ]); + } + const event_name = oddElemArray.join('_'); + return { + event_name: event_name, + wildCardObject: Object.fromEntries(wildCardArray), + }; +} diff --git a/node/starter/README.md b/node/starter/README.md index 10c6c29f..df0ce108 100644 --- a/node/starter/README.md +++ b/node/starter/README.md @@ -26,7 +26,7 @@ Sample `200` Response: ```json { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io" diff --git a/node/starter/src/main.js b/node/starter/src/main.js index f6c625bb..64e00a47 100644 --- a/node/starter/src/main.js +++ b/node/starter/src/main.js @@ -25,7 +25,7 @@ export default async ({ req, res, log, error }) => { // `res.json()` is a handy helper for sending JSON return res.json({ - motto: 'Build Fast. Scale Big. All in One Place.', + motto: 'Build like a team of hundreds_', learn: 'https://appwrite.io/docs', connect: 'https://appwrite.io/discord', getInspired: 'https://builtwith.appwrite.io', diff --git a/php/starter/README.md b/php/starter/README.md index 1b19cf01..2b3d87f8 100644 --- a/php/starter/README.md +++ b/php/starter/README.md @@ -26,7 +26,7 @@ Sample `200` Response: ```json { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io" diff --git a/php/starter/src/index.php b/php/starter/src/index.php index ac257a5c..29557a59 100644 --- a/php/starter/src/index.php +++ b/php/starter/src/index.php @@ -31,7 +31,7 @@ // `res.json()` is a handy helper for sending JSON return $context->res->json([ - 'motto' => 'Build Fast. Scale Big. All in One Place.', + 'motto' => 'Build like a team of hundreds_', 'learn' => 'https://appwrite.io/docs', 'connect' => 'https://appwrite.io/discord', 'getInspired' => 'https://builtwith.appwrite.io', diff --git a/python/starter/README.md b/python/starter/README.md index b835e811..1e844a02 100644 --- a/python/starter/README.md +++ b/python/starter/README.md @@ -26,7 +26,7 @@ Sample `200` Response: ```json { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io" diff --git a/python/starter/src/main.py b/python/starter/src/main.py index 4c2976b4..d8ed3a0a 100644 --- a/python/starter/src/main.py +++ b/python/starter/src/main.py @@ -29,7 +29,7 @@ def main(context): # `ctx.res.json()` is a handy helper for sending JSON return context.res.json( { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io", diff --git a/ruby/starter/README.md b/ruby/starter/README.md index 261cd1a4..dd966608 100644 --- a/ruby/starter/README.md +++ b/ruby/starter/README.md @@ -26,7 +26,7 @@ Sample `200` Response: ```json { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io" diff --git a/ruby/starter/lib/main.rb b/ruby/starter/lib/main.rb index 9c4b488d..33d1427d 100644 --- a/ruby/starter/lib/main.rb +++ b/ruby/starter/lib/main.rb @@ -27,7 +27,7 @@ def main(context) # `ctx.res.json()` is a handy helper for sending JSON return context.res.json( { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io", diff --git a/swift/starter/README.md b/swift/starter/README.md index 3b58a2b9..d5b1dbe5 100644 --- a/swift/starter/README.md +++ b/swift/starter/README.md @@ -26,7 +26,7 @@ Sample `200` Response: ```json { - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io" diff --git a/swift/starter/Sources/index.swift b/swift/starter/Sources/index.swift index 32a116af..009d74cf 100644 --- a/swift/starter/Sources/index.swift +++ b/swift/starter/Sources/index.swift @@ -27,7 +27,7 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput { // `context.res.json()` is a handy helper for sending JSON return try context.res.json([ - "motto": "Build Fast. Scale Big. All in One Place.", + "motto": "Build like a team of hundreds_", "learn": "https://appwrite.io/docs", "connect": "https://appwrite.io/discord", "getInspired": "https://builtwith.appwrite.io",