Edge Functions API - arilonUK/iotagentmesh GitHub Wiki
Edge Functions provide serverless compute capabilities for custom business logic, integrations, and real-time processing within the IoT Agent Mesh platform. These TypeScript functions run globally at the edge for low latency.
Edge Functions enable:
- Custom business logic processing
- Third-party service integrations
- Webhook handling and event processing
- Real-time data transformation
- Automated alert processing and notifications
- Custom API endpoints with advanced routing
/functions/v1/
Edge Functions support multiple authentication methods:
JWT Authentication (Recommended):
Authorization: Bearer YOUR_JWT_TOKEN
API Key Authentication:
Authorization: Bearer YOUR_API_KEY
No Authentication (Webhooks only):
Functions can be deployed with --no-verify-jwt
for webhook endpoints.
Process and validate telemetry data before storage.
POST /functions/v1/process-device-data
{
"agent_id": "agent_01H8K2M3N4P5Q6R7S8T9U0V1W2",
"raw_data": {
"temp": "23.5",
"hum": "65.2",
"batt": "87",
"sig": "-65"
},
"metadata": {
"firmware_version": "1.4.2",
"timestamp": "2024-07-23T16:45:00Z"
}
}
{
"processed_data": {
"temperature": 23.5,
"humidity": 65.2,
"battery_level": 87,
"signal_strength": -65
},
"validation_results": {
"valid": true,
"warnings": [],
"errors": []
},
"transformations_applied": [
"string_to_number",
"field_mapping",
"range_validation"
],
"stored": true,
"telemetry_id": "01H8K3L4M5N6O7P8Q9R0S1T2U3V4"
}
JavaScript/TypeScript:
const response = await supabase.functions.invoke('process-device-data', {
body: {
agent_id: 'agent_01H8K2M3N4P5Q6R7S8T9U0V1W2',
raw_data: {
temp: '23.5',
hum: '65.2',
batt: '87'
},
metadata: {
firmware_version: '1.4.2'
}
}
})
console.log('Processed data:', response.data)
Python:
import requests
response = requests.post(
'https://your-project-id.supabase.co/functions/v1/process-device-data',
headers={
'Authorization': f'Bearer {jwt_token}',
'Content-Type': 'application/json'
},
json={
'agent_id': 'agent_01H8K2M3N4P5Q6R7S8T9U0V1W2',
'raw_data': {
'temp': '23.5',
'hum': '65.2',
'batt': '87'
}
}
)
data = response.json()
Generic webhook handler for external service integrations.
POST /functions/v1/webhook-handler
X-Webhook-Source: stripe|github|custom
X-Webhook-Signature: sha256=signature_hash
Content-Type: application/json
{
"id": "evt_1234567890",
"object": "event",
"type": "invoice.payment_succeeded",
"data": {
"object": {
"id": "in_1234567890",
"customer": "cus_organization_123",
"amount_paid": 2999,
"status": "paid"
}
},
"created": 1721750400
}
{
"received": true,
"event_type": "invoice.payment_succeeded",
"processed": true,
"actions_taken": [
"updated_subscription_status",
"sent_confirmation_email",
"updated_organization_limits"
],
"processing_time_ms": 245
}
Webhook Integration:
// Configure webhook in external service to POST to:
// https://your-project-id.supabase.co/functions/v1/webhook-handler
// The function automatically handles:
// - Signature verification
// - Event deduplication
// - Retry logic
// - Database updates
Process and send alert notifications through multiple channels.
POST /functions/v1/send-alert-notification
{
"alert_id": "alert_01H8K3L4M5N6O7P8Q9R0S1T2U3V4",
"agent_id": "agent_01H8K2M3N4P5Q6R7S8T9U0V1W2",
"severity": "high",
"message": "Temperature exceeds threshold",
"data": {
"current_temperature": 42.5,
"threshold": 35.0,
"location": "warehouse-a"
},
"notification_channels": ["email", "sms", "webhook"],
"recipients": [
{
"type": "user",
"id": "user_01H8K2M3N4P5Q6R7S8T9U0V1W2"
},
{
"type": "role",
"role": "admin"
}
]
}
{
"alert_id": "alert_01H8K3L4M5N6O7P8Q9R0S1T2U3V4",
"notifications_sent": 3,
"results": [
{
"channel": "email",
"recipient": "[email protected]",
"status": "sent",
"sent_at": "2024-07-23T16:45:01Z"
},
{
"channel": "sms",
"recipient": "+1-555-0123",
"status": "sent",
"sent_at": "2024-07-23T16:45:02Z"
},
{
"channel": "webhook",
"recipient": "https://company.com/alerts",
"status": "sent",
"sent_at": "2024-07-23T16:45:03Z"
}
],
"processing_time_ms": 1250
}
JavaScript/TypeScript:
const response = await supabase.functions.invoke('send-alert-notification', {
body: {
alert_id: 'alert_01H8K3L4M5N6O7P8Q9R0S1T2U3V4',
agent_id: 'agent_01H8K2M3N4P5Q6R7S8T9U0V1W2',
severity: 'high',
message: 'Temperature exceeds threshold',
data: {
current_temperature: 42.5,
threshold: 35.0,
location: 'warehouse-a'
},
notification_channels: ['email', 'sms', 'webhook']
}
})
console.log('Notifications sent:', response.data.notifications_sent)
Perform complex data aggregations and analytics.
POST /functions/v1/data-aggregation
{
"aggregation_type": "time_series",
"agents": ["agent_01H8K2M3N4P5Q6R7S8T9U0V1W2", "agent_02H8K2M3N4P5Q6R7S8T9U0V1W3"],
"fields": [
{
"name": "temperature",
"operations": ["avg", "min", "max", "stddev"]
},
{
"name": "humidity",
"operations": ["avg"]
}
],
"time_range": {
"start": "2024-07-23T00:00:00Z",
"end": "2024-07-23T23:59:59Z"
},
"interval": "1h",
"filters": {
"temperature": {
"min": -50,
"max": 100
}
},
"output_format": "json"
}
{
"aggregation_id": "agg_01H8K3L4M5N6O7P8Q9R0S1T2U3V4",
"agents_processed": 2,
"time_range": {
"start": "2024-07-23T00:00:00Z",
"end": "2024-07-23T23:59:59Z"
},
"interval": "1h",
"data": [
{
"timestamp": "2024-07-23T00:00:00Z",
"temperature": {
"avg": 22.3,
"min": 19.8,
"max": 24.7,
"stddev": 1.2
},
"humidity": {
"avg": 65.4
},
"sample_count": 120
},
{
"timestamp": "2024-07-23T01:00:00Z",
"temperature": {
"avg": 22.1,
"min": 19.5,
"max": 24.3,
"stddev": 1.1
},
"humidity": {
"avg": 66.1
},
"sample_count": 120
}
],
"summary": {
"total_samples": 2880,
"processing_time_ms": 450,
"cache_hit_rate": 0.85
}
}
JavaScript/TypeScript:
const response = await supabase.functions.invoke('data-aggregation', {
body: {
aggregation_type: 'time_series',
agents: ['agent_01H8K2M3N4P5Q6R7S8T9U0V1W2'],
fields: [
{
name: 'temperature',
operations: ['avg', 'min', 'max']
}
],
time_range: {
start: '2024-07-23T00:00:00Z',
end: '2024-07-23T23:59:59Z'
},
interval: '1h'
}
})
console.log('Aggregated data:', response.data.data)
Generate comprehensive reports with data visualization.
POST /functions/v1/generate-report
{
"report_type": "organization_summary",
"organization_id": "org_01H8K2M3N4P5Q6R7S8T9U0V1W2",
"time_period": {
"start": "2024-07-01T00:00:00Z",
"end": "2024-07-31T23:59:59Z"
},
"sections": [
"agent_overview",
"telemetry_summary",
"alert_analysis",
"performance_metrics"
],
"format": "pdf",
"include_charts": true,
"recipients": ["[email protected]"]
}
{
"report_id": "report_01H8K3L4M5N6O7P8Q9R0S1T2U3V4",
"status": "generated",
"format": "pdf",
"file_size": "2.3MB",
"download_url": "https://your-project-id.supabase.co/storage/v1/object/reports/report_01H8K3L4M5N6O7P8Q9R0S1T2U3V4.pdf",
"expires_at": "2024-08-23T16:45:00Z",
"sections_included": [
"agent_overview",
"telemetry_summary",
"alert_analysis",
"performance_metrics"
],
"generation_time_ms": 3500,
"email_sent": true
}
Integrate with third-party services and APIs.
POST /functions/v1/external-integration
{
"service": "weather_api",
"action": "get_weather_data",
"parameters": {
"location": "warehouse-a",
"coordinates": {
"lat": 40.7128,
"lon": -74.0060
}
},
"agent_id": "agent_01H8K2M3N4P5Q6R7S8T9U0V1W2",
"correlation_fields": ["temperature", "humidity", "pressure"]
}
{
"service": "weather_api",
"status": "success",
"data": {
"temperature": 24.3,
"humidity": 68.5,
"pressure": 1013.2,
"wind_speed": 5.2,
"conditions": "partly_cloudy"
},
"correlation_analysis": {
"temperature_correlation": 0.87,
"humidity_correlation": 0.72,
"pressure_correlation": 0.93
},
"recommendations": [
"External temperature is consistent with sensor readings",
"Consider calibrating humidity sensor - 3.3% deviation",
"Pressure readings are highly accurate"
],
"cached_until": "2024-07-23T17:45:00Z"
}
You can deploy custom Edge Functions for specific business logic:
// supabase/functions/custom-logic/index.ts
import { serve } from 'https://deno.land/[email protected]/http/server.ts'
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}
serve(async (req) => {
// Handle CORS preflight requests
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders })
}
try {
// Initialize Supabase client
const supabase = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? ''
)
// Get request body
const { agent_id, custom_data } = await req.json()
// Your custom business logic here
const result = await processCustomLogic(agent_id, custom_data, supabase)
return new Response(
JSON.stringify(result),
{
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
status: 200,
}
)
} catch (error) {
return new Response(
JSON.stringify({ error: error.message }),
{
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
status: 400,
}
)
}
})
async function processCustomLogic(agentId: string, data: any, supabase: any) {
// Implement your custom logic
const { data: agent } = await supabase
.from('agents')
.select('*')
.eq('id', agentId)
.single()
// Process data and return results
return {
agent_id: agentId,
processed: true,
result: 'Custom processing completed'
}
}
# Deploy the function
supabase functions deploy custom-logic
Deploy with specific permissions
supabase functions deploy custom-logic --no-verify-jwt
const response = await supabase.functions.invoke('custom-logic', {
body: {
agent_id: 'agent_123',
custom_data: {
type: 'sensor_calibration',
values: [1, 2, 3, 4, 5]
}
}
})
Edge Functions can handle multiple HTTP methods:
serve(async (req) => {
const url = new URL(req.url)
const path = url.pathname
const method = req.method
switch (method) {
case 'GET':
return handleGet(path, url.searchParams)
case 'POST':
return handlePost(path, await req.json())
case 'PUT':
return handlePut(path, await req.json())
case 'DELETE':
return handleDelete(path)
default:
return new Response('Method not allowed', { status: 405 })
}
})
import { Hono } from 'jsr:@hono/hono'
const app = new Hono()
app.get('/agents/:id', async (c) => {
const agentId = c.req.param('id')
// Handle GET /agents/:id
})
app.post('/agents/:id/telemetry', async (c) => {
const agentId = c.req.param('id')
const telemetryData = await c.req.json()
// Handle POST /agents/:id/telemetry
})
Deno.serve(app.fetch)
Edge Functions have access to these environment variables:
Variable | Description |
---|---|
SUPABASE_URL | Your Supabase project URL |
SUPABASE_ANON_KEY | Public anonymous key |
SUPABASE_SERVICE_ROLE_KEY | Service role key (full access) |
SUPABASE_DB_URL | Direct database connection URL |
Rate limits are per authenticated user per organization, except for webhook handlers which are per IP address.
# Edge Functions APIEdge Functions provide serverless compute capabilities for custom business logic, integrations, and real-time processing within the IoT Agent Mesh platform. These TypeScript functions run globally at the edge for low latency.
Edge Functions enable:
- Custom business logic processing
- Third-party service integrations
- Webhook handling and event processing
- Real-time data transformation
- Automated alert processing and notifications
- Custom API endpoints with advanced routing
/functions/v1/
Edge Functions support multiple authentication methods:
JWT Authentication (Recommended):
Authorization: Bearer YOUR_JWT_TOKEN
API Key Authentication:
Authorization: Bearer YOUR_API_KEY
No Authentication (Webhooks only):
Functions can be deployed with --no-verify-jwt
for webhook endpoints.
Process and validate telemetry data before storage.
POST /functions/v1/process-device-data
{
"agent_id": "agent_01H8K2M3N4P5Q6R7S8T9U0V1W2",
"raw_data": {
"temp": "23.5",
"hum": "65.2",
"batt": "87",
"sig": "-65"
},
"metadata": {
"firmware_version": "1.4.2",
"timestamp": "2024-07-23T16:45:00Z"
}
}
{
"processed_data": {
"temperature": 23.5,
"humidity": 65.2,
"battery_level": 87,
"signal_strength": -65
},
"validation_results": {
"valid": true,
"warnings": [],
"errors": []
},
"transformations_applied": [
"string_to_number",
"field_mapping",
"range_validation"
],
"stored": true,
"telemetry_id": "01H8K3L4M5N6O7P8Q9R0S1T2U3V4"
}
JavaScript/TypeScript:
const response = await supabase.functions.invoke('process-device-data', {
body: {
agent_id: 'agent_01H8K2M3N4P5Q6R7S8T9U0V1W2',
raw_data: {
temp: '23.5',
hum: '65.2',
batt: '87'
},
metadata: {
firmware_version: '1.4.2'
}
}
})
console.log('Processed data:', response.data)
Python:
import requests
response = requests.post(
'https://your-project-id.supabase.co/functions/v1/process-device-data',
headers={
'Authorization': f'Bearer {jwt_token}',
'Content-Type': 'application/json'
},
json={
'agent_id': 'agent_01H8K2M3N4P5Q6R7S8T9U0V1W2',
'raw_data': {
'temp': '23.5',
'hum': '65.2',
'batt': '87'
}
}
)
data = response.json()
Generic webhook handler for external service integrations.
POST /functions/v1/webhook-handler
X-Webhook-Source: stripe|github|custom
X-Webhook-Signature: sha256=signature_hash
Content-Type: application/json
{
"id": "evt_1234567890",
"object": "event",
"type": "invoice.payment_succeeded",
"data": {
"object": {
"id": "in_1234567890",
"customer": "cus_organization_123",
"amount_paid": 2999,
"status": "paid"
}
},
"created": 1721750400
}
{
"received": true,
"event_type": "invoice.payment_succeeded",
"processed": true,
"actions_taken": [
"updated_subscription_status",
"sent_confirmation_email",
"updated_organization_limits"
],
"processing_time_ms": 245
}
Webhook Integration:
// Configure webhook in external service to POST to:
// https://your-project-id.supabase.co/functions/v1/webhook-handler
// The function automatically handles:
// - Signature verification
// - Event deduplication
// - Retry logic
// - Database updates
Process and send alert notifications through multiple channels.
POST /functions/v1/send-alert-notification
{
"alert_id": "alert_01H8K3L4M5N6O7P8Q9R0S1T2U3V4",
"agent_id": "agent_01H8K2M3N4P5Q6R7S8T9U0V1W2",
"severity": "high",
"message": "Temperature exceeds threshold",
"data": {
"current_temperature": 42.5,
"threshold": 35.0,
"location": "warehouse-a"
},
"notification_channels": ["email", "sms", "webhook"],
"recipients": [
{
"type": "user",
"id": "user_01H8K2M3N4P5Q6R7S8T9U0V1W2"
},
{
"type": "role",
"role": "admin"
}
]
}
{
"alert_id": "alert_01H8K3L4M5N6O7P8Q9R0S1T2U3V4",
"notifications_sent": 3,
"results": [
{
"channel": "email",
"recipient": "[email protected]",
"status": "sent",
"sent_at": "2024-07-23T16:45:01Z"
},
{
"channel": "sms",
"recipient": "+1-555-0123",
"status": "sent",
"sent_at": "2024-07-23T16:45:02Z"
},
{
"channel": "webhook",
"recipient": "https://company.com/alerts",
"status": "sent",
"sent_at": "2024-07-23T16:45:03Z"
}
],
"processing_time_ms": 1250
}
JavaScript/TypeScript:
const response = await supabase.functions.invoke('send-alert-notification', {
body: {
alert_id: 'alert_01H8K3L4M5N6O7P8Q9R0S1T2U3V4',
agent_id: 'agent_01H8K2M3N4P5Q6R7S8T9U0V1W2',
severity: 'high',
message: 'Temperature exceeds threshold',
data: {
current_temperature: 42.5,
threshold: 35.0,
location: 'warehouse-a'
},
notification_channels: ['email', 'sms', 'webhook']
}
})
console.log('Notifications sent:', response.data.notifications_sent)
Perform complex data aggregations and analytics.
POST /functions/v1/data-aggregation
{
"aggregation_type": "time_series",
"agents": ["agent_01H8K2M3N4P5Q6R7S8T9U0V1W2", "agent_02H8K2M3N4P5Q6R7S8T9U0V1W3"],
"fields": [
{
"name": "temperature",
"operations": ["avg", "min", "max", "stddev"]
},
{
"name": "humidity",
"operations": ["avg"]
}
],
"time_range": {
"start": "2024-07-23T00:00:00Z",
"end": "2024-07-23T23:59:59Z"
},
"interval": "1h",
"filters": {
"temperature": {
"min": -50,
"max": 100
}
},
"output_format": "json"
}
{
"aggregation_id": "agg_01H8K3L4M5N6O7P8Q9R0S1T2U3V4",
"agents_processed": 2,
"time_range": {
"start": "2024-07-23T00:00:00Z",
"end": "2024-07-23T23:59:59Z"
},
"interval": "1h",
"data": [
{
"timestamp": "2024-07-23T00:00:00Z",
"temperature": {
"avg": 22.3,
"min": 19.8,
"max": 24.7,
"stddev": 1.2
},
"humidity": {
"avg": 65.4
},
"sample_count": 120
},
{
"timestamp": "2024-07-23T01:00:00Z",
"temperature": {
"avg": 22.1,
"min": 19.5,
"max": 24.3,
"stddev": 1.1
},
"humidity": {
"avg": 66.1
},
"sample_count": 120
}
],
"summary": {
"total_samples": 2880,
"processing_time_ms": 450,
"cache_hit_rate": 0.85
}
}
JavaScript/TypeScript:
const response = await supabase.functions.invoke('data-aggregation', {
body: {
aggregation_type: 'time_series',
agents: ['agent_01H8K2M3N4P5Q6R7S8T9U0V1W2'],
fields: [
{
name: 'temperature',
operations: ['avg', 'min', 'max']
}
],
time_range: {
start: '2024-07-23T00:00:00Z',
end: '2024-07-23T23:59:59Z'
},
interval: '1h'
}
})
console.log('Aggregated data:', response.data.data)
Generate comprehensive reports with data visualization.
POST /functions/v1/generate-report
{
"report_type": "organization_summary",
"organization_id": "org_01H8K2M3N4P5Q6R7S8T9U0V1W2",
"time_period": {
"start": "2024-07-01T00:00:00Z",
"end": "2024-07-31T23:59:59Z"
},
"sections": [
"agent_overview",
"telemetry_summary",
"alert_analysis",
"performance_metrics"
],
"format": "pdf",
"include_charts": true,
"recipients": ["[email protected]"]
}
{
"report_id": "report_01H8K3L4M5N6O7P8Q9R0S1T2U3V4",
"status": "generated",
"format": "pdf",
"file_size": "2.3MB",
"download_url": "https://your-project-id.supabase.co/storage/v1/object/reports/report_01H8K3L4M5N6O7P8Q9R0S1T2U3V4.pdf",
"expires_at": "2024-08-23T16:45:00Z",
"sections_included": [
"agent_overview",
"telemetry_summary",
"alert_analysis",
"performance_metrics"
],
"generation_time_ms": 3500,
"email_sent": true
}
Integrate with third-party services and APIs.
POST /functions/v1/external-integration
{
"service": "weather_api",
"action": "get_weather_data",
"parameters": {
"location": "warehouse-a",
"coordinates": {
"lat": 40.7128,
"lon": -74.0060
}
},
"agent_id": "agent_01H8K2M3N4P5Q6R7S8T9U0V1W2",
"correlation_fields": ["temperature", "humidity", "pressure"]
}
{
"service": "weather_api",
"status": "success",
"data": {
"temperature": 24.3,
"humidity": 68.5,
"pressure": 1013.2,
"wind_speed": 5.2,
"conditions": "partly_cloudy"
},
"correlation_analysis": {
"temperature_correlation": 0.87,
"humidity_correlation": 0.72,
"pressure_correlation": 0.93
},
"recommendations": [
"External temperature is consistent with sensor readings",
"Consider calibrating humidity sensor - 3.3% deviation",
"Pressure readings are highly accurate"
],
"cached_until": "2024-07-23T17:45:00Z"
}
You can deploy custom Edge Functions for specific business logic:
// supabase/functions/custom-logic/index.ts
import { serve } from 'https://deno.land/[email protected]/http/server.ts'
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}
serve(async (req) => {
// Handle CORS preflight requests
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders })
}
try {
// Initialize Supabase client
const supabase = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? ''
)
// Get request body
const { agent_id, custom_data } = await req.json()
// Your custom business logic here
const result = await processCustomLogic(agent_id, custom_data, supabase)
return new Response(
JSON.stringify(result),
{
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
status: 200,
}
)
} catch (error) {
return new Response(
JSON.stringify({ error: error.message }),
{
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
status: 400,
}
)
}
})
async function processCustomLogic(agentId: string, data: any, supabase: any) {
// Implement your custom logic
const { data: agent } = await supabase
.from('agents')
.select('*')
.eq('id', agentId)
.single()
// Process data and return results
return {
agent_id: agentId,
processed: true,
result: 'Custom processing completed'
}
}
# Deploy the function
supabase functions deploy custom-logic
# Deploy with specific permissions
supabase functions deploy custom-logic --no-verify-jwt
const response = await supabase.functions.invoke('custom-logic', {
body: {
agent_id: 'agent_123',
custom_data: {
type: 'sensor_calibration',
values: [1, 2, 3, 4, 5]
}
}
})
Edge Functions can handle multiple HTTP methods:
serve(async (req) => {
const url = new URL(req.url)
const path = url.pathname
const method = req.method
switch (method) {
case 'GET':
return handleGet(path, url.searchParams)
case 'POST':
return handlePost(path, await req.json())
case 'PUT':
return handlePut(path, await req.json())
case 'DELETE':
return handleDelete(path)
default:
return new Response('Method not allowed', { status: 405 })
}
})
import { Hono } from 'jsr:@hono/hono'
const app = new Hono()
app.get('/agents/:id', async (c) => {
const agentId = c.req.param('id')
// Handle GET /agents/:id
})
app.post('/agents/:id/telemetry', async (c) => {
const agentId = c.req.param('id')
const telemetryData = await c.req.json()
// Handle POST /agents/:id/telemetry
})
Deno.serve(app.fetch)
Edge Functions have access to these environment variables:
Variable | Description |
---|---|
SUPABASE_URL |
Your Supabase project URL |
SUPABASE_ANON_KEY |
Public anonymous key |
SUPABASE_SERVICE_ROLE_KEY |
Service role key (full access) |
SUPABASE_DB_URL |
Direct database connection URL |
// Access custom environment variables
const API_KEY = Deno.env.get('THIRD_PARTY_API_KEY')
const WEBHOOK_SECRET = Deno.env.get('WEBHOOK_SECRET')
const SMTP_CONFIG = {
host: Deno.env.get('SMTP_HOST'),
port: Deno.env.get('SMTP_PORT'),
user: Deno.env.get('SMTP_USER'),
pass: Deno.env.get('SMTP_PASS')
}
{
"error": {
"code": "FUNCTION_ERROR",
"message": "Error processing request",
"details": {
"function": "process-device-data",
"timestamp": "2024-07-23T16:45:00Z",
"request_id": "req_01H8K3L4M5N6O7P8Q9R0S1T2U3V4"
}
},
"status": 500
}
serve(async (req) => {
try {
// Function logic here
return new Response(JSON.stringify(result), {
headers: { 'Content-Type': 'application/json' },
status: 200
})
} catch (error) {
console.error('Function error:', error)
return new Response(JSON.stringify({
error: {
code: 'FUNCTION_ERROR',
message: error.message,
details: {
function: 'function-name',
timestamp: new Date().toISOString()
}
}
}), {
headers: { 'Content-Type': 'application/json' },
status: 500
})
}
})
-
Cold Start Optimization:
// Initialize expensive resources outside the serve handler const supabase = createClient(url, key) const httpClient = new HTTPClient() serve(async (req) => { // Use pre-initialized resources })
-
Connection Pooling:
// Reuse database connections const dbPool = new Pool({ connectionString: Deno.env.get('SUPABASE_DB_URL'), max: 10 })
-
Caching:
const cache = new Map() async function getCachedData(key: string) { if (cache.has(key)) { return cache.get(key) } const data = await fetchData(key) cache.set(key, data) return data }
-
Streaming Responses:
serve(async (req) => { const stream = new ReadableStream({ start(controller) { // Stream large datasets processDataInChunks((chunk) => { controller.enqueue(chunk) }) } }) return new Response(stream, { headers: { 'Content-Type': 'application/json' } }) })
// Add performance monitoring
const startTime = performance.now()
// Function logic here
const endTime = performance.now()
const executionTime = endTime - startTime
console.log(`Function executed in ${executionTime}ms`)
// Log metrics for monitoring
await logMetrics({
function_name: 'process-device-data',
execution_time_ms: executionTime,
memory_usage: Deno.memoryUsage(),
timestamp: new Date().toISOString()
})
# Start local Supabase stack
supabase start
# Your function is available at:
# http://localhost:54321/functions/v1/your-function-name
# Test with curl
curl -X POST http://localhost:54321/functions/v1/process-device-data \
-H "Authorization: Bearer YOUR_LOCAL_JWT" \
-H "Content-Type: application/json" \
-d '{"agent_id": "test-agent", "data": {"temp": 25}}'
// tests/process-device-data.test.ts
import { assertEquals } from 'https://deno.land/[email protected]/testing/asserts.ts'
import { processDeviceData } from '../functions/process-device-data/index.ts'
Deno.test('should process device data correctly', async () => {
const input = {
agent_id: 'test-agent',
raw_data: { temp: '25.5', hum: '60' }
}
const result = await processDeviceData(input)
assertEquals(result.processed_data.temperature, 25.5)
assertEquals(result.processed_data.humidity, 60)
assertEquals(result.validation_results.valid, true)
})
// Test with real Supabase instance
const supabase = createClient(TEST_URL, TEST_KEY)
const response = await supabase.functions.invoke('process-device-data', {
body: {
agent_id: 'test-agent',
raw_data: { temp: '25.5' }
}
})
assertEquals(response.status, 200)
assertEquals(response.data.processed_data.temperature, 25.5)
import { createClient } from '@supabase/supabase-js'
async function validateAuth(req: Request) {
const authHeader = req.headers.get('Authorization')
if (!authHeader) {
throw new Error('Missing authorization header')
}
const token = authHeader.replace('Bearer ', '')
const supabase = createClient(url, anonKey)
const { data: { user }, error } = await supabase.auth.getUser(token)
if (error || !user) {
throw new Error('Invalid token')
}
return user
}
import { z } from 'https://deno.land/x/zod/mod.ts'
const inputSchema = z.object({
agent_id: z.string().min(1),
data: z.object({
temperature: z.number().min(-50).max(100)
})
})
serve(async (req) => {
try {
const body = await req.json()
const validatedInput = inputSchema.parse(body)
// Process validated input
} catch (error) {
return new Response(JSON.stringify({
error: 'Invalid input',
details: error.issues
}), { status: 400 })
}
})
const requestCounts = new Map()
function rateLimit(identifier: string, limit: number, window: number) {
const now = Date.now()
const windowStart = now - window
const requests = requestCounts.get(identifier) || []
const recentRequests = requests.filter(time => time > windowStart)
if (recentRequests.length >= limit) {
throw new Error('Rate limit exceeded')
}
recentRequests.push(now)
requestCounts.set(identifier, recentRequests)
}
- [Telemetry API](API-Telemetry.md) - Data processing and storage
- [Alerts API](API-Alerts.md) - Alert processing and notifications
- [Webhooks API](API-Webhooks.md) - Webhook configuration and handling
- [Authentication API](API-Authentication.md) - Function authentication methods
Function Type | Rate Limit | Window |
---|---|---|
Data Processing | 1000 requests | 1 minute |
Webhook Handlers | 2000 requests | 1 minute |
Report Generation | 10 requests | 1 hour |
External Integrations | 100 requests | 1 minute |
Custom Functions | 500 requests | 1 minute |
Rate limits are per authenticated user per organization, except for webhook handlers which are per IP address.