### Install Dependencies and Run Dev Server Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/first-realtime-app.mdx After creating the project, install its dependencies and start the development server. ```bash cd pnpm install pnpm run dev ``` -------------------------------- ### Clone TrailBase Example Project Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/first-realtime-app.mdx Clone the repository and navigate to the example project directory to get started. ```bash $ git clone ${repo} $ cd trailbase/examples/collab-clicker-ssr ``` -------------------------------- ### Installation Bundle Directory Setup Source: https://github.com/trailbaseio/trailbase/blob/main/examples/blog/flutter/linux/CMakeLists.txt Configures the installation prefix to create a relocatable bundle in the build directory and starts with a clean bundle directory on each install. ```cmake # === Installation === # By default, "installing" just makes a relocatable bundle in the build # directory. set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) endif() # Start with a clean build bundle directory every time. install(CODE " file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") " COMPONENT Runtime) set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") ``` -------------------------------- ### Install and Develop UI Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/first-ui-app.mdx Install project dependencies and start the development server for your UI application. This enables hot-reloading for rapid development. ```bash $ npm install && npm dev ``` -------------------------------- ### Build and Run TrailBase Blog Manually Source: https://github.com/trailbaseio/trailbase/blob/main/examples/blog/README.md Manual build and run instructions for the TrailBase blog example. Requires cargo, pnpm, and flutter to be installed. ```bash # Build the Blog's web UI: pnpm --dir web build # Build and start TrailBase: cargo run -- run --public-dir web/dist # Build and start the Flutter app on a specified device, e.g. Chrome, Linux, Emulator. cd flutter flutter run -d Chrome ``` -------------------------------- ### Start TrailBase Blog with Docker Compose Source: https://github.com/trailbaseio/trailbase/blob/main/examples/blog/README.md Use this command to quickly set up and run the TrailBase blog example with a reverse proxy for TLS termination. Access the blog at http://localhost. ```bash cd examples/blog docker compose up --build -d ``` -------------------------------- ### Install Trailbase One-Liners Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/_getting_trailbase.mdx Use these commands to quickly install Trailbase. Ensure you have the necessary prerequisites installed. ```bash npm create trailbase@latest # or yarn create trailbase # or pnpm create trailbase ``` -------------------------------- ### Install TrailBase on Windows Source: https://github.com/trailbaseio/trailbase/blob/main/README.md Use this PowerShell command to install TrailBase by downloading and executing the installation script. ```powershell iwr https://trailbase.io/install.ps1 | iex ``` -------------------------------- ### Install Application Executable Source: https://github.com/trailbaseio/trailbase/blob/main/examples/blog/flutter/linux/CMakeLists.txt Installs the application executable to the specified destination within the bundle. ```cmake install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) ``` -------------------------------- ### TypeScript API Example Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_js.mdx Register a parameterized route, query the database, and return a string body or HTTP error. Requires WASM component setup. ```typescript import { HandleRequest, HttpRequest, HttpResponse, RouteParams, } from "@/lib/trailbase.ts"; export const onRequest: HandleRequest = async ( req: HttpRequest, params: RouteParams ): Promise => { const table = params.table; if (!table) { return new HttpResponse(400, "Table name is required."); } const result = await req.db.query( `SELECT * FROM ${table} LIMIT 1` ); if (result.error) { return new HttpResponse(500, `Database error: ${result.error.message}`); } return new HttpResponse(200, JSON.stringify(result.data)); }; ``` -------------------------------- ### Run TrailBase WASM Component in Development Source: https://github.com/trailbaseio/trailbase/blob/main/examples/wasm-guest-js/README.md Use this command to start a TrailBase server with the component and enable a file watcher for automatic reloads. Ensure `trail` is installed and in your PATH. ```bash npm run dev ``` -------------------------------- ### Clone TrailBase Example Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/first-ui-app.mdx Clone the TrailBase repository and navigate to the coffee vector search example directory. ```bash $ git clone https://github.com/trailbaseio/trailbase $ cd trailbase/examples/coffee-vector-search ``` -------------------------------- ### Install Trailbase on Linux/macOS Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/_install_oneliners.mdx Use this command to download and execute the installation script on Linux and macOS systems. ```sh curl -sSL https://trailbase.io/install.sh | bash ``` -------------------------------- ### Start TrailBase with Podman Source: https://github.com/trailbaseio/trailbase/blob/main/deploy/k8s/README.md Use this command to start TrailBase and expose it on port 4010. Ensure 'trailbase-deployment.yml' is in the current directory. ```bash $ podman play kube trailbase-deployment.yml --publish=4010:4000 ``` -------------------------------- ### Check TrailBase Installation Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/install.mdx Run this command after installation to verify the executable is properly set up and to list all available command-line options. ```sh trail help ``` -------------------------------- ### Setup TypeScript Endpoint Project Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/first-ui-app.mdx Initializes a Node.js ESM project for a TypeScript endpoint, installs necessary dependencies including Vite and Trailbase WASM, and configures TypeScript and Vite. ```bash mkdir endpoint cd endpoint # Init a node ESM project: npm init -y npm pkg set type="module"; # Install dependencies: npm install -D vite typescript ts-node eslint prettier @types/node @bytecodealliance/jco npm install trailbase-wasm # Init TypeScript: npx tsc --init touch index.ts # Init Vite: echo "import { defineConfig } from 'vite'\n\nexport default defineConfig({ build: { lib: { entry: './index.ts', formats: ['es'], fileName: 'index', }, rollupOptions: { preserveEntrySignatures: 'strict', external: /(wasi|trailbase):.*/, }, }, })" > vite.config.ts # Build empty 'index.ts' to check everything works: npx vite build ``` -------------------------------- ### Build Web App Source: https://github.com/trailbaseio/trailbase/blob/main/examples/coffee-vector-search/README.md Install dependencies and build the web application using pnpm. ```bash $ pnpm i $ pnpm build ``` -------------------------------- ### Record API Configuration Example Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_record.mdx Example of how to configure a Record API in the TrailBase configuration file to expose user profiles. ```APIDOC ## Configuration Record APIs can be configured via the admin dashboard or directly in TrailBase's configuration file. An example API setup for managing user profiles: ```textproto # file: /config.textproto # schema-file: /crates/core/proto/config.proto record_apis: [ { name: "profiles" table_name: "profiles" conflict_resolution: REPLACE acl_authenticated: [READ, CREATE] create_access_rule: "_REQ_.user = _USER_.id" }, ] ``` A quick explanation: * The `name` needs to be unique. It's what is used to access the API via `{apiPath({name:"name", prefix:"http://"})}` * `table_name` references the `TABLE` or `VIEW` that is being exposed. * `conflict_resolution` declares what should happen if a newly created record is conflicting with an existing one. * `autofill_missing_user_id_column` lets you omit fields for columns with a foreign key relationship to `_user(id)`. The field will then be filled with the credentials of the authenticated user. In most cases, this should probably be off, this only useful if you cannot explicitly provide the user id yourself, e.g. in a static HTML form. * `acl_world` and `acl_authenticated` define that anyone can read avatars but only authenticated users can modify them. The following `access_rules` further narrow mutations to records where the `user` column (or request field for insertions) match. In other words, user X cannot modify user Y's avatar. Note that and `TABLE`/`VIEW` can be exposed multiple times as different APIs with different properties. ``` -------------------------------- ### Install Flutter Library Source: https://github.com/trailbaseio/trailbase/blob/main/examples/blog/flutter/linux/CMakeLists.txt Installs the main Flutter library file to the lib directory within the bundle. ```cmake install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) ``` -------------------------------- ### Install Bundled Plugin Libraries Source: https://github.com/trailbaseio/trailbase/blob/main/examples/blog/flutter/linux/CMakeLists.txt Installs any bundled libraries from plugins to the lib directory within the bundle. ```cmake foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) install(FILES "${bundled_library}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endforeach(bundled_library) ``` -------------------------------- ### Setup Rust Endpoint Project Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/first-ui-app.mdx Initializes a new Rust library project for a Trailbase WASM endpoint and adds the trailbase-wasm dependency. ```bash cargo init --lib endpoint cd endpoint cargo add trailbase-wasm echo ' [lib] crate-type = ["cdylib"] ' >> Cargo.toml ``` -------------------------------- ### Create Record API Examples Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_record.mdx Provides examples for creating new records using the TrailBase Record API across various programming languages. These snippets demonstrate how to interact with the create endpoint. ```typescript import { TrailbaseClient } from "@trailbase/client"; const client = new TrailbaseClient("YOUR_API_KEY"); async function createRecord() { const record = { name: "John Doe", email: "john.doe@example.com", age: 30 }; try { const createdRecord = await client.create("users", record); console.log("Record created:", createdRecord); } catch (error) { console.error("Error creating record:", error); } } createRecord(); ``` ```dart import 'package:trailbase_client/trailbase_client.dart'; Future createRecord() async { final client = TrailbaseClient('YOUR_API_KEY'); final record = { 'name': 'Jane Doe', 'email': 'jane.doe@example.com', 'age': 28, }; try { final createdRecord = await client.create('users', record); print('Record created: $createdRecord'); } catch (e) { print('Error creating record: $e'); } } createRecord(); ``` ```swift import TrailbaseClient func createRecord() { let client = TrailbaseClient(apiKey: "YOUR_API_KEY") let record: [String: Any] = [ "name": "Peter Jones", "email": "peter.jones@example.com", "age": 45 ] client.create(collection: "users", record: record) { result in switch result { case .success(let createdRecord): print("Record created: \(createdRecord)") case .failure(let error): print("Error creating record: \(error)") } } } createRecord() ``` ```kotlin import com.example.trailbase.client.TrailbaseClient fun createRecord() { val client = TrailbaseClient("YOUR_API_KEY") val record = mapOf( "name" to "Alice Smith", "email" to "alice.smith@example.com", "age" to 22 ) client.create("users", record) { result -> result.onSuccess { println("Record created: $it") }.onFailure { println("Error creating record: ${it.message}") } } } createRecord() ``` ```cs using Trailbase.Client; using System; using System.Collections.Generic; public class RecordApiExample { public static void CreateRecord() { var client = new TrailbaseClient("YOUR_API_KEY"); var record = new Dictionary { { "name", "Bob Johnson" }, { "email", "bob.johnson@example.com" }, { "age", 50 } }; client.Create("users", record, (result) => { if (result.IsSuccess) { Console.WriteLine($"Record created: {result.Value}"); } else { Console.WriteLine($"Error creating record: {result.Error.Message}"); } }); } } RecordApiExample.CreateRecord(); ``` ```rust use trailbase_client::TrailbaseClient; #[tokio::main] async fn main() -> Result<(), Box> { let client = TrailbaseClient::new("YOUR_API_KEY"); let record = serde_json::json!({ "name": "Charlie Brown", "email": "charlie.brown@example.com", "age": 15 }); match client.create("users", record).await { Ok(created_record) => { println!("Record created: {}", created_record); } Err(e) => { eprintln!("Error creating record: {}", e); } } Ok(()) } ``` ```go package main import ( "fmt" "github.com/trailbase/client-go" ) func main() { client := trailbase_client.NewClient("YOUR_API_KEY") record := map[string]interface{}{ "name": "Diana Prince", "email": "diana.prince@example.com", "age": 35, } createdRecord, err := client.Create("users", record) if err != nil { fmt.Printf("Error creating record: %v\n", err) return } fmt.Printf("Record created: %v\n", createdRecord) } ``` ```python from trailbase_client import TrailbaseClient client = TrailbaseClient("YOUR_API_KEY") record = { "name": "Ethan Hunt", "email": "ethan.hunt@example.com", "age": 40 } try: created_record = client.create("users", record) print(f"Record created: {created_record}") except Exception as e: print(f"Error creating record: {e}") ``` ```sh curl -X POST \ http://localhost:8080/api/v1/users \ -H 'Content-Type: application/json' \ -d '{ "name": "Fiona Glenanne", "email": "fiona.glenanne@example.com", "age": 32 }' ``` -------------------------------- ### Permissions Example Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_record.mdx Example of a custom SQL access rule to validate a secret key and group membership. ```APIDOC ### Permissions Access can be controlled through combination of a simple ACL-based system (a matrix of who and what) and custom SQL access rules of the nature: `f(req, user, row) -> bool`. Generally, the ACLs are checked first and then the access rules are evaluated when present. For example, to validate that the requester provided a secret key and is member of a group `'mygroup'`: ```sql (_REQ_.secret = 'foo' AND EXISTS( SELECT 1 FROM groups WHERE groups.member = _USER_.id AND groups.name = 'mygroup' )) ``` * `_REQ_` is an injected sub-query containing a user request's fields. It is available in the access rules for `CREATE` and `UPDATE` operations. Fields that were either absent in the request or explicitly passed as `null`, will be `NULL`. * To check for the presence of a specific field in a `CREATE` or `UPDATE` request, you can use `'field' IN _REQ__FIELDS_`. Note that `_REQ_FIELDS_` may only contain fields with a corresponding column in the underlying `TABLE` or `VIEW`. * Similarly, `_ROW_` is a sub-query of the target record. It is available in the access rules for `READ`, `UPDATE`, and `DELETE` operations. * Lastly, `_USER_.id` references the id of the currently authenticated user and `NULL` otherwise. Independently, you can use `VIEW`s to filter which rows and columns of your `TABLE`s should be accessible. #### Building Access Groups and Capabilities As hinted at by the example above, the SQL access rules can be used to build higher-level access protection such as group ACLs or capabilities. What makes the most sense in your case, is very application dependent. The `/examples/blog` has an "editor" group to control who can write blog posts. Somewhat on a tangent, group and capability tables can themselves be exposed via Record APIs. This can be used to programmatically manage permissions, e.g. for building a moderation dashboard. When exposing authorization primitives, make sure the permissions are appropriately tight to avoid permission escalations. ``` -------------------------------- ### Rust API Example Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_js.mdx Register an HTTP route, read query parameters, query the database, and return a JSON response or errors. This example is for Rust WASM components. ```rust use trailbase_sdk::prelude::*; #[handler] async fn handle_request(req: HttpRequest) -> HttpResponse { let query = req.params.get("query").unwrap_or_default(); let limit = req.params.get("limit").and_then(|l| l.parse::().ok()).unwrap_or(10); match req.db.query(&format!("SELECT * FROM items WHERE name LIKE '%{}%' LIMIT {}", query, limit)).await { Ok(data) => HttpResponse::ok_json(data), Err(e) => HttpResponse::error(500, &format!("Database error: {}", e.message)), } } ``` -------------------------------- ### Cross-Building Sysroot Setup Source: https://github.com/trailbaseio/trailbase/blob/main/examples/blog/flutter/linux/CMakeLists.txt Sets up the sysroot and find root path modes for cross-building when FLUTTER_TARGET_PLATFORM_SYSROOT is defined. ```cmake # Root filesystem for cross-building. if(FLUTTER_TARGET_PLATFORM_SYSROOT) set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) endif() ``` -------------------------------- ### Read Record API Examples Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_record.mdx Examples for reading a specific record by its ID across different languages. ```ts import { TrailbaseClient } from "@trailbase/client"; const client = new TrailbaseClient(); async function readRecord(id: string) { const record = await client.record.read(id); console.log(record); } ``` ```dart import "package:trailbase_client/trailbase_client.dart"; final client = TrailbaseClient(); Future readRecord(String id) async { final record = await client.record.read(id); print(record); } ``` ```swift import TrailbaseClient let client = TrailbaseClient() func readRecord(id: String) async { do { let record = try await client.record.read(id: id) print(record) } catch { print("Error reading record: \(error)") } } ``` ```kotlin import com.trailbase.client.TrailbaseClient val client = TrailbaseClient() import kotlinx.coroutines.runBlocking fun readRecord(id: String) = runBlocking { val record = client.record.read(id) println(record) } ``` ```cs using Trailbase.Client; var client = new TrailbaseClient(); var record = await client.Record.ReadAsync(id: "your_record_id"); Console.WriteLine(record); ``` ```rust use trailbase_client::TrailbaseClient; #[tokio::main] async fn main() -> anyhow::Result<()> { let client = TrailbaseClient::new(); let record = client.record().read("your_record_id").await?; println!("{}", record); Ok(()) } ``` ```go package main import ( "fmt" "github.com/trailbase/client-go" ) func main() { client := trailbase.NewClient() record, err := client.Record.Read("your_record_id") if err != nil { panic(err) } fmt.Println(record) } ``` ```python from record_api_py.client import TrailbaseClient client = TrailbaseClient() record = client.record.read("your_record_id") print(record) ``` ```sh curl -X GET "https://your-trailbase-domain.com/api/v1/record/your_record_id" \ -H "Authorization: Bearer YOUR_API_KEY" ``` -------------------------------- ### Example SQL Migration Statement Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/migrations.mdx This is an example of a SQL statement that can be added to a migration file to create a new table with an integer primary key and strict constraints. ```sql CREATE TABLE new_table (id INTEGER PRIMARY KEY) STRICT ``` -------------------------------- ### Start Vite Dev Server Source: https://github.com/trailbaseio/trailbase/blob/main/crates/assets/js/admin/README.md After starting the TrailBase binary in dev mode, run the Vite dev server for hot module reloading during frontend development. ```bash $ pnpm run dev ``` -------------------------------- ### Build TrailBase from Source (Windows Symlink Config) Source: https://github.com/trailbaseio/trailbase/blob/main/README.md Configuration step for Windows to enable symlinks for Git, followed by submodule updates and dependency installation. ```sh # Windows only: make sure to enable symlinks (w/o `mklink` permissions for your # user, git will fall back to copies). git config core.symlinks true && git reset --hard # Download necessary git sub-modules. git submodule update --init --recursive # Install Javascript dependencies first. Required for the next step. pnpm install # Build the executable. Adding `--release` will yield a more optimized binary # but slow builds significantly. cargo build --bin trail ``` -------------------------------- ### Install ICU Data File Source: https://github.com/trailbaseio/trailbase/blob/main/examples/blog/flutter/linux/CMakeLists.txt Installs the ICU data file to the data directory within the bundle. ```cmake install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) ``` -------------------------------- ### Install Native Assets Source: https://github.com/trailbaseio/trailbase/blob/main/examples/blog/flutter/linux/CMakeLists.txt Installs native assets provided by build.dart from all packages to the lib directory within the bundle. ```cmake # Copy the native assets provided by the build.dart from all packages. set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") install(DIRECTORY "${NATIVE_ASSETS_DIR}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) # Fully re-copy the assets directory on each build to avoid having stale files ``` -------------------------------- ### Run TrailBase Server Source: https://github.com/trailbaseio/trailbase/blob/main/README.md Command to start the TrailBase server. It will bootstrap a data directory and create an admin user on the first run. ```sh trail run ``` -------------------------------- ### Record API Filtering Examples Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_record.mdx Examples demonstrating how to filter records using date ranges and numeric ranges. ```APIDOC ## GET /api/records/v1/events ### Description Retrieves events within a specified date range. ### Method GET ### Endpoint /api/records/v1/events ### Query Parameters - **filter[date][$gte]** (string) - Required - The start date for filtering (inclusive). - **filter[date][$lte]** (string) - Required - The end date for filtering (inclusive). ### Request Example ``` GET /api/records/v1/events?filter[date][$gte]=2025-01-01&filter[date][$lte]=2025-12-31 ``` ## GET /api/records/v1/products ### Description Finds products within a specified price range. ### Method GET ### Endpoint /api/records/v1/products ### Query Parameters - **filter[price][$gte]** (number) - Required - The minimum price for filtering (inclusive). - **filter[price][$lt]** (number) - Required - The maximum price for filtering (exclusive). ### Request Example ``` GET /api/records/v1/products?filter[price][$gte]=10.00&filter[price][$lt]=50.00 ``` ``` -------------------------------- ### Install Flutter Assets Source: https://github.com/trailbaseio/trailbase/blob/main/examples/blog/flutter/linux/CMakeLists.txt Installs Flutter assets to the application bundle. It first removes any existing assets directory and then copies the new one. ```cmake set(FLUTTER_ASSET_DIR_NAME "flutter_assets") install(CODE " file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") " COMPONENT Runtime) install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) ``` -------------------------------- ### Start TrailBase Binary in Dev Mode Source: https://github.com/trailbaseio/trailbase/blob/main/crates/assets/js/admin/README.md Run the TrailBase binary in development mode to enable permissive CORS and cookie policies, necessary for frontend development. ```bash $ cargo run -- --data-dir client/testfixture run --dev ``` -------------------------------- ### Create a SQL VIEW for Server-Side Joins Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/models_and_relations.mdx Provides an example of creating a SQL VIEW to implement server-side joins for complex relations, pushing join logic to the server instead of handling it on the client. ```sql CREATE VIEW post_tag_view AS SELECT * FROM post AS P LEFT JOIN post_tag AS PT ON P.id = PT.post LEFT JOIN tag AS T ON T.ID = PT.tag; ``` -------------------------------- ### Install AOT Library (Non-Debug) Source: https://github.com/trailbaseio/trailbase/blob/main/examples/blog/flutter/linux/CMakeLists.txt Installs the Ahead-Of-Time (AOT) compiled library to the application bundle. This is conditionally executed only for non-Debug build types. ```cmake # Install the AOT library on non-Debug builds only. if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() ``` -------------------------------- ### Update Record API Examples Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_record.mdx Examples for partially updating an existing record by its ID across different languages. ```ts import { TrailbaseClient } from "@trailbase/client"; const client = new TrailbaseClient(); async function updateRecord(id: string, data: Record) { const record = await client.record.update(id, data); console.log(record); } ``` ```dart import "package:trailbase_client/trailbase_client.dart"; final client = TrailbaseClient(); Future updateRecord(String id, Map data) async { final record = await client.record.update(id, data); print(record); } ``` ```swift import TrailbaseClient let client = TrailbaseClient() func updateRecord(id: String, data: [String: Any]) async { do { let record = try await client.record.update(id: id, data: data) print(record) } catch { print("Error updating record: \(error)") } } ``` ```kotlin import com.trailbase.client.TrailbaseClient val client = TrailbaseClient() import kotlinx.coroutines.runBlocking fun updateRecord(id: String, data: Map) = runBlocking { val record = client.record.update(id, data) println(record) } ``` ```cs using Trailbase.Client; var client = new TrailbaseClient(); var record = await client.Record.UpdateAsync(id: "your_record_id", data: new Dictionary { { "field", "value" } }); Console.WriteLine(record); ``` ```rust use trailbase_client::TrailbaseClient; #[tokio::main] async fn main() -> anyhow::Result<()> { let client = TrailbaseClient::new(); let mut data = std::collections::HashMap::new(); data.insert("field", "value"); let record = client.record().update("your_record_id", data).await?; println!("{}", record); Ok(()) } ``` ```go package main import ( "fmt" "github.com/trailbase/client-go" ) func main() { client := trailbase.NewClient() data := map[string]interface{}{ "field": "value", } record, err := client.Record.Update("your_record_id", data) if err != nil { panic(err) } fmt.Println(record) } ``` ```python from record_api_py.client import TrailbaseClient client = TrailbaseClient() data = { "field": "value" } record = client.record.update("your_record_id", data) print(record) ``` ```sh curl -X PATCH "https://your-trailbase-domain.com/api/v1/record/your_record_id" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"field": "value"}' ``` -------------------------------- ### TypeScript Example for Writing Data Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/first-cli-app.mdx This TypeScript program demonstrates how to use the TrailBase client to write data. It assumes you have generated type definitions and are using them to interact with the API. ```typescript import fillCode from "@root/examples/data-cli-tutorial/src/fill.ts?raw"; ``` -------------------------------- ### TypeScript JSON Response Example Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_js.mdx Read query parameters and produce a JSON response. This example is suitable for handling requests that require structured data output. ```typescript import { HandleRequest, HttpRequest, HttpResponse, RouteParams, } from "@/lib/trailbase.ts"; export const onRequest: HandleRequest = async ( req: HttpRequest, params: RouteParams ): Promise => { const query = params.query; const limit = params.limit ? parseInt(params.limit as string) : 10; const result = await req.db.query( `SELECT * FROM items WHERE name LIKE '%${query}%' LIMIT ${limit}` ); if (result.error) { return new HttpResponse(500, `Database error: ${result.error.message}`); } return new HttpResponse(200, JSON.stringify(result.data)); }; ``` -------------------------------- ### SQL Access Rule Example Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_record.mdx An example SQL access rule to validate that a requester provided a secret key and is a member of a specific group. This demonstrates how to use request fields (_REQ_) and user information (_USER_) within access control. ```sql (_REQ_.secret = 'foo' AND EXISTS( SELECT 1 FROM groups WHERE groups.member = _USER_.id AND groups.name = 'mygroup' )) ``` -------------------------------- ### Subscribe to Record Changes in Multiple Languages Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_record.mdx Examples demonstrating how to subscribe to real-time changes (insertions, updates, deletions) in tables or specific records using various programming languages. ```ts import { RecordClient } from "@trailbase/client"; const client = new RecordClient(); async function subscribeToEvents() { const stream = await client.records("events").subscribe(); for await (const change of stream) { console.log(change); } } ``` ```dart import 'package:client/client.dart'; final client = RecordClient(); Future subscribeToEvents() async { final stream = await client.records('events').subscribe(); await for (final change in stream) { print(change); } } ``` ```cs using Trailbase.Client; var client = new RecordClient(); public async Task SubscribeToEvents() { var stream = await client.Records("events").SubscribeAsync(); await foreach (var change in stream) { Console.WriteLine(change); } } ``` ```rust use client::RecordClient; #[tokio::main] async fn main() -> Result<(), Box> { let client = RecordClient::new(); let mut stream = client.records("events").subscribe().await?; while let Some(change) = stream.next().await { println!("{:?}", change?); } Ok(()) } ``` -------------------------------- ### Requesting Joins with Expansions Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/models_and_relations.mdx Demonstrates how to request joins for configured foreign key columns during read and list operations using the 'expand' query parameter. The example shows a curl command and the expected JSON response with nested 'post' and 'tag' data. ```shell curl -H "Content-Type: application/json" \ $\{SITE\}/api/records/v1/post_tag/1?expand=post,tag { "post": { "id": 1, "data": { "id": 1, "author": "AZUECMTAfqOZJjHfEzAqkA==", "title": "first post", "body": "body" } }, "tag": { "id": 5, "data": { "id": 5, "label": "whimsical" } } } ``` -------------------------------- ### Generate Protobuf Code Source: https://github.com/trailbaseio/trailbase/blob/main/crates/assets/js/admin/README.md Execute the command to generate protobuf code using ts-proto. Ensure system dependencies like protoc and descriptor.proto are installed. ```bash $ pnpm run proto ``` -------------------------------- ### SQL Table Creation with Geometry Column Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_record.mdx Example SQL statement to create a table with a geometry column, including a check constraint for valid geometry. ```sql CREATE TABLE table_with_geometry ( id INTEGER PRIMARY KEY, geometry BLOB CHECK(ST_IsValid(geometry)) ) STRICT; ``` -------------------------------- ### Express.js SSR Handler Example Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/first-realtime-app.mdx A simplified implementation of an Express.js handler for Server-Side Rendering, demonstrating how to render the application and serve the HTML template. ```typescript async function handler(req, res) { const render = (await import('./dist/server/entry-server.js')).render; // 1. Call render function. const rendered = await render(req.url); // 2. Build HTML template. const html = templateHtml .replace(``, generateHydrationScript()) .replace(``, rendered.html); res.status(200).set({ 'Content-Type': 'text/html' }).send(html) } ``` -------------------------------- ### Install Trailbase with Docker Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/_install_oneliners.mdx This alias sets up and runs Trailbase using Docker. It maps port 4000 and mounts a local directory for persistent data. Add this alias to your shell's rc file to make it permanent. ```sh # Mimic "install" with Docker. Add the alias to your shell's rc to persist. alias trail=' mkdir -p traildepot && \ docker run \ -p 4000:4000 \ -e ADDRESS=0.0.0.0:4000 \ --mount type=bind,source="$PWD"/traildepot,target=/app/traildepot \ trailbase/trailbase /app/trail' ``` -------------------------------- ### List Records in Multiple Languages Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_record.mdx Examples of how to list records with complex filtering criteria across various programming languages. This includes filtering by watch time, description content, and ranking. ```ts import { RecordClient } from "@trailbase/client"; const client = new RecordClient(); async function listMovies() { const response = await client.records("movies").list({ filter: { watch_time: { $lt: 7200 }, description: { $contains: "love" }, }, sort: [{ rank: "desc" }], limit: 3, }); return response.data; } ``` ```dart import 'package:client/client.dart'; final client = RecordClient(); Future>> listMovies() async { final response = await client.records('movies').list( filter: { 'watch_time': {'lt': 7200}, 'description': {'contains': 'love'}, }, sort: [{'rank': 'desc'}], limit: 3, ); return response.data; } ``` ```swift import Client let client = RecordClient() func listMovies() async throws -> [Record] { let response = try await client.records("movies").list( filter: [ "watch_time": AnyEncodable(Filter.lessThan(7200)), "description": AnyEncodable(Filter.contains("love")), ], sort: [Sort(field: "rank", direction: .descending)], limit: 3 ) return response.data } ``` ```kotlin import com.example.client.RecordClient val client = RecordClient() @OptIn(ExperimentalStdlibApi::class) suspend fun listMovies(): List> { val response = client.records("movies").list( filter = mapOf( "watch_time" to mapOf("$lt" to 7200), "description" to mapOf("contains" to "love") ), sort = listOf(Sort("rank", Sort.Direction.DESCENDING)), limit = 3 ) return response.data } ``` ```cs using Trailbase.Client; var client = new RecordClient(); public async Task>> ListMovies() { var response = await client.Records("movies").ListAsync( new ListOptions { Filter = new Dictionary { { "watch_time", new Dictionary { { "$lt", 7200 } } }, { "description", new Dictionary { { "contains", "love" } } } }, Sort = new List { new Dictionary { { "rank", "desc" } } }, Limit = 3 } ); return response.Data; } ``` ```rust use client::RecordClient; #[tokio::main] async fn main() -> Result<(), Box> { let client = RecordClient::new(); let response = client.records("movies").list( client::ListOptions { filter: Some(serde_json::json!({ "watch_time": { "$lt": 7200 }, "description": { "contains": "love" }, })), sort: Some(serde_json::json!([{ "rank": "desc" }])), limit: Some(3), ..Default::default() }, ) .await?; println!("{:?}", response.data); Ok(()) } ``` ```go package main import ( "fmt" "github.com/trailbaseio/trailbase-client-go" ) func main() { client := trailbaseclient.NewRecordClient() response, err := client.Records("movies").List( trailbaseclient.ListOptions{ Filter: map[string]interface{}{ "watch_time": map[string]interface{}{"$lt": 7200}, "description": map[string]interface{}{"contains": "love"}, }, Sort: []map[string]interface{}{{ "rank": "desc", }}, Limit: 3, }, ) if err != nil { panic(err) } fmt.Println(response.Data) } ``` ```python from record_api_py.client import RecordClient client = RecordClient() def list_movies(): response = client.records("movies").list( filter={ "watch_time": {"$lt": 7200}, "description": {"contains": "love"}, }, sort=[{"rank": "desc"}], limit=3, ) return response.data ``` ```sh curl -X POST \ http://localhost:8080/api/records/v1/movies/query \ -H 'Content-Type: application/json' \ -d '{ "filter": { "watch_time": {"$lt": 7200}, "description": {"contains": "love"} }, "sort": [{"rank": "desc"}], "limit": 3 }' ``` -------------------------------- ### Bootstrap Database with SQLite CLI Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/first-cli-app.mdx Manually create the database file and apply the schema using the sqlite3 CLI, useful for pre-existing datasets. ```bash mkdir traildepot/data sqlite3 traildepot/data/main.db < traildepot/migrations/U1728810800__create_table_movies.sql ``` -------------------------------- ### Initiate Authentication Code Flow with PKCE Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/auth.mdx Use these parameters when initiating the authentication code flow with PKCE to `/api/auth/v1/login` or `/api/auth/v1/oauth//login`. Native apps must register their custom scheme first. ```url response_type=code pkce_code_challenge= redirect_uri= ``` -------------------------------- ### Delete Record API Examples Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_record.mdx Examples for deleting a specific record by its ID across different languages. ```ts import { TrailbaseClient } from "@trailbase/client"; const client = new TrailbaseClient(); async function deleteRecord(id: string) { await client.record.delete(id); console.log(`Record ${id} deleted successfully.`); } ``` ```dart import "package:trailbase_client/trailbase_client.dart"; final client = TrailbaseClient(); Future deleteRecord(String id) async { await client.record.delete(id); print('Record $id deleted successfully.'); } ``` ```swift import TrailbaseClient let client = TrailbaseClient() func deleteRecord(id: String) async { do { try await client.record.delete(id: id) print("Record \(id) deleted successfully.") } catch { print("Error deleting record: \(error)") } } ``` ```kotlin import com.trailbase.client.TrailbaseClient val client = TrailbaseClient() import kotlinx.coroutines.runBlocking fun deleteRecord(id: String) = runBlocking { client.record.delete(id) println("Record $id deleted successfully.") } ``` ```cs using Trailbase.Client; var client = new TrailbaseClient(); await client.Record.DeleteAsync(id: "your_record_id"); Console.WriteLine("Record your_record_id deleted successfully."); ``` ```rust use trailbase_client::TrailbaseClient; #[tokio::main] async fn main() -> anyhow::Result<()> { let client = TrailbaseClient::new(); client.record().delete("your_record_id").await?; println!("Record your_record_id deleted successfully."); Ok(()) } ``` ```go package main import ( "fmt" "github.com/trailbase/client-go" ) func main() { client := trailbase.NewClient() err := client.Record.Delete("your_record_id") if err != nil { panic(err) } fmt.Println("Record your_record_id deleted successfully.") } ``` ```python from record_api_py.client import TrailbaseClient client = TrailbaseClient() client.record.delete("your_record_id") print("Record your_record_id deleted successfully.") ``` ```sh curl -X DELETE "https://your-trailbase-domain.com/api/v1/record/your_record_id" \ -H "Authorization: Bearer YOUR_API_KEY" ``` -------------------------------- ### Build and Run Docker Container Source: https://github.com/trailbaseio/trailbase/blob/main/examples/coffee-vector-search/README.md Build the Docker image for the coffee search application and run it, exposing port 4001. ```bash $ docker build . -t coffee && docker run -p 4001:4000 coffee ``` -------------------------------- ### Docker Build and Run Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/first-ui-app.mdx Build a Docker image for your TrailBase application and run it. This command bundles the application and its dependencies for easy deployment. ```bash $ docker build -t coffee . && docker run -p 4000:4000 coffee ``` -------------------------------- ### Create a Blog Post Table Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/models_and_relations.mdx Defines a 'post' table with an ID, creation timestamp, author reference, title, and body. It includes a foreign key constraint for the author and cascading delete behavior. ```sql CREATE TABLE post ( id INTEGER PRIMARY KEY, created INTEGER NOT NULL DEFAULT (UNIXEPOCH()), author INTEGER NOT NULL REFERENCES _user ON DELETE CASCADE, title TEXT NOT NULL, body TEXT NOT NULL ); ``` -------------------------------- ### Create New Migration File Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/migrations.mdx Use this command to create a new, empty migration file with the current timestamp in the `traildepot/migrations/` directory. You can then rename it and add your SQL statements. ```bash trail migration ``` -------------------------------- ### Get Schema Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/documentation/apis_record.mdx Retrieves the schema definition for a record API. ```APIDOC ## GET /{recordApiName}/schema ### Description Retrieves the schema definition for a record API. ### Method GET ### Endpoint /{recordApiName}/schema ### Parameters #### Path Parameters - **recordApiName** (string) - Required - The name of the record API. ### Response #### Success Response (200) - **schema** (object) - The schema definition of the record API. #### Response Example ```json { "example": "response body" } ``` ``` -------------------------------- ### Stop TrailBase Blog with Docker Compose Source: https://github.com/trailbaseio/trailbase/blob/main/examples/blog/README.md Use this command to shut down the services started by Docker Compose. ```bash docker compose down ``` -------------------------------- ### View TrailBase Container Logs Source: https://github.com/trailbaseio/trailbase/blob/main/deploy/k8s/README.md Retrieve the logs from the TrailBase container to get generated login credentials. ```bash $ podman logs trailbase-deployment-pod-trailbase ``` -------------------------------- ### Build UI for Production Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/first-ui-app.mdx Compile your JSX/TSX web UI into static HTML, JavaScript, and CSS artifacts. These are the files that will be served to the browser. ```bash $ npm install && npm build ``` -------------------------------- ### SSR Render Function Call Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/first-realtime-app.mdx Illustrates the core concept of calling a render function to get the HTML body for SSR. ```typescript import { render } from "dist/server/entry-server.js"; const htmlBody : string = render(/*...*/); ``` -------------------------------- ### System Dependencies (GTK) Source: https://github.com/trailbaseio/trailbase/blob/main/examples/blog/flutter/linux/CMakeLists.txt Finds and checks for the GTK+ 3.0 system library using PkgConfig. ```cmake # System-level dependencies. find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") ``` -------------------------------- ### Test Public Endpoint with Curl Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/first-ui-app.mdx After deploying your custom server-side endpoint, test its functionality by sending a GET request with specific query parameters. ```bash $ curl "http://localhost:4000/search?aroma=8&flavor=8&acidity=8&sweetness=8" [ ["juan luis alvarado romero",7.92,7.58,7.58,8], ["eileen koyanagi",7.5,7.33,7.58,8], ... ] ``` -------------------------------- ### Find and check system libraries Source: https://github.com/trailbaseio/trailbase/blob/main/examples/blog/flutter/linux/flutter/CMakeLists.txt Uses PkgConfig to find and check for required system libraries: GTK, GLIB, and GIO. These are essential for Flutter's Linux integration. ```cmake find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) ``` -------------------------------- ### Add TrailBase Auth UI Component Source: https://github.com/trailbaseio/trailbase/blob/main/README.md Command to install the authentication UI component for TrailBase, which adds a WASM component for additional UI endpoints. ```sh trail components add trailbase/auth_ui ``` -------------------------------- ### OTP Sign-in Link Generation Source: https://github.com/trailbaseio/trailbase/blob/main/crates/assets/templates/default_email_otp_body.html This snippet shows how to construct a sign-in link using email, OTP code, and an optional redirect URI. Ensure all placeholders are correctly substituted before sending. ```html [{{ CODE }}]({{ SITE_URL }}/_/auth/otp/login?email={{ EMAIL }}&code={{ CODE }}{%- if REDIRECT_URI -%}&redirect_uri={{ REDIRECT_URI }}{%- endif -%}) ``` -------------------------------- ### Generate Vite App Source: https://github.com/trailbaseio/trailbase/blob/main/examples/collab-clicker-ssr/README.md Use this command to create a new Vite project. Follow the template assistant to select the SSR template for your chosen framework. ```bash pnpm create vite@latest ``` -------------------------------- ### Manage TrailBase User Credentials Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/install.mdx Commands to change the password and email for the admin user. Useful for setting up custom credentials after the initial server start. ```sh trail user change-password admin@localhost mypassword trail user change-email admin@localhost me@mydomain.org ``` -------------------------------- ### Import Data using SQLite CLI Source: https://github.com/trailbaseio/trailbase/blob/main/docs/src/content/docs/getting-started/first-cli-app.mdx Import data from a CSV file into the 'movies' table using the sqlite3 CLI. Expect a warning for the header row. ```bash sqlite3 traildepot/data/main.db .mode csv .import ./data/Top_1000_IMDb_movies_New_version.csv movies ```