appwrite-typescript

安装量: 167
排名: #5160

安装

npx skills add https://github.com/appwrite/agent-skills --skill appwrite-typescript

Appwrite TypeScript SDK Installation

Web

npm install appwrite

React Native

npm install react-native-appwrite

Node.js / Deno

npm install node-appwrite Setting Up the Client Client-side (Web / React Native) // Web import { Client , Account , TablesDB , Storage , ID , Query } from 'appwrite' ; // React Native import { Client , Account , TablesDB , Storage , ID , Query } from 'react-native-appwrite' ; const client = new Client ( ) . setEndpoint ( 'https://.cloud.appwrite.io/v1' ) . setProject ( '[PROJECT_ID]' ) ; Server-side (Node.js / Deno) import { Client , Users , TablesDB , Storage , Functions , ID , Query } from 'node-appwrite' ; const client = new Client ( ) . setEndpoint ( 'https://.cloud.appwrite.io/v1' ) . setProject ( process . env . APPWRITE_PROJECT_ID ) . setKey ( process . env . APPWRITE_API_KEY ) ; Code Examples Authentication (client-side) const account = new Account ( client ) ; // Email signup await account . create ( { userId : ID . unique ( ) , email : 'user@example.com' , password : 'password123' , name : 'User Name' } ) ; // Email login const session = await account . createEmailPasswordSession ( { email : 'user@example.com' , password : 'password123' } ) ; // OAuth login (Web) account . createOAuth2Session ( { provider : OAuthProvider . Github , success : 'https://example.com/success' , failure : 'https://example.com/fail' , scopes : [ 'repo' , 'user' ] // optional — provider-specific scopes } ) ; // Get current user const user = await account . get ( ) ; // Logout await account . deleteSession ( { sessionId : 'current' } ) ; OAuth 2 Login (React Native) Important: createOAuth2Session() does not work on React Native. You must use createOAuth2Token() with deep linking instead. Setup Install the required dependencies: npx expo install react-native-appwrite react-native-url-polyfill npm install expo-auth-session expo-web-browser expo-linking Set the URL scheme in your app.json : { "expo" : { "scheme" : "appwrite-callback-[PROJECT_ID]" } } OAuth Flow import { Client , Account , OAuthProvider } from 'react-native-appwrite' ; import { makeRedirectUri } from 'expo-auth-session' ; import * as WebBrowser from 'expo-web-browser' ; const client = new Client ( ) . setEndpoint ( 'https://.cloud.appwrite.io/v1' ) . setProject ( '[PROJECT_ID]' ) ; const account = new Account ( client ) ; async function oauthLogin ( provider : OAuthProvider ) { // Create deep link that works across Expo environments const deepLink = new URL ( makeRedirectUri ( { preferLocalhost : true } ) ) ; const scheme = ${ deepLink . protocol } // ; // e.g. 'exp://' or 'appwrite-callback-[PROJECT_ID]://' // Get the OAuth login URL const loginUrl = await account . createOAuth2Token ( { provider , success : ${ deepLink } , failure : ${ deepLink } , } ) ; // Open browser and listen for the scheme redirect const result = await WebBrowser . openAuthSessionAsync ( ${ loginUrl } , scheme ) ; if ( result . type !== 'success' ) return ; // Extract credentials from the redirect URL const url = new URL ( result . url ) ; const secret = url . searchParams . get ( 'secret' ) ; const userId = url . searchParams . get ( 'userId' ) ; // Create session with the OAuth credentials await account . createSession ( { userId , secret } ) ; } // Usage await oauthLogin ( OAuthProvider . Github ) ; await oauthLogin ( OAuthProvider . Google ) ; User Management (server-side) const users = new Users ( client ) ; // Create user const user = await users . create ( { userId : ID . unique ( ) , email : 'user@example.com' , password : 'password123' , name : 'User Name' } ) ; // List users const list = await users . list ( { queries : [ Query . limit ( 25 ) ] } ) ; // Get user const fetched = await users . get ( { userId : '[USER_ID]' } ) ; // Delete user await users . delete ( { userId : '[USER_ID]' } ) ; Database Operations Note: Use TablesDB (not the deprecated Databases class) for all new code. Only use Databases if the existing codebase already relies on it or the user explicitly requests it. Tip: Prefer the object-params calling style (e.g., { databaseId: '...' } ) for all SDK method calls. Only use positional arguments if the existing codebase already uses them or the user explicitly requests it. const tablesDB = new TablesDB ( client ) ; // Create database (server-side only) const db = await tablesDB . create ( { databaseId : ID . unique ( ) , name : 'My Database' } ) ; // Create table (server-side only) const col = await tablesDB . createTable ( { databaseId : '[DATABASE_ID]' , tableId : ID . unique ( ) , name : 'My Table' } ) ; // Create row const doc = await tablesDB . createRow ( { databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , rowId : ID . unique ( ) , data : { title : 'Hello World' , content : 'Example content' } } ) ; // List rows with query const results = await tablesDB . listRows ( { databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , queries : [ Query . equal ( 'status' , 'active' ) , Query . limit ( 10 ) ] } ) ; // Get row const row = await tablesDB . getRow ( { databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , rowId : '[ROW_ID]' } ) ; // Update row await tablesDB . updateRow ( { databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , rowId : '[ROW_ID]' , data : { title : 'Updated Title' } } ) ; // Delete row await tablesDB . deleteRow ( { databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , rowId : '[ROW_ID]' } ) ; String Column Types Note: The legacy string type is deprecated. Use explicit column types for all new columns. Type Max characters Indexing Storage varchar 16,383 Full index (if size ≤ 768) Inline in row text 16,383 Prefix only Off-page mediumtext 4,194,303 Prefix only Off-page longtext 1,073,741,823 Prefix only Off-page varchar is stored inline and counts towards the 64 KB row size limit. Prefer for short, indexed fields like names, slugs, or identifiers. text , mediumtext , and longtext are stored off-page (only a 20-byte pointer lives in the row), so they don't consume the row size budget. size is not required for these types. // Create table with explicit string column types await tablesDB . createTable ( { databaseId : '[DATABASE_ID]' , tableId : ID . unique ( ) , name : 'articles' , columns : [ { key : 'title' , type : 'varchar' , size : 255 , required : true } , // inline, fully indexable { key : 'summary' , type : 'text' , required : false } , // off-page, prefix index only { key : 'body' , type : 'mediumtext' , required : false } , // up to ~4 M chars { key : 'raw_data' , type : 'longtext' , required : false } , // up to ~1 B chars ] } ) ; TypeScript Generics import { Models } from 'appwrite' ; // Server-side: import from 'node-appwrite' // Define a typed interface for your row data interface Todo { title : string ; done : boolean ; priority : number ; } // listRows returns Models.DocumentList by default // Cast or use generics for typed results const results = await tablesDB . listRows ( { databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , queries : [ Query . equal ( 'done' , false ) ] } ) ; // Each document includes built-in fields alongside your data const doc = results . documents [ 0 ] ; doc . $id ; // string — unique row ID doc . $createdAt ; // string — ISO 8601 creation timestamp doc . $updatedAt ; // string — ISO 8601 update timestamp doc . $permissions ; // string[] — permission strings doc . $databaseId ; // string doc . $collectionId ; // string // Common model types // Models.User — user account // Models.Session — auth session // Models.File — storage file metadata // Models.Team — team object // Models.Execution — function execution result // Models.DocumentList — paginated list with total count Query Methods // Filtering Query . equal ( 'field' , 'value' ) // field == value (or pass array for IN) Query . notEqual ( 'field' , 'value' ) // field != value Query . lessThan ( 'field' , 100 ) // field < value Query . lessThanEqual ( 'field' , 100 ) // field <= value Query . greaterThan ( 'field' , 100 ) // field > value Query . greaterThanEqual ( 'field' , 100 ) // field >= value Query . between ( 'field' , 1 , 100 ) // 1 <= field <= 100 Query . isNull ( 'field' ) // field is null Query . isNotNull ( 'field' ) // field is not null Query . startsWith ( 'field' , 'prefix' ) // string starts with prefix Query . endsWith ( 'field' , 'suffix' ) // string ends with suffix Query . contains ( 'field' , 'substring' ) // string/array contains value Query . search ( 'field' , 'keywords' ) // full-text search (requires full-text index) // Sorting Query . orderAsc ( 'field' ) // sort ascending Query . orderDesc ( 'field' ) // sort descending // Pagination Query . limit ( 25 ) // max rows returned (default 25, max 100) Query . offset ( 0 ) // skip N rows Query . cursorAfter ( '[ROW_ID]' ) // paginate after this row ID (preferred for large datasets) Query . cursorBefore ( '[ROW_ID]' ) // paginate before this row ID // Selection Query . select ( [ 'field1' , 'field2' ] ) // return only specified fields // Logical Query . or ( [ Query . equal ( 'a' , 1 ) , Query . equal ( 'b' , 2 ) ] ) // OR condition Query . and ( [ Query . greaterThan ( 'age' , 18 ) , Query . lessThan ( 'age' , 65 ) ] ) // explicit AND (queries are AND by default) File Storage const storage = new Storage ( client ) ; // Upload file (client-side — from file input) const file = await storage . createFile ( { bucketId : '[BUCKET_ID]' , fileId : ID . unique ( ) , file : document . getElementById ( 'file-input' ) . files [ 0 ] } ) ; // Upload file (server-side — from path) import { InputFile } from 'node-appwrite/file' ; const file2 = await storage . createFile ( { bucketId : '[BUCKET_ID]' , fileId : ID . unique ( ) , file : InputFile . fromPath ( '/path/to/file.png' , 'file.png' ) } ) ; // List files const files = await storage . listFiles ( { bucketId : '[BUCKET_ID]' } ) ; // Get file preview (image) const preview = storage . getFilePreview ( { bucketId : '[BUCKET_ID]' , fileId : '[FILE_ID]' , width : 300 , height : 300 } ) ; // Download file const download = await storage . getFileDownload ( { bucketId : '[BUCKET_ID]' , fileId : '[FILE_ID]' } ) ; // Delete file await storage . deleteFile ( { bucketId : '[BUCKET_ID]' , fileId : '[FILE_ID]' } ) ; InputFile Factory Methods (server-side) import { InputFile } from 'node-appwrite/file' ; InputFile . fromPath ( '/path/to/file.png' , 'file.png' ) // from filesystem path InputFile . fromBuffer ( buffer , 'file.png' ) // from Buffer InputFile . fromStream ( readableStream , 'file.png' , size ) // from ReadableStream (size in bytes required) InputFile . fromPlainText ( 'Hello world' , 'hello.txt' ) // from string content Teams const teams = new Teams ( client ) ; // Create team const team = await teams . create ( { teamId : ID . unique ( ) , name : 'Engineering' } ) ; // List teams const list = await teams . list ( ) ; // Create membership (invite a user by email) const membership = await teams . createMembership ( { teamId : '[TEAM_ID]' , roles : [ 'editor' ] , email : 'user@example.com' , } ) ; // List memberships const members = await teams . listMemberships ( { teamId : '[TEAM_ID]' } ) ; // Update membership roles await teams . updateMembership ( { teamId : '[TEAM_ID]' , membershipId : '[MEMBERSHIP_ID]' , roles : [ 'admin' ] , } ) ; // Delete team await teams . delete ( { teamId : '[TEAM_ID]' } ) ; Role-based access: Use Role.team('[TEAM_ID]') for all team members or Role.team('[TEAM_ID]', 'editor') for a specific team role when setting permissions. Real-time Subscriptions (client-side) import { Realtime , Channel } from 'appwrite' ; const realtime = new Realtime ( client ) ; // Subscribe to row changes const subscription = await realtime . subscribe ( Channel . tablesdb ( '[DATABASE_ID]' ) . table ( '[TABLE_ID]' ) . row ( ) , ( response ) => { console . log ( response . events ) ; // e.g. ['tablesdb..tables..rows..create'] console . log ( response . payload ) ; // the affected resource } ) ; // Subscribe to a specific row await realtime . subscribe ( Channel . tablesdb ( '[DATABASE_ID]' ) . table ( '[TABLE_ID]' ) . row ( '[ROW_ID]' ) , ( response ) => { / ... / } ) ; // Subscribe to multiple channels await realtime . subscribe ( [ Channel . tablesdb ( '[DATABASE_ID]' ) . table ( '[TABLE_ID]' ) . row ( ) , Channel . bucket ( '[BUCKET_ID]' ) . file ( ) , ] , ( response ) => { / ... */ } ) ; // Unsubscribe await subscription . close ( ) ; Available channels: Channel Description account Changes to the authenticated user's account tablesdb.[DB_ID].tables.[TABLE_ID].rows All rows in a table tablesdb.[DB_ID].tables.[TABLE_ID].rows.[ROW_ID] A specific row buckets.[BUCKET_ID].files All files in a bucket buckets.[BUCKET_ID].files.[FILE_ID] A specific file teams Changes to teams the user belongs to teams.[TEAM_ID] Changes to a specific team memberships Changes to the user's team memberships memberships.[MEMBERSHIP_ID] A specific membership functions.[FUNCTION_ID].executions Execution updates for a function The response object includes: events (array of event strings), payload (the affected resource), channels (channels matched), and timestamp (ISO 8601). Serverless Functions (server-side) const functions = new Functions ( client ) ; // Execute function const execution = await functions . createExecution ( { functionId : '[FUNCTION_ID]' , body : JSON . stringify ( { key : 'value' } ) } ) ; // List executions const executions = await functions . listExecutions ( { functionId : '[FUNCTION_ID]' } ) ; Writing a Function Handler (Node.js runtime) When deploying your own Appwrite Function, the entry point file must export a default async function: // src/main.js (or src/main.ts) export default async ( { req , res , log , error } ) => { // Request properties // req.body — raw request body (string) // req.bodyJson — parsed JSON body (object, or undefined if not JSON) // req.headers — request headers (object) // req.method — HTTP method (GET, POST, PUT, DELETE, PATCH) // req.path — URL path (e.g. '/hello') // req.query — parsed query parameters (object) // req.queryString — raw query string log ( 'Processing request: ' + req . method + ' ' + req . path ) ; if ( req . method === 'GET' ) { return res . json ( { message : 'Hello from Appwrite Function!' } ) ; } const data = req . bodyJson ; if ( ! data ?. name ) { error ( 'Missing name field' ) ; return res . json ( { error : 'Name is required' } , 400 ) ; } // Response methods return res . json ( { success : true } ) ; // JSON (sets Content-Type automatically) // return res.text('Hello'); // plain text // return res.empty(); // 204 No Content // return res.redirect('https://example.com'); // 302 Redirect // return res.send('data', 200, { 'X-Custom': '1' }); // custom body, status, headers } ; Server-Side Rendering (SSR) Authentication SSR apps (Next.js, SvelteKit, Nuxt, Remix, Astro) use the server SDK ( node-appwrite ) to handle auth. You need two clients: Admin client — uses an API key, creates sessions, bypasses rate limits (reusable singleton) Session client — uses a session cookie, acts on behalf of a user (create per-request, never share) import { Client , Account , OAuthProvider } from 'node-appwrite' ; // Admin client (reusable) const adminClient = new Client ( ) . setEndpoint ( 'https://.cloud.appwrite.io/v1' ) . setProject ( '[PROJECT_ID]' ) . setKey ( process . env . APPWRITE_API_KEY ) ; // Session client (create per-request) const sessionClient = new Client ( ) . setEndpoint ( 'https://.cloud.appwrite.io/v1' ) . setProject ( '[PROJECT_ID]' ) ; const session = req . cookies [ 'a_session_[PROJECT_ID]' ] ; if ( session ) { sessionClient . setSession ( session ) ; } Email/Password Login app . post ( '/login' , async ( req , res ) => { const account = new Account ( adminClient ) ; const session = await account . createEmailPasswordSession ( { email : req . body . email , password : req . body . password , } ) ; // Cookie name must be a_session_ res . cookie ( 'a_session_[PROJECT_ID]' , session . secret , { httpOnly : true , secure : true , sameSite : 'strict' , expires : new Date ( session . expire ) , path : '/' , } ) ; res . json ( { success : true } ) ; } ) ; Authenticated Requests app . get ( '/user' , async ( req , res ) => { const session = req . cookies [ 'a_session_[PROJECT_ID]' ] ; if ( ! session ) return res . status ( 401 ) . json ( { error : 'Unauthorized' } ) ; // Create a fresh session client per request const sessionClient = new Client ( ) . setEndpoint ( 'https://.cloud.appwrite.io/v1' ) . setProject ( '[PROJECT_ID]' ) . setSession ( session ) ; const account = new Account ( sessionClient ) ; const user = await account . get ( ) ; res . json ( user ) ; } ) ; OAuth2 SSR Flow // Step 1: Redirect to OAuth provider app . get ( '/oauth' , async ( req , res ) => { const account = new Account ( adminClient ) ; const redirectUrl = await account . createOAuth2Token ( { provider : OAuthProvider . Github , success : 'https://example.com/oauth/success' , failure : 'https://example.com/oauth/failure' , } ) ; res . redirect ( redirectUrl ) ; } ) ; // Step 2: Handle callback — exchange token for session app . get ( '/oauth/success' , async ( req , res ) => { const account = new Account ( adminClient ) ; const session = await account . createSession ( { userId : req . query . userId , secret : req . query . secret , } ) ; res . cookie ( 'a_session_[PROJECT_ID]' , session . secret , { httpOnly : true , secure : true , sameSite : 'strict' , expires : new Date ( session . expire ) , path : '/' , } ) ; res . json ( { success : true } ) ; } ) ; Cookie security: Always use httpOnly , secure , and sameSite: 'strict' to prevent XSS. The cookie name must be a_session_ . Forwarding user agent: Call sessionClient.setForwardedUserAgent(req.headers['user-agent']) to record the end-user's browser info for debugging and security. Error Handling import { AppwriteException } from 'appwrite' ; // Server-side: import from 'node-appwrite' try { const doc = await tablesDB . getRow ( { databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , rowId : '[ROW_ID]' , } ) ; } catch ( err ) { if ( err instanceof AppwriteException ) { console . log ( err . message ) ; // human-readable error message console . log ( err . code ) ; // HTTP status code (number) console . log ( err . type ) ; // Appwrite error type string (e.g. 'document_not_found') console . log ( err . response ) ; // full response body (object) } } Common error codes: Code Meaning 401 Unauthorized — missing or invalid session/API key 403 Forbidden — insufficient permissions for this action 404 Not found — resource does not exist 409 Conflict — duplicate ID or unique constraint violation 429 Rate limited — too many requests, retry after backoff Permissions & Roles (Critical) Appwrite uses permission strings to control access to resources. Each permission pairs an action ( read , update , delete , create , or write which grants create + update + delete) with a role target. By default, no user has access unless permissions are explicitly set at the document/file level or inherited from the collection/bucket settings. Permissions are arrays of strings built with the Permission and Role helpers. import { Permission , Role } from 'appwrite' ; // Server-side: import from 'node-appwrite' Database Row with Permissions const doc = await tablesDB . createRow ( { databaseId : '[DATABASE_ID]' , tableId : '[TABLE_ID]' , rowId : ID . unique ( ) , data : { title : 'Hello World' } , permissions : [ Permission . read ( Role . user ( '[USER_ID]' ) ) , // specific user can read Permission . update ( Role . user ( '[USER_ID]' ) ) , // specific user can update Permission . read ( Role . team ( '[TEAM_ID]' ) ) , // all team members can read Permission . read ( Role . any ( ) ) , // anyone (including guests) can read ] } ) ; File Upload with Permissions const file = await storage . createFile ( { bucketId : '[BUCKET_ID]' , fileId : ID . unique ( ) , file : document . getElementById ( 'file-input' ) . files [ 0 ] , permissions : [ Permission . read ( Role . any ( ) ) , Permission . update ( Role . user ( '[USER_ID]' ) ) , Permission . delete ( Role . user ( '[USER_ID]' ) ) , ] } ) ; When to set permissions: Set document/file-level permissions when you need per-resource access control. If all documents in a collection share the same rules, configure permissions at the collection/bucket level and leave document permissions empty. Common mistakes: Forgetting permissions — the resource becomes inaccessible to all users (including the creator) Role.any() with write / update / delete — allows any user, including unauthenticated guests, to modify or remove the resource Permission.read(Role.any()) on sensitive data — makes the resource publicly readable

返回排行榜