### Example output of Supabase Edge Runtime startup Source: https://www.pgflow.dev/llms-full.txt Illustrates the expected terminal output when the Supabase Edge Runtime successfully starts, showing the server address, Deno version compatibility, and a message indicating a function is being served. ```plaintext Setting up Edge Functions runtime... Serving functions on http://127.0.0.1:54321/functions/v1/ Using supabase-edge-runtime-1.67.4 (compatible with Deno v1.45.2) serving the request with supabase/functions/greet_user_worker ``` -------------------------------- ### Supabase Database Setup: Create 'websites' Table with Migrations Source: https://www.pgflow.dev/llms-full.txt This section details how to set up a 'websites' table in a Supabase database. It involves creating a new migration file, defining the table schema with columns like 'website_url', 'summary', and 'tags', and then applying the migration locally. Ensure 'supabase start' is running before applying. ```bash npx supabase migration new add_websites ``` ```sql create table public.websites ( id bigserial primary key, website_url text not null, summary text, tags text[], created_at timestamptz default now() ); ``` ```bash npx supabase migrations up --local ``` -------------------------------- ### Verify pgflow Installation with SQL Queries Source: https://www.pgflow.dev/llms-small.txt After completing the pgflow installation, execute these SQL queries to confirm the successful setup of the pgflow.workers and pgflow.flows schemas. These queries validate the installation even if they return no rows, indicating readiness for use. ```SQL -- Verify worker schema SELECT * FROM pgflow.workers LIMIT 1; -- Verify pgflow schema SELECT * FROM pgflow.flows LIMIT 1; ``` -------------------------------- ### Starting EdgeWorker with Zero Configuration Source: https://www.pgflow.dev/llms-full.txt This TypeScript example illustrates the simplest way to initialize an EdgeWorker instance. It highlights that EdgeWorker comes with sensible default settings, requiring only a handler function to begin processing messages from the queue. ```typescript EdgeWorker.start(console.log); ``` -------------------------------- ### Start Supabase Services Source: https://www.pgflow.dev/llms-small.txt This command restarts all Supabase services, applying any new configurations and ensuring the Edge Worker setup is fully active. ```bash npx supabase start ``` -------------------------------- ### Install pgflow using npx Source: https://www.pgflow.dev/llms-full.txt This command runs the automatic installer for pgflow. It detects the Supabase project, updates `config.toml`, copies migrations, and creates environment files, preventing duplicates on subsequent runs. ```bash npx pgflow@latest install ``` -------------------------------- ### Restart Supabase Services Source: https://www.pgflow.dev/llms-full.txt To apply configuration changes after installation or modification, use these commands to stop and then start the Supabase services. This ensures that all new settings are properly loaded and active. ```bash npx supabase stop npx supabase start ``` -------------------------------- ### Start Supabase Edge Runtime Source: https://www.pgflow.dev/llms-full.txt Execute this `npx` command to start the local Supabase Edge Runtime. This action enables the environment to listen for incoming HTTP requests, which is essential for deploying and testing Edge Functions and workers. ```bash npx supabase functions serve ``` -------------------------------- ### Install pgflow using the automatic installer Source: https://www.pgflow.dev/llms-small.txt This command runs the automatic installer for pgflow, which detects your Supabase project, updates `config.toml` to enable connection pooling, copies required migrations, and creates a functions environment file if needed. It also prevents duplicate migrations on subsequent runs. ```bash npx pgflow@latest install ``` -------------------------------- ### Install pgflow in Supabase Project using npm Source: https://www.pgflow.dev/llms-full.txt This Bash command initiates the installation of pgflow into your Supabase project. It uses 'npx' to execute the latest version of the pgflow installer, setting up the necessary components for workflow management. ```bash npx pgflow@latest install ``` -------------------------------- ### Install pgflow CLI Source: https://www.pgflow.dev/llms-full.txt Install the pgflow command-line interface. This step is crucial as it automatically configures environment variables required for the Edge Worker within your Supabase project. ```sh npx pgflow@latest install ``` -------------------------------- ### Install Edge Worker and Apply Migrations Source: https://www.pgflow.dev/llms-full.txt This section provides commands for installing Edge Worker using the `pgflow` installer, which automates Supabase project detection, configuration updates, and migration copying. It also includes an alternative command for specifying the Supabase path and the command to apply database migrations. ```bash npx pgflow@latest install ``` ```bash npx pgflow@latest install --supabase-path=./path/to/supabase ``` ```bash npx supabase migrations up ``` -------------------------------- ### Example output of a triggered pgflow run Source: https://www.pgflow.dev/llms-full.txt Displays the expected tabular output from the SQL query that triggers a flow, showing the `run_id`, `flow_slug`, `status`, `input` data, `output`, and `remaining_steps` for the newly started workflow run. ```plaintext run_id | flow_slug | status | input | output | remaining_steps --------------+--------------+---------+-----------------------------------------------+--------+----------------- | greet_user | started | {"first_name": "Alice", "last_name": "Smith"} | null | 2 ``` -------------------------------- ### Start Supabase Edge Runtime Source: https://www.pgflow.dev/llms-small.txt This command starts the Supabase Edge Runtime locally, making it listen for incoming HTTP requests. It's a prerequisite for running Edge Functions and workers. ```bash npx supabase functions serve ``` -------------------------------- ### Initialize Supabase Local Project Source: https://www.pgflow.dev/llms-full.txt Before starting, initialize a Supabase project locally using the Supabase CLI. This command sets up the necessary project structure for local development. ```sh npx supabase init ``` -------------------------------- ### Verify pgflow and Worker Schema Installation Source: https://www.pgflow.dev/llms-full.txt After completing the manual installation, run these SQL queries to verify that the `worker` and `pgflow` schemas, along with their respective tables, have been successfully created in your Supabase database. Expected output is no errors, even if no rows are returned. ```sql -- Verify worker schema SELECT * FROM pgflow.workers LIMIT 1; ``` ```sql -- Verify pgflow schema SELECT * FROM pgflow.flows LIMIT 1; ``` -------------------------------- ### Start Supabase Edge Runtime Server Source: https://www.pgflow.dev/llms-small.txt Start the local Supabase Edge Runtime server. This makes your worker function available for execution and allows it to receive requests. ```bash npx supabase functions serve ``` -------------------------------- ### Install pgflow components for Supabase Source: https://www.pgflow.dev/llms-small.txt This command initializes pgflow within your Supabase project, setting up all necessary components including Edge Functions and PostgreSQL configurations. ```Shell npx pgflow install ``` -------------------------------- ### Install Edge Worker using pgflow installer Source: https://www.pgflow.dev/llms-small.txt This command runs the pgflow installer to automatically set up Edge Worker, including updating `config.toml` for connection pooling, copying migrations, and creating environment files. ```bash npx pgflow@latest install ``` -------------------------------- ### Example of pgflow generated SQL for flow definition Source: https://www.pgflow.dev/llms-full.txt This SQL snippet illustrates the commands generated by pgflow to define a flow named 'greet_user' and its associated steps ('full_name' and 'greeting'). The 'greeting' step is shown with a dependency on 'full_name', demonstrating how flow structure is represented in the database. ```sql SELECT pgflow.create_flow('greet_user'); SELECT pgflow.add_step('greet_user', 'full_name'); SELECT pgflow.add_step('greet_user', 'greeting', ARRAY['full_name']); ``` -------------------------------- ### Good Task Design Example in TypeScript Source: https://www.pgflow.dev/llms-small.txt This example demonstrates a well-designed pgflow task function, summarizeContent, which accepts a direct content parameter, promoting reusability and clear interfaces. It shows how to integrate such a task into a pgflow step by mapping the input. ```typescript // Good: Task accepts direct content parameter async function summarizeContent(content: string) { // Process the content directly return { summary: "Processed summary..." }; } // In your flow: .step( { slug: 'summary', dependsOn: ['website'] }, async (input) => await summarizeContent(input.website.content) ) ``` -------------------------------- ### Start the Supabase Edge Runtime server Source: https://www.pgflow.dev/llms-full.txt Initiates the local Supabase Edge Runtime server using `npx supabase functions serve`, making worker functions available for execution. This command starts the server but does not activate the worker itself. ```bash npx supabase functions serve ``` -------------------------------- ### Example pgflow generated SQL Source: https://www.pgflow.dev/llms-small.txt This SQL snippet illustrates the commands generated by `pgflow` to register a flow and its steps in the database. It demonstrates how `pgflow.create_flow` and `pgflow.add_step` functions are used to define the workflow structure. ```sql SELECT pgflow.create_flow('greet_user'); SELECT pgflow.add_step('greet_user', 'full_name'); SELECT pgflow.add_step('greet_user', 'greeting', ARRAY['full_name']); ``` -------------------------------- ### pgflow: Example of Step Input Structure with Dependencies Source: https://www.pgflow.dev/llms-full.txt This JSON snippet illustrates the structure of input data for a workflow step when it has dependencies. It shows how the 'greeting' step's input combines the initial flow run data with the output from its dependency, 'full_name', ensuring type safety by providing all necessary data. ```JSON // If 'greeting' depends on 'full_name', its input looks like: { "run": { "first": "Jane", "last": "Doe" }, "full_name": "Jane Doe" } ``` -------------------------------- ### Example: Multi-Step Data Flow Definition in pgflow Source: https://www.pgflow.dev/llms-small.txt This comprehensive example demonstrates defining a multi-step data processing workflow using pgflow's TypeScript DSL. It showcases how to define flow input types, chain steps with dependencies, process data in parallel, and combine results while maintaining access to original input parameters and ensuring type safety throughout the workflow. ```typescript type Input = { userId: string, includeDetails: boolean, reportType: 'basic' | 'advanced' }; new Flow({ slug: 'user_report', }) // Step 1: Fetch user data .step( { slug: 'user' }, async (input) => { return await fetchUser(input.run.userId); } ) // Steps 2 & 3: Process user data in parallel .step( { slug: 'activity', dependsOn: ['user'] }, async (input) => { // Uses input.run.reportType to determine timespan const timespan = input.run.reportType === 'advanced' ? '1y' : '30d'; return await getUserActivity(input.user.id, timespan); } ) .step( { slug: 'preferences', dependsOn: ['user'] }, async (input) => { // Uses input.run.includeDetails parameter return await getUserPreferences(input.user.id, input.run.includeDetails); } ) // Step 4: Combine results .step( { slug: 'report', dependsOn: ['activity', 'preferences'] }, async (input) => { return { user: input.user, activity: input.activity, preferences: input.preferences, reportType: input.run.reportType, // Original parameter still available generatedAt: new Date().toISOString() }; } ); ``` -------------------------------- ### Expected Edge Runtime Output for Worker Start Source: https://www.pgflow.dev/llms-small.txt Upon successfully starting the worker via the HTTP request, you should observe these log messages in your Edge Runtime terminal. They confirm that the Deno adapter is active and the worker has begun processing. ```plaintext [Info] [INFO] worker_id=unknown module=DenoAdapter DenoAdapter logger instance created and working. [Info] [INFO] worker_id=unknown module=DenoAdapter HTTP Request: null ``` -------------------------------- ### Start a pgflow Workflow from SQL Editor Source: https://www.pgflow.dev/llms-full.txt Executes a SQL query within the Supabase SQL Editor to manually initiate the `analyzeWebsite` flow. It passes an `input` JSON object containing the URL to be processed by the flow. ```sql select * from pgflow.start_flow( flow_slug => 'analyzeWebsite', input => '{"url":"https://supabase.com"}' ); ``` -------------------------------- ### Get pgflow Execution Timeline for a Run using SQL Source: https://www.pgflow.dev/llms-small.txt To analyze how long each step took to execute within a specific pgflow run, query the `pgflow.step_states` table. This query calculates the duration in seconds for each step, from its start to completion or failure, and orders them by creation time. ```SQL SELECT step_slug, status, created_at, started_at, completed_at, failed_at, EXTRACT(EPOCH FROM (COALESCE(completed_at, failed_at) - started_at)) AS duration_seconds FROM pgflow.step_states WHERE run_id = 'your-run-id-here' ORDER BY created_at ASC; ``` -------------------------------- ### Example: Calling pgflow.delete_flow_and_data Source: https://www.pgflow.dev/llms-small.txt An example SQL query demonstrating how to invoke the `pgflow.delete_flow_and_data` function. Replace `'your_flow_slug'` with the actual slug of the flow you wish to delete. This action is irreversible. ```sql -- Delete a specific flow SELECT pgflow.delete_flow_and_data('your_flow_slug'); ``` -------------------------------- ### Poor Task Design Example in TypeScript Source: https://www.pgflow.dev/llms-small.txt This example illustrates an anti-pattern where the summarizeWebsite task is tightly coupled to the specific structure of the flow's input object (input.website.content). This design reduces reusability and makes the task harder to test in isolation. ```typescript // Bad: Task expects specific step structure async function summarizeWebsite(input: { website: { content: string } }) { // Tightly coupled to previous step name and structure return { summary: "Processed summary..." }; } // In your flow: .step( { slug: 'summary', dependsOn: ['website'] }, async (input) => await summarizeWebsite(input) // Passing entire input object ) ``` -------------------------------- ### Returning JSON-Serializable Data from pgflow Steps (Good Example) Source: https://www.pgflow.dev/llms-small.txt This example illustrates a good practice for returning data from pgflow steps. It shows how to ensure all step outputs are fully serializable to JSON, including converting `Date` objects to ISO strings, which is crucial for pgflow's internal storage in JSONB database columns. ```typescript // GOOD: Fully serializable objects .step( { slug: 'processData' }, async (input) => { return { count: 42, items: ["apple", "banana"], metadata: { processed: true, timestamp: new Date().toISOString() // Convert Date to string } }; } ) ``` -------------------------------- ### Install pgflow CLI and Edge Worker Environment Source: https://www.pgflow.dev/llms-small.txt Installs the latest version of the pgflow CLI, which also automatically configures the Edge Worker environment variables required for workflow execution. ```sh npx pgflow@latest install ``` -------------------------------- ### Good Task Design Example in TypeScript Source: https://www.pgflow.dev/llms-full.txt This example demonstrates a well-designed task function that accepts specific parameters (`content: string`) rather than the entire flow input object. It processes the content directly and returns a clearly defined output structure, making it testable in isolation and independent of other tasks or the overall flow. ```typescript // Good: Task accepts direct content parameter async function summarizeContent(content: string) { // Process the content directly return { summary: "Processed summary..." }; } // In your flow: .step( { slug: 'summary', dependsOn: ['website'] }, async (input) => await summarizeContent(input.website.content) ) ``` -------------------------------- ### Apply Supabase configuration changes Source: https://www.pgflow.dev/llms-full.txt After installing pgflow, restart your local Supabase instance to ensure all configuration updates, such as connection pooling, are properly applied and take effect. ```bash npx supabase stop npx supabase start ``` -------------------------------- ### Serve Supabase Edge Functions Locally Source: https://www.pgflow.dev/llms-full.txt Starts the local Supabase Edge Functions server, which is necessary for the `analyze_website_worker` to run and continuously poll for tasks. This command should be kept running in a dedicated terminal. ```bash npx supabase functions serve ``` -------------------------------- ### Expected Edge Runtime Server Output Source: https://www.pgflow.dev/llms-small.txt This is the typical console output you should see when the Supabase Edge Runtime server successfully starts, indicating it's ready to serve functions. ```plaintext Setting up Edge Functions runtime... Serving functions on http://127.0.0.1:54321/functions/v1/ Using supabase-edge-runtime-1.67.4 (compatible with Deno v1.45.2) serving the request with supabase/functions/greet_user_worker ``` -------------------------------- ### Poor Task Design Example in TypeScript Source: https://www.pgflow.dev/llms-full.txt This example illustrates a poorly designed task function that expects a specific step structure (`input: { website: { content: string } }`). This design creates tight coupling to previous step names and structures, making the task less reusable and harder to test independently, as it requires the entire input object to be passed. ```typescript // Bad: Task expects specific step structure async function summarizeWebsite(input: { website: { content: string } }) { // Tightly coupled to previous step name and structure return { summary: "Processed summary..." }; } // In your flow: .step( { slug: 'summary', dependsOn: ['website'] }, async (input) => await summarizeWebsite(input) // Passing entire input object ) ``` -------------------------------- ### Accessing Flow and Step Inputs in pgflow Steps Source: https://www.pgflow.dev/llms-small.txt This example illustrates how pgflow steps receive a unified `input` object. It shows how `input.run` provides access to the original flow input across all steps, and `input.{stepName}` provides outputs from dependent steps, enabling combination of original and processed data. ```typescript new Flow<{ url: string, userId: string }>({ slug: 'analyze_website', }) .step( { slug: 'scrape' }, async (input) => { // Access to input.run.url and input.run.userId return await scrapeWebsite(input.run.url); } ) .step( { slug: 'analyze', dependsOn: ['scrape'] }, async (input) => { // Still has access to input.run.userId // Now also has access to input.scrape return await analyzeContent(input.scrape.content); } ); ``` -------------------------------- ### Example pgflow Run Completion Status Output Source: https://www.pgflow.dev/llms-full.txt Illustrates the output format for a completed pgflow run, showing `run_id`, `flow_slug`, `status`, `input`, `output`, and `remaining_steps`. This output confirms the successful completion of a workflow and its final state. ```plaintext run_id | flow_slug | status | input | output | remaining_steps --------------+--------------+-----------+-----------------------------------------------+-------------------------------------+----------------- | greet_user | completed | {"first_name": "Alice", "last_name": "Smith"} | {"greeting": "Hello, Alice Smith!"} | 0 ``` -------------------------------- ### Examples of Pruning pgflow Data by Interval Source: https://www.pgflow.dev/llms-small.txt These examples demonstrate how to use the `pgflow.prune_data_older_than` function with various `INTERVAL` values. You can specify retention periods in days, months, or weeks using `make_interval` or standard `INTERVAL` literals. ```SQL -- Keep 30 days of data using make_interval SELECT pgflow.prune_data_older_than(make_interval(days => 30)); -- Keep 7 days of data SELECT pgflow.prune_data_older_than(make_interval(days => 7)); -- Keep 3 months of data using interval literals SELECT pgflow.prune_data_older_than(INTERVAL '3 months'); -- Keep 2 weeks SELECT pgflow.prune_data_older_than(INTERVAL '2 weeks'); ``` -------------------------------- ### Integrating Reusable Tasks into pgflow Workflows Source: https://www.pgflow.dev/llms-small.txt This TypeScript example demonstrates how to import and utilize reusable tasks like scrapeWebsite and summarizeWithAI within a pgflow definition. It showcases the Flow class, step definitions, and how to pass outputs from one task as inputs to another using dependsOn. ```typescript import { Flow } from 'npm:@pgflow/dsl'; import scrapeWebsite from '../_tasks/scrapeWebsite.ts'; import summarizeWithAI from '../_tasks/summarizeWithAI.ts'; type Input = { url: string; }; export default new Flow({ slug: 'analyze_website', }) .step( { slug: 'website' }, async (input) => await scrapeWebsite(input.run.url), ) .step( { slug: 'summary', dependsOn: ['website'] }, async (input) => await summarizeWithAI(input.website.content), ); ``` -------------------------------- ### Defining a Multi-Step Data Flow in pgflow with TypeScript Source: https://www.pgflow.dev/llms-full.txt This comprehensive example demonstrates how to construct a multi-step data flow in pgflow, showcasing input parameter handling, parallel step execution, and data aggregation. It highlights how original flow parameters remain accessible throughout the workflow and how dependencies ensure correct execution order. ```typescript // Flow with multiple input parameters type Input = { userId: string, includeDetails: boolean, reportType: 'basic' | 'advanced' }; new Flow({ slug: 'user_report', }) // Step 1: Fetch user data .step( { slug: 'user' }, async (input) => { return await fetchUser(input.run.userId); } ) // Steps 2 & 3: Process user data in parallel .step( { slug: 'activity', dependsOn: ['user'] }, async (input) => { // Uses input.run.reportType to determine timespan const timespan = input.run.reportType === 'advanced' ? '1y' : '30d'; return await getUserActivity(input.user.id, timespan); } ) .step( { slug: 'preferences', dependsOn: ['user'] }, async (input) => { // Uses input.run.includeDetails parameter return await getUserPreferences(input.user.id, input.run.includeDetails); } ) // Step 4: Combine results .step( { slug: 'report', dependsOn: ['activity', 'preferences'] }, async (input) => { return { user: input.user, activity: input.activity, preferences: input.preferences, reportType: input.run.reportType, // Original parameter still available generatedAt: new Date().toISOString() }; } ); ``` -------------------------------- ### Apply pgflow database migrations Source: https://www.pgflow.dev/llms-small.txt This command applies the necessary database migrations to create the pgflow schema and tables within your Supabase project. These migrations are copied by the installer with timestamps to ensure they run after your existing migrations. ```bash npx supabase migrations up ``` -------------------------------- ### Trigger a pgflow workflow using SQL in Supabase Studio Source: https://www.pgflow.dev/llms-full.txt Executes a SQL query in Supabase Studio to start a new run of the `greet_user` workflow, providing initial input data. This action creates a new workflow run, initiates root steps, and returns run details. ```sql SELECT * FROM pgflow.start_flow( flow_slug => 'greet_user', input => '{"first_name": "Alice", "last_name": "Smith"}'::jsonb ); ``` -------------------------------- ### Apply Supabase Database Migrations Source: https://www.pgflow.dev/llms-small.txt This command applies the necessary database migrations, including all Edge Worker tables, after the installer has copied them to the migrations folder. ```bash npx supabase migrations up ``` -------------------------------- ### Defining a pgflow Workflow with Unified Step Inputs Source: https://www.pgflow.dev/llms-full.txt This TypeScript example demonstrates a pgflow workflow where each step receives a unified `input` object. It shows how `input.run` provides access to the original flow parameters, and `input.{stepName}` provides outputs from dependent steps, allowing steps to combine original and processed data. ```typescript new Flow<{ url: string, userId: string }> ({ slug: 'analyze_website', }) .step( { slug: 'scrape' }, async (input) => { // Access to input.run.url and input.run.userId return await scrapeWebsite(input.run.url); } ) .step( { slug: 'analyze', dependsOn: ['scrape'] }, async (input) => { // Still has access to input.run.userId // Now also has access to input.scrape return await analyzeContent(input.scrape.content); } ); ``` -------------------------------- ### Integrating Reusable Tasks into pgflow Definitions Source: https://www.pgflow.dev/llms-full.txt This example illustrates how to import and utilize previously defined reusable tasks, such as `scrapeWebsite` and `summarizeWithAI`, within a `pgflow` definition. It shows how to chain tasks using `dependsOn` and pass outputs from one task as inputs to the next, demonstrating a modular and efficient workflow construction. ```typescript import { Flow } from 'npm:@pgflow/dsl'; import scrapeWebsite from '../_tasks/scrapeWebsite.ts'; import summarizeWithAI from '../_tasks/summarizeWithAI.ts'; type Input = { url: string; }; export default new Flow({ slug: 'analyze_website', }) .step( { slug: 'website' }, async (input) => await scrapeWebsite(input.run.url), ) .step( { slug: 'summary', dependsOn: ['website'] }, async (input) => await summarizeWithAI(input.website.content), ); ``` -------------------------------- ### Start pgflow Edge Worker via HTTP Request Source: https://www.pgflow.dev/llms-small.txt In a new terminal, send an HTTP POST request to the local Edge Runtime endpoint. This action initiates your `greet_user_worker` function, making it active and ready to process workflow tasks. ```bash curl -X POST http://localhost:54321/functions/v1/greet_user_worker ``` -------------------------------- ### Restart Supabase instance to apply configuration changes Source: https://www.pgflow.dev/llms-small.txt After installing pgflow, restart your Supabase instance to ensure all configuration changes, including connection pooling, are applied correctly. This step is crucial for the workflow engine to function as expected. ```bash npx supabase stop npx supabase start ``` -------------------------------- ### pgflow Step State Machine Lifecycle Source: https://www.pgflow.dev/llms-small.txt Illustrates the lifecycle of a step in pgflow, showing the transitions between its possible statuses: created, started, completed, and failed. A workflow run concludes when all steps reach a terminal status (completed or failed). ```plaintext created → started → completed ↘ failed ``` -------------------------------- ### Implementing Type Safety in pgflow Workflows Source: https://www.pgflow.dev/llms-full.txt This TypeScript example illustrates pgflow's robust type system, which automatically enforces input types for the flow and tracks each step's output type. It demonstrates how `input.run` and dependency outputs are strongly typed, providing IDE autocompletion and compile-time error checking. ```typescript // Define input type for the flow type WebsiteInput = { url: string, userId: string }; // Create a flow with that input type new Flow({ slug: 'analyze_website', }) .step( { slug: 'scrape' }, async (input) => { // input.run is typed as WebsiteInput return { content: "..." }; } ) .step( { slug: 'analyze', dependsOn: ['scrape'] }, async (input) => { // input.scrape is typed based on the scrape step's return type return { analysis: "..." }; } ); ``` -------------------------------- ### Restart Supabase Services Source: https://www.pgflow.dev/llms-full.txt These `npx` commands are used to stop and then restart the Supabase services. This step is crucial to ensure that all recent configuration changes, particularly those related to Edge Worker installation, are properly applied and take effect. ```bash npx supabase stop ``` ```bash npx supabase start ``` -------------------------------- ### Set Up pgflow Project Directory Structure Source: https://www.pgflow.dev/llms-small.txt This snippet demonstrates the recommended directory structure for a pgflow project. It creates `_flows` and `_tasks` directories within `supabase/functions` to separate flow definitions from individual task implementations, enhancing organization and modularity. ```bash mkdir -p supabase/functions/_flows supabase/functions/_tasks ``` -------------------------------- ### Initialize Supabase Project Locally Source: https://www.pgflow.dev/llms-small.txt Initializes a Supabase project in your local environment, setting up the necessary files and configurations for development. ```sh npx supabase init ``` -------------------------------- ### Reusable Website Scraping Task in TypeScript Source: https://www.pgflow.dev/llms-small.txt This TypeScript example defines a reusable scrapeWebsite task function for pgflow. It fetches content from a given URL and returns a structured object containing the HTML content and metadata, demonstrating best practices for task design and output. ```typescript /** * Fetches website content from a URL */ export default async function scrapeWebsite(url: string) { console.log(`Fetching content from: ${url}`); // Implementation details... const response = await fetch(url); const html = await response.text(); return { content: html, metadata: { url, fetched_at: new Date().toISOString() } }; } ``` -------------------------------- ### Define a Workflow with pgflow's TypeScript DSL Source: https://www.pgflow.dev/llms-full.txt This example demonstrates how to define a simple workflow in pgflow using its TypeScript DSL. Workflows are orchestrated by PostgreSQL, with steps compiled into SQL migrations. It shows how to define steps and specify explicit dependencies between them, ensuring tasks execute only when their prerequisites are met. ```typescript // In pgflow, the database orchestrates the workflow new Flow<{ url: string }> ({ slug: 'analyze_website', }) .step( { slug: 'extract' }, async (input) => /* extract data */ ) .step( { slug: 'transform', dependsOn: ['extract'] }, async (input) => /* transform using extract results */ ); ``` -------------------------------- ### Define a Sequential pgflow Workflow in TypeScript Source: https://www.pgflow.dev/llms-full.txt This TypeScript example demonstrates how to define a simple two-step sequential workflow using the pgflow DSL. It defines an input type, then two steps: 'full_name' which concatenates first and last names, and 'greeting' which depends on 'full_name' and uses its output. The DSL provides full type inference and IntelliSense for safe access to step outputs. ```typescript import { Flow } from "npm:@pgflow/dsl"; type Input = { first: string; last: string }; export default new Flow({ slug: "greet_user" }) .step( { slug: "full_name" }, (input) => `${input.run.first} ${input.run.last}` // return type inferred ) .step( { slug: "greeting", dependsOn: ["full_name"] }, (input) => `Hello, ${input.full_name}!` // safe access, full IntelliSense ); ``` -------------------------------- ### Define and Compile a Simple Two-Step pgflow Workflow Source: https://www.pgflow.dev/llms-small.txt Demonstrates how to define a basic two-step sequential workflow named 'greet_user' using the pgflow TypeScript DSL. It also shows the corresponding SQL statements automatically generated by the compiler, which create the flow and its steps in the Postgres database. ```typescript import { Flow } from "npm:@pgflow/dsl"; type Input = { first: string; last: string }; export default new Flow({ slug: "greet_user" }) .step( { slug: "full_name" }, (input) => `${input.run.first} ${input.run.last}` // return type inferred ) .step( { slug: "greeting", dependsOn: ["full_name"] }, (input) => `Hello, ${input.full_name}!` // safe access, full IntelliSense ); ``` ```sql SELECT pgflow.create_flow('greet_user'); SELECT pgflow.add_step('greet_user', 'full_name'); SELECT pgflow.add_step('greet_user', 'greeting', ARRAY['full_name']); ``` -------------------------------- ### Construct PostgreSQL Database Connection String Source: https://www.pgflow.dev/llms-small.txt After encoding your database password, construct the PostgreSQL connection string using the standard URI format. This includes the username, encoded password, host, port, and database name, as shown in the general format and a specific example for a Supabase pooler connection. ```Plaintext postgresql://username:ENCODED_PASSWORD@host:port/database ``` ```Plaintext postgresql://postgres.pooler-dev:my%40complex%26password%21@db.example.com:6543/postgres ``` -------------------------------- ### Define DBOS Workflow with Decorators and Transactions Source: https://www.pgflow.dev/llms-full.txt This TypeScript example illustrates how DBOS enhances application code with durability using decorators. It shows defining a step, a transactional database operation, and a complete workflow. DBOS checkpoints function state in PostgreSQL, allowing standard imperative control flow while ensuring reliability. ```typescript // In DBOS, your code drives the workflow class DataPipeline { @DBOS.step() static async extract(url: string) { /* extract data */ } // Direct database operations using transaction decorator @DBOS.transaction() static async saveToDatabase(data: any) { // Uses DBOS.knexClient, DBOS.drizzleClient, etc. await DBOS.knexClient('data_table').insert(data); } @DBOS.workflow() static async analyzeWebsite(url: string) { const data = await DataPipeline.extract(url); await DataPipeline.saveToDatabase(data); } } ``` -------------------------------- ### Ensuring JSON Serialization for pgflow Step Outputs (Good Example) Source: https://www.pgflow.dev/llms-full.txt This TypeScript snippet demonstrates a correctly implemented pgflow step that returns a JSON-serializable object. It highlights the use of primitive types, plain objects, arrays, and converting `Date` objects to ISO strings to ensure compatibility with JSONB database columns. ```typescript // GOOD: Fully serializable objects .step( { slug: 'processData' }, async (input) => { return { count: 42, items: ["apple", "banana"], metadata: { processed: true, timestamp: new Date().toISOString() // Convert Date to string } }; } ) ``` -------------------------------- ### View pgflow Individual Step Details for a Run using SQL Source: https://www.pgflow.dev/llms-small.txt To check the status of individual steps within a specific workflow run, query the `pgflow.step_states` table, joining with `pgflow.step_tasks` to retrieve output for completed tasks. This query shows the status of each step, its remaining dependencies, remaining tasks, and output. Step statuses include `created`, `started`, `completed`, and `failed`. ```SQL SELECT ss.step_slug, ss.status, ss.remaining_deps, ss.remaining_tasks, st.output FROM pgflow.step_states ss LEFT JOIN pgflow.step_tasks st ON ss.run_id = st.run_id AND ss.step_slug = st.step_slug AND st.status = 'completed' WHERE ss.run_id = 'your-run-id-here'; ``` -------------------------------- ### Initialize Pgflow Project Directory Structure Source: https://www.pgflow.dev/llms-full.txt This bash command creates the essential `_flows` and `_tasks` directories within the `supabase/functions` path, establishing the recommended project layout for pgflow applications. ```bash mkdir -p supabase/functions/_flows supabase/functions/_tasks ``` -------------------------------- ### Query pgflow.step_states for Individual Step Details Source: https://www.pgflow.dev/llms-full.txt To check the status of individual steps within a specific workflow run, join `pgflow.step_states` with `pgflow.step_tasks`. This query provides the step slug, status, remaining dependencies, remaining tasks, and output for each step in a given run. Step statuses include `created`, `started`, `completed`, and `failed`. ```SQL SELECT ss.step_slug, ss.status, ss.remaining_deps, ss.remaining_tasks, st.output FROM pgflow.step_states ss LEFT JOIN pgflow.step_tasks st ON ss.run_id = st.run_id AND ss.step_slug = st.step_slug AND st.status = 'completed' WHERE ss.run_id = 'your-run-id-here'; ``` ```plaintext step_slug | status | remaining_deps | remaining_tasks | output -------------+-----------+----------------+----------------+--------------------------- process_data | completed | 0 | 0 | {"processed": true} send_email | completed | 0 | 0 | "Email sent successfully" final_step | created | 2 | 1 | null ``` -------------------------------- ### Apply pgflow database migrations Source: https://www.pgflow.dev/llms-small.txt After copying the pgflow migration files from the extracted archive's `pkgs/core/supabase/migrations/*.sql` to your project's `supabase/migrations/` folder, apply them using the Supabase CLI to set up the necessary database schemas and functions. ```bash npx supabase migration up ``` -------------------------------- ### Defining Tasks and Orchestrating Workflows with Trigger.dev in TypeScript Source: https://www.pgflow.dev/llms-small.txt Trigger.dev provides a task-based system where individual tasks are defined with handlers and optional lifecycle hooks. This example shows how to define an 'extractData' task with an initialization hook and a parent 'analyzeWebsite' task that coordinates the workflow by triggering and awaiting the 'extractData' task, demonstrating Trigger.dev's function-based API. ```typescript // In Trigger.dev, you define tasks with handlers and hooks import { task } from "@trigger.dev/sdk/v3"; export const extractData = task({ id: "extract-data", // Optional initialization hook init: async (payload) => { return { client: createApiClient() }; }, run: async (payload: { url: string }, { init }) => { // Use resources from init return await init.client.fetch(payload.url); } }); // Parent task that coordinates workflow export const analyzeWebsite = task({ id: "analyze-website", run: async (payload: { url: string }) => { // Extract data and wait for result const data = await extractData.triggerAndWait({ url: payload.url }).unwrap(); // Process data and return result return processData(data); } }); ``` -------------------------------- ### Example: Deleting a Specific pgflow Flow Source: https://www.pgflow.dev/llms-full.txt This SQL example demonstrates how to call the `pgflow.delete_flow_and_data` function to remove a specific flow. Replace `'your_flow_slug'` with the actual slug of the flow you wish to delete. Remember this operation is irreversible and should only be used in development. ```SQL -- Delete a specific flow SELECT pgflow.delete_flow_and_data('your_flow_slug'); ``` -------------------------------- ### Avoiding Non-Serializable Types in pgflow Step Outputs (Bad Example) Source: https://www.pgflow.dev/llms-full.txt This TypeScript snippet illustrates common mistakes that lead to non-serializable data in pgflow step outputs, which will cause runtime errors. It shows examples of `Date` objects, regular expressions, and functions, none of which can be directly stored in JSONB columns. ```typescript // BAD: Non-serializable types will cause runtime errors .step( { slug: 'badExample' }, async (input) => { return { date: new Date(), // Use toISOString() instead regex: /test/, // Not serializable function: () => {} // Functions can't be serialized }; } ) ``` -------------------------------- ### Define a simple greeting workflow with pgflow DSL Source: https://www.pgflow.dev/llms-small.txt This TypeScript code defines a `greet_user` workflow using the pgflow DSL. It takes `first_name` and `last_name` as input, formats a full name in the first step (`full_name`), and then creates a personalized greeting in the second step (`greeting`), demonstrating step dependencies and input access. ```typescript import { Flow } from 'npm:@pgflow/dsl'; type Input = { first_name: string; last_name: string; }; export default new Flow({ slug: 'greet_user', }) .step( { slug: 'full_name' }, (input) => `${input.run.first_name} ${input.run.last_name}` ) .step( { slug: 'greeting', dependsOn: ['full_name'] }, (input) => `Hello, ${input.full_name}!` ); ``` -------------------------------- ### Initialize Supabase Edge Function for pgflow Source: https://www.pgflow.dev/llms-full.txt Uses `npx supabase functions new` to create a new Edge Function directory and boilerplate for `analyze_website_worker`, which will host the pgflow worker. ```bash npx supabase functions new analyze_website_worker ``` -------------------------------- ### Edge Worker Startup Output Source: https://www.pgflow.dev/llms-small.txt This output shows the console messages indicating that the worker has successfully booted, its ID, and that it's ensuring the 'tasks' queue exists for message processing. ```bash [Info] worker_id= [WorkerLifecycle] Ensuring queue 'tasks' exists... ``` -------------------------------- ### Apply pgflow database migrations Source: https://www.pgflow.dev/llms-full.txt Run this command to apply the necessary database migrations. This creates the pgflow schema, tables, and core SQL functions required for workflow definitions and runtime state within your Supabase project. ```bash npx supabase migrations up ``` -------------------------------- ### Stop Supabase Services Source: https://www.pgflow.dev/llms-small.txt This command stops all running Supabase services to ensure that configuration changes, such as those made by the pgflow installer, are properly applied upon restart. ```bash npx supabase stop ``` -------------------------------- ### Disable JWT verification for pgflow worker in Supabase config Source: https://www.pgflow.dev/llms-full.txt Modifies the `supabase/config.toml` file to disable JWT verification for the `greet_user_worker` function, ensuring it can be started without authentication for development purposes. ```toml [functions.greet_user_worker] enabled = true verify_jwt = true verify_jwt = false import_map = "./functions/greet_user_worker/deno.json" ``` -------------------------------- ### Defining Workflows with pgflow's Fluent DSL Source: https://www.pgflow.dev/llms-small.txt This snippet demonstrates the fluent interface of the pgflow DSL, where `Flow` instances are created and chained using `.step()` calls. Each call returns a new `Flow` instance, ensuring immutability and predictability in workflow definitions. ```typescript // Method chaining for flow definition new Flow({ slug: 'my_flow' }) .step({ slug: 'step1' }, async (input) => { /* ... */ }) .step({ slug: 'step2' }, async (input) => { /* ... */ }); ``` -------------------------------- ### pgflow: Compiler-Generated Flow Creation SQL Source: https://www.pgflow.dev/llms-full.txt This SQL snippet demonstrates how the pgflow compiler generates commands to define a workflow. It shows the creation of a flow named 'greet_user' and the addition of two steps, 'full_name' and 'greeting', with 'greeting' depending on 'full_name'. ```SQL SELECT pgflow.create_flow('greet_user'); SELECT pgflow.add_step('greet_user', 'full_name'); SELECT pgflow.add_step('greet_user', 'greeting', ARRAY['full_name']); ``` -------------------------------- ### Expected terminal output after pgflow worker activation Source: https://www.pgflow.dev/llms-full.txt Shows the log messages that appear in the Edge Runtime terminal once the `greet_user_worker` has successfully started, indicating DenoAdapter initialization and an HTTP request being processed. ```plaintext [Info] [INFO] worker_id=unknown module=DenoAdapter DenoAdapter logger instance created and working. [Info] [INFO] worker_id=unknown module=DenoAdapter HTTP Request: null ``` -------------------------------- ### Send Test Message to Edge Worker Queue Source: https://www.pgflow.dev/llms-small.txt This SQL command uses `pgmq.send` to enqueue a test message with a URL payload into the 'tasks' queue. The worker, once started, will poll and process this message. ```sql SELECT pgmq.send( queue_name => 'tasks', msg => '{"url": "https://example.com"}'::jsonb ); ``` -------------------------------- ### Edge Worker Message Processing Output Source: https://www.pgflow.dev/llms-small.txt This output displays the console logs from the worker, showing that it has scheduled the execution of a task and successfully scraped the example website, including the URL and HTTP status. ```bash [Info] worker_id= [ExecutionController] Scheduling execution of task 1 [Info] Scraped website! { url: "https://example.com", status: 200 } ``` -------------------------------- ### Apply Hybrid Naming for pgflow Workflow Steps Source: https://www.pgflow.dev/llms-full.txt Illustrates the recommended hybrid naming convention for pgflow steps, using nouns for data-producing steps and verb-noun combinations for terminal actions to improve readability and maintainability. ```typescript // Data-producing steps use nouns .step({ slug: "website" }, ...) .step({ slug: "summary", dependsOn: ["website"] }, ...) // Terminal action step uses verb-noun .step({ slug: "saveToDb", dependsOn: ["summary"] }, ...) ``` -------------------------------- ### Construct Database Connection String with Encoded Password Source: https://www.pgflow.dev/llms-full.txt After encoding your database password, construct the full connection string. Ensure only the password portion is encoded. This example shows the structure and a concrete instance for a Supabase pooler connection. ```plaintext postgresql://username:ENCODED_PASSWORD@host:port/database ``` ```plaintext postgresql://postgres.pooler-dev:my%40complex%26password%21@db.example.com:6543/postgres ``` -------------------------------- ### Apply Supabase database migration Source: https://www.pgflow.dev/llms-small.txt Execute this command to apply the generated SQL migration file to your Supabase database. This registers the `pgflow` definition in the database, making it available for the `pgflow` runtime system. ```bash npx supabase migrations up ``` -------------------------------- ### EdgeWorker Configuration: queueName Source: https://www.pgflow.dev/llms-full.txt This API documentation describes the `queueName` configuration option for EdgeWorker. It specifies the data type, default value, and provides a TypeScript example for customizing the name of the PGMQ queue that EdgeWorker listens to for messages. ```APIDOC queueName: Type: string Default: 'tasks' Description: The name of the PGMQ queue to listen to for messages. ``` ```typescript EdgeWorker.start(handler, { queueName: 'my_custom_queue' }); ``` -------------------------------- ### View generated pgflow SQL migration Source: https://www.pgflow.dev/llms-small.txt Use this command to inspect the contents of the SQL migration file generated by `pgflow`. The file contains SQL commands to create the flow definition, add steps with their configurations, and define dependencies between steps. ```bash cat supabase/migrations/*_create_greet_user_flow.sql ``` -------------------------------- ### Define pgflow Edge Worker Logic in TypeScript Source: https://www.pgflow.dev/llms-small.txt Replace the default content of the `index.ts` file for your new Edge Function. This code imports the `EdgeWorker` and your flow definition, then starts the worker to process tasks for the `GreetUser` flow. ```typescript import { EdgeWorker } from "jsr:@pgflow/edge-worker"; import GreetUser from '../_flows/greet_user.ts'; // Pass the flow definition to the Edge Worker EdgeWorker.start(GreetUser); ``` -------------------------------- ### Trigger pgflow Workflow using Supabase SQL Editor Source: https://www.pgflow.dev/llms-small.txt Execute this SQL query within the Supabase Studio SQL Editor to initiate a new run of your `greet_user` workflow. Provide the necessary input parameters for the flow to begin processing. ```sql SELECT * FROM pgflow.start_flow( flow_slug => 'greet_user', input => '{"first_name": "Alice", "last_name": "Smith"}'::jsonb ); ``` -------------------------------- ### Define pgflow Edge Worker logic in TypeScript Source: https://www.pgflow.dev/llms-full.txt Replaces the default `index.ts` content with TypeScript code that imports `EdgeWorker` and a flow definition (`GreetUser`), then starts the Edge Worker, enabling it to poll for tasks, process steps, and handle retries. ```typescript import { EdgeWorker } from "jsr:@pgflow/edge-worker"; import GreetUser from '../_flows/greet_user.ts'; // Pass the flow definition to the Edge Worker EdgeWorker.start(GreetUser); ``` -------------------------------- ### Create a Web Scraping Edge Worker with TypeScript Source: https://www.pgflow.dev/llms-small.txt This code defines an Edge Worker that listens for URLs, fetches their content, and logs the scraping results. It uses `jsr:@pgflow/edge-worker` to start the worker and process payloads containing a URL. ```typescript import { EdgeWorker } from "jsr:@pgflow/edge-worker"; EdgeWorker.start(async (payload: { url: string }) => { const response = await fetch(payload.url); console.log("Scraped website!", { url: payload.url, status: response.status, }); }); ```