> ## Documentation Index
> Fetch the complete documentation index at: https://platform.docs.zenoo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sharables

> Sharables allow you to create secure, time-limited tokens for sharing executable workflows, functions, or data payloads.

# Sharables

Sharables are a powerful feature that allows you to create secure, time-limited tokens for sharing executable workflows, functions, or data payloads. They enable asynchronous execution patterns, external integrations, and data polling mechanisms.

## Overview

There are two types of sharables:

* **Payload Sharables** - Store data that can be accessed across different executions
* **Execution Sharables** - Create links that can be shared to start workflows or functions with specific data

The sharables and their data are stored in AWS DynamoDB table `sharable`. Related events are stored in `sharable-events` Kafka topic.
Sharable events can be processed for real-time metrics and analytics purposes. There is also `sharable-requests` Kafka topic used
internally by hub to process sharable requests and commands.

## Table of Contents

### Getting Started

* [Token Management](#token-management)
  * [Token Generation](#token-generation)
  * [Security Considerations](#security-considerations)
  * [Default Expiration](#default-expiration)

### Execution Sharables

* [Execution Sharables](#execution-sharables)
  * [DSL Syntax](#dsl-syntax)
    * [Basic Function Execution](#basic-function-execution)
    * [Workflow Execution](#workflow-execution)
    * [Advanced Options](#advanced-options)
  * [DSL Options Reference](#dsl-options-reference)
  * [Use Cases](#use-cases)
    * [Email Notifications with Actions](#1-email-notifications-with-actions)
    * [External System Integration](#2-external-system-integration)
    * [Multi-step Workflows](#3-multi-step-workflows)
    * [Reusable Service Endpoints](#4-reusable-service-endpoints)
  * [API Endpoints](#api-endpoints)
    * [Execute Sharable](#execute-sharable)

### Payload Sharables

* [Payload Sharables](#payload-sharables)
  * [DSL Syntax](#dsl-syntax-1)
  * [Use Cases](#use-cases-1)
    * [Polling Pattern](#1-polling-pattern-1)
    * [Data Caching](#2-data-caching-1)
  * [API Endpoints](#api-endpoints-1)
    * [Retrieve Payload Data](#retrieve-payload-data)

### Lifecycle Management

* [Expiration and Lifecycle](#expiration-and-lifecycle)
  * [Expiration Behavior](#expiration-behavior)
  * [Expiration Formats](#expiration-formats)
  * [Manual Expiration](#manual-expiration)

### Events and Monitoring

* [Event System](#event-system)
  * [Payload Sharable Events](#payload-sharable-events)
  * [Execution Sharable Events](#execution-sharable-events)
  * [Common Events](#common-events)
  * [Error Events](#error-events)

### Integration Patterns

* [Integration Patterns](#integration-patterns)
  * [Async Processing with Polling](#1-async-processing-with-polling)
  * [External Callback Integration](#2-external-callback-integration)
  * [User Action Workflows](#3-user-action-workflows)
  * [Multi-tenant Service Access](#4-multi-tenant-service-access)
  * [Mobile Hand-off with Terminal Route Result](#5-mobile-hand-off-with-terminal-route-result)

### Operations

* [Configuration and Operations](#configuration-and-operations)
  * [Timeout Configuration](#timeout-configuration)
  * [Monitoring and Metrics](#monitoring-and-metrics)
  * [Storage Details](#storage-details)
  * [Best Practices](#best-practices)
  * [Troubleshooting](#troubleshooting)

## Token Management

### Token Generation

* **Default**: 6 random alphanumeric characters (e.g., `aB3xY9`)
* **Custom**: You can specify your own token
* **Collision Handling**: If a token already exists, the operation will fail

### Security Considerations

* Tokens are **bearer tokens** - anyone with the token has full access
* Use appropriate expiration times to limit exposure
* Consider the security implications when sharing URLs containing tokens
* Store tokens securely and avoid logging them in plain text

### Default Expiration

* **Default expiration**: 24 hours if not specified
* **Custom expiration**: Use `expireIn` with ISO-8601 duration or simple format
* **Automatic cleanup**: DynamoDB TTL automatically removes expired records

## Execution Sharables

Execution sharables create links that can be shared to start workflows or functions with predefined or dynamic input data.

### DSL Syntax

#### Basic Function Execution

```groovy theme={null}
// Simple function sharable
link << sharable {
    function 'process-payment'
}

// Function with predefined input and context
payment_link << sharable {
    function 'process-payment' {
        input amount: 100, currency: "USD"
        context merchant_id: "12345"
    }
    expireIn "PT1H"  // 1 hour
}
```

#### Workflow Execution

```groovy theme={null}
// Workflow sharable with custom URL
approval_link << sharable {
    url "https://approval.company.com/workflow/${token}"
    workflow 'approval-process' {
        input document_id: input.document_id
        context user_id: execution.context.user_id
    }
    reusable()  // Can be executed multiple times
}
```

#### Advanced Options

```groovy theme={null}
// Latest version resolution
sharable {
    function 'data-processor'
    latest()     // Resolve to latest version at execution time
    reusable()   // Allow multiple executions
    namespace result  // Store execution result asynchronously
    expireIn "P1D"    // 1 day (ISO-8601 format)
}
```

### DSL Options Reference

| Option           | Description                       | Example                              |
| ---------------- | --------------------------------- | ------------------------------------ |
| `function(name)` | Execute a function                | `function 'my-function'`             |
| `workflow(name)` | Execute a workflow                | `workflow 'my-workflow'`             |
| `input`          | Predefined input data             | `input userId: "123"`                |
| `context`        | Predefined context data           | `context region: "us-east"`          |
| `reusable()`     | Allow multiple executions         | `reusable()`                         |
| `latest()`       | Resolve version at execution time | `latest()`                           |
| `namespace`      | Store result asynchronously       | `namespace result`                   |
| `expireIn`       | Custom expiration time            | `expireIn "30m"`                     |
| `url(template)`  | Custom URL template               | `url "https://example.com/${token}"` |

### Use Cases

#### 1. **Email Notifications with Actions**

```groovy theme={null}
function("send-approval-email") { input ->
    // Create approval and rejection links
    approve_link << sharable {
        url "https://company.com/approve/${token}"
        function 'approve-request' {
            input request_id: input.request_id
            context approver: input.approver_email
        }
        expireIn "P7D"  // 7 days
    }

    reject_link << sharable {
        url "https://company.com/reject/${token}"
        function 'reject-request' {
            input request_id: input.request_id
            context approver: input.approver_email
        }
        expireIn "P7D"
    }

    send_email([
        to: input.approver_email,
        subject: "Approval Required",
        body: """
        Please review the request:

        Approve: ${approve_link}
        Reject: ${reject_link}
        """
    ])
}
```

#### 2. **External System Integration**

```groovy theme={null}
function("webhook-handler") { input ->
    // Create callback for external system
    callback_token << sharable {
        function 'process-webhook-response' {
            input webhook_id: input.webhook_id
        }
        expireIn "PT2H"  // 2 hours
    }

    // Send to external system
    http.post("https://external-system.com/api/process") {
        body([
            data: input.payload,
            callback_url: "https://our-hub.com/api/gateway/sharable/${callback_token}"
        ])
    }

    [
        status: "processing",
        callback_token: callback_token
    ]
}
```

#### 3. **Multi-step Workflows**

```groovy theme={null}
workflow("document-approval") {
    route("Submit") {
        uri '/submit'

        // Create links for each approval step
        step1_link << sharable {
            workflow 'approval-step' {
                input step: 1, document_id: input.document_id
                context previous_step: execution.uuid
            }
            expireIn "P14D"  // 14 days
        }

        export step1_url: "https://portal.com/approve/${step1_link}"

        route("NextStep")
    }

    route("NextStep") {
        uri '/next-step'
        terminal()
    }
}
```

#### 4. **Reusable Service Endpoints**

```groovy theme={null}
function("create-service-endpoint") { input ->
    service_token << sharable {
        reusable()  // Allow multiple calls
        function 'service-handler' {
            context service_config: input.config
        }
        expireIn "P30D"  // 30 days
    }

    [
        endpoint_url: "https://api.company.com/service/${service_token}",
        token: service_token,
        expires_at: now().plusDays(30)
    ]
}
```

### API Endpoints

#### Execute Sharable

```
POST /api/gateway/sharable/{token}
```

**Request Body:** JSON payload (optional) - becomes execution input
**Response Codes:**

* `201 Created` - Execution started successfully
* `400 Bad Request` - Token doesn't exist
* `410 Gone` - Token has expired
* `504 Gateway Timeout` - Operation timeout

**Example:**

```bash theme={null}
curl -X POST https://hub.example.com/api/gateway/sharable/aB3xY9 \
  -H "Content-Type: application/json" \
  -d '{"user_id": "12345", "action": "approve"}'
```

**Response:**

```json theme={null}
{
    "uuid": "89828e1e-c834-42a2-86f1-893209f63ab5",
    "requestURI": "/api/gateway/request/89828e1e-c834-42a2-86f1-893209f63ab5",
    "executionURI": "/api/gateway/execution/89828e1e-c834-42a2-86f1-893209f63ab5"
}
```

## Payload Sharables

Payload sharables store data that can be accessed across different executions, enabling polling and data sharing patterns.

### DSL Syntax

```groovy theme={null}
// Basic payload sharable with auto-generated token
token << sharable {
    payload application: [
        id: "12345",
        status: "pending"
    ]
}

// Custom token with expiration
sharable("custom-token-123") {
    payload result: calculation_result
    expireIn "PT30M"  // 30 minutes
}

// Simple expiration format
sharable {
    payload data: response_data
    expireIn "5s"     // 5 seconds
}
```

### Use Cases

#### 1. **Polling Pattern**

External systems can poll for data availability:

```groovy theme={null}
// Component generates data and provides polling token
exposed("generate-report") { input ->
    // Start async report generation
    report_data << async_report_generation(input)

    // Create polling token
    poll_token << sharable {
        payload result: report_data
        expireIn "1h"
    }

    [
        status: "processing",
        poll_url: "https://api.example.com/poll/${poll_token}",
        poll_token: poll_token
    ]
}
```

#### 2. **Data Caching**

Store computed results for reuse:

```groovy theme={null}
function("expensive-calculation") { input ->
    cache_key << sharable {
        payload result: expensive_computation(input)
        expireIn "24h"
    }

    // Return both result and cache reference
    [
        result: expensive_computation(input),
        cache_token: cache_key
    ]
}
```

### API Endpoints

#### Retrieve Payload Data

```
GET /api/gateway/sharable-payload/{token}
```

**Response Codes:**

* `200 OK` - Payload data returned as JSON
* `404 Not Found` - Token doesn't exist or has expired
* `504 Gateway Timeout` - Operation timeout

**Example:**

```bash theme={null}
curl -X GET https://hub.example.com/api/gateway/sharable-payload/aB3xY9
```

**Response:**

```json theme={null}
{
    "application": {
        "id": "12345",
        "status": "completed"
    }
}
```

## Expiration and Lifecycle

### Expiration Behavior

* **Payload Sharables**: Expire based on `expireIn` setting or default (24h)
* **Execution Sharables**:
  * **Reusable**: Only expire based on time settings
  * **Single-use**: Expire after execution terminates OR time limit

### Expiration Formats

```groovy theme={null}
// ISO-8601 duration format
expireIn "PT30M"    // 30 minutes
expireIn "PT2H"     // 2 hours
expireIn "P1D"      // 1 day
expireIn "P7D"      // 7 days

// Simple format
expireIn "30s"      // 30 seconds
expireIn "5m"       // 5 minutes
expireIn "2h"       // 2 hours
expireIn "1d"       // 1 day
```

### Manual Expiration

```groovy theme={null}
// Expire a specific token
sharable('token-to-expire') {
    expired()
}

// Expire the current execution's sharable token
sharable(execution.sharable) {
    expired()
}
```

## Event System

### Payload Sharable Events

#### CreatedPayloadSharable

Produced when payload sharable is created:

* `token` - identifier of created sharable

#### ExpiredSharable

Produced when payload sharable expires:

* `token` - identifier of expired sharable
* `executable` - associated function/workflow (if any)
* `requestContext` - execution context

### Execution Sharable Events

#### CreatedExecuteSharable

Produced when execution sharable is created:

* `token` - identifier of created sharable
* `reusable` - whether sharable can be executed repeatedly
* `executable` - function/workflow to execute
* `requestContext` - execution context

#### ExecutedSharable

Produced when execution sharable is invoked:

* `token` - identifier of executed sharable
* `executable` - function/workflow executed
* `requestContext` - execution context

#### TerminatedSharable

Produced when workflow started by execution sharable terminates:

* `token` - identifier of terminated sharable
* `executable` - function/workflow terminated
* `requestContext` - execution context

### Common Events

#### DeletedSharable

Produced when a sharable is deleted:

* `token` - identifier of deleted sharable

### Error Events

All error events include:

* `token` - identifier of sharable that failed
* `message` - error message

#### CreatingPayloadSharableError

Produced when creating payload sharable fails

#### CreatingExecuteSharableError

Produced when creating execute sharable fails

#### DeletingSharableError

Produced when deleting sharable fails

#### ExecutingSharableError

Produced when executing sharable fails:

* `errorType` - GENERAL, SHARABLE\_EXPIRED, SHARABLE\_NOT\_FOUND, COMPONENT\_NOT\_FOUND, NO\_EXECUTE\_REQUEST
* `requestContext` - execution context

#### ExpiringSharableError

Produced when expiring sharable fails

## Integration Patterns

### 1. **Async Processing with Polling**

```groovy theme={null}
// Service endpoint for long-running tasks
exposed("start-processing") { input ->
    // Start async processing
    processing_job << async_processor(input.data)

    // Create status polling token
    status_token << sharable {
        payload status: processing_job.status,
                progress: processing_job.progress,
                result: processing_job.result
        expireIn "24h"
    }

    [
        job_id: processing_job.id,
        status_url: "https://api.company.com/status/${status_token}",
        estimated_completion: "PT2H"
    ]
}
```

### 2. **External Callback Integration**

```groovy theme={null}
function("external-api-call") { input ->
    callback_token << sharable {
        function 'handle-external-response' {
            input original_request: input
        }
        expireIn "PT1H"
    }

    http.post("https://external-api.com/process") {
        body([
            data: input.payload,
            webhook_url: "https://our-hub.com/api/gateway/sharable/${callback_token}"
        ])
    }

    // Wait for callback or timeout
    await(callback_response, "55m") {
        timeout {
            log "External API call timed out"
            [status: "timeout"]
        }
        success {
            callback_response
        }
    }
}
```

### 3. **User Action Workflows**

```groovy theme={null}
workflow("user-approval-flow") {
    route("RequestApproval") {
        uri '/request'

        // Create user action links
        approve_token << sharable {
            workflow 'approval-granted' {
                input request_id: input.request_id
                context decision: "approved"
            }
        }

        reject_token << sharable {
            workflow 'approval-denied' {
                input request_id: input.request_id
                context decision: "rejected"
            }
        }

        // Send notification
        send_notification([
            user: input.approver,
            message: "Approval required",
            approve_url: "https://portal.com/approve/${approve_token}",
            reject_url: "https://portal.com/reject/${reject_token}"
        ])

        route("AwaitDecision")
    }

    route("AwaitDecision") {
        uri '/await'

        await(decision_result, "P7D") {
            timeout {
                export status: "expired"
                route("Timeout")
            }
            success {
                export status: "decided", result: decision_result
                route("Complete")
            }
        }
    }
}
```

### 4. **Multi-tenant Service Access**

```groovy theme={null}
function("create-tenant-access") { input ->
    tenant_token << sharable {
        reusable()  // Allow multiple API calls
        function 'tenant-api-handler' {
            context tenant_id: input.tenant_id,
                    permissions: input.permissions
        }
        expireIn "P90D"  // 90 days
    }

    [
        tenant_id: input.tenant_id,
        api_token: tenant_token,
        api_url: "https://api.company.com/tenant/${tenant_token}",
        expires_at: now().plusDays(90)
    ]
}
```

### 5. **Mobile Hand-off with Terminal Route Result**

Pass execution control to a mobile device or external system, then receive the result back into the main execution flow:

```groovy theme={null}
workflow("mobile-handoff-flow") {
    payload ->
        // Create a sharable workflow for mobile execution
        sharable(payload) {
            workflow 'mobile-workflow'
            namespace handoff  // Result will be stored in this namespace
            expireIn "PT1H"    // 1 hour for user to complete on mobile
        }

        // Wait for mobile workflow to complete and return result
        await(handoff, "1h") {
            onTimeout {
                // Handle timeout if user doesn't complete mobile workflow
                log.error("Mobile verification timeout")
            }
        }

        // After await completes, mobile workflow result is available in handoff namespace
        route('result') {
            uri '/result'
            export handoff  // Export the result received from mobile workflow
            terminal()
        }
}

// Mobile workflow that runs independently on mobile device
workflow("mobile-workflow") {
    payload ->
        route('verify-identity') {
            uri '/verify'
            // User performs biometric verification or other mobile actions
        }

        route('capture-data') {
            uri '/capture'
            // Capture photos, signatures, etc.
        }

        route('complete') {
            uri '/complete'
            // Terminal route with result data that gets passed back to main execution
            terminal([
                verified: true,
                biometric_score: input.biometric_score,
                captured_images: input.images,
                completed_at: now()
            ])
        }
}
```

**Key Features:**

* **Namespace Assignment**: Use `namespace` in the sharable to specify where the hand-off result will be stored
* **Terminal Route Result**: The mobile workflow ends with `terminal(payload)` to pass data back
* **Await Command**: `await(namespace, timeout)` pauses execution until the mobile workflow completes
* **Automatic Result Propagation**: Terminal route result is automatically sent to the awaiting execution
* **Timeout Handling**: Use `onTimeout` block to handle cases where the mobile workflow isn't completed in time
* **Result Access**: After await completes, access the result via the namespace variable (e.g., `handoff`)

**Use Cases:**

* Mobile biometric verification during web onboarding
* Photo/document capture on mobile device
* Mobile signature collection
* Two-factor authentication via mobile app
* Mobile payment authorization

**Flow Diagram:**

1. Main execution creates sharable with namespace and starts await
2. Mobile device receives sharable token and executes workflow independently
3. Mobile workflow terminates with `terminal(result_data)`
4. Result is automatically propagated to main execution's namespace
5. Main execution resumes and accesses result via namespace variable

## Configuration and Operations

### Timeout Configuration

```yaml theme={null}
# application.yml
hub:
  sharable:
    operation-timeout: PT30S    # DynamoDB operations
    execute-timeout: PT1M       # Execution preparation
```

### Monitoring and Metrics

Monitor these Kafka topics for sharable activity:

* `sharable-events` - All sharable lifecycle events
* `sharable-requests` - Internal processing requests

Key metrics to track:

* Token creation rate
* Token execution rate
* Token expiration rate
* Error rates by type
* Average token lifetime

### Storage Details

* **DynamoDB Table**: `sharable`
* **Partition Key**: `token` (string)
* **TTL Attribute**: `ttlEpochSeconds` for automatic cleanup
* **State Store**: Kafka Streams state store for expiration tracking

### Best Practices

1. **Security**
   * Use appropriate expiration times
   * Don't log tokens in plain text
   * Consider token rotation for long-lived services

2. **Performance**
   * Use reusable tokens for high-frequency access
   * Set reasonable expiration times to prevent storage bloat
   * Monitor token usage patterns

3. **Error Handling**
   * Always handle 410 Gone responses for expired tokens
   * Implement retry logic for timeout errors
   * Log sharable events for debugging

4. **Integration**
   * Use polling patterns for async operations
   * Implement proper webhook validation
   * Consider rate limiting for reusable tokens

## Troubleshooting

### Common Issues

#### Token Not Found (400 Bad Request)

* Verify token exists and hasn't been deleted
* Check for typos in token value
* Ensure proper URL encoding

#### Token Expired (410 Gone)

* Check `expireIn` settings
* Verify token hasn't timed out
* For single-use tokens, ensure execution hasn't already completed

#### Timeout Errors (504 Gateway Timeout)

* Check DynamoDB connectivity
* Verify operation timeout configuration
* Monitor Kafka topics for processing delays

#### Execution Errors

* Verify component availability
* Check function/workflow references
* Review execution permissions and context
