Function configuration from appwrite.json, live Appwrite settings, and behavior derived from the function source code.
functions/news_refresh, functions/fact_check, functions/chat_write, or functions/like_sync.npm install fails because there is no root package.json.providerRootDirectory together when changing live settings.Purpose: fetches external news articles, normalizes them into content rows, removes duplicates, applies quality filters, and optionally prunes old content.
| Field | Value |
|---|---|
| Runtime | node-22 |
| Entrypoint | functions/news_refresh/src/main.js |
| Timeout | 300 seconds |
| Execute | none; schedule/runtime only |
| Schedule | 0 */6 * * * |
| Install command | npm install |
| Build/runtime specification | s-0.5vcpu-512mb |
Scopes:
databases.readdatabases.writetables.readtables.writedocuments.readdocuments.writerows.readrows.writeExpected input: no request body is required by the implementation. Required environment variables are NEWS_API_KEY or NEWSAPIKEY, APPWRITE_ENDPOINT, APPWRITE_PROJECT_ID, and APPWRITE_API_KEY. Optional environment variables are GUARDIANKEY, SENTRY_DSN, MIN_BODY_CHARS, REQUIRE_IMAGE, CONTENT_RETENTION_DAYS, CONTENT_RETENTION_MAX_DELETES, and CONTENT_BODY_MAX_CHARS.
Output:
inserted, skipped_duplicate, skipped_empty, skipped_invalid_url, skipped_short_body, skipped_missing_image, insert_errors, insert_error_samples, duplicate_report, quality_report, and retention_report.error string.error, inserted: 0, skipped_duplicate: 0, skipped_empty: 0, and skipped_invalid_url: 0.Implementation notes:
en and de across category keywords.GUARDIANKEY is set.sourceUrl and checks existing content rows by sourceUrl.404.Purpose: validates a claim, reuses a recent exact cache hit when available, otherwise checks the claim with Perplexity and stores a fact-check row.
| Field | Value |
|---|---|
| Runtime | node-22 |
| Entrypoint | functions/fact_check/src/index.js |
| Timeout | 30 seconds |
| Execute | any |
| Schedule | none |
| Install command | npm install |
| Build/runtime specification | s-0.5vcpu-512mb |
Scopes:
tables.readtables.writerows.readrows.writeExpected input:
{
"claim": "Claim text, 500 characters or fewer",
"userId": "optional user id for private history only"
}
The function supports OPTIONS for CORS and only accepts POST for execution. PERPLEXITY_API_KEY is required when no cache hit is returned.
Output:
claim, verdict, confidence, explanation, citations, and createdAt. Shared cache responses are anonymous and do not include userId.400: { "error": "Claim is required and must be 500 characters or fewer" } or invalid JSON error.402: { "error": "Insufficient API credits" } when Perplexity returns 402.504: { "error": "Perplexity request timed out" }.405: { "error": "Only POST requests are supported" }.500: provider or internal error.Implementation notes:
equal("claim"), then falls back to search("claim").sonar and asks for JSON fields verdict, confidence, explanation, and citations.fact_checks cache rows do not store caller userId; per-user history belongs only in user_fact_check_history.confidence, explanation, citations, createdAt) and legacy fields consumed by Flutter (confidenceLevel, confidenceScore, source, sourceUrl, contextBlock, checkedAt, language).Purpose: performs trusted server-side writes for 1:1 threads, text messages, and article shares after verifying authenticated user and accepted friendship.
| Field | Value |
|---|---|
| Runtime | node-22 |
| Entrypoint | functions/chat_write/src/index.js |
| Timeout | 30 seconds |
| Execute | users |
| Schedule | none |
| Install command | npm install |
| Build/runtime specification | s-0.5vcpu-512mb |
Scopes:
tables.readtables.writerows.readrows.writeExpected input by action:
{ "action": "getOrCreateThread", "otherUserId": "user id" }
{ "action": "postMessage", "threadId": "thread id", "body": "encrypted message body" }
{
"action": "shareArticle",
"recipientId": "user id",
"contentId": "content row id",
"message": "optional encrypted message"
}
The function reads the current user from Appwrite execution headers such as x-appwrite-user-id. It supports OPTIONS for CORS and only accepts POST.
Output:
getOrCreateThread: { "thread": { ...thread row... } }.postMessage: { "messageId": "...", "threadId": "...", "sentAt": "ISO datetime" }.shareArticle: { "thread": { ...thread row... }, "messageId": "...", "sentAt": "ISO datetime" }.401: { "error": "Sign in to continue." }.403: { "error": "Only accepted friends can chat." } or thread access error.400: missing field, invalid self-chat, too-long body/message, unsupported action, or invalid JSON.405: unsupported method.500: internal error.Implementation notes:
pairKey; contentId is also written as dm:{pairKey} for compatibility.type: "article" and contentId; a legacy body prefix is used if the typed schema fails.Purpose: synchronizes the denormalized content.likeCount after a client like row is created or deleted.
| Field | Value |
|---|---|
| Runtime | node-22 |
| Entrypoint | functions/like_sync/src/main.js |
| Timeout | 15 seconds |
| Execute | users |
| Schedule | none |
| Install command | npm install |
| Build/runtime specification | s-0.5vcpu-512mb |
Scopes:
databases.readdatabases.writedocuments.readdocuments.writetables.readtables.writerows.readrows.writeExpected input:
{
"contentId": "content row id, at most 64 characters",
"liked": true
}
Output:
{ "success": true, "likeCount": number }.400: invalid liked state, invalid contentId, or invalid JSON.404: { "error": "Content not found" }.405: { "error": "Only POST requests are supported" }.500: internal error.Implementation notes:
content_likes, recomputes the canonical count from content_likes, and writes that count back to the content row.increment / decrement requests are accepted for compatibility but are reconciled idempotently instead of blindly applying a numeric delta.