diff --git a/content/docs/references/auth/config.mdx b/content/docs/references/auth/config.mdx
index f78bdb912..a5268eb2d 100644
--- a/content/docs/references/auth/config.mdx
+++ b/content/docs/references/auth/config.mdx
@@ -12,8 +12,8 @@ description: Config protocol schemas
## TypeScript Usage
```typescript
-import { AccountLinkingConfigSchema, AuthConfigSchema, AuthPluginConfigSchema, AuthStrategySchema, CSRFConfigSchema, DatabaseAdapterSchema, DatabaseMappingSchema, EmailPasswordConfigSchema, EnterpriseAuthConfigSchema, LDAPConfigSchema, MagicLinkConfigSchema, OAuthProviderSchema, OIDCConfigSchema, PasskeyConfigSchema, RateLimitConfigSchema, SAMLConfigSchema, SessionConfigSchema, StandardAuthProviderSchema, TwoFactorConfigSchema, UserFieldMappingSchema } from '@objectstack/spec/auth';
-import type { AccountLinkingConfig, AuthConfig, AuthPluginConfig, AuthStrategy, CSRFConfig, DatabaseAdapter, DatabaseMapping, EmailPasswordConfig, EnterpriseAuthConfig, LDAPConfig, MagicLinkConfig, OAuthProvider, OIDCConfig, PasskeyConfig, RateLimitConfig, SAMLConfig, SessionConfig, StandardAuthProvider, TwoFactorConfig, UserFieldMapping } from '@objectstack/spec/auth';
+import { AccountLinkingConfigSchema, AuthConfigSchema, AuthPluginConfigSchema, AuthStrategySchema, CSRFConfigSchema, DatabaseAdapterSchema, DatabaseMappingSchema, EmailPasswordConfigSchema, EnterpriseAuthConfigSchema, LDAPConfigSchema, MagicLinkConfigSchema, OAuthProviderSchema, OIDCConfigSchema, PasskeyConfigSchema, SAMLConfigSchema, SessionConfigSchema, StandardAuthProviderSchema, TwoFactorConfigSchema, UserFieldMappingSchema } from '@objectstack/spec/auth';
+import type { AccountLinkingConfig, AuthConfig, AuthPluginConfig, AuthStrategy, CSRFConfig, DatabaseAdapter, DatabaseMapping, EmailPasswordConfig, EnterpriseAuthConfig, LDAPConfig, MagicLinkConfig, OAuthProvider, OIDCConfig, PasskeyConfig, SAMLConfig, SessionConfig, StandardAuthProvider, TwoFactorConfig, UserFieldMapping } from '@objectstack/spec/auth';
// Validate data
const result = AccountLinkingConfigSchema.parse(data);
@@ -238,20 +238,6 @@ const result = AccountLinkingConfigSchema.parse(data);
---
-## RateLimitConfig
-
-### Properties
-
-| Property | Type | Required | Description |
-| :--- | :--- | :--- | :--- |
-| **enabled** | `boolean` | optional | |
-| **maxAttempts** | `number` | optional | Maximum login attempts |
-| **windowMs** | `number` | optional | Time window in milliseconds (default 15 min) |
-| **blockDuration** | `number` | optional | Block duration after max attempts in ms |
-| **skipSuccessfulRequests** | `boolean` | optional | Only count failed requests |
-
----
-
## SAMLConfig
### Properties
diff --git a/content/docs/references/auth/connector.mdx b/content/docs/references/auth/connector.mdx
new file mode 100644
index 000000000..91607ac82
--- /dev/null
+++ b/content/docs/references/auth/connector.mdx
@@ -0,0 +1,35 @@
+---
+title: Connector
+description: Connector protocol schemas
+---
+
+# Connector
+
+
+**Source:** `packages/spec/src/auth/connector.zod.ts`
+
+
+## TypeScript Usage
+
+```typescript
+import { RateLimitConfigSchema } from '@objectstack/spec/auth';
+import type { RateLimitConfig } from '@objectstack/spec/auth';
+
+// Validate data
+const result = RateLimitConfigSchema.parse(data);
+```
+
+---
+
+## RateLimitConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **enabled** | `boolean` | optional | |
+| **maxAttempts** | `number` | optional | Maximum login attempts |
+| **windowMs** | `number` | optional | Time window in milliseconds (default 15 min) |
+| **blockDuration** | `number` | optional | Block duration after max attempts in ms |
+| **skipSuccessfulRequests** | `boolean` | optional | Only count failed requests |
+
diff --git a/content/docs/references/automation/connector.mdx b/content/docs/references/automation/connector.mdx
index a0363065b..7b9e0dfb6 100644
--- a/content/docs/references/automation/connector.mdx
+++ b/content/docs/references/automation/connector.mdx
@@ -12,8 +12,8 @@ description: Connector protocol schemas
## TypeScript Usage
```typescript
-import { AuthFieldSchema, AuthenticationSchema, AuthenticationTypeSchema, ConnectorSchema, ConnectorCategorySchema, ConnectorInstanceSchema, ConnectorOperationSchema, ConnectorTriggerSchema, OAuth2ConfigSchema, OperationParameterSchema, OperationTypeSchema } from '@objectstack/spec/automation';
-import type { AuthField, Authentication, AuthenticationType, Connector, ConnectorCategory, ConnectorInstance, ConnectorOperation, ConnectorTrigger, OAuth2Config, OperationParameter, OperationType } from '@objectstack/spec/automation';
+import { AuthFieldSchema, AuthenticationSchema, AuthenticationTypeSchema, ConflictResolutionSchema, ConnectorSchema, ConnectorCategorySchema, ConnectorInstanceSchema, ConnectorOperationSchema, ConnectorTriggerSchema, DataSyncConfigSchema, FieldMappingSchema, OAuth2ConfigSchema, OperationParameterSchema, OperationTypeSchema } from '@objectstack/spec/automation';
+import type { AuthField, Authentication, AuthenticationType, ConflictResolution, Connector, ConnectorCategory, ConnectorInstance, ConnectorOperation, ConnectorTrigger, DataSyncConfig, FieldMapping, OAuth2Config, OperationParameter, OperationType } from '@objectstack/spec/automation';
// Validate data
const result = AuthFieldSchema.parse(data);
@@ -65,6 +65,18 @@ const result = AuthFieldSchema.parse(data);
---
+## ConflictResolution
+
+### Allowed Values
+
+* `source_wins`
+* `destination_wins`
+* `latest_wins`
+* `manual`
+* `merge`
+
+---
+
## Connector
### Properties
@@ -167,6 +179,48 @@ const result = AuthFieldSchema.parse(data);
---
+## DataSyncConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **name** | `string` | ✅ | Sync configuration name (snake_case) |
+| **label** | `string` | optional | Sync display name |
+| **description** | `string` | optional | Sync description |
+| **source** | `object` | ✅ | Data source |
+| **destination** | `object` | ✅ | Data destination |
+| **direction** | `Enum<'push' \| 'pull' \| 'bidirectional'>` | optional | Sync direction |
+| **syncMode** | `Enum<'full' \| 'incremental' \| 'realtime'>` | optional | Sync mode |
+| **conflictResolution** | `Enum<'source_wins' \| 'destination_wins' \| 'latest_wins' \| 'manual' \| 'merge'>` | optional | Conflict resolution |
+| **schedule** | `string` | optional | Cron schedule |
+| **enabled** | `boolean` | optional | Sync enabled |
+| **changeTrackingField** | `string` | optional | Field for change tracking |
+| **batchSize** | `integer` | optional | Batch size for processing |
+| **retry** | `object` | optional | Retry configuration |
+| **validation** | `object` | optional | Validation rules |
+| **errorHandling** | `object` | optional | Error handling |
+| **optimization** | `object` | optional | Performance optimization |
+| **audit** | `object` | optional | Audit configuration |
+| **tags** | `string[]` | optional | Sync tags |
+| **metadata** | `Record` | optional | Custom metadata |
+
+---
+
+## FieldMapping
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **sourceField** | `string` | ✅ | Source field name |
+| **destinationField** | `string` | ✅ | Destination field name |
+| **transform** | `string` | optional | Transformation formula |
+| **default** | `any` | optional | Default value |
+| **syncNull** | `boolean` | optional | Sync null values |
+
+---
+
## OAuth2Config
### Properties
diff --git a/content/docs/references/automation/mapping.mdx b/content/docs/references/automation/mapping.mdx
deleted file mode 100644
index b20c29daf..000000000
--- a/content/docs/references/automation/mapping.mdx
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: Mapping
-description: Mapping protocol schemas
----
-
-# Mapping
-
-
-**Source:** `packages/spec/src/automation/mapping.zod.ts`
-
-
-## TypeScript Usage
-
-```typescript
-import { FieldMappingSchema } from '@objectstack/spec/automation';
-import type { FieldMapping } from '@objectstack/spec/automation';
-
-// Validate data
-const result = FieldMappingSchema.parse(data);
-```
-
----
-
-## FieldMapping
-
-### Properties
-
-| Property | Type | Required | Description |
-| :--- | :--- | :--- | :--- |
-| **sourceField** | `string` | ✅ | Source field name |
-| **destinationField** | `string` | ✅ | Destination field name |
-| **transform** | `string` | optional | Transformation formula |
-| **default** | `any` | optional | Default value |
-| **syncNull** | `boolean` | optional | Sync null values |
-
diff --git a/content/docs/references/automation/sync.mdx b/content/docs/references/automation/sync.mdx
index 89a4a0762..6169fc73c 100644
--- a/content/docs/references/automation/sync.mdx
+++ b/content/docs/references/automation/sync.mdx
@@ -12,27 +12,15 @@ description: Sync protocol schemas
## TypeScript Usage
```typescript
-import { ConflictResolutionSchema, DataDestinationConfigSchema, DataSourceConfigSchema, DataSyncConfigSchema, SyncDirectionSchema, SyncExecutionResultSchema, SyncExecutionStatusSchema, SyncModeSchema } from '@objectstack/spec/automation';
-import type { ConflictResolution, DataDestinationConfig, DataSourceConfig, DataSyncConfig, SyncDirection, SyncExecutionResult, SyncExecutionStatus, SyncMode } from '@objectstack/spec/automation';
+import { DataDestinationConfigSchema, DataSourceConfigSchema, SyncDirectionSchema, SyncExecutionResultSchema, SyncExecutionStatusSchema, SyncModeSchema } from '@objectstack/spec/automation';
+import type { DataDestinationConfig, DataSourceConfig, SyncDirection, SyncExecutionResult, SyncExecutionStatus, SyncMode } from '@objectstack/spec/automation';
// Validate data
-const result = ConflictResolutionSchema.parse(data);
+const result = DataDestinationConfigSchema.parse(data);
```
---
-## ConflictResolution
-
-### Allowed Values
-
-* `source_wins`
-* `destination_wins`
-* `latest_wins`
-* `manual`
-* `merge`
-
----
-
## DataDestinationConfig
### Properties
@@ -62,34 +50,6 @@ const result = ConflictResolutionSchema.parse(data);
---
-## DataSyncConfig
-
-### Properties
-
-| Property | Type | Required | Description |
-| :--- | :--- | :--- | :--- |
-| **name** | `string` | ✅ | Sync configuration name (snake_case) |
-| **label** | `string` | optional | Sync display name |
-| **description** | `string` | optional | Sync description |
-| **source** | `object` | ✅ | Data source |
-| **destination** | `object` | ✅ | Data destination |
-| **direction** | `Enum<'push' \| 'pull' \| 'bidirectional'>` | optional | Sync direction |
-| **syncMode** | `Enum<'full' \| 'incremental' \| 'realtime'>` | optional | Sync mode |
-| **conflictResolution** | `Enum<'source_wins' \| 'destination_wins' \| 'latest_wins' \| 'manual' \| 'merge'>` | optional | Conflict resolution |
-| **schedule** | `string` | optional | Cron schedule |
-| **enabled** | `boolean` | optional | Sync enabled |
-| **changeTrackingField** | `string` | optional | Field for change tracking |
-| **batchSize** | `integer` | optional | Batch size for processing |
-| **retry** | `object` | optional | Retry configuration |
-| **validation** | `object` | optional | Validation rules |
-| **errorHandling** | `object` | optional | Error handling |
-| **optimization** | `object` | optional | Performance optimization |
-| **audit** | `object` | optional | Audit configuration |
-| **tags** | `string[]` | optional | Sync tags |
-| **metadata** | `Record` | optional | Custom metadata |
-
----
-
## SyncDirection
### Allowed Values
diff --git a/content/docs/references/integration/connector.mdx b/content/docs/references/integration/connector.mdx
new file mode 100644
index 000000000..be140f015
--- /dev/null
+++ b/content/docs/references/integration/connector.mdx
@@ -0,0 +1,355 @@
+---
+title: Connector
+description: Connector protocol schemas
+---
+
+# Connector
+
+
+**Source:** `packages/spec/src/integration/connector.zod.ts`
+
+
+## TypeScript Usage
+
+```typescript
+import { ApiKeyAuthSchema, AuthenticationSchema, BasicAuthSchema, BearerTokenAuthSchema, ConflictResolutionSchema, ConnectorSchema, ConnectorStatusSchema, ConnectorTypeSchema, DataSyncConfigSchema, FieldMappingSchema, FieldTransformSchema, JwtAuthSchema, NoAuthSchema, OAuth2AuthSchema, RateLimitConfigSchema, RateLimitStrategySchema, RetryConfigSchema, RetryStrategySchema, SamlAuthSchema, SyncStrategySchema, WebhookConfigSchema, WebhookEventSchema, WebhookSignatureAlgorithmSchema } from '@objectstack/spec/integration';
+import type { ApiKeyAuth, Authentication, BasicAuth, BearerTokenAuth, ConflictResolution, Connector, ConnectorStatus, ConnectorType, DataSyncConfig, FieldMapping, FieldTransform, JwtAuth, NoAuth, OAuth2Auth, RateLimitConfig, RateLimitStrategy, RetryConfig, RetryStrategy, SamlAuth, SyncStrategy, WebhookConfig, WebhookEvent, WebhookSignatureAlgorithm } from '@objectstack/spec/integration';
+
+// Validate data
+const result = ApiKeyAuthSchema.parse(data);
+```
+
+---
+
+## ApiKeyAuth
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **type** | `string` | ✅ | Authentication type |
+| **apiKey** | `string` | ✅ | API key (typically from ENV) |
+| **headerName** | `string` | optional | HTTP header name for API key |
+| **paramName** | `string` | optional | Query parameter name (alternative to header) |
+
+---
+
+## Authentication
+
+---
+
+## BasicAuth
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **type** | `string` | ✅ | Authentication type |
+| **username** | `string` | ✅ | Username |
+| **password** | `string` | ✅ | Password (typically from ENV) |
+
+---
+
+## BearerTokenAuth
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **type** | `string` | ✅ | Authentication type |
+| **token** | `string` | ✅ | Bearer token |
+
+---
+
+## ConflictResolution
+
+Conflict resolution strategy
+
+### Allowed Values
+
+* `source_wins`
+* `target_wins`
+* `latest_wins`
+* `manual`
+
+---
+
+## Connector
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **name** | `string` | ✅ | Unique connector identifier |
+| **label** | `string` | ✅ | Display label |
+| **type** | `Enum<'saas' \| 'database' \| 'file_storage' \| 'message_queue' \| 'api' \| 'custom'>` | ✅ | Connector type |
+| **description** | `string` | optional | Connector description |
+| **icon** | `string` | optional | Icon identifier |
+| **authentication** | `object \| object \| object \| object \| object \| object \| object` | ✅ | Authentication configuration |
+| **syncConfig** | `object` | optional | Data sync configuration |
+| **fieldMappings** | `object[]` | optional | Field mapping rules |
+| **webhooks** | `object[]` | optional | Webhook configurations |
+| **rateLimitConfig** | `object` | optional | Rate limiting configuration |
+| **retryConfig** | `object` | optional | Retry configuration |
+| **connectionTimeoutMs** | `number` | optional | Connection timeout in ms |
+| **requestTimeoutMs** | `number` | optional | Request timeout in ms |
+| **status** | `Enum<'active' \| 'inactive' \| 'error' \| 'configuring'>` | optional | Connector status |
+| **enabled** | `boolean` | optional | Enable connector |
+| **metadata** | `Record` | optional | Custom connector metadata |
+
+---
+
+## ConnectorStatus
+
+Connector status
+
+### Allowed Values
+
+* `active`
+* `inactive`
+* `error`
+* `configuring`
+
+---
+
+## ConnectorType
+
+Connector type
+
+### Allowed Values
+
+* `saas`
+* `database`
+* `file_storage`
+* `message_queue`
+* `api`
+* `custom`
+
+---
+
+## DataSyncConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **strategy** | `Enum<'full' \| 'incremental' \| 'upsert' \| 'append_only'>` | optional | Synchronization strategy |
+| **direction** | `Enum<'import' \| 'export' \| 'bidirectional'>` | optional | Sync direction |
+| **schedule** | `string` | optional | Cron expression for scheduled sync |
+| **realtimeSync** | `boolean` | optional | Enable real-time sync |
+| **timestampField** | `string` | optional | Field to track last modification time |
+| **conflictResolution** | `Enum<'source_wins' \| 'target_wins' \| 'latest_wins' \| 'manual'>` | optional | Conflict resolution strategy |
+| **batchSize** | `number` | optional | Records per batch |
+| **deleteMode** | `Enum<'hard_delete' \| 'soft_delete' \| 'ignore'>` | optional | Delete handling mode |
+| **filters** | `Record` | optional | Filter criteria for selective sync |
+
+---
+
+## FieldMapping
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **sourceField** | `string` | ✅ | Field name in external system |
+| **targetField** | `string` | ✅ | Field name in ObjectStack (snake_case) |
+| **dataType** | `Enum<'string' \| 'number' \| 'boolean' \| 'date' \| 'datetime' \| 'json' \| 'array'>` | optional | Target data type |
+| **required** | `boolean` | optional | Field is required |
+| **defaultValue** | `any` | optional | Default value |
+| **transform** | `object` | optional | Field transformation |
+| **syncMode** | `Enum<'read_only' \| 'write_only' \| 'bidirectional'>` | optional | Sync mode |
+
+---
+
+## FieldTransform
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **type** | `Enum<'uppercase' \| 'lowercase' \| 'trim' \| 'date_format' \| 'number_format' \| 'custom'>` | ✅ | Transformation type |
+| **params** | `Record` | optional | Transformation parameters |
+| **function** | `string` | optional | Custom JavaScript function for transformation |
+
+---
+
+## JwtAuth
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **type** | `string` | ✅ | Authentication type |
+| **token** | `string` | optional | Pre-generated JWT token |
+| **secretKey** | `string` | optional | Secret key for JWT signing |
+| **algorithm** | `Enum<'HS256' \| 'HS384' \| 'HS512' \| 'RS256' \| 'RS384' \| 'RS512' \| 'ES256' \| 'ES384' \| 'ES512'>` | optional | JWT signing algorithm |
+| **issuer** | `string` | optional | JWT issuer claim |
+| **audience** | `string` | optional | JWT audience claim |
+| **subject** | `string` | optional | JWT subject claim |
+| **expiresIn** | `number` | optional | Token expiry in seconds |
+| **claims** | `Record` | optional | Additional JWT claims |
+
+---
+
+## NoAuth
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **type** | `string` | ✅ | No authentication required |
+
+---
+
+## OAuth2Auth
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **type** | `string` | ✅ | Authentication type |
+| **clientId** | `string` | ✅ | OAuth2 client ID |
+| **clientSecret** | `string` | ✅ | OAuth2 client secret (typically from ENV) |
+| **authorizationUrl** | `string` | ✅ | OAuth2 authorization endpoint |
+| **tokenUrl** | `string` | ✅ | OAuth2 token endpoint |
+| **scopes** | `string[]` | optional | Requested OAuth2 scopes |
+| **redirectUri** | `string` | optional | OAuth2 callback URL |
+| **grantType** | `Enum<'authorization_code' \| 'client_credentials' \| 'password' \| 'refresh_token'>` | optional | OAuth2 grant type |
+| **refreshToken** | `string` | optional | Refresh token for token renewal |
+| **tokenExpiry** | `number` | optional | Token expiry timestamp |
+
+---
+
+## RateLimitConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **strategy** | `Enum<'fixed_window' \| 'sliding_window' \| 'token_bucket' \| 'leaky_bucket'>` | optional | Rate limiting strategy |
+| **maxRequests** | `number` | ✅ | Maximum requests per window |
+| **windowSeconds** | `number` | ✅ | Time window in seconds |
+| **burstCapacity** | `number` | optional | Burst capacity |
+| **respectUpstreamLimits** | `boolean` | optional | Respect external rate limit headers |
+| **rateLimitHeaders** | `object` | optional | Custom rate limit headers |
+
+---
+
+## RateLimitStrategy
+
+Rate limiting strategy
+
+### Allowed Values
+
+* `fixed_window`
+* `sliding_window`
+* `token_bucket`
+* `leaky_bucket`
+
+---
+
+## RetryConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **strategy** | `Enum<'exponential_backoff' \| 'linear_backoff' \| 'fixed_delay' \| 'no_retry'>` | optional | Retry strategy |
+| **maxAttempts** | `number` | optional | Maximum retry attempts |
+| **initialDelayMs** | `number` | optional | Initial retry delay in ms |
+| **maxDelayMs** | `number` | optional | Maximum retry delay in ms |
+| **backoffMultiplier** | `number` | optional | Exponential backoff multiplier |
+| **retryableStatusCodes** | `number[]` | optional | HTTP status codes to retry |
+| **retryOnNetworkError** | `boolean` | optional | Retry on network errors |
+| **jitter** | `boolean` | optional | Add jitter to retry delays |
+
+---
+
+## RetryStrategy
+
+Retry strategy
+
+### Allowed Values
+
+* `exponential_backoff`
+* `linear_backoff`
+* `fixed_delay`
+* `no_retry`
+
+---
+
+## SamlAuth
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **type** | `string` | ✅ | Authentication type |
+| **entryPoint** | `string` | ✅ | SAML IdP entry point URL |
+| **issuer** | `string` | ✅ | SAML service provider issuer |
+| **certificate** | `string` | ✅ | SAML IdP certificate (X.509) |
+| **privateKey** | `string` | optional | SAML service provider private key |
+| **callbackUrl** | `string` | optional | SAML assertion consumer service URL |
+| **signatureAlgorithm** | `Enum<'sha1' \| 'sha256' \| 'sha512'>` | optional | SAML signature algorithm |
+| **wantAssertionsSigned** | `boolean` | optional | Require signed SAML assertions |
+| **identifierFormat** | `string` | optional | SAML NameID format |
+
+---
+
+## SyncStrategy
+
+Synchronization strategy
+
+### Allowed Values
+
+* `full`
+* `incremental`
+* `upsert`
+* `append_only`
+
+---
+
+## WebhookConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **url** | `string` | ✅ | Webhook endpoint URL |
+| **events** | `Enum<'record.created' \| 'record.updated' \| 'record.deleted' \| 'sync.started' \| 'sync.completed' \| 'sync.failed' \| 'auth.expired' \| 'rate_limit.exceeded'>[]` | ✅ | Events to subscribe to |
+| **secret** | `string` | optional | Secret for HMAC signature |
+| **signatureAlgorithm** | `Enum<'hmac_sha256' \| 'hmac_sha512' \| 'none'>` | optional | Webhook signature algorithm |
+| **headers** | `Record` | optional | Custom HTTP headers |
+| **retryConfig** | `object` | optional | Retry configuration |
+| **timeoutMs** | `number` | optional | Request timeout in ms |
+| **enabled** | `boolean` | optional | Enable webhook |
+
+---
+
+## WebhookEvent
+
+Webhook event type
+
+### Allowed Values
+
+* `record.created`
+* `record.updated`
+* `record.deleted`
+* `sync.started`
+* `sync.completed`
+* `sync.failed`
+* `auth.expired`
+* `rate_limit.exceeded`
+
+---
+
+## WebhookSignatureAlgorithm
+
+Webhook signature algorithm
+
+### Allowed Values
+
+* `hmac_sha256`
+* `hmac_sha512`
+* `none`
+
diff --git a/content/docs/references/integration/index.mdx b/content/docs/references/integration/index.mdx
new file mode 100644
index 000000000..a9e78c5a5
--- /dev/null
+++ b/content/docs/references/integration/index.mdx
@@ -0,0 +1,13 @@
+---
+title: Integration Protocol Overview
+description: Complete reference for all integration protocol schemas
+---
+
+# Integration Protocol
+
+This section contains all protocol schemas for the integration layer of ObjectStack.
+
+
+
+
+
diff --git a/content/docs/references/integration/meta.json b/content/docs/references/integration/meta.json
new file mode 100644
index 000000000..c07e1f0e2
--- /dev/null
+++ b/content/docs/references/integration/meta.json
@@ -0,0 +1,6 @@
+{
+ "title": "Integration Protocol",
+ "pages": [
+ "connector"
+ ]
+}
\ No newline at end of file
diff --git a/content/docs/references/integration/misc.mdx b/content/docs/references/integration/misc.mdx
new file mode 100644
index 000000000..a002a9d45
--- /dev/null
+++ b/content/docs/references/integration/misc.mdx
@@ -0,0 +1,529 @@
+---
+title: Misc
+description: Misc protocol schemas
+---
+
+# Misc
+
+
+**Source:** `packages/spec/src/integration/misc.zod.ts`
+
+
+## TypeScript Usage
+
+```typescript
+import { AckModeSchema, ApiVersionConfigSchema, CdcConfigSchema, ConsumerConfigSchema, DatabaseConnectorSchema, DatabasePoolConfigSchema, DatabaseProviderSchema, DatabaseTableSchema, DeliveryGuaranteeSchema, DlqConfigSchema, FileAccessPatternSchema, FileFilterConfigSchema, FileMetadataConfigSchema, FileStorageConnectorSchema, FileStorageProviderSchema, FileVersioningConfigSchema, MessageFormatSchema, MessageQueueConnectorSchema, MessageQueueProviderSchema, MultipartUploadConfigSchema, ProducerConfigSchema, SaasConnectorSchema, SaasObjectTypeSchema, SaasProviderSchema, SslConfigSchema, StorageBucketSchema, TopicQueueSchema } from '@objectstack/spec/integration';
+import type { AckMode, ApiVersionConfig, CdcConfig, ConsumerConfig, DatabaseConnector, DatabasePoolConfig, DatabaseProvider, DatabaseTable, DeliveryGuarantee, DlqConfig, FileAccessPattern, FileFilterConfig, FileMetadataConfig, FileStorageConnector, FileStorageProvider, FileVersioningConfig, MessageFormat, MessageQueueConnector, MessageQueueProvider, MultipartUploadConfig, ProducerConfig, SaasConnector, SaasObjectType, SaasProvider, SslConfig, StorageBucket, TopicQueue } from '@objectstack/spec/integration';
+
+// Validate data
+const result = AckModeSchema.parse(data);
+```
+
+---
+
+## AckMode
+
+Message acknowledgment mode
+
+### Allowed Values
+
+* `auto`
+* `manual`
+* `client`
+
+---
+
+## ApiVersionConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **version** | `string` | ✅ | API version (e.g., "v2", "2023-10-01") |
+| **isDefault** | `boolean` | optional | Is this the default version |
+| **deprecationDate** | `string` | optional | API version deprecation date (ISO 8601) |
+| **sunsetDate** | `string` | optional | API version sunset date (ISO 8601) |
+
+---
+
+## CdcConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **enabled** | `boolean` | optional | Enable CDC |
+| **method** | `Enum<'log_based' \| 'trigger_based' \| 'query_based' \| 'custom'>` | ✅ | CDC method |
+| **slotName** | `string` | optional | Replication slot name (for log-based CDC) |
+| **publicationName** | `string` | optional | Publication name (for PostgreSQL) |
+| **startPosition** | `string` | optional | Starting position/LSN for CDC stream |
+| **batchSize** | `number` | optional | CDC batch size |
+| **pollIntervalMs** | `number` | optional | CDC polling interval in ms |
+
+---
+
+## ConsumerConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **enabled** | `boolean` | optional | Enable consumer |
+| **consumerGroup** | `string` | optional | Consumer group ID |
+| **concurrency** | `number` | optional | Number of concurrent consumers |
+| **prefetchCount** | `number` | optional | Prefetch count |
+| **ackMode** | `Enum<'auto' \| 'manual' \| 'client'>` | optional | Message acknowledgment mode |
+| **autoCommit** | `boolean` | optional | Auto-commit offsets |
+| **autoCommitIntervalMs** | `number` | optional | Auto-commit interval in ms |
+| **sessionTimeoutMs** | `number` | optional | Session timeout in ms |
+| **rebalanceTimeoutMs** | `number` | optional | Rebalance timeout in ms |
+
+---
+
+## DatabaseConnector
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **name** | `string` | ✅ | Unique connector identifier |
+| **label** | `string` | ✅ | Display label |
+| **type** | `string` | ✅ | |
+| **description** | `string` | optional | Connector description |
+| **icon** | `string` | optional | Icon identifier |
+| **authentication** | `object \| object \| object \| object \| object \| object \| object` | ✅ | Authentication configuration |
+| **syncConfig** | `object` | optional | Data sync configuration |
+| **fieldMappings** | `object[]` | optional | Field mapping rules |
+| **webhooks** | `object[]` | optional | Webhook configurations |
+| **rateLimitConfig** | `object` | optional | Rate limiting configuration |
+| **retryConfig** | `object` | optional | Retry configuration |
+| **connectionTimeoutMs** | `number` | optional | Connection timeout in ms |
+| **requestTimeoutMs** | `number` | optional | Request timeout in ms |
+| **status** | `Enum<'active' \| 'inactive' \| 'error' \| 'configuring'>` | optional | Connector status |
+| **enabled** | `boolean` | optional | Enable connector |
+| **metadata** | `Record` | optional | Custom connector metadata |
+| **provider** | `Enum<'postgresql' \| 'mysql' \| 'mariadb' \| 'mssql' \| 'oracle' \| 'mongodb' \| 'redis' \| 'cassandra' \| 'snowflake' \| 'bigquery' \| 'redshift' \| 'custom'>` | ✅ | Database provider type |
+| **connectionConfig** | `object` | ✅ | Database connection configuration |
+| **poolConfig** | `object` | optional | Connection pool configuration |
+| **sslConfig** | `object` | optional | SSL/TLS configuration |
+| **tables** | `object[]` | ✅ | Tables to sync |
+| **cdcConfig** | `object` | optional | CDC configuration |
+| **readReplicaConfig** | `object` | optional | Read replica configuration |
+| **queryTimeoutMs** | `number` | optional | Query timeout in ms |
+| **enableQueryLogging** | `boolean` | optional | Enable SQL query logging |
+
+---
+
+## DatabasePoolConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **min** | `number` | optional | Minimum connections in pool |
+| **max** | `number` | optional | Maximum connections in pool |
+| **idleTimeoutMs** | `number` | optional | Idle connection timeout in ms |
+| **connectionTimeoutMs** | `number` | optional | Connection establishment timeout in ms |
+| **acquireTimeoutMs** | `number` | optional | Connection acquisition timeout in ms |
+| **evictionRunIntervalMs** | `number` | optional | Connection eviction check interval in ms |
+| **testOnBorrow** | `boolean` | optional | Test connection before use |
+
+---
+
+## DatabaseProvider
+
+Database provider type
+
+### Allowed Values
+
+* `postgresql`
+* `mysql`
+* `mariadb`
+* `mssql`
+* `oracle`
+* `mongodb`
+* `redis`
+* `cassandra`
+* `snowflake`
+* `bigquery`
+* `redshift`
+* `custom`
+
+---
+
+## DatabaseTable
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **name** | `string` | ✅ | Table name in ObjectStack (snake_case) |
+| **label** | `string` | ✅ | Display label |
+| **schema** | `string` | optional | Database schema name |
+| **tableName** | `string` | ✅ | Actual table name in database |
+| **primaryKey** | `string` | ✅ | Primary key column |
+| **enabled** | `boolean` | optional | Enable sync for this table |
+| **fieldMappings** | `object[]` | optional | Table-specific field mappings |
+| **whereClause** | `string` | optional | SQL WHERE clause for filtering |
+
+---
+
+## DeliveryGuarantee
+
+Message delivery guarantee
+
+### Allowed Values
+
+* `at_most_once`
+* `at_least_once`
+* `exactly_once`
+
+---
+
+## DlqConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **enabled** | `boolean` | optional | Enable DLQ |
+| **queueName** | `string` | ✅ | Dead letter queue/topic name |
+| **maxRetries** | `number` | optional | Max retries before DLQ |
+| **retryDelayMs** | `number` | optional | Retry delay in ms |
+
+---
+
+## FileAccessPattern
+
+File access pattern
+
+### Allowed Values
+
+* `public_read`
+* `private`
+* `authenticated_read`
+* `bucket_owner_read`
+* `bucket_owner_full`
+
+---
+
+## FileFilterConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **includePatterns** | `string[]` | optional | File patterns to include (glob) |
+| **excludePatterns** | `string[]` | optional | File patterns to exclude (glob) |
+| **minFileSize** | `number` | optional | Minimum file size in bytes |
+| **maxFileSize** | `number` | optional | Maximum file size in bytes |
+| **allowedExtensions** | `string[]` | optional | Allowed file extensions |
+| **blockedExtensions** | `string[]` | optional | Blocked file extensions |
+
+---
+
+## FileMetadataConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **extractMetadata** | `boolean` | optional | Extract file metadata |
+| **metadataFields** | `Enum<'content_type' \| 'file_size' \| 'last_modified' \| 'etag' \| 'checksum' \| 'creator' \| 'created_at' \| 'custom'>[]` | optional | Metadata fields to extract |
+| **customMetadata** | `Record` | optional | Custom metadata key-value pairs |
+
+---
+
+## FileStorageConnector
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **name** | `string` | ✅ | Unique connector identifier |
+| **label** | `string` | ✅ | Display label |
+| **type** | `string` | ✅ | |
+| **description** | `string` | optional | Connector description |
+| **icon** | `string` | optional | Icon identifier |
+| **authentication** | `object \| object \| object \| object \| object \| object \| object` | ✅ | Authentication configuration |
+| **syncConfig** | `object` | optional | Data sync configuration |
+| **fieldMappings** | `object[]` | optional | Field mapping rules |
+| **webhooks** | `object[]` | optional | Webhook configurations |
+| **rateLimitConfig** | `object` | optional | Rate limiting configuration |
+| **retryConfig** | `object` | optional | Retry configuration |
+| **connectionTimeoutMs** | `number` | optional | Connection timeout in ms |
+| **requestTimeoutMs** | `number` | optional | Request timeout in ms |
+| **status** | `Enum<'active' \| 'inactive' \| 'error' \| 'configuring'>` | optional | Connector status |
+| **enabled** | `boolean` | optional | Enable connector |
+| **metadata** | `Record` | optional | Custom connector metadata |
+| **provider** | `Enum<'s3' \| 'azure_blob' \| 'gcs' \| 'dropbox' \| 'box' \| 'onedrive' \| 'google_drive' \| 'sharepoint' \| 'ftp' \| 'local' \| 'custom'>` | ✅ | File storage provider type |
+| **storageConfig** | `object` | optional | Storage configuration |
+| **buckets** | `object[]` | ✅ | Buckets/containers to sync |
+| **metadataConfig** | `object` | optional | Metadata extraction configuration |
+| **multipartConfig** | `object` | optional | Multipart upload configuration |
+| **versioningConfig** | `object` | optional | File versioning configuration |
+| **encryption** | `object` | optional | Encryption configuration |
+| **lifecyclePolicy** | `object` | optional | Lifecycle policy |
+| **contentProcessing** | `object` | optional | Content processing configuration |
+| **bufferSize** | `number` | optional | Buffer size in bytes |
+| **transferAcceleration** | `boolean` | optional | Enable transfer acceleration |
+
+---
+
+## FileStorageProvider
+
+File storage provider type
+
+### Allowed Values
+
+* `s3`
+* `azure_blob`
+* `gcs`
+* `dropbox`
+* `box`
+* `onedrive`
+* `google_drive`
+* `sharepoint`
+* `ftp`
+* `local`
+* `custom`
+
+---
+
+## FileVersioningConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **enabled** | `boolean` | optional | Enable file versioning |
+| **maxVersions** | `number` | optional | Maximum versions to retain |
+| **retentionDays** | `number` | optional | Version retention period in days |
+
+---
+
+## MessageFormat
+
+Message format/serialization
+
+### Allowed Values
+
+* `json`
+* `xml`
+* `protobuf`
+* `avro`
+* `text`
+* `binary`
+
+---
+
+## MessageQueueConnector
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **name** | `string` | ✅ | Unique connector identifier |
+| **label** | `string` | ✅ | Display label |
+| **type** | `string` | ✅ | |
+| **description** | `string` | optional | Connector description |
+| **icon** | `string` | optional | Icon identifier |
+| **authentication** | `object \| object \| object \| object \| object \| object \| object` | ✅ | Authentication configuration |
+| **syncConfig** | `object` | optional | Data sync configuration |
+| **fieldMappings** | `object[]` | optional | Field mapping rules |
+| **webhooks** | `object[]` | optional | Webhook configurations |
+| **rateLimitConfig** | `object` | optional | Rate limiting configuration |
+| **retryConfig** | `object` | optional | Retry configuration |
+| **connectionTimeoutMs** | `number` | optional | Connection timeout in ms |
+| **requestTimeoutMs** | `number` | optional | Request timeout in ms |
+| **status** | `Enum<'active' \| 'inactive' \| 'error' \| 'configuring'>` | optional | Connector status |
+| **enabled** | `boolean` | optional | Enable connector |
+| **metadata** | `Record` | optional | Custom connector metadata |
+| **provider** | `Enum<'rabbitmq' \| 'kafka' \| 'redis_pubsub' \| 'redis_streams' \| 'aws_sqs' \| 'aws_sns' \| 'google_pubsub' \| 'azure_service_bus' \| 'azure_event_hubs' \| 'nats' \| 'pulsar' \| 'activemq' \| 'custom'>` | ✅ | Message queue provider type |
+| **brokerConfig** | `object` | ✅ | Broker connection configuration |
+| **topics** | `object[]` | ✅ | Topics/queues to sync |
+| **deliveryGuarantee** | `Enum<'at_most_once' \| 'at_least_once' \| 'exactly_once'>` | optional | Message delivery guarantee |
+| **sslConfig** | `object` | optional | SSL/TLS configuration |
+| **saslConfig** | `object` | optional | SASL authentication configuration |
+| **schemaRegistry** | `object` | optional | Schema registry configuration |
+| **preserveOrder** | `boolean` | optional | Preserve message ordering |
+| **enableMetrics** | `boolean` | optional | Enable message queue metrics |
+| **enableTracing** | `boolean` | optional | Enable distributed tracing |
+
+---
+
+## MessageQueueProvider
+
+Message queue provider type
+
+### Allowed Values
+
+* `rabbitmq`
+* `kafka`
+* `redis_pubsub`
+* `redis_streams`
+* `aws_sqs`
+* `aws_sns`
+* `google_pubsub`
+* `azure_service_bus`
+* `azure_event_hubs`
+* `nats`
+* `pulsar`
+* `activemq`
+* `custom`
+
+---
+
+## MultipartUploadConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **enabled** | `boolean` | optional | Enable multipart uploads |
+| **partSize** | `number` | optional | Part size in bytes (min 5MB) |
+| **maxConcurrentParts** | `number` | optional | Maximum concurrent part uploads |
+| **threshold** | `number` | optional | File size threshold for multipart upload in bytes |
+
+---
+
+## ProducerConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **enabled** | `boolean` | optional | Enable producer |
+| **acks** | `Enum<'0' \| '1' \| 'all'>` | optional | Acknowledgment level |
+| **compressionType** | `Enum<'none' \| 'gzip' \| 'snappy' \| 'lz4' \| 'zstd'>` | optional | Compression type |
+| **batchSize** | `number` | optional | Batch size in bytes |
+| **lingerMs** | `number` | optional | Linger time in ms |
+| **maxInFlightRequests** | `number` | optional | Max in-flight requests |
+| **idempotence** | `boolean` | optional | Enable idempotent producer |
+| **transactional** | `boolean` | optional | Enable transactional producer |
+| **transactionTimeoutMs** | `number` | optional | Transaction timeout in ms |
+
+---
+
+## SaasConnector
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **name** | `string` | ✅ | Unique connector identifier |
+| **label** | `string` | ✅ | Display label |
+| **type** | `string` | ✅ | |
+| **description** | `string` | optional | Connector description |
+| **icon** | `string` | optional | Icon identifier |
+| **authentication** | `object \| object \| object \| object \| object \| object \| object` | ✅ | Authentication configuration |
+| **syncConfig** | `object` | optional | Data sync configuration |
+| **fieldMappings** | `object[]` | optional | Field mapping rules |
+| **webhooks** | `object[]` | optional | Webhook configurations |
+| **rateLimitConfig** | `object` | optional | Rate limiting configuration |
+| **retryConfig** | `object` | optional | Retry configuration |
+| **connectionTimeoutMs** | `number` | optional | Connection timeout in ms |
+| **requestTimeoutMs** | `number` | optional | Request timeout in ms |
+| **status** | `Enum<'active' \| 'inactive' \| 'error' \| 'configuring'>` | optional | Connector status |
+| **enabled** | `boolean` | optional | Enable connector |
+| **metadata** | `Record` | optional | Custom connector metadata |
+| **provider** | `Enum<'salesforce' \| 'hubspot' \| 'stripe' \| 'shopify' \| 'zendesk' \| 'intercom' \| 'mailchimp' \| 'slack' \| 'microsoft_dynamics' \| 'servicenow' \| 'netsuite' \| 'custom'>` | ✅ | SaaS provider type |
+| **baseUrl** | `string` | ✅ | API base URL |
+| **apiVersion** | `object` | optional | API version configuration |
+| **objectTypes** | `object[]` | ✅ | Syncable object types |
+| **oauthSettings** | `object` | optional | OAuth-specific configuration |
+| **paginationConfig** | `object` | optional | Pagination configuration |
+| **sandboxConfig** | `object` | optional | Sandbox environment configuration |
+| **customHeaders** | `Record` | optional | Custom HTTP headers for all requests |
+
+---
+
+## SaasObjectType
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **name** | `string` | ✅ | Object type name (snake_case) |
+| **label** | `string` | ✅ | Display label |
+| **apiName** | `string` | ✅ | API name in external system |
+| **enabled** | `boolean` | optional | Enable sync for this object |
+| **supportsCreate** | `boolean` | optional | Supports record creation |
+| **supportsUpdate** | `boolean` | optional | Supports record updates |
+| **supportsDelete** | `boolean` | optional | Supports record deletion |
+| **fieldMappings** | `object[]` | optional | Object-specific field mappings |
+
+---
+
+## SaasProvider
+
+SaaS provider type
+
+### Allowed Values
+
+* `salesforce`
+* `hubspot`
+* `stripe`
+* `shopify`
+* `zendesk`
+* `intercom`
+* `mailchimp`
+* `slack`
+* `microsoft_dynamics`
+* `servicenow`
+* `netsuite`
+* `custom`
+
+---
+
+## SslConfig
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **enabled** | `boolean` | optional | Enable SSL/TLS |
+| **rejectUnauthorized** | `boolean` | optional | Reject unauthorized certificates |
+| **ca** | `string` | optional | Certificate Authority certificate |
+| **cert** | `string` | optional | Client certificate |
+| **key** | `string` | optional | Client private key |
+
+---
+
+## StorageBucket
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **name** | `string` | ✅ | Bucket identifier in ObjectStack (snake_case) |
+| **label** | `string` | ✅ | Display label |
+| **bucketName** | `string` | ✅ | Actual bucket/container name in storage system |
+| **region** | `string` | optional | Storage region |
+| **enabled** | `boolean` | optional | Enable sync for this bucket |
+| **prefix** | `string` | optional | Prefix/path within bucket |
+| **accessPattern** | `Enum<'public_read' \| 'private' \| 'authenticated_read' \| 'bucket_owner_read' \| 'bucket_owner_full'>` | optional | Access pattern |
+| **fileFilters** | `object` | optional | File filter configuration |
+
+---
+
+## TopicQueue
+
+### Properties
+
+| Property | Type | Required | Description |
+| :--- | :--- | :--- | :--- |
+| **name** | `string` | ✅ | Topic/queue identifier in ObjectStack (snake_case) |
+| **label** | `string` | ✅ | Display label |
+| **topicName** | `string` | ✅ | Actual topic/queue name in message queue system |
+| **enabled** | `boolean` | optional | Enable sync for this topic/queue |
+| **mode** | `Enum<'consumer' \| 'producer' \| 'both'>` | optional | Consumer, producer, or both |
+| **messageFormat** | `Enum<'json' \| 'xml' \| 'protobuf' \| 'avro' \| 'text' \| 'binary'>` | optional | Message format/serialization |
+| **partitions** | `number` | optional | Number of partitions (for Kafka) |
+| **replicationFactor** | `number` | optional | Replication factor (for Kafka) |
+| **consumerConfig** | `object` | optional | Consumer-specific configuration |
+| **producerConfig** | `object` | optional | Producer-specific configuration |
+| **dlqConfig** | `object` | optional | Dead letter queue configuration |
+| **routingKey** | `string` | optional | Routing key pattern |
+| **messageFilter** | `object` | optional | Message filter criteria |
+
diff --git a/packages/spec/json-schema/integration/AckMode.json b/packages/spec/json-schema/integration/AckMode.json
new file mode 100644
index 000000000..5328349c3
--- /dev/null
+++ b/packages/spec/json-schema/integration/AckMode.json
@@ -0,0 +1,15 @@
+{
+ "$ref": "#/definitions/AckMode",
+ "definitions": {
+ "AckMode": {
+ "type": "string",
+ "enum": [
+ "auto",
+ "manual",
+ "client"
+ ],
+ "description": "Message acknowledgment mode"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/ApiKeyAuth.json b/packages/spec/json-schema/integration/ApiKeyAuth.json
new file mode 100644
index 000000000..9aa189132
--- /dev/null
+++ b/packages/spec/json-schema/integration/ApiKeyAuth.json
@@ -0,0 +1,34 @@
+{
+ "$ref": "#/definitions/ApiKeyAuth",
+ "definitions": {
+ "ApiKeyAuth": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "api_key",
+ "description": "Authentication type"
+ },
+ "apiKey": {
+ "type": "string",
+ "description": "API key (typically from ENV)"
+ },
+ "headerName": {
+ "type": "string",
+ "default": "X-API-Key",
+ "description": "HTTP header name for API key"
+ },
+ "paramName": {
+ "type": "string",
+ "description": "Query parameter name (alternative to header)"
+ }
+ },
+ "required": [
+ "type",
+ "apiKey"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/ApiVersionConfig.json b/packages/spec/json-schema/integration/ApiVersionConfig.json
new file mode 100644
index 000000000..d73530305
--- /dev/null
+++ b/packages/spec/json-schema/integration/ApiVersionConfig.json
@@ -0,0 +1,32 @@
+{
+ "$ref": "#/definitions/ApiVersionConfig",
+ "definitions": {
+ "ApiVersionConfig": {
+ "type": "object",
+ "properties": {
+ "version": {
+ "type": "string",
+ "description": "API version (e.g., \"v2\", \"2023-10-01\")"
+ },
+ "isDefault": {
+ "type": "boolean",
+ "default": false,
+ "description": "Is this the default version"
+ },
+ "deprecationDate": {
+ "type": "string",
+ "description": "API version deprecation date (ISO 8601)"
+ },
+ "sunsetDate": {
+ "type": "string",
+ "description": "API version sunset date (ISO 8601)"
+ }
+ },
+ "required": [
+ "version"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/Authentication.json b/packages/spec/json-schema/integration/Authentication.json
new file mode 100644
index 000000000..dd8b4df1d
--- /dev/null
+++ b/packages/spec/json-schema/integration/Authentication.json
@@ -0,0 +1,280 @@
+{
+ "$ref": "#/definitions/Authentication",
+ "definitions": {
+ "Authentication": {
+ "anyOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "api_key",
+ "description": "Authentication type"
+ },
+ "apiKey": {
+ "type": "string",
+ "description": "API key (typically from ENV)"
+ },
+ "headerName": {
+ "type": "string",
+ "default": "X-API-Key",
+ "description": "HTTP header name for API key"
+ },
+ "paramName": {
+ "type": "string",
+ "description": "Query parameter name (alternative to header)"
+ }
+ },
+ "required": [
+ "type",
+ "apiKey"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "oauth2",
+ "description": "Authentication type"
+ },
+ "clientId": {
+ "type": "string",
+ "description": "OAuth2 client ID"
+ },
+ "clientSecret": {
+ "type": "string",
+ "description": "OAuth2 client secret (typically from ENV)"
+ },
+ "authorizationUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 authorization endpoint"
+ },
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 token endpoint"
+ },
+ "scopes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Requested OAuth2 scopes"
+ },
+ "redirectUri": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 callback URL"
+ },
+ "grantType": {
+ "type": "string",
+ "enum": [
+ "authorization_code",
+ "client_credentials",
+ "password",
+ "refresh_token"
+ ],
+ "default": "authorization_code",
+ "description": "OAuth2 grant type"
+ },
+ "refreshToken": {
+ "type": "string",
+ "description": "Refresh token for token renewal"
+ },
+ "tokenExpiry": {
+ "type": "number",
+ "description": "Token expiry timestamp"
+ }
+ },
+ "required": [
+ "type",
+ "clientId",
+ "clientSecret",
+ "authorizationUrl",
+ "tokenUrl"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "jwt",
+ "description": "Authentication type"
+ },
+ "token": {
+ "type": "string",
+ "description": "Pre-generated JWT token"
+ },
+ "secretKey": {
+ "type": "string",
+ "description": "Secret key for JWT signing"
+ },
+ "algorithm": {
+ "type": "string",
+ "enum": [
+ "HS256",
+ "HS384",
+ "HS512",
+ "RS256",
+ "RS384",
+ "RS512",
+ "ES256",
+ "ES384",
+ "ES512"
+ ],
+ "default": "HS256",
+ "description": "JWT signing algorithm"
+ },
+ "issuer": {
+ "type": "string",
+ "description": "JWT issuer claim"
+ },
+ "audience": {
+ "type": "string",
+ "description": "JWT audience claim"
+ },
+ "subject": {
+ "type": "string",
+ "description": "JWT subject claim"
+ },
+ "expiresIn": {
+ "type": "number",
+ "default": 3600,
+ "description": "Token expiry in seconds"
+ },
+ "claims": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Additional JWT claims"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "saml",
+ "description": "Authentication type"
+ },
+ "entryPoint": {
+ "type": "string",
+ "format": "uri",
+ "description": "SAML IdP entry point URL"
+ },
+ "issuer": {
+ "type": "string",
+ "description": "SAML service provider issuer"
+ },
+ "certificate": {
+ "type": "string",
+ "description": "SAML IdP certificate (X.509)"
+ },
+ "privateKey": {
+ "type": "string",
+ "description": "SAML service provider private key"
+ },
+ "callbackUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "SAML assertion consumer service URL"
+ },
+ "signatureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "sha1",
+ "sha256",
+ "sha512"
+ ],
+ "default": "sha256",
+ "description": "SAML signature algorithm"
+ },
+ "wantAssertionsSigned": {
+ "type": "boolean",
+ "default": true,
+ "description": "Require signed SAML assertions"
+ },
+ "identifierFormat": {
+ "type": "string",
+ "description": "SAML NameID format"
+ }
+ },
+ "required": [
+ "type",
+ "entryPoint",
+ "issuer",
+ "certificate"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "basic",
+ "description": "Authentication type"
+ },
+ "username": {
+ "type": "string",
+ "description": "Username"
+ },
+ "password": {
+ "type": "string",
+ "description": "Password (typically from ENV)"
+ }
+ },
+ "required": [
+ "type",
+ "username",
+ "password"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "bearer",
+ "description": "Authentication type"
+ },
+ "token": {
+ "type": "string",
+ "description": "Bearer token"
+ }
+ },
+ "required": [
+ "type",
+ "token"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "none",
+ "description": "No authentication required"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/BasicAuth.json b/packages/spec/json-schema/integration/BasicAuth.json
new file mode 100644
index 000000000..a0c27be00
--- /dev/null
+++ b/packages/spec/json-schema/integration/BasicAuth.json
@@ -0,0 +1,30 @@
+{
+ "$ref": "#/definitions/BasicAuth",
+ "definitions": {
+ "BasicAuth": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "basic",
+ "description": "Authentication type"
+ },
+ "username": {
+ "type": "string",
+ "description": "Username"
+ },
+ "password": {
+ "type": "string",
+ "description": "Password (typically from ENV)"
+ }
+ },
+ "required": [
+ "type",
+ "username",
+ "password"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/BearerTokenAuth.json b/packages/spec/json-schema/integration/BearerTokenAuth.json
new file mode 100644
index 000000000..d688756bc
--- /dev/null
+++ b/packages/spec/json-schema/integration/BearerTokenAuth.json
@@ -0,0 +1,25 @@
+{
+ "$ref": "#/definitions/BearerTokenAuth",
+ "definitions": {
+ "BearerTokenAuth": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "bearer",
+ "description": "Authentication type"
+ },
+ "token": {
+ "type": "string",
+ "description": "Bearer token"
+ }
+ },
+ "required": [
+ "type",
+ "token"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/CdcConfig.json b/packages/spec/json-schema/integration/CdcConfig.json
new file mode 100644
index 000000000..2b59c2f59
--- /dev/null
+++ b/packages/spec/json-schema/integration/CdcConfig.json
@@ -0,0 +1,55 @@
+{
+ "$ref": "#/definitions/CdcConfig",
+ "definitions": {
+ "CdcConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable CDC"
+ },
+ "method": {
+ "type": "string",
+ "enum": [
+ "log_based",
+ "trigger_based",
+ "query_based",
+ "custom"
+ ],
+ "description": "CDC method"
+ },
+ "slotName": {
+ "type": "string",
+ "description": "Replication slot name (for log-based CDC)"
+ },
+ "publicationName": {
+ "type": "string",
+ "description": "Publication name (for PostgreSQL)"
+ },
+ "startPosition": {
+ "type": "string",
+ "description": "Starting position/LSN for CDC stream"
+ },
+ "batchSize": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 10000,
+ "default": 1000,
+ "description": "CDC batch size"
+ },
+ "pollIntervalMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 1000,
+ "description": "CDC polling interval in ms"
+ }
+ },
+ "required": [
+ "method"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/ConflictResolution.json b/packages/spec/json-schema/integration/ConflictResolution.json
new file mode 100644
index 000000000..eea0fc6b6
--- /dev/null
+++ b/packages/spec/json-schema/integration/ConflictResolution.json
@@ -0,0 +1,16 @@
+{
+ "$ref": "#/definitions/ConflictResolution",
+ "definitions": {
+ "ConflictResolution": {
+ "type": "string",
+ "enum": [
+ "source_wins",
+ "target_wins",
+ "latest_wins",
+ "manual"
+ ],
+ "description": "Conflict resolution strategy"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/Connector.json b/packages/spec/json-schema/integration/Connector.json
new file mode 100644
index 000000000..ad19b3653
--- /dev/null
+++ b/packages/spec/json-schema/integration/Connector.json
@@ -0,0 +1,744 @@
+{
+ "$ref": "#/definitions/Connector",
+ "definitions": {
+ "Connector": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Unique connector identifier"
+ },
+ "label": {
+ "type": "string",
+ "description": "Display label"
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "saas",
+ "database",
+ "file_storage",
+ "message_queue",
+ "api",
+ "custom"
+ ],
+ "description": "Connector type"
+ },
+ "description": {
+ "type": "string",
+ "description": "Connector description"
+ },
+ "icon": {
+ "type": "string",
+ "description": "Icon identifier"
+ },
+ "authentication": {
+ "anyOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "api_key",
+ "description": "Authentication type"
+ },
+ "apiKey": {
+ "type": "string",
+ "description": "API key (typically from ENV)"
+ },
+ "headerName": {
+ "type": "string",
+ "default": "X-API-Key",
+ "description": "HTTP header name for API key"
+ },
+ "paramName": {
+ "type": "string",
+ "description": "Query parameter name (alternative to header)"
+ }
+ },
+ "required": [
+ "type",
+ "apiKey"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "oauth2",
+ "description": "Authentication type"
+ },
+ "clientId": {
+ "type": "string",
+ "description": "OAuth2 client ID"
+ },
+ "clientSecret": {
+ "type": "string",
+ "description": "OAuth2 client secret (typically from ENV)"
+ },
+ "authorizationUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 authorization endpoint"
+ },
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 token endpoint"
+ },
+ "scopes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Requested OAuth2 scopes"
+ },
+ "redirectUri": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 callback URL"
+ },
+ "grantType": {
+ "type": "string",
+ "enum": [
+ "authorization_code",
+ "client_credentials",
+ "password",
+ "refresh_token"
+ ],
+ "default": "authorization_code",
+ "description": "OAuth2 grant type"
+ },
+ "refreshToken": {
+ "type": "string",
+ "description": "Refresh token for token renewal"
+ },
+ "tokenExpiry": {
+ "type": "number",
+ "description": "Token expiry timestamp"
+ }
+ },
+ "required": [
+ "type",
+ "clientId",
+ "clientSecret",
+ "authorizationUrl",
+ "tokenUrl"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "jwt",
+ "description": "Authentication type"
+ },
+ "token": {
+ "type": "string",
+ "description": "Pre-generated JWT token"
+ },
+ "secretKey": {
+ "type": "string",
+ "description": "Secret key for JWT signing"
+ },
+ "algorithm": {
+ "type": "string",
+ "enum": [
+ "HS256",
+ "HS384",
+ "HS512",
+ "RS256",
+ "RS384",
+ "RS512",
+ "ES256",
+ "ES384",
+ "ES512"
+ ],
+ "default": "HS256",
+ "description": "JWT signing algorithm"
+ },
+ "issuer": {
+ "type": "string",
+ "description": "JWT issuer claim"
+ },
+ "audience": {
+ "type": "string",
+ "description": "JWT audience claim"
+ },
+ "subject": {
+ "type": "string",
+ "description": "JWT subject claim"
+ },
+ "expiresIn": {
+ "type": "number",
+ "default": 3600,
+ "description": "Token expiry in seconds"
+ },
+ "claims": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Additional JWT claims"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "saml",
+ "description": "Authentication type"
+ },
+ "entryPoint": {
+ "type": "string",
+ "format": "uri",
+ "description": "SAML IdP entry point URL"
+ },
+ "issuer": {
+ "type": "string",
+ "description": "SAML service provider issuer"
+ },
+ "certificate": {
+ "type": "string",
+ "description": "SAML IdP certificate (X.509)"
+ },
+ "privateKey": {
+ "type": "string",
+ "description": "SAML service provider private key"
+ },
+ "callbackUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "SAML assertion consumer service URL"
+ },
+ "signatureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "sha1",
+ "sha256",
+ "sha512"
+ ],
+ "default": "sha256",
+ "description": "SAML signature algorithm"
+ },
+ "wantAssertionsSigned": {
+ "type": "boolean",
+ "default": true,
+ "description": "Require signed SAML assertions"
+ },
+ "identifierFormat": {
+ "type": "string",
+ "description": "SAML NameID format"
+ }
+ },
+ "required": [
+ "type",
+ "entryPoint",
+ "issuer",
+ "certificate"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "basic",
+ "description": "Authentication type"
+ },
+ "username": {
+ "type": "string",
+ "description": "Username"
+ },
+ "password": {
+ "type": "string",
+ "description": "Password (typically from ENV)"
+ }
+ },
+ "required": [
+ "type",
+ "username",
+ "password"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "bearer",
+ "description": "Authentication type"
+ },
+ "token": {
+ "type": "string",
+ "description": "Bearer token"
+ }
+ },
+ "required": [
+ "type",
+ "token"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "none",
+ "description": "No authentication required"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ }
+ ],
+ "description": "Authentication configuration"
+ },
+ "syncConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "full",
+ "incremental",
+ "upsert",
+ "append_only"
+ ],
+ "description": "Synchronization strategy",
+ "default": "incremental"
+ },
+ "direction": {
+ "type": "string",
+ "enum": [
+ "import",
+ "export",
+ "bidirectional"
+ ],
+ "default": "import",
+ "description": "Sync direction"
+ },
+ "schedule": {
+ "type": "string",
+ "description": "Cron expression for scheduled sync"
+ },
+ "realtimeSync": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable real-time sync"
+ },
+ "timestampField": {
+ "type": "string",
+ "description": "Field to track last modification time"
+ },
+ "conflictResolution": {
+ "type": "string",
+ "enum": [
+ "source_wins",
+ "target_wins",
+ "latest_wins",
+ "manual"
+ ],
+ "description": "Conflict resolution strategy",
+ "default": "latest_wins"
+ },
+ "batchSize": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 10000,
+ "default": 1000,
+ "description": "Records per batch"
+ },
+ "deleteMode": {
+ "type": "string",
+ "enum": [
+ "hard_delete",
+ "soft_delete",
+ "ignore"
+ ],
+ "default": "soft_delete",
+ "description": "Delete handling mode"
+ },
+ "filters": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Filter criteria for selective sync"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Data sync configuration"
+ },
+ "fieldMappings": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sourceField": {
+ "type": "string",
+ "description": "Field name in external system"
+ },
+ "targetField": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Field name in ObjectStack (snake_case)"
+ },
+ "dataType": {
+ "type": "string",
+ "enum": [
+ "string",
+ "number",
+ "boolean",
+ "date",
+ "datetime",
+ "json",
+ "array"
+ ],
+ "description": "Target data type"
+ },
+ "required": {
+ "type": "boolean",
+ "default": false,
+ "description": "Field is required"
+ },
+ "defaultValue": {
+ "description": "Default value"
+ },
+ "transform": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "uppercase",
+ "lowercase",
+ "trim",
+ "date_format",
+ "number_format",
+ "custom"
+ ],
+ "description": "Transformation type"
+ },
+ "params": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Transformation parameters"
+ },
+ "function": {
+ "type": "string",
+ "description": "Custom JavaScript function for transformation"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "description": "Field transformation"
+ },
+ "syncMode": {
+ "type": "string",
+ "enum": [
+ "read_only",
+ "write_only",
+ "bidirectional"
+ ],
+ "default": "bidirectional",
+ "description": "Sync mode"
+ }
+ },
+ "required": [
+ "sourceField",
+ "targetField"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Field mapping rules"
+ },
+ "webhooks": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "url": {
+ "type": "string",
+ "format": "uri",
+ "description": "Webhook endpoint URL"
+ },
+ "events": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "record.created",
+ "record.updated",
+ "record.deleted",
+ "sync.started",
+ "sync.completed",
+ "sync.failed",
+ "auth.expired",
+ "rate_limit.exceeded"
+ ],
+ "description": "Webhook event type"
+ },
+ "description": "Events to subscribe to"
+ },
+ "secret": {
+ "type": "string",
+ "description": "Secret for HMAC signature"
+ },
+ "signatureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "hmac_sha256",
+ "hmac_sha512",
+ "none"
+ ],
+ "description": "Webhook signature algorithm",
+ "default": "hmac_sha256"
+ },
+ "headers": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Custom HTTP headers"
+ },
+ "retryConfig": {
+ "type": "object",
+ "properties": {
+ "maxAttempts": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 10,
+ "default": 3,
+ "description": "Maximum retry attempts"
+ },
+ "backoffMultiplier": {
+ "type": "number",
+ "minimum": 1,
+ "default": 2,
+ "description": "Exponential backoff multiplier"
+ },
+ "initialDelayMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 1000,
+ "description": "Initial retry delay in ms"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Retry configuration"
+ },
+ "timeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 60000,
+ "default": 30000,
+ "description": "Request timeout in ms"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable webhook"
+ }
+ },
+ "required": [
+ "url",
+ "events"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Webhook configurations"
+ },
+ "rateLimitConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "fixed_window",
+ "sliding_window",
+ "token_bucket",
+ "leaky_bucket"
+ ],
+ "description": "Rate limiting strategy",
+ "default": "token_bucket"
+ },
+ "maxRequests": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Maximum requests per window"
+ },
+ "windowSeconds": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Time window in seconds"
+ },
+ "burstCapacity": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Burst capacity"
+ },
+ "respectUpstreamLimits": {
+ "type": "boolean",
+ "default": true,
+ "description": "Respect external rate limit headers"
+ },
+ "rateLimitHeaders": {
+ "type": "object",
+ "properties": {
+ "remaining": {
+ "type": "string",
+ "default": "X-RateLimit-Remaining",
+ "description": "Header for remaining requests"
+ },
+ "limit": {
+ "type": "string",
+ "default": "X-RateLimit-Limit",
+ "description": "Header for rate limit"
+ },
+ "reset": {
+ "type": "string",
+ "default": "X-RateLimit-Reset",
+ "description": "Header for reset time"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Custom rate limit headers"
+ }
+ },
+ "required": [
+ "maxRequests",
+ "windowSeconds"
+ ],
+ "additionalProperties": false,
+ "description": "Rate limiting configuration"
+ },
+ "retryConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "exponential_backoff",
+ "linear_backoff",
+ "fixed_delay",
+ "no_retry"
+ ],
+ "description": "Retry strategy",
+ "default": "exponential_backoff"
+ },
+ "maxAttempts": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 10,
+ "default": 3,
+ "description": "Maximum retry attempts"
+ },
+ "initialDelayMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 1000,
+ "description": "Initial retry delay in ms"
+ },
+ "maxDelayMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 60000,
+ "description": "Maximum retry delay in ms"
+ },
+ "backoffMultiplier": {
+ "type": "number",
+ "minimum": 1,
+ "default": 2,
+ "description": "Exponential backoff multiplier"
+ },
+ "retryableStatusCodes": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ },
+ "default": [
+ 408,
+ 429,
+ 500,
+ 502,
+ 503,
+ 504
+ ],
+ "description": "HTTP status codes to retry"
+ },
+ "retryOnNetworkError": {
+ "type": "boolean",
+ "default": true,
+ "description": "Retry on network errors"
+ },
+ "jitter": {
+ "type": "boolean",
+ "default": true,
+ "description": "Add jitter to retry delays"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Retry configuration"
+ },
+ "connectionTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 300000,
+ "default": 30000,
+ "description": "Connection timeout in ms"
+ },
+ "requestTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 300000,
+ "default": 30000,
+ "description": "Request timeout in ms"
+ },
+ "status": {
+ "type": "string",
+ "enum": [
+ "active",
+ "inactive",
+ "error",
+ "configuring"
+ ],
+ "description": "Connector status",
+ "default": "inactive"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable connector"
+ },
+ "metadata": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Custom connector metadata"
+ }
+ },
+ "required": [
+ "name",
+ "label",
+ "type",
+ "authentication"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/ConnectorStatus.json b/packages/spec/json-schema/integration/ConnectorStatus.json
new file mode 100644
index 000000000..fd0d99f53
--- /dev/null
+++ b/packages/spec/json-schema/integration/ConnectorStatus.json
@@ -0,0 +1,16 @@
+{
+ "$ref": "#/definitions/ConnectorStatus",
+ "definitions": {
+ "ConnectorStatus": {
+ "type": "string",
+ "enum": [
+ "active",
+ "inactive",
+ "error",
+ "configuring"
+ ],
+ "description": "Connector status"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/ConnectorType.json b/packages/spec/json-schema/integration/ConnectorType.json
new file mode 100644
index 000000000..2af49a983
--- /dev/null
+++ b/packages/spec/json-schema/integration/ConnectorType.json
@@ -0,0 +1,18 @@
+{
+ "$ref": "#/definitions/ConnectorType",
+ "definitions": {
+ "ConnectorType": {
+ "type": "string",
+ "enum": [
+ "saas",
+ "database",
+ "file_storage",
+ "message_queue",
+ "api",
+ "custom"
+ ],
+ "description": "Connector type"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/ConsumerConfig.json b/packages/spec/json-schema/integration/ConsumerConfig.json
new file mode 100644
index 000000000..cf7fbc71f
--- /dev/null
+++ b/packages/spec/json-schema/integration/ConsumerConfig.json
@@ -0,0 +1,67 @@
+{
+ "$ref": "#/definitions/ConsumerConfig",
+ "definitions": {
+ "ConsumerConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable consumer"
+ },
+ "consumerGroup": {
+ "type": "string",
+ "description": "Consumer group ID"
+ },
+ "concurrency": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 100,
+ "default": 1,
+ "description": "Number of concurrent consumers"
+ },
+ "prefetchCount": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 1000,
+ "default": 10,
+ "description": "Prefetch count"
+ },
+ "ackMode": {
+ "type": "string",
+ "enum": [
+ "auto",
+ "manual",
+ "client"
+ ],
+ "description": "Message acknowledgment mode",
+ "default": "manual"
+ },
+ "autoCommit": {
+ "type": "boolean",
+ "default": false,
+ "description": "Auto-commit offsets"
+ },
+ "autoCommitIntervalMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 5000,
+ "description": "Auto-commit interval in ms"
+ },
+ "sessionTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 30000,
+ "description": "Session timeout in ms"
+ },
+ "rebalanceTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "description": "Rebalance timeout in ms"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/DataSyncConfig.json b/packages/spec/json-schema/integration/DataSyncConfig.json
new file mode 100644
index 000000000..17fbf42cf
--- /dev/null
+++ b/packages/spec/json-schema/integration/DataSyncConfig.json
@@ -0,0 +1,79 @@
+{
+ "$ref": "#/definitions/DataSyncConfig",
+ "definitions": {
+ "DataSyncConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "full",
+ "incremental",
+ "upsert",
+ "append_only"
+ ],
+ "description": "Synchronization strategy",
+ "default": "incremental"
+ },
+ "direction": {
+ "type": "string",
+ "enum": [
+ "import",
+ "export",
+ "bidirectional"
+ ],
+ "default": "import",
+ "description": "Sync direction"
+ },
+ "schedule": {
+ "type": "string",
+ "description": "Cron expression for scheduled sync"
+ },
+ "realtimeSync": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable real-time sync"
+ },
+ "timestampField": {
+ "type": "string",
+ "description": "Field to track last modification time"
+ },
+ "conflictResolution": {
+ "type": "string",
+ "enum": [
+ "source_wins",
+ "target_wins",
+ "latest_wins",
+ "manual"
+ ],
+ "description": "Conflict resolution strategy",
+ "default": "latest_wins"
+ },
+ "batchSize": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 10000,
+ "default": 1000,
+ "description": "Records per batch"
+ },
+ "deleteMode": {
+ "type": "string",
+ "enum": [
+ "hard_delete",
+ "soft_delete",
+ "ignore"
+ ],
+ "default": "soft_delete",
+ "description": "Delete handling mode"
+ },
+ "filters": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Filter criteria for selective sync"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/DatabaseConnector.json b/packages/spec/json-schema/integration/DatabaseConnector.json
new file mode 100644
index 000000000..de017214b
--- /dev/null
+++ b/packages/spec/json-schema/integration/DatabaseConnector.json
@@ -0,0 +1,1114 @@
+{
+ "$ref": "#/definitions/DatabaseConnector",
+ "definitions": {
+ "DatabaseConnector": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Unique connector identifier"
+ },
+ "label": {
+ "type": "string",
+ "description": "Display label"
+ },
+ "type": {
+ "type": "string",
+ "const": "database"
+ },
+ "description": {
+ "type": "string",
+ "description": "Connector description"
+ },
+ "icon": {
+ "type": "string",
+ "description": "Icon identifier"
+ },
+ "authentication": {
+ "anyOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "api_key",
+ "description": "Authentication type"
+ },
+ "apiKey": {
+ "type": "string",
+ "description": "API key (typically from ENV)"
+ },
+ "headerName": {
+ "type": "string",
+ "default": "X-API-Key",
+ "description": "HTTP header name for API key"
+ },
+ "paramName": {
+ "type": "string",
+ "description": "Query parameter name (alternative to header)"
+ }
+ },
+ "required": [
+ "type",
+ "apiKey"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "oauth2",
+ "description": "Authentication type"
+ },
+ "clientId": {
+ "type": "string",
+ "description": "OAuth2 client ID"
+ },
+ "clientSecret": {
+ "type": "string",
+ "description": "OAuth2 client secret (typically from ENV)"
+ },
+ "authorizationUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 authorization endpoint"
+ },
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 token endpoint"
+ },
+ "scopes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Requested OAuth2 scopes"
+ },
+ "redirectUri": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 callback URL"
+ },
+ "grantType": {
+ "type": "string",
+ "enum": [
+ "authorization_code",
+ "client_credentials",
+ "password",
+ "refresh_token"
+ ],
+ "default": "authorization_code",
+ "description": "OAuth2 grant type"
+ },
+ "refreshToken": {
+ "type": "string",
+ "description": "Refresh token for token renewal"
+ },
+ "tokenExpiry": {
+ "type": "number",
+ "description": "Token expiry timestamp"
+ }
+ },
+ "required": [
+ "type",
+ "clientId",
+ "clientSecret",
+ "authorizationUrl",
+ "tokenUrl"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "jwt",
+ "description": "Authentication type"
+ },
+ "token": {
+ "type": "string",
+ "description": "Pre-generated JWT token"
+ },
+ "secretKey": {
+ "type": "string",
+ "description": "Secret key for JWT signing"
+ },
+ "algorithm": {
+ "type": "string",
+ "enum": [
+ "HS256",
+ "HS384",
+ "HS512",
+ "RS256",
+ "RS384",
+ "RS512",
+ "ES256",
+ "ES384",
+ "ES512"
+ ],
+ "default": "HS256",
+ "description": "JWT signing algorithm"
+ },
+ "issuer": {
+ "type": "string",
+ "description": "JWT issuer claim"
+ },
+ "audience": {
+ "type": "string",
+ "description": "JWT audience claim"
+ },
+ "subject": {
+ "type": "string",
+ "description": "JWT subject claim"
+ },
+ "expiresIn": {
+ "type": "number",
+ "default": 3600,
+ "description": "Token expiry in seconds"
+ },
+ "claims": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Additional JWT claims"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "saml",
+ "description": "Authentication type"
+ },
+ "entryPoint": {
+ "type": "string",
+ "format": "uri",
+ "description": "SAML IdP entry point URL"
+ },
+ "issuer": {
+ "type": "string",
+ "description": "SAML service provider issuer"
+ },
+ "certificate": {
+ "type": "string",
+ "description": "SAML IdP certificate (X.509)"
+ },
+ "privateKey": {
+ "type": "string",
+ "description": "SAML service provider private key"
+ },
+ "callbackUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "SAML assertion consumer service URL"
+ },
+ "signatureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "sha1",
+ "sha256",
+ "sha512"
+ ],
+ "default": "sha256",
+ "description": "SAML signature algorithm"
+ },
+ "wantAssertionsSigned": {
+ "type": "boolean",
+ "default": true,
+ "description": "Require signed SAML assertions"
+ },
+ "identifierFormat": {
+ "type": "string",
+ "description": "SAML NameID format"
+ }
+ },
+ "required": [
+ "type",
+ "entryPoint",
+ "issuer",
+ "certificate"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "basic",
+ "description": "Authentication type"
+ },
+ "username": {
+ "type": "string",
+ "description": "Username"
+ },
+ "password": {
+ "type": "string",
+ "description": "Password (typically from ENV)"
+ }
+ },
+ "required": [
+ "type",
+ "username",
+ "password"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "bearer",
+ "description": "Authentication type"
+ },
+ "token": {
+ "type": "string",
+ "description": "Bearer token"
+ }
+ },
+ "required": [
+ "type",
+ "token"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "none",
+ "description": "No authentication required"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ }
+ ],
+ "description": "Authentication configuration"
+ },
+ "syncConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "full",
+ "incremental",
+ "upsert",
+ "append_only"
+ ],
+ "description": "Synchronization strategy",
+ "default": "incremental"
+ },
+ "direction": {
+ "type": "string",
+ "enum": [
+ "import",
+ "export",
+ "bidirectional"
+ ],
+ "default": "import",
+ "description": "Sync direction"
+ },
+ "schedule": {
+ "type": "string",
+ "description": "Cron expression for scheduled sync"
+ },
+ "realtimeSync": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable real-time sync"
+ },
+ "timestampField": {
+ "type": "string",
+ "description": "Field to track last modification time"
+ },
+ "conflictResolution": {
+ "type": "string",
+ "enum": [
+ "source_wins",
+ "target_wins",
+ "latest_wins",
+ "manual"
+ ],
+ "description": "Conflict resolution strategy",
+ "default": "latest_wins"
+ },
+ "batchSize": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 10000,
+ "default": 1000,
+ "description": "Records per batch"
+ },
+ "deleteMode": {
+ "type": "string",
+ "enum": [
+ "hard_delete",
+ "soft_delete",
+ "ignore"
+ ],
+ "default": "soft_delete",
+ "description": "Delete handling mode"
+ },
+ "filters": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Filter criteria for selective sync"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Data sync configuration"
+ },
+ "fieldMappings": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sourceField": {
+ "type": "string",
+ "description": "Field name in external system"
+ },
+ "targetField": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Field name in ObjectStack (snake_case)"
+ },
+ "dataType": {
+ "type": "string",
+ "enum": [
+ "string",
+ "number",
+ "boolean",
+ "date",
+ "datetime",
+ "json",
+ "array"
+ ],
+ "description": "Target data type"
+ },
+ "required": {
+ "type": "boolean",
+ "default": false,
+ "description": "Field is required"
+ },
+ "defaultValue": {
+ "description": "Default value"
+ },
+ "transform": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "uppercase",
+ "lowercase",
+ "trim",
+ "date_format",
+ "number_format",
+ "custom"
+ ],
+ "description": "Transformation type"
+ },
+ "params": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Transformation parameters"
+ },
+ "function": {
+ "type": "string",
+ "description": "Custom JavaScript function for transformation"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "description": "Field transformation"
+ },
+ "syncMode": {
+ "type": "string",
+ "enum": [
+ "read_only",
+ "write_only",
+ "bidirectional"
+ ],
+ "default": "bidirectional",
+ "description": "Sync mode"
+ }
+ },
+ "required": [
+ "sourceField",
+ "targetField"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Field mapping rules"
+ },
+ "webhooks": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "url": {
+ "type": "string",
+ "format": "uri",
+ "description": "Webhook endpoint URL"
+ },
+ "events": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "record.created",
+ "record.updated",
+ "record.deleted",
+ "sync.started",
+ "sync.completed",
+ "sync.failed",
+ "auth.expired",
+ "rate_limit.exceeded"
+ ],
+ "description": "Webhook event type"
+ },
+ "description": "Events to subscribe to"
+ },
+ "secret": {
+ "type": "string",
+ "description": "Secret for HMAC signature"
+ },
+ "signatureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "hmac_sha256",
+ "hmac_sha512",
+ "none"
+ ],
+ "description": "Webhook signature algorithm",
+ "default": "hmac_sha256"
+ },
+ "headers": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Custom HTTP headers"
+ },
+ "retryConfig": {
+ "type": "object",
+ "properties": {
+ "maxAttempts": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 10,
+ "default": 3,
+ "description": "Maximum retry attempts"
+ },
+ "backoffMultiplier": {
+ "type": "number",
+ "minimum": 1,
+ "default": 2,
+ "description": "Exponential backoff multiplier"
+ },
+ "initialDelayMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 1000,
+ "description": "Initial retry delay in ms"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Retry configuration"
+ },
+ "timeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 60000,
+ "default": 30000,
+ "description": "Request timeout in ms"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable webhook"
+ }
+ },
+ "required": [
+ "url",
+ "events"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Webhook configurations"
+ },
+ "rateLimitConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "fixed_window",
+ "sliding_window",
+ "token_bucket",
+ "leaky_bucket"
+ ],
+ "description": "Rate limiting strategy",
+ "default": "token_bucket"
+ },
+ "maxRequests": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Maximum requests per window"
+ },
+ "windowSeconds": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Time window in seconds"
+ },
+ "burstCapacity": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Burst capacity"
+ },
+ "respectUpstreamLimits": {
+ "type": "boolean",
+ "default": true,
+ "description": "Respect external rate limit headers"
+ },
+ "rateLimitHeaders": {
+ "type": "object",
+ "properties": {
+ "remaining": {
+ "type": "string",
+ "default": "X-RateLimit-Remaining",
+ "description": "Header for remaining requests"
+ },
+ "limit": {
+ "type": "string",
+ "default": "X-RateLimit-Limit",
+ "description": "Header for rate limit"
+ },
+ "reset": {
+ "type": "string",
+ "default": "X-RateLimit-Reset",
+ "description": "Header for reset time"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Custom rate limit headers"
+ }
+ },
+ "required": [
+ "maxRequests",
+ "windowSeconds"
+ ],
+ "additionalProperties": false,
+ "description": "Rate limiting configuration"
+ },
+ "retryConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "exponential_backoff",
+ "linear_backoff",
+ "fixed_delay",
+ "no_retry"
+ ],
+ "description": "Retry strategy",
+ "default": "exponential_backoff"
+ },
+ "maxAttempts": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 10,
+ "default": 3,
+ "description": "Maximum retry attempts"
+ },
+ "initialDelayMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 1000,
+ "description": "Initial retry delay in ms"
+ },
+ "maxDelayMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 60000,
+ "description": "Maximum retry delay in ms"
+ },
+ "backoffMultiplier": {
+ "type": "number",
+ "minimum": 1,
+ "default": 2,
+ "description": "Exponential backoff multiplier"
+ },
+ "retryableStatusCodes": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ },
+ "default": [
+ 408,
+ 429,
+ 500,
+ 502,
+ 503,
+ 504
+ ],
+ "description": "HTTP status codes to retry"
+ },
+ "retryOnNetworkError": {
+ "type": "boolean",
+ "default": true,
+ "description": "Retry on network errors"
+ },
+ "jitter": {
+ "type": "boolean",
+ "default": true,
+ "description": "Add jitter to retry delays"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Retry configuration"
+ },
+ "connectionTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 300000,
+ "default": 30000,
+ "description": "Connection timeout in ms"
+ },
+ "requestTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 300000,
+ "default": 30000,
+ "description": "Request timeout in ms"
+ },
+ "status": {
+ "type": "string",
+ "enum": [
+ "active",
+ "inactive",
+ "error",
+ "configuring"
+ ],
+ "description": "Connector status",
+ "default": "inactive"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable connector"
+ },
+ "metadata": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Custom connector metadata"
+ },
+ "provider": {
+ "type": "string",
+ "enum": [
+ "postgresql",
+ "mysql",
+ "mariadb",
+ "mssql",
+ "oracle",
+ "mongodb",
+ "redis",
+ "cassandra",
+ "snowflake",
+ "bigquery",
+ "redshift",
+ "custom"
+ ],
+ "description": "Database provider type"
+ },
+ "connectionConfig": {
+ "type": "object",
+ "properties": {
+ "host": {
+ "type": "string",
+ "description": "Database host"
+ },
+ "port": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 65535,
+ "description": "Database port"
+ },
+ "database": {
+ "type": "string",
+ "description": "Database name"
+ },
+ "username": {
+ "type": "string",
+ "description": "Database username"
+ },
+ "password": {
+ "type": "string",
+ "description": "Database password (typically from ENV)"
+ },
+ "options": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Driver-specific connection options"
+ }
+ },
+ "required": [
+ "host",
+ "port",
+ "database",
+ "username",
+ "password"
+ ],
+ "additionalProperties": false,
+ "description": "Database connection configuration"
+ },
+ "poolConfig": {
+ "type": "object",
+ "properties": {
+ "min": {
+ "type": "number",
+ "minimum": 0,
+ "default": 2,
+ "description": "Minimum connections in pool"
+ },
+ "max": {
+ "type": "number",
+ "minimum": 1,
+ "default": 10,
+ "description": "Maximum connections in pool"
+ },
+ "idleTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 30000,
+ "description": "Idle connection timeout in ms"
+ },
+ "connectionTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 10000,
+ "description": "Connection establishment timeout in ms"
+ },
+ "acquireTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 30000,
+ "description": "Connection acquisition timeout in ms"
+ },
+ "evictionRunIntervalMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 30000,
+ "description": "Connection eviction check interval in ms"
+ },
+ "testOnBorrow": {
+ "type": "boolean",
+ "default": true,
+ "description": "Test connection before use"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Connection pool configuration"
+ },
+ "sslConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable SSL/TLS"
+ },
+ "rejectUnauthorized": {
+ "type": "boolean",
+ "default": true,
+ "description": "Reject unauthorized certificates"
+ },
+ "ca": {
+ "type": "string",
+ "description": "Certificate Authority certificate"
+ },
+ "cert": {
+ "type": "string",
+ "description": "Client certificate"
+ },
+ "key": {
+ "type": "string",
+ "description": "Client private key"
+ }
+ },
+ "additionalProperties": false,
+ "description": "SSL/TLS configuration"
+ },
+ "tables": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Table name in ObjectStack (snake_case)"
+ },
+ "label": {
+ "type": "string",
+ "description": "Display label"
+ },
+ "schema": {
+ "type": "string",
+ "description": "Database schema name"
+ },
+ "tableName": {
+ "type": "string",
+ "description": "Actual table name in database"
+ },
+ "primaryKey": {
+ "type": "string",
+ "description": "Primary key column"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable sync for this table"
+ },
+ "fieldMappings": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sourceField": {
+ "type": "string",
+ "description": "Field name in external system"
+ },
+ "targetField": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Field name in ObjectStack (snake_case)"
+ },
+ "dataType": {
+ "type": "string",
+ "enum": [
+ "string",
+ "number",
+ "boolean",
+ "date",
+ "datetime",
+ "json",
+ "array"
+ ],
+ "description": "Target data type"
+ },
+ "required": {
+ "type": "boolean",
+ "default": false,
+ "description": "Field is required"
+ },
+ "defaultValue": {
+ "description": "Default value"
+ },
+ "transform": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "uppercase",
+ "lowercase",
+ "trim",
+ "date_format",
+ "number_format",
+ "custom"
+ ],
+ "description": "Transformation type"
+ },
+ "params": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Transformation parameters"
+ },
+ "function": {
+ "type": "string",
+ "description": "Custom JavaScript function for transformation"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "description": "Field transformation"
+ },
+ "syncMode": {
+ "type": "string",
+ "enum": [
+ "read_only",
+ "write_only",
+ "bidirectional"
+ ],
+ "default": "bidirectional",
+ "description": "Sync mode"
+ }
+ },
+ "required": [
+ "sourceField",
+ "targetField"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Table-specific field mappings"
+ },
+ "whereClause": {
+ "type": "string",
+ "description": "SQL WHERE clause for filtering"
+ }
+ },
+ "required": [
+ "name",
+ "label",
+ "tableName",
+ "primaryKey"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Tables to sync"
+ },
+ "cdcConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable CDC"
+ },
+ "method": {
+ "type": "string",
+ "enum": [
+ "log_based",
+ "trigger_based",
+ "query_based",
+ "custom"
+ ],
+ "description": "CDC method"
+ },
+ "slotName": {
+ "type": "string",
+ "description": "Replication slot name (for log-based CDC)"
+ },
+ "publicationName": {
+ "type": "string",
+ "description": "Publication name (for PostgreSQL)"
+ },
+ "startPosition": {
+ "type": "string",
+ "description": "Starting position/LSN for CDC stream"
+ },
+ "batchSize": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 10000,
+ "default": 1000,
+ "description": "CDC batch size"
+ },
+ "pollIntervalMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 1000,
+ "description": "CDC polling interval in ms"
+ }
+ },
+ "required": [
+ "method"
+ ],
+ "additionalProperties": false,
+ "description": "CDC configuration"
+ },
+ "readReplicaConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Use read replicas"
+ },
+ "hosts": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "host": {
+ "type": "string",
+ "description": "Replica host"
+ },
+ "port": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 65535,
+ "description": "Replica port"
+ },
+ "weight": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 1,
+ "default": 1,
+ "description": "Load balancing weight"
+ }
+ },
+ "required": [
+ "host",
+ "port"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Read replica hosts"
+ }
+ },
+ "required": [
+ "hosts"
+ ],
+ "additionalProperties": false,
+ "description": "Read replica configuration"
+ },
+ "queryTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 300000,
+ "default": 30000,
+ "description": "Query timeout in ms"
+ },
+ "enableQueryLogging": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable SQL query logging"
+ }
+ },
+ "required": [
+ "name",
+ "label",
+ "type",
+ "authentication",
+ "provider",
+ "connectionConfig",
+ "tables"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/DatabasePoolConfig.json b/packages/spec/json-schema/integration/DatabasePoolConfig.json
new file mode 100644
index 000000000..8b6fba409
--- /dev/null
+++ b/packages/spec/json-schema/integration/DatabasePoolConfig.json
@@ -0,0 +1,53 @@
+{
+ "$ref": "#/definitions/DatabasePoolConfig",
+ "definitions": {
+ "DatabasePoolConfig": {
+ "type": "object",
+ "properties": {
+ "min": {
+ "type": "number",
+ "minimum": 0,
+ "default": 2,
+ "description": "Minimum connections in pool"
+ },
+ "max": {
+ "type": "number",
+ "minimum": 1,
+ "default": 10,
+ "description": "Maximum connections in pool"
+ },
+ "idleTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 30000,
+ "description": "Idle connection timeout in ms"
+ },
+ "connectionTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 10000,
+ "description": "Connection establishment timeout in ms"
+ },
+ "acquireTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 30000,
+ "description": "Connection acquisition timeout in ms"
+ },
+ "evictionRunIntervalMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 30000,
+ "description": "Connection eviction check interval in ms"
+ },
+ "testOnBorrow": {
+ "type": "boolean",
+ "default": true,
+ "description": "Test connection before use"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/DatabaseProvider.json b/packages/spec/json-schema/integration/DatabaseProvider.json
new file mode 100644
index 000000000..6eb33b9ff
--- /dev/null
+++ b/packages/spec/json-schema/integration/DatabaseProvider.json
@@ -0,0 +1,24 @@
+{
+ "$ref": "#/definitions/DatabaseProvider",
+ "definitions": {
+ "DatabaseProvider": {
+ "type": "string",
+ "enum": [
+ "postgresql",
+ "mysql",
+ "mariadb",
+ "mssql",
+ "oracle",
+ "mongodb",
+ "redis",
+ "cassandra",
+ "snowflake",
+ "bigquery",
+ "redshift",
+ "custom"
+ ],
+ "description": "Database provider type"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/DatabaseTable.json b/packages/spec/json-schema/integration/DatabaseTable.json
new file mode 100644
index 000000000..0d106d38b
--- /dev/null
+++ b/packages/spec/json-schema/integration/DatabaseTable.json
@@ -0,0 +1,133 @@
+{
+ "$ref": "#/definitions/DatabaseTable",
+ "definitions": {
+ "DatabaseTable": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Table name in ObjectStack (snake_case)"
+ },
+ "label": {
+ "type": "string",
+ "description": "Display label"
+ },
+ "schema": {
+ "type": "string",
+ "description": "Database schema name"
+ },
+ "tableName": {
+ "type": "string",
+ "description": "Actual table name in database"
+ },
+ "primaryKey": {
+ "type": "string",
+ "description": "Primary key column"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable sync for this table"
+ },
+ "fieldMappings": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sourceField": {
+ "type": "string",
+ "description": "Field name in external system"
+ },
+ "targetField": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Field name in ObjectStack (snake_case)"
+ },
+ "dataType": {
+ "type": "string",
+ "enum": [
+ "string",
+ "number",
+ "boolean",
+ "date",
+ "datetime",
+ "json",
+ "array"
+ ],
+ "description": "Target data type"
+ },
+ "required": {
+ "type": "boolean",
+ "default": false,
+ "description": "Field is required"
+ },
+ "defaultValue": {
+ "description": "Default value"
+ },
+ "transform": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "uppercase",
+ "lowercase",
+ "trim",
+ "date_format",
+ "number_format",
+ "custom"
+ ],
+ "description": "Transformation type"
+ },
+ "params": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Transformation parameters"
+ },
+ "function": {
+ "type": "string",
+ "description": "Custom JavaScript function for transformation"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "description": "Field transformation"
+ },
+ "syncMode": {
+ "type": "string",
+ "enum": [
+ "read_only",
+ "write_only",
+ "bidirectional"
+ ],
+ "default": "bidirectional",
+ "description": "Sync mode"
+ }
+ },
+ "required": [
+ "sourceField",
+ "targetField"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Table-specific field mappings"
+ },
+ "whereClause": {
+ "type": "string",
+ "description": "SQL WHERE clause for filtering"
+ }
+ },
+ "required": [
+ "name",
+ "label",
+ "tableName",
+ "primaryKey"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/DeliveryGuarantee.json b/packages/spec/json-schema/integration/DeliveryGuarantee.json
new file mode 100644
index 000000000..05a05f0aa
--- /dev/null
+++ b/packages/spec/json-schema/integration/DeliveryGuarantee.json
@@ -0,0 +1,15 @@
+{
+ "$ref": "#/definitions/DeliveryGuarantee",
+ "definitions": {
+ "DeliveryGuarantee": {
+ "type": "string",
+ "enum": [
+ "at_most_once",
+ "at_least_once",
+ "exactly_once"
+ ],
+ "description": "Message delivery guarantee"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/DlqConfig.json b/packages/spec/json-schema/integration/DlqConfig.json
new file mode 100644
index 000000000..8ca5879ad
--- /dev/null
+++ b/packages/spec/json-schema/integration/DlqConfig.json
@@ -0,0 +1,37 @@
+{
+ "$ref": "#/definitions/DlqConfig",
+ "definitions": {
+ "DlqConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable DLQ"
+ },
+ "queueName": {
+ "type": "string",
+ "description": "Dead letter queue/topic name"
+ },
+ "maxRetries": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 100,
+ "default": 3,
+ "description": "Max retries before DLQ"
+ },
+ "retryDelayMs": {
+ "type": "number",
+ "minimum": 0,
+ "default": 60000,
+ "description": "Retry delay in ms"
+ }
+ },
+ "required": [
+ "queueName"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/FieldMapping.json b/packages/spec/json-schema/integration/FieldMapping.json
new file mode 100644
index 000000000..d8782c613
--- /dev/null
+++ b/packages/spec/json-schema/integration/FieldMapping.json
@@ -0,0 +1,87 @@
+{
+ "$ref": "#/definitions/FieldMapping",
+ "definitions": {
+ "FieldMapping": {
+ "type": "object",
+ "properties": {
+ "sourceField": {
+ "type": "string",
+ "description": "Field name in external system"
+ },
+ "targetField": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Field name in ObjectStack (snake_case)"
+ },
+ "dataType": {
+ "type": "string",
+ "enum": [
+ "string",
+ "number",
+ "boolean",
+ "date",
+ "datetime",
+ "json",
+ "array"
+ ],
+ "description": "Target data type"
+ },
+ "required": {
+ "type": "boolean",
+ "default": false,
+ "description": "Field is required"
+ },
+ "defaultValue": {
+ "description": "Default value"
+ },
+ "transform": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "uppercase",
+ "lowercase",
+ "trim",
+ "date_format",
+ "number_format",
+ "custom"
+ ],
+ "description": "Transformation type"
+ },
+ "params": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Transformation parameters"
+ },
+ "function": {
+ "type": "string",
+ "description": "Custom JavaScript function for transformation"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "description": "Field transformation"
+ },
+ "syncMode": {
+ "type": "string",
+ "enum": [
+ "read_only",
+ "write_only",
+ "bidirectional"
+ ],
+ "default": "bidirectional",
+ "description": "Sync mode"
+ }
+ },
+ "required": [
+ "sourceField",
+ "targetField"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/FieldTransform.json b/packages/spec/json-schema/integration/FieldTransform.json
new file mode 100644
index 000000000..6d8ce629f
--- /dev/null
+++ b/packages/spec/json-schema/integration/FieldTransform.json
@@ -0,0 +1,36 @@
+{
+ "$ref": "#/definitions/FieldTransform",
+ "definitions": {
+ "FieldTransform": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "uppercase",
+ "lowercase",
+ "trim",
+ "date_format",
+ "number_format",
+ "custom"
+ ],
+ "description": "Transformation type"
+ },
+ "params": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Transformation parameters"
+ },
+ "function": {
+ "type": "string",
+ "description": "Custom JavaScript function for transformation"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/FileAccessPattern.json b/packages/spec/json-schema/integration/FileAccessPattern.json
new file mode 100644
index 000000000..72e82ae87
--- /dev/null
+++ b/packages/spec/json-schema/integration/FileAccessPattern.json
@@ -0,0 +1,17 @@
+{
+ "$ref": "#/definitions/FileAccessPattern",
+ "definitions": {
+ "FileAccessPattern": {
+ "type": "string",
+ "enum": [
+ "public_read",
+ "private",
+ "authenticated_read",
+ "bucket_owner_read",
+ "bucket_owner_full"
+ ],
+ "description": "File access pattern"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/FileFilterConfig.json b/packages/spec/json-schema/integration/FileFilterConfig.json
new file mode 100644
index 000000000..261beffff
--- /dev/null
+++ b/packages/spec/json-schema/integration/FileFilterConfig.json
@@ -0,0 +1,50 @@
+{
+ "$ref": "#/definitions/FileFilterConfig",
+ "definitions": {
+ "FileFilterConfig": {
+ "type": "object",
+ "properties": {
+ "includePatterns": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "File patterns to include (glob)"
+ },
+ "excludePatterns": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "File patterns to exclude (glob)"
+ },
+ "minFileSize": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Minimum file size in bytes"
+ },
+ "maxFileSize": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Maximum file size in bytes"
+ },
+ "allowedExtensions": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Allowed file extensions"
+ },
+ "blockedExtensions": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Blocked file extensions"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/FileMetadataConfig.json b/packages/spec/json-schema/integration/FileMetadataConfig.json
new file mode 100644
index 000000000..b6e18bab5
--- /dev/null
+++ b/packages/spec/json-schema/integration/FileMetadataConfig.json
@@ -0,0 +1,41 @@
+{
+ "$ref": "#/definitions/FileMetadataConfig",
+ "definitions": {
+ "FileMetadataConfig": {
+ "type": "object",
+ "properties": {
+ "extractMetadata": {
+ "type": "boolean",
+ "default": true,
+ "description": "Extract file metadata"
+ },
+ "metadataFields": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "content_type",
+ "file_size",
+ "last_modified",
+ "etag",
+ "checksum",
+ "creator",
+ "created_at",
+ "custom"
+ ]
+ },
+ "description": "Metadata fields to extract"
+ },
+ "customMetadata": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Custom metadata key-value pairs"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/FileStorageConnector.json b/packages/spec/json-schema/integration/FileStorageConnector.json
new file mode 100644
index 000000000..ff454c3a7
--- /dev/null
+++ b/packages/spec/json-schema/integration/FileStorageConnector.json
@@ -0,0 +1,1065 @@
+{
+ "$ref": "#/definitions/FileStorageConnector",
+ "definitions": {
+ "FileStorageConnector": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Unique connector identifier"
+ },
+ "label": {
+ "type": "string",
+ "description": "Display label"
+ },
+ "type": {
+ "type": "string",
+ "const": "file_storage"
+ },
+ "description": {
+ "type": "string",
+ "description": "Connector description"
+ },
+ "icon": {
+ "type": "string",
+ "description": "Icon identifier"
+ },
+ "authentication": {
+ "anyOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "api_key",
+ "description": "Authentication type"
+ },
+ "apiKey": {
+ "type": "string",
+ "description": "API key (typically from ENV)"
+ },
+ "headerName": {
+ "type": "string",
+ "default": "X-API-Key",
+ "description": "HTTP header name for API key"
+ },
+ "paramName": {
+ "type": "string",
+ "description": "Query parameter name (alternative to header)"
+ }
+ },
+ "required": [
+ "type",
+ "apiKey"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "oauth2",
+ "description": "Authentication type"
+ },
+ "clientId": {
+ "type": "string",
+ "description": "OAuth2 client ID"
+ },
+ "clientSecret": {
+ "type": "string",
+ "description": "OAuth2 client secret (typically from ENV)"
+ },
+ "authorizationUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 authorization endpoint"
+ },
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 token endpoint"
+ },
+ "scopes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Requested OAuth2 scopes"
+ },
+ "redirectUri": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 callback URL"
+ },
+ "grantType": {
+ "type": "string",
+ "enum": [
+ "authorization_code",
+ "client_credentials",
+ "password",
+ "refresh_token"
+ ],
+ "default": "authorization_code",
+ "description": "OAuth2 grant type"
+ },
+ "refreshToken": {
+ "type": "string",
+ "description": "Refresh token for token renewal"
+ },
+ "tokenExpiry": {
+ "type": "number",
+ "description": "Token expiry timestamp"
+ }
+ },
+ "required": [
+ "type",
+ "clientId",
+ "clientSecret",
+ "authorizationUrl",
+ "tokenUrl"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "jwt",
+ "description": "Authentication type"
+ },
+ "token": {
+ "type": "string",
+ "description": "Pre-generated JWT token"
+ },
+ "secretKey": {
+ "type": "string",
+ "description": "Secret key for JWT signing"
+ },
+ "algorithm": {
+ "type": "string",
+ "enum": [
+ "HS256",
+ "HS384",
+ "HS512",
+ "RS256",
+ "RS384",
+ "RS512",
+ "ES256",
+ "ES384",
+ "ES512"
+ ],
+ "default": "HS256",
+ "description": "JWT signing algorithm"
+ },
+ "issuer": {
+ "type": "string",
+ "description": "JWT issuer claim"
+ },
+ "audience": {
+ "type": "string",
+ "description": "JWT audience claim"
+ },
+ "subject": {
+ "type": "string",
+ "description": "JWT subject claim"
+ },
+ "expiresIn": {
+ "type": "number",
+ "default": 3600,
+ "description": "Token expiry in seconds"
+ },
+ "claims": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Additional JWT claims"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "saml",
+ "description": "Authentication type"
+ },
+ "entryPoint": {
+ "type": "string",
+ "format": "uri",
+ "description": "SAML IdP entry point URL"
+ },
+ "issuer": {
+ "type": "string",
+ "description": "SAML service provider issuer"
+ },
+ "certificate": {
+ "type": "string",
+ "description": "SAML IdP certificate (X.509)"
+ },
+ "privateKey": {
+ "type": "string",
+ "description": "SAML service provider private key"
+ },
+ "callbackUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "SAML assertion consumer service URL"
+ },
+ "signatureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "sha1",
+ "sha256",
+ "sha512"
+ ],
+ "default": "sha256",
+ "description": "SAML signature algorithm"
+ },
+ "wantAssertionsSigned": {
+ "type": "boolean",
+ "default": true,
+ "description": "Require signed SAML assertions"
+ },
+ "identifierFormat": {
+ "type": "string",
+ "description": "SAML NameID format"
+ }
+ },
+ "required": [
+ "type",
+ "entryPoint",
+ "issuer",
+ "certificate"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "basic",
+ "description": "Authentication type"
+ },
+ "username": {
+ "type": "string",
+ "description": "Username"
+ },
+ "password": {
+ "type": "string",
+ "description": "Password (typically from ENV)"
+ }
+ },
+ "required": [
+ "type",
+ "username",
+ "password"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "bearer",
+ "description": "Authentication type"
+ },
+ "token": {
+ "type": "string",
+ "description": "Bearer token"
+ }
+ },
+ "required": [
+ "type",
+ "token"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "none",
+ "description": "No authentication required"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ }
+ ],
+ "description": "Authentication configuration"
+ },
+ "syncConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "full",
+ "incremental",
+ "upsert",
+ "append_only"
+ ],
+ "description": "Synchronization strategy",
+ "default": "incremental"
+ },
+ "direction": {
+ "type": "string",
+ "enum": [
+ "import",
+ "export",
+ "bidirectional"
+ ],
+ "default": "import",
+ "description": "Sync direction"
+ },
+ "schedule": {
+ "type": "string",
+ "description": "Cron expression for scheduled sync"
+ },
+ "realtimeSync": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable real-time sync"
+ },
+ "timestampField": {
+ "type": "string",
+ "description": "Field to track last modification time"
+ },
+ "conflictResolution": {
+ "type": "string",
+ "enum": [
+ "source_wins",
+ "target_wins",
+ "latest_wins",
+ "manual"
+ ],
+ "description": "Conflict resolution strategy",
+ "default": "latest_wins"
+ },
+ "batchSize": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 10000,
+ "default": 1000,
+ "description": "Records per batch"
+ },
+ "deleteMode": {
+ "type": "string",
+ "enum": [
+ "hard_delete",
+ "soft_delete",
+ "ignore"
+ ],
+ "default": "soft_delete",
+ "description": "Delete handling mode"
+ },
+ "filters": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Filter criteria for selective sync"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Data sync configuration"
+ },
+ "fieldMappings": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sourceField": {
+ "type": "string",
+ "description": "Field name in external system"
+ },
+ "targetField": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Field name in ObjectStack (snake_case)"
+ },
+ "dataType": {
+ "type": "string",
+ "enum": [
+ "string",
+ "number",
+ "boolean",
+ "date",
+ "datetime",
+ "json",
+ "array"
+ ],
+ "description": "Target data type"
+ },
+ "required": {
+ "type": "boolean",
+ "default": false,
+ "description": "Field is required"
+ },
+ "defaultValue": {
+ "description": "Default value"
+ },
+ "transform": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "uppercase",
+ "lowercase",
+ "trim",
+ "date_format",
+ "number_format",
+ "custom"
+ ],
+ "description": "Transformation type"
+ },
+ "params": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Transformation parameters"
+ },
+ "function": {
+ "type": "string",
+ "description": "Custom JavaScript function for transformation"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "description": "Field transformation"
+ },
+ "syncMode": {
+ "type": "string",
+ "enum": [
+ "read_only",
+ "write_only",
+ "bidirectional"
+ ],
+ "default": "bidirectional",
+ "description": "Sync mode"
+ }
+ },
+ "required": [
+ "sourceField",
+ "targetField"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Field mapping rules"
+ },
+ "webhooks": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "url": {
+ "type": "string",
+ "format": "uri",
+ "description": "Webhook endpoint URL"
+ },
+ "events": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "record.created",
+ "record.updated",
+ "record.deleted",
+ "sync.started",
+ "sync.completed",
+ "sync.failed",
+ "auth.expired",
+ "rate_limit.exceeded"
+ ],
+ "description": "Webhook event type"
+ },
+ "description": "Events to subscribe to"
+ },
+ "secret": {
+ "type": "string",
+ "description": "Secret for HMAC signature"
+ },
+ "signatureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "hmac_sha256",
+ "hmac_sha512",
+ "none"
+ ],
+ "description": "Webhook signature algorithm",
+ "default": "hmac_sha256"
+ },
+ "headers": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Custom HTTP headers"
+ },
+ "retryConfig": {
+ "type": "object",
+ "properties": {
+ "maxAttempts": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 10,
+ "default": 3,
+ "description": "Maximum retry attempts"
+ },
+ "backoffMultiplier": {
+ "type": "number",
+ "minimum": 1,
+ "default": 2,
+ "description": "Exponential backoff multiplier"
+ },
+ "initialDelayMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 1000,
+ "description": "Initial retry delay in ms"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Retry configuration"
+ },
+ "timeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 60000,
+ "default": 30000,
+ "description": "Request timeout in ms"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable webhook"
+ }
+ },
+ "required": [
+ "url",
+ "events"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Webhook configurations"
+ },
+ "rateLimitConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "fixed_window",
+ "sliding_window",
+ "token_bucket",
+ "leaky_bucket"
+ ],
+ "description": "Rate limiting strategy",
+ "default": "token_bucket"
+ },
+ "maxRequests": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Maximum requests per window"
+ },
+ "windowSeconds": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Time window in seconds"
+ },
+ "burstCapacity": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Burst capacity"
+ },
+ "respectUpstreamLimits": {
+ "type": "boolean",
+ "default": true,
+ "description": "Respect external rate limit headers"
+ },
+ "rateLimitHeaders": {
+ "type": "object",
+ "properties": {
+ "remaining": {
+ "type": "string",
+ "default": "X-RateLimit-Remaining",
+ "description": "Header for remaining requests"
+ },
+ "limit": {
+ "type": "string",
+ "default": "X-RateLimit-Limit",
+ "description": "Header for rate limit"
+ },
+ "reset": {
+ "type": "string",
+ "default": "X-RateLimit-Reset",
+ "description": "Header for reset time"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Custom rate limit headers"
+ }
+ },
+ "required": [
+ "maxRequests",
+ "windowSeconds"
+ ],
+ "additionalProperties": false,
+ "description": "Rate limiting configuration"
+ },
+ "retryConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "exponential_backoff",
+ "linear_backoff",
+ "fixed_delay",
+ "no_retry"
+ ],
+ "description": "Retry strategy",
+ "default": "exponential_backoff"
+ },
+ "maxAttempts": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 10,
+ "default": 3,
+ "description": "Maximum retry attempts"
+ },
+ "initialDelayMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 1000,
+ "description": "Initial retry delay in ms"
+ },
+ "maxDelayMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 60000,
+ "description": "Maximum retry delay in ms"
+ },
+ "backoffMultiplier": {
+ "type": "number",
+ "minimum": 1,
+ "default": 2,
+ "description": "Exponential backoff multiplier"
+ },
+ "retryableStatusCodes": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ },
+ "default": [
+ 408,
+ 429,
+ 500,
+ 502,
+ 503,
+ 504
+ ],
+ "description": "HTTP status codes to retry"
+ },
+ "retryOnNetworkError": {
+ "type": "boolean",
+ "default": true,
+ "description": "Retry on network errors"
+ },
+ "jitter": {
+ "type": "boolean",
+ "default": true,
+ "description": "Add jitter to retry delays"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Retry configuration"
+ },
+ "connectionTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 300000,
+ "default": 30000,
+ "description": "Connection timeout in ms"
+ },
+ "requestTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 300000,
+ "default": 30000,
+ "description": "Request timeout in ms"
+ },
+ "status": {
+ "type": "string",
+ "enum": [
+ "active",
+ "inactive",
+ "error",
+ "configuring"
+ ],
+ "description": "Connector status",
+ "default": "inactive"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable connector"
+ },
+ "metadata": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Custom connector metadata"
+ },
+ "provider": {
+ "type": "string",
+ "enum": [
+ "s3",
+ "azure_blob",
+ "gcs",
+ "dropbox",
+ "box",
+ "onedrive",
+ "google_drive",
+ "sharepoint",
+ "ftp",
+ "local",
+ "custom"
+ ],
+ "description": "File storage provider type"
+ },
+ "storageConfig": {
+ "type": "object",
+ "properties": {
+ "endpoint": {
+ "type": "string",
+ "format": "uri",
+ "description": "Custom endpoint URL"
+ },
+ "region": {
+ "type": "string",
+ "description": "Default region"
+ },
+ "pathStyle": {
+ "type": "boolean",
+ "default": false,
+ "description": "Use path-style URLs (for S3-compatible)"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Storage configuration"
+ },
+ "buckets": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Bucket identifier in ObjectStack (snake_case)"
+ },
+ "label": {
+ "type": "string",
+ "description": "Display label"
+ },
+ "bucketName": {
+ "type": "string",
+ "description": "Actual bucket/container name in storage system"
+ },
+ "region": {
+ "type": "string",
+ "description": "Storage region"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable sync for this bucket"
+ },
+ "prefix": {
+ "type": "string",
+ "description": "Prefix/path within bucket"
+ },
+ "accessPattern": {
+ "type": "string",
+ "enum": [
+ "public_read",
+ "private",
+ "authenticated_read",
+ "bucket_owner_read",
+ "bucket_owner_full"
+ ],
+ "description": "Access pattern"
+ },
+ "fileFilters": {
+ "type": "object",
+ "properties": {
+ "includePatterns": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "File patterns to include (glob)"
+ },
+ "excludePatterns": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "File patterns to exclude (glob)"
+ },
+ "minFileSize": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Minimum file size in bytes"
+ },
+ "maxFileSize": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Maximum file size in bytes"
+ },
+ "allowedExtensions": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Allowed file extensions"
+ },
+ "blockedExtensions": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Blocked file extensions"
+ }
+ },
+ "additionalProperties": false,
+ "description": "File filter configuration"
+ }
+ },
+ "required": [
+ "name",
+ "label",
+ "bucketName"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Buckets/containers to sync"
+ },
+ "metadataConfig": {
+ "type": "object",
+ "properties": {
+ "extractMetadata": {
+ "type": "boolean",
+ "default": true,
+ "description": "Extract file metadata"
+ },
+ "metadataFields": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "content_type",
+ "file_size",
+ "last_modified",
+ "etag",
+ "checksum",
+ "creator",
+ "created_at",
+ "custom"
+ ]
+ },
+ "description": "Metadata fields to extract"
+ },
+ "customMetadata": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Custom metadata key-value pairs"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Metadata extraction configuration"
+ },
+ "multipartConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable multipart uploads"
+ },
+ "partSize": {
+ "type": "number",
+ "minimum": 5242880,
+ "default": 5242880,
+ "description": "Part size in bytes (min 5MB)"
+ },
+ "maxConcurrentParts": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 10,
+ "default": 5,
+ "description": "Maximum concurrent part uploads"
+ },
+ "threshold": {
+ "type": "number",
+ "minimum": 5242880,
+ "default": 104857600,
+ "description": "File size threshold for multipart upload in bytes"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Multipart upload configuration"
+ },
+ "versioningConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable file versioning"
+ },
+ "maxVersions": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 100,
+ "description": "Maximum versions to retain"
+ },
+ "retentionDays": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Version retention period in days"
+ }
+ },
+ "additionalProperties": false,
+ "description": "File versioning configuration"
+ },
+ "encryption": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable server-side encryption"
+ },
+ "algorithm": {
+ "type": "string",
+ "enum": [
+ "AES256",
+ "aws:kms",
+ "custom"
+ ],
+ "description": "Encryption algorithm"
+ },
+ "kmsKeyId": {
+ "type": "string",
+ "description": "KMS key ID (for aws:kms)"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Encryption configuration"
+ },
+ "lifecyclePolicy": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable lifecycle policy"
+ },
+ "deleteAfterDays": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Delete files after N days"
+ },
+ "archiveAfterDays": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Archive files after N days"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Lifecycle policy"
+ },
+ "contentProcessing": {
+ "type": "object",
+ "properties": {
+ "extractText": {
+ "type": "boolean",
+ "default": false,
+ "description": "Extract text from documents"
+ },
+ "generateThumbnails": {
+ "type": "boolean",
+ "default": false,
+ "description": "Generate image thumbnails"
+ },
+ "thumbnailSizes": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "width": {
+ "type": "number",
+ "minimum": 1
+ },
+ "height": {
+ "type": "number",
+ "minimum": 1
+ }
+ },
+ "required": [
+ "width",
+ "height"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Thumbnail sizes"
+ },
+ "virusScan": {
+ "type": "boolean",
+ "default": false,
+ "description": "Scan for viruses"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Content processing configuration"
+ },
+ "bufferSize": {
+ "type": "number",
+ "minimum": 1024,
+ "default": 65536,
+ "description": "Buffer size in bytes"
+ },
+ "transferAcceleration": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable transfer acceleration"
+ }
+ },
+ "required": [
+ "name",
+ "label",
+ "type",
+ "authentication",
+ "provider",
+ "buckets"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/FileStorageProvider.json b/packages/spec/json-schema/integration/FileStorageProvider.json
new file mode 100644
index 000000000..6dbef63e2
--- /dev/null
+++ b/packages/spec/json-schema/integration/FileStorageProvider.json
@@ -0,0 +1,23 @@
+{
+ "$ref": "#/definitions/FileStorageProvider",
+ "definitions": {
+ "FileStorageProvider": {
+ "type": "string",
+ "enum": [
+ "s3",
+ "azure_blob",
+ "gcs",
+ "dropbox",
+ "box",
+ "onedrive",
+ "google_drive",
+ "sharepoint",
+ "ftp",
+ "local",
+ "custom"
+ ],
+ "description": "File storage provider type"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/FileVersioningConfig.json b/packages/spec/json-schema/integration/FileVersioningConfig.json
new file mode 100644
index 000000000..fc12b87f4
--- /dev/null
+++ b/packages/spec/json-schema/integration/FileVersioningConfig.json
@@ -0,0 +1,28 @@
+{
+ "$ref": "#/definitions/FileVersioningConfig",
+ "definitions": {
+ "FileVersioningConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable file versioning"
+ },
+ "maxVersions": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 100,
+ "description": "Maximum versions to retain"
+ },
+ "retentionDays": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Version retention period in days"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/JwtAuth.json b/packages/spec/json-schema/integration/JwtAuth.json
new file mode 100644
index 000000000..7d482903d
--- /dev/null
+++ b/packages/spec/json-schema/integration/JwtAuth.json
@@ -0,0 +1,66 @@
+{
+ "$ref": "#/definitions/JwtAuth",
+ "definitions": {
+ "JwtAuth": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "jwt",
+ "description": "Authentication type"
+ },
+ "token": {
+ "type": "string",
+ "description": "Pre-generated JWT token"
+ },
+ "secretKey": {
+ "type": "string",
+ "description": "Secret key for JWT signing"
+ },
+ "algorithm": {
+ "type": "string",
+ "enum": [
+ "HS256",
+ "HS384",
+ "HS512",
+ "RS256",
+ "RS384",
+ "RS512",
+ "ES256",
+ "ES384",
+ "ES512"
+ ],
+ "default": "HS256",
+ "description": "JWT signing algorithm"
+ },
+ "issuer": {
+ "type": "string",
+ "description": "JWT issuer claim"
+ },
+ "audience": {
+ "type": "string",
+ "description": "JWT audience claim"
+ },
+ "subject": {
+ "type": "string",
+ "description": "JWT subject claim"
+ },
+ "expiresIn": {
+ "type": "number",
+ "default": 3600,
+ "description": "Token expiry in seconds"
+ },
+ "claims": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Additional JWT claims"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/MessageFormat.json b/packages/spec/json-schema/integration/MessageFormat.json
new file mode 100644
index 000000000..a4090f8cc
--- /dev/null
+++ b/packages/spec/json-schema/integration/MessageFormat.json
@@ -0,0 +1,18 @@
+{
+ "$ref": "#/definitions/MessageFormat",
+ "definitions": {
+ "MessageFormat": {
+ "type": "string",
+ "enum": [
+ "json",
+ "xml",
+ "protobuf",
+ "avro",
+ "text",
+ "binary"
+ ],
+ "description": "Message format/serialization"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/MessageQueueConnector.json b/packages/spec/json-schema/integration/MessageQueueConnector.json
new file mode 100644
index 000000000..6ebaa45fc
--- /dev/null
+++ b/packages/spec/json-schema/integration/MessageQueueConnector.json
@@ -0,0 +1,1150 @@
+{
+ "$ref": "#/definitions/MessageQueueConnector",
+ "definitions": {
+ "MessageQueueConnector": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Unique connector identifier"
+ },
+ "label": {
+ "type": "string",
+ "description": "Display label"
+ },
+ "type": {
+ "type": "string",
+ "const": "message_queue"
+ },
+ "description": {
+ "type": "string",
+ "description": "Connector description"
+ },
+ "icon": {
+ "type": "string",
+ "description": "Icon identifier"
+ },
+ "authentication": {
+ "anyOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "api_key",
+ "description": "Authentication type"
+ },
+ "apiKey": {
+ "type": "string",
+ "description": "API key (typically from ENV)"
+ },
+ "headerName": {
+ "type": "string",
+ "default": "X-API-Key",
+ "description": "HTTP header name for API key"
+ },
+ "paramName": {
+ "type": "string",
+ "description": "Query parameter name (alternative to header)"
+ }
+ },
+ "required": [
+ "type",
+ "apiKey"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "oauth2",
+ "description": "Authentication type"
+ },
+ "clientId": {
+ "type": "string",
+ "description": "OAuth2 client ID"
+ },
+ "clientSecret": {
+ "type": "string",
+ "description": "OAuth2 client secret (typically from ENV)"
+ },
+ "authorizationUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 authorization endpoint"
+ },
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 token endpoint"
+ },
+ "scopes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Requested OAuth2 scopes"
+ },
+ "redirectUri": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 callback URL"
+ },
+ "grantType": {
+ "type": "string",
+ "enum": [
+ "authorization_code",
+ "client_credentials",
+ "password",
+ "refresh_token"
+ ],
+ "default": "authorization_code",
+ "description": "OAuth2 grant type"
+ },
+ "refreshToken": {
+ "type": "string",
+ "description": "Refresh token for token renewal"
+ },
+ "tokenExpiry": {
+ "type": "number",
+ "description": "Token expiry timestamp"
+ }
+ },
+ "required": [
+ "type",
+ "clientId",
+ "clientSecret",
+ "authorizationUrl",
+ "tokenUrl"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "jwt",
+ "description": "Authentication type"
+ },
+ "token": {
+ "type": "string",
+ "description": "Pre-generated JWT token"
+ },
+ "secretKey": {
+ "type": "string",
+ "description": "Secret key for JWT signing"
+ },
+ "algorithm": {
+ "type": "string",
+ "enum": [
+ "HS256",
+ "HS384",
+ "HS512",
+ "RS256",
+ "RS384",
+ "RS512",
+ "ES256",
+ "ES384",
+ "ES512"
+ ],
+ "default": "HS256",
+ "description": "JWT signing algorithm"
+ },
+ "issuer": {
+ "type": "string",
+ "description": "JWT issuer claim"
+ },
+ "audience": {
+ "type": "string",
+ "description": "JWT audience claim"
+ },
+ "subject": {
+ "type": "string",
+ "description": "JWT subject claim"
+ },
+ "expiresIn": {
+ "type": "number",
+ "default": 3600,
+ "description": "Token expiry in seconds"
+ },
+ "claims": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Additional JWT claims"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "saml",
+ "description": "Authentication type"
+ },
+ "entryPoint": {
+ "type": "string",
+ "format": "uri",
+ "description": "SAML IdP entry point URL"
+ },
+ "issuer": {
+ "type": "string",
+ "description": "SAML service provider issuer"
+ },
+ "certificate": {
+ "type": "string",
+ "description": "SAML IdP certificate (X.509)"
+ },
+ "privateKey": {
+ "type": "string",
+ "description": "SAML service provider private key"
+ },
+ "callbackUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "SAML assertion consumer service URL"
+ },
+ "signatureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "sha1",
+ "sha256",
+ "sha512"
+ ],
+ "default": "sha256",
+ "description": "SAML signature algorithm"
+ },
+ "wantAssertionsSigned": {
+ "type": "boolean",
+ "default": true,
+ "description": "Require signed SAML assertions"
+ },
+ "identifierFormat": {
+ "type": "string",
+ "description": "SAML NameID format"
+ }
+ },
+ "required": [
+ "type",
+ "entryPoint",
+ "issuer",
+ "certificate"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "basic",
+ "description": "Authentication type"
+ },
+ "username": {
+ "type": "string",
+ "description": "Username"
+ },
+ "password": {
+ "type": "string",
+ "description": "Password (typically from ENV)"
+ }
+ },
+ "required": [
+ "type",
+ "username",
+ "password"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "bearer",
+ "description": "Authentication type"
+ },
+ "token": {
+ "type": "string",
+ "description": "Bearer token"
+ }
+ },
+ "required": [
+ "type",
+ "token"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "none",
+ "description": "No authentication required"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ }
+ ],
+ "description": "Authentication configuration"
+ },
+ "syncConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "full",
+ "incremental",
+ "upsert",
+ "append_only"
+ ],
+ "description": "Synchronization strategy",
+ "default": "incremental"
+ },
+ "direction": {
+ "type": "string",
+ "enum": [
+ "import",
+ "export",
+ "bidirectional"
+ ],
+ "default": "import",
+ "description": "Sync direction"
+ },
+ "schedule": {
+ "type": "string",
+ "description": "Cron expression for scheduled sync"
+ },
+ "realtimeSync": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable real-time sync"
+ },
+ "timestampField": {
+ "type": "string",
+ "description": "Field to track last modification time"
+ },
+ "conflictResolution": {
+ "type": "string",
+ "enum": [
+ "source_wins",
+ "target_wins",
+ "latest_wins",
+ "manual"
+ ],
+ "description": "Conflict resolution strategy",
+ "default": "latest_wins"
+ },
+ "batchSize": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 10000,
+ "default": 1000,
+ "description": "Records per batch"
+ },
+ "deleteMode": {
+ "type": "string",
+ "enum": [
+ "hard_delete",
+ "soft_delete",
+ "ignore"
+ ],
+ "default": "soft_delete",
+ "description": "Delete handling mode"
+ },
+ "filters": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Filter criteria for selective sync"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Data sync configuration"
+ },
+ "fieldMappings": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sourceField": {
+ "type": "string",
+ "description": "Field name in external system"
+ },
+ "targetField": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Field name in ObjectStack (snake_case)"
+ },
+ "dataType": {
+ "type": "string",
+ "enum": [
+ "string",
+ "number",
+ "boolean",
+ "date",
+ "datetime",
+ "json",
+ "array"
+ ],
+ "description": "Target data type"
+ },
+ "required": {
+ "type": "boolean",
+ "default": false,
+ "description": "Field is required"
+ },
+ "defaultValue": {
+ "description": "Default value"
+ },
+ "transform": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "uppercase",
+ "lowercase",
+ "trim",
+ "date_format",
+ "number_format",
+ "custom"
+ ],
+ "description": "Transformation type"
+ },
+ "params": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Transformation parameters"
+ },
+ "function": {
+ "type": "string",
+ "description": "Custom JavaScript function for transformation"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "description": "Field transformation"
+ },
+ "syncMode": {
+ "type": "string",
+ "enum": [
+ "read_only",
+ "write_only",
+ "bidirectional"
+ ],
+ "default": "bidirectional",
+ "description": "Sync mode"
+ }
+ },
+ "required": [
+ "sourceField",
+ "targetField"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Field mapping rules"
+ },
+ "webhooks": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "url": {
+ "type": "string",
+ "format": "uri",
+ "description": "Webhook endpoint URL"
+ },
+ "events": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "record.created",
+ "record.updated",
+ "record.deleted",
+ "sync.started",
+ "sync.completed",
+ "sync.failed",
+ "auth.expired",
+ "rate_limit.exceeded"
+ ],
+ "description": "Webhook event type"
+ },
+ "description": "Events to subscribe to"
+ },
+ "secret": {
+ "type": "string",
+ "description": "Secret for HMAC signature"
+ },
+ "signatureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "hmac_sha256",
+ "hmac_sha512",
+ "none"
+ ],
+ "description": "Webhook signature algorithm",
+ "default": "hmac_sha256"
+ },
+ "headers": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Custom HTTP headers"
+ },
+ "retryConfig": {
+ "type": "object",
+ "properties": {
+ "maxAttempts": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 10,
+ "default": 3,
+ "description": "Maximum retry attempts"
+ },
+ "backoffMultiplier": {
+ "type": "number",
+ "minimum": 1,
+ "default": 2,
+ "description": "Exponential backoff multiplier"
+ },
+ "initialDelayMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 1000,
+ "description": "Initial retry delay in ms"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Retry configuration"
+ },
+ "timeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 60000,
+ "default": 30000,
+ "description": "Request timeout in ms"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable webhook"
+ }
+ },
+ "required": [
+ "url",
+ "events"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Webhook configurations"
+ },
+ "rateLimitConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "fixed_window",
+ "sliding_window",
+ "token_bucket",
+ "leaky_bucket"
+ ],
+ "description": "Rate limiting strategy",
+ "default": "token_bucket"
+ },
+ "maxRequests": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Maximum requests per window"
+ },
+ "windowSeconds": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Time window in seconds"
+ },
+ "burstCapacity": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Burst capacity"
+ },
+ "respectUpstreamLimits": {
+ "type": "boolean",
+ "default": true,
+ "description": "Respect external rate limit headers"
+ },
+ "rateLimitHeaders": {
+ "type": "object",
+ "properties": {
+ "remaining": {
+ "type": "string",
+ "default": "X-RateLimit-Remaining",
+ "description": "Header for remaining requests"
+ },
+ "limit": {
+ "type": "string",
+ "default": "X-RateLimit-Limit",
+ "description": "Header for rate limit"
+ },
+ "reset": {
+ "type": "string",
+ "default": "X-RateLimit-Reset",
+ "description": "Header for reset time"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Custom rate limit headers"
+ }
+ },
+ "required": [
+ "maxRequests",
+ "windowSeconds"
+ ],
+ "additionalProperties": false,
+ "description": "Rate limiting configuration"
+ },
+ "retryConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "exponential_backoff",
+ "linear_backoff",
+ "fixed_delay",
+ "no_retry"
+ ],
+ "description": "Retry strategy",
+ "default": "exponential_backoff"
+ },
+ "maxAttempts": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 10,
+ "default": 3,
+ "description": "Maximum retry attempts"
+ },
+ "initialDelayMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 1000,
+ "description": "Initial retry delay in ms"
+ },
+ "maxDelayMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 60000,
+ "description": "Maximum retry delay in ms"
+ },
+ "backoffMultiplier": {
+ "type": "number",
+ "minimum": 1,
+ "default": 2,
+ "description": "Exponential backoff multiplier"
+ },
+ "retryableStatusCodes": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ },
+ "default": [
+ 408,
+ 429,
+ 500,
+ 502,
+ 503,
+ 504
+ ],
+ "description": "HTTP status codes to retry"
+ },
+ "retryOnNetworkError": {
+ "type": "boolean",
+ "default": true,
+ "description": "Retry on network errors"
+ },
+ "jitter": {
+ "type": "boolean",
+ "default": true,
+ "description": "Add jitter to retry delays"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Retry configuration"
+ },
+ "connectionTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 300000,
+ "default": 30000,
+ "description": "Connection timeout in ms"
+ },
+ "requestTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 300000,
+ "default": 30000,
+ "description": "Request timeout in ms"
+ },
+ "status": {
+ "type": "string",
+ "enum": [
+ "active",
+ "inactive",
+ "error",
+ "configuring"
+ ],
+ "description": "Connector status",
+ "default": "inactive"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable connector"
+ },
+ "metadata": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Custom connector metadata"
+ },
+ "provider": {
+ "type": "string",
+ "enum": [
+ "rabbitmq",
+ "kafka",
+ "redis_pubsub",
+ "redis_streams",
+ "aws_sqs",
+ "aws_sns",
+ "google_pubsub",
+ "azure_service_bus",
+ "azure_event_hubs",
+ "nats",
+ "pulsar",
+ "activemq",
+ "custom"
+ ],
+ "description": "Message queue provider type"
+ },
+ "brokerConfig": {
+ "type": "object",
+ "properties": {
+ "brokers": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Broker addresses (host:port)"
+ },
+ "clientId": {
+ "type": "string",
+ "description": "Client ID"
+ },
+ "connectionTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 30000,
+ "description": "Connection timeout in ms"
+ },
+ "requestTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 30000,
+ "description": "Request timeout in ms"
+ }
+ },
+ "required": [
+ "brokers"
+ ],
+ "additionalProperties": false,
+ "description": "Broker connection configuration"
+ },
+ "topics": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Topic/queue identifier in ObjectStack (snake_case)"
+ },
+ "label": {
+ "type": "string",
+ "description": "Display label"
+ },
+ "topicName": {
+ "type": "string",
+ "description": "Actual topic/queue name in message queue system"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable sync for this topic/queue"
+ },
+ "mode": {
+ "type": "string",
+ "enum": [
+ "consumer",
+ "producer",
+ "both"
+ ],
+ "default": "both",
+ "description": "Consumer, producer, or both"
+ },
+ "messageFormat": {
+ "type": "string",
+ "enum": [
+ "json",
+ "xml",
+ "protobuf",
+ "avro",
+ "text",
+ "binary"
+ ],
+ "description": "Message format/serialization",
+ "default": "json"
+ },
+ "partitions": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Number of partitions (for Kafka)"
+ },
+ "replicationFactor": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Replication factor (for Kafka)"
+ },
+ "consumerConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable consumer"
+ },
+ "consumerGroup": {
+ "type": "string",
+ "description": "Consumer group ID"
+ },
+ "concurrency": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 100,
+ "default": 1,
+ "description": "Number of concurrent consumers"
+ },
+ "prefetchCount": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 1000,
+ "default": 10,
+ "description": "Prefetch count"
+ },
+ "ackMode": {
+ "type": "string",
+ "enum": [
+ "auto",
+ "manual",
+ "client"
+ ],
+ "description": "Message acknowledgment mode",
+ "default": "manual"
+ },
+ "autoCommit": {
+ "type": "boolean",
+ "default": false,
+ "description": "Auto-commit offsets"
+ },
+ "autoCommitIntervalMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 5000,
+ "description": "Auto-commit interval in ms"
+ },
+ "sessionTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 30000,
+ "description": "Session timeout in ms"
+ },
+ "rebalanceTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "description": "Rebalance timeout in ms"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Consumer-specific configuration"
+ },
+ "producerConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable producer"
+ },
+ "acks": {
+ "type": "string",
+ "enum": [
+ "0",
+ "1",
+ "all"
+ ],
+ "default": "all",
+ "description": "Acknowledgment level"
+ },
+ "compressionType": {
+ "type": "string",
+ "enum": [
+ "none",
+ "gzip",
+ "snappy",
+ "lz4",
+ "zstd"
+ ],
+ "default": "none",
+ "description": "Compression type"
+ },
+ "batchSize": {
+ "type": "number",
+ "minimum": 1,
+ "default": 16384,
+ "description": "Batch size in bytes"
+ },
+ "lingerMs": {
+ "type": "number",
+ "minimum": 0,
+ "default": 0,
+ "description": "Linger time in ms"
+ },
+ "maxInFlightRequests": {
+ "type": "number",
+ "minimum": 1,
+ "default": 5,
+ "description": "Max in-flight requests"
+ },
+ "idempotence": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable idempotent producer"
+ },
+ "transactional": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable transactional producer"
+ },
+ "transactionTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "description": "Transaction timeout in ms"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Producer-specific configuration"
+ },
+ "dlqConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable DLQ"
+ },
+ "queueName": {
+ "type": "string",
+ "description": "Dead letter queue/topic name"
+ },
+ "maxRetries": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 100,
+ "default": 3,
+ "description": "Max retries before DLQ"
+ },
+ "retryDelayMs": {
+ "type": "number",
+ "minimum": 0,
+ "default": 60000,
+ "description": "Retry delay in ms"
+ }
+ },
+ "required": [
+ "queueName"
+ ],
+ "additionalProperties": false,
+ "description": "Dead letter queue configuration"
+ },
+ "routingKey": {
+ "type": "string",
+ "description": "Routing key pattern"
+ },
+ "messageFilter": {
+ "type": "object",
+ "properties": {
+ "headers": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Filter by message headers"
+ },
+ "attributes": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Filter by message attributes"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Message filter criteria"
+ }
+ },
+ "required": [
+ "name",
+ "label",
+ "topicName"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Topics/queues to sync"
+ },
+ "deliveryGuarantee": {
+ "type": "string",
+ "enum": [
+ "at_most_once",
+ "at_least_once",
+ "exactly_once"
+ ],
+ "description": "Message delivery guarantee",
+ "default": "at_least_once"
+ },
+ "sslConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable SSL/TLS"
+ },
+ "rejectUnauthorized": {
+ "type": "boolean",
+ "default": true,
+ "description": "Reject unauthorized certificates"
+ },
+ "ca": {
+ "type": "string",
+ "description": "CA certificate"
+ },
+ "cert": {
+ "type": "string",
+ "description": "Client certificate"
+ },
+ "key": {
+ "type": "string",
+ "description": "Client private key"
+ }
+ },
+ "additionalProperties": false,
+ "description": "SSL/TLS configuration"
+ },
+ "saslConfig": {
+ "type": "object",
+ "properties": {
+ "mechanism": {
+ "type": "string",
+ "enum": [
+ "plain",
+ "scram-sha-256",
+ "scram-sha-512",
+ "aws"
+ ],
+ "description": "SASL mechanism"
+ },
+ "username": {
+ "type": "string",
+ "description": "SASL username"
+ },
+ "password": {
+ "type": "string",
+ "description": "SASL password"
+ }
+ },
+ "required": [
+ "mechanism"
+ ],
+ "additionalProperties": false,
+ "description": "SASL authentication configuration"
+ },
+ "schemaRegistry": {
+ "type": "object",
+ "properties": {
+ "url": {
+ "type": "string",
+ "format": "uri",
+ "description": "Schema registry URL"
+ },
+ "auth": {
+ "type": "object",
+ "properties": {
+ "username": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "required": [
+ "url"
+ ],
+ "additionalProperties": false,
+ "description": "Schema registry configuration"
+ },
+ "preserveOrder": {
+ "type": "boolean",
+ "default": true,
+ "description": "Preserve message ordering"
+ },
+ "enableMetrics": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable message queue metrics"
+ },
+ "enableTracing": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable distributed tracing"
+ }
+ },
+ "required": [
+ "name",
+ "label",
+ "type",
+ "authentication",
+ "provider",
+ "brokerConfig",
+ "topics"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/MessageQueueProvider.json b/packages/spec/json-schema/integration/MessageQueueProvider.json
new file mode 100644
index 000000000..748908f29
--- /dev/null
+++ b/packages/spec/json-schema/integration/MessageQueueProvider.json
@@ -0,0 +1,25 @@
+{
+ "$ref": "#/definitions/MessageQueueProvider",
+ "definitions": {
+ "MessageQueueProvider": {
+ "type": "string",
+ "enum": [
+ "rabbitmq",
+ "kafka",
+ "redis_pubsub",
+ "redis_streams",
+ "aws_sqs",
+ "aws_sns",
+ "google_pubsub",
+ "azure_service_bus",
+ "azure_event_hubs",
+ "nats",
+ "pulsar",
+ "activemq",
+ "custom"
+ ],
+ "description": "Message queue provider type"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/MultipartUploadConfig.json b/packages/spec/json-schema/integration/MultipartUploadConfig.json
new file mode 100644
index 000000000..118f67295
--- /dev/null
+++ b/packages/spec/json-schema/integration/MultipartUploadConfig.json
@@ -0,0 +1,36 @@
+{
+ "$ref": "#/definitions/MultipartUploadConfig",
+ "definitions": {
+ "MultipartUploadConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable multipart uploads"
+ },
+ "partSize": {
+ "type": "number",
+ "minimum": 5242880,
+ "default": 5242880,
+ "description": "Part size in bytes (min 5MB)"
+ },
+ "maxConcurrentParts": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 10,
+ "default": 5,
+ "description": "Maximum concurrent part uploads"
+ },
+ "threshold": {
+ "type": "number",
+ "minimum": 5242880,
+ "default": 104857600,
+ "description": "File size threshold for multipart upload in bytes"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/NoAuth.json b/packages/spec/json-schema/integration/NoAuth.json
new file mode 100644
index 000000000..e363a3b90
--- /dev/null
+++ b/packages/spec/json-schema/integration/NoAuth.json
@@ -0,0 +1,20 @@
+{
+ "$ref": "#/definitions/NoAuth",
+ "definitions": {
+ "NoAuth": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "none",
+ "description": "No authentication required"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/OAuth2Auth.json b/packages/spec/json-schema/integration/OAuth2Auth.json
new file mode 100644
index 000000000..668dc3137
--- /dev/null
+++ b/packages/spec/json-schema/integration/OAuth2Auth.json
@@ -0,0 +1,73 @@
+{
+ "$ref": "#/definitions/OAuth2Auth",
+ "definitions": {
+ "OAuth2Auth": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "oauth2",
+ "description": "Authentication type"
+ },
+ "clientId": {
+ "type": "string",
+ "description": "OAuth2 client ID"
+ },
+ "clientSecret": {
+ "type": "string",
+ "description": "OAuth2 client secret (typically from ENV)"
+ },
+ "authorizationUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 authorization endpoint"
+ },
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 token endpoint"
+ },
+ "scopes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Requested OAuth2 scopes"
+ },
+ "redirectUri": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 callback URL"
+ },
+ "grantType": {
+ "type": "string",
+ "enum": [
+ "authorization_code",
+ "client_credentials",
+ "password",
+ "refresh_token"
+ ],
+ "default": "authorization_code",
+ "description": "OAuth2 grant type"
+ },
+ "refreshToken": {
+ "type": "string",
+ "description": "Refresh token for token renewal"
+ },
+ "tokenExpiry": {
+ "type": "number",
+ "description": "Token expiry timestamp"
+ }
+ },
+ "required": [
+ "type",
+ "clientId",
+ "clientSecret",
+ "authorizationUrl",
+ "tokenUrl"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/ProducerConfig.json b/packages/spec/json-schema/integration/ProducerConfig.json
new file mode 100644
index 000000000..fee6dd42e
--- /dev/null
+++ b/packages/spec/json-schema/integration/ProducerConfig.json
@@ -0,0 +1,72 @@
+{
+ "$ref": "#/definitions/ProducerConfig",
+ "definitions": {
+ "ProducerConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable producer"
+ },
+ "acks": {
+ "type": "string",
+ "enum": [
+ "0",
+ "1",
+ "all"
+ ],
+ "default": "all",
+ "description": "Acknowledgment level"
+ },
+ "compressionType": {
+ "type": "string",
+ "enum": [
+ "none",
+ "gzip",
+ "snappy",
+ "lz4",
+ "zstd"
+ ],
+ "default": "none",
+ "description": "Compression type"
+ },
+ "batchSize": {
+ "type": "number",
+ "minimum": 1,
+ "default": 16384,
+ "description": "Batch size in bytes"
+ },
+ "lingerMs": {
+ "type": "number",
+ "minimum": 0,
+ "default": 0,
+ "description": "Linger time in ms"
+ },
+ "maxInFlightRequests": {
+ "type": "number",
+ "minimum": 1,
+ "default": 5,
+ "description": "Max in-flight requests"
+ },
+ "idempotence": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable idempotent producer"
+ },
+ "transactional": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable transactional producer"
+ },
+ "transactionTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "description": "Transaction timeout in ms"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/RateLimitConfig.json b/packages/spec/json-schema/integration/RateLimitConfig.json
new file mode 100644
index 000000000..144648410
--- /dev/null
+++ b/packages/spec/json-schema/integration/RateLimitConfig.json
@@ -0,0 +1,69 @@
+{
+ "$ref": "#/definitions/RateLimitConfig",
+ "definitions": {
+ "RateLimitConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "fixed_window",
+ "sliding_window",
+ "token_bucket",
+ "leaky_bucket"
+ ],
+ "description": "Rate limiting strategy",
+ "default": "token_bucket"
+ },
+ "maxRequests": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Maximum requests per window"
+ },
+ "windowSeconds": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Time window in seconds"
+ },
+ "burstCapacity": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Burst capacity"
+ },
+ "respectUpstreamLimits": {
+ "type": "boolean",
+ "default": true,
+ "description": "Respect external rate limit headers"
+ },
+ "rateLimitHeaders": {
+ "type": "object",
+ "properties": {
+ "remaining": {
+ "type": "string",
+ "default": "X-RateLimit-Remaining",
+ "description": "Header for remaining requests"
+ },
+ "limit": {
+ "type": "string",
+ "default": "X-RateLimit-Limit",
+ "description": "Header for rate limit"
+ },
+ "reset": {
+ "type": "string",
+ "default": "X-RateLimit-Reset",
+ "description": "Header for reset time"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Custom rate limit headers"
+ }
+ },
+ "required": [
+ "maxRequests",
+ "windowSeconds"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/RateLimitStrategy.json b/packages/spec/json-schema/integration/RateLimitStrategy.json
new file mode 100644
index 000000000..c4fae0815
--- /dev/null
+++ b/packages/spec/json-schema/integration/RateLimitStrategy.json
@@ -0,0 +1,16 @@
+{
+ "$ref": "#/definitions/RateLimitStrategy",
+ "definitions": {
+ "RateLimitStrategy": {
+ "type": "string",
+ "enum": [
+ "fixed_window",
+ "sliding_window",
+ "token_bucket",
+ "leaky_bucket"
+ ],
+ "description": "Rate limiting strategy"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/RetryConfig.json b/packages/spec/json-schema/integration/RetryConfig.json
new file mode 100644
index 000000000..8dd7fca6e
--- /dev/null
+++ b/packages/spec/json-schema/integration/RetryConfig.json
@@ -0,0 +1,73 @@
+{
+ "$ref": "#/definitions/RetryConfig",
+ "definitions": {
+ "RetryConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "exponential_backoff",
+ "linear_backoff",
+ "fixed_delay",
+ "no_retry"
+ ],
+ "description": "Retry strategy",
+ "default": "exponential_backoff"
+ },
+ "maxAttempts": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 10,
+ "default": 3,
+ "description": "Maximum retry attempts"
+ },
+ "initialDelayMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 1000,
+ "description": "Initial retry delay in ms"
+ },
+ "maxDelayMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 60000,
+ "description": "Maximum retry delay in ms"
+ },
+ "backoffMultiplier": {
+ "type": "number",
+ "minimum": 1,
+ "default": 2,
+ "description": "Exponential backoff multiplier"
+ },
+ "retryableStatusCodes": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ },
+ "default": [
+ 408,
+ 429,
+ 500,
+ 502,
+ 503,
+ 504
+ ],
+ "description": "HTTP status codes to retry"
+ },
+ "retryOnNetworkError": {
+ "type": "boolean",
+ "default": true,
+ "description": "Retry on network errors"
+ },
+ "jitter": {
+ "type": "boolean",
+ "default": true,
+ "description": "Add jitter to retry delays"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/RetryStrategy.json b/packages/spec/json-schema/integration/RetryStrategy.json
new file mode 100644
index 000000000..ebb0f30ce
--- /dev/null
+++ b/packages/spec/json-schema/integration/RetryStrategy.json
@@ -0,0 +1,16 @@
+{
+ "$ref": "#/definitions/RetryStrategy",
+ "definitions": {
+ "RetryStrategy": {
+ "type": "string",
+ "enum": [
+ "exponential_backoff",
+ "linear_backoff",
+ "fixed_delay",
+ "no_retry"
+ ],
+ "description": "Retry strategy"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/SaasConnector.json b/packages/spec/json-schema/integration/SaasConnector.json
new file mode 100644
index 000000000..857143334
--- /dev/null
+++ b/packages/spec/json-schema/integration/SaasConnector.json
@@ -0,0 +1,1009 @@
+{
+ "$ref": "#/definitions/SaasConnector",
+ "definitions": {
+ "SaasConnector": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Unique connector identifier"
+ },
+ "label": {
+ "type": "string",
+ "description": "Display label"
+ },
+ "type": {
+ "type": "string",
+ "const": "saas"
+ },
+ "description": {
+ "type": "string",
+ "description": "Connector description"
+ },
+ "icon": {
+ "type": "string",
+ "description": "Icon identifier"
+ },
+ "authentication": {
+ "anyOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "api_key",
+ "description": "Authentication type"
+ },
+ "apiKey": {
+ "type": "string",
+ "description": "API key (typically from ENV)"
+ },
+ "headerName": {
+ "type": "string",
+ "default": "X-API-Key",
+ "description": "HTTP header name for API key"
+ },
+ "paramName": {
+ "type": "string",
+ "description": "Query parameter name (alternative to header)"
+ }
+ },
+ "required": [
+ "type",
+ "apiKey"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "oauth2",
+ "description": "Authentication type"
+ },
+ "clientId": {
+ "type": "string",
+ "description": "OAuth2 client ID"
+ },
+ "clientSecret": {
+ "type": "string",
+ "description": "OAuth2 client secret (typically from ENV)"
+ },
+ "authorizationUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 authorization endpoint"
+ },
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 token endpoint"
+ },
+ "scopes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Requested OAuth2 scopes"
+ },
+ "redirectUri": {
+ "type": "string",
+ "format": "uri",
+ "description": "OAuth2 callback URL"
+ },
+ "grantType": {
+ "type": "string",
+ "enum": [
+ "authorization_code",
+ "client_credentials",
+ "password",
+ "refresh_token"
+ ],
+ "default": "authorization_code",
+ "description": "OAuth2 grant type"
+ },
+ "refreshToken": {
+ "type": "string",
+ "description": "Refresh token for token renewal"
+ },
+ "tokenExpiry": {
+ "type": "number",
+ "description": "Token expiry timestamp"
+ }
+ },
+ "required": [
+ "type",
+ "clientId",
+ "clientSecret",
+ "authorizationUrl",
+ "tokenUrl"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "jwt",
+ "description": "Authentication type"
+ },
+ "token": {
+ "type": "string",
+ "description": "Pre-generated JWT token"
+ },
+ "secretKey": {
+ "type": "string",
+ "description": "Secret key for JWT signing"
+ },
+ "algorithm": {
+ "type": "string",
+ "enum": [
+ "HS256",
+ "HS384",
+ "HS512",
+ "RS256",
+ "RS384",
+ "RS512",
+ "ES256",
+ "ES384",
+ "ES512"
+ ],
+ "default": "HS256",
+ "description": "JWT signing algorithm"
+ },
+ "issuer": {
+ "type": "string",
+ "description": "JWT issuer claim"
+ },
+ "audience": {
+ "type": "string",
+ "description": "JWT audience claim"
+ },
+ "subject": {
+ "type": "string",
+ "description": "JWT subject claim"
+ },
+ "expiresIn": {
+ "type": "number",
+ "default": 3600,
+ "description": "Token expiry in seconds"
+ },
+ "claims": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Additional JWT claims"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "saml",
+ "description": "Authentication type"
+ },
+ "entryPoint": {
+ "type": "string",
+ "format": "uri",
+ "description": "SAML IdP entry point URL"
+ },
+ "issuer": {
+ "type": "string",
+ "description": "SAML service provider issuer"
+ },
+ "certificate": {
+ "type": "string",
+ "description": "SAML IdP certificate (X.509)"
+ },
+ "privateKey": {
+ "type": "string",
+ "description": "SAML service provider private key"
+ },
+ "callbackUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "SAML assertion consumer service URL"
+ },
+ "signatureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "sha1",
+ "sha256",
+ "sha512"
+ ],
+ "default": "sha256",
+ "description": "SAML signature algorithm"
+ },
+ "wantAssertionsSigned": {
+ "type": "boolean",
+ "default": true,
+ "description": "Require signed SAML assertions"
+ },
+ "identifierFormat": {
+ "type": "string",
+ "description": "SAML NameID format"
+ }
+ },
+ "required": [
+ "type",
+ "entryPoint",
+ "issuer",
+ "certificate"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "basic",
+ "description": "Authentication type"
+ },
+ "username": {
+ "type": "string",
+ "description": "Username"
+ },
+ "password": {
+ "type": "string",
+ "description": "Password (typically from ENV)"
+ }
+ },
+ "required": [
+ "type",
+ "username",
+ "password"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "bearer",
+ "description": "Authentication type"
+ },
+ "token": {
+ "type": "string",
+ "description": "Bearer token"
+ }
+ },
+ "required": [
+ "type",
+ "token"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "none",
+ "description": "No authentication required"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false
+ }
+ ],
+ "description": "Authentication configuration"
+ },
+ "syncConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "full",
+ "incremental",
+ "upsert",
+ "append_only"
+ ],
+ "description": "Synchronization strategy",
+ "default": "incremental"
+ },
+ "direction": {
+ "type": "string",
+ "enum": [
+ "import",
+ "export",
+ "bidirectional"
+ ],
+ "default": "import",
+ "description": "Sync direction"
+ },
+ "schedule": {
+ "type": "string",
+ "description": "Cron expression for scheduled sync"
+ },
+ "realtimeSync": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable real-time sync"
+ },
+ "timestampField": {
+ "type": "string",
+ "description": "Field to track last modification time"
+ },
+ "conflictResolution": {
+ "type": "string",
+ "enum": [
+ "source_wins",
+ "target_wins",
+ "latest_wins",
+ "manual"
+ ],
+ "description": "Conflict resolution strategy",
+ "default": "latest_wins"
+ },
+ "batchSize": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 10000,
+ "default": 1000,
+ "description": "Records per batch"
+ },
+ "deleteMode": {
+ "type": "string",
+ "enum": [
+ "hard_delete",
+ "soft_delete",
+ "ignore"
+ ],
+ "default": "soft_delete",
+ "description": "Delete handling mode"
+ },
+ "filters": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Filter criteria for selective sync"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Data sync configuration"
+ },
+ "fieldMappings": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sourceField": {
+ "type": "string",
+ "description": "Field name in external system"
+ },
+ "targetField": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Field name in ObjectStack (snake_case)"
+ },
+ "dataType": {
+ "type": "string",
+ "enum": [
+ "string",
+ "number",
+ "boolean",
+ "date",
+ "datetime",
+ "json",
+ "array"
+ ],
+ "description": "Target data type"
+ },
+ "required": {
+ "type": "boolean",
+ "default": false,
+ "description": "Field is required"
+ },
+ "defaultValue": {
+ "description": "Default value"
+ },
+ "transform": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "uppercase",
+ "lowercase",
+ "trim",
+ "date_format",
+ "number_format",
+ "custom"
+ ],
+ "description": "Transformation type"
+ },
+ "params": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Transformation parameters"
+ },
+ "function": {
+ "type": "string",
+ "description": "Custom JavaScript function for transformation"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "description": "Field transformation"
+ },
+ "syncMode": {
+ "type": "string",
+ "enum": [
+ "read_only",
+ "write_only",
+ "bidirectional"
+ ],
+ "default": "bidirectional",
+ "description": "Sync mode"
+ }
+ },
+ "required": [
+ "sourceField",
+ "targetField"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Field mapping rules"
+ },
+ "webhooks": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "url": {
+ "type": "string",
+ "format": "uri",
+ "description": "Webhook endpoint URL"
+ },
+ "events": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "record.created",
+ "record.updated",
+ "record.deleted",
+ "sync.started",
+ "sync.completed",
+ "sync.failed",
+ "auth.expired",
+ "rate_limit.exceeded"
+ ],
+ "description": "Webhook event type"
+ },
+ "description": "Events to subscribe to"
+ },
+ "secret": {
+ "type": "string",
+ "description": "Secret for HMAC signature"
+ },
+ "signatureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "hmac_sha256",
+ "hmac_sha512",
+ "none"
+ ],
+ "description": "Webhook signature algorithm",
+ "default": "hmac_sha256"
+ },
+ "headers": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Custom HTTP headers"
+ },
+ "retryConfig": {
+ "type": "object",
+ "properties": {
+ "maxAttempts": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 10,
+ "default": 3,
+ "description": "Maximum retry attempts"
+ },
+ "backoffMultiplier": {
+ "type": "number",
+ "minimum": 1,
+ "default": 2,
+ "description": "Exponential backoff multiplier"
+ },
+ "initialDelayMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 1000,
+ "description": "Initial retry delay in ms"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Retry configuration"
+ },
+ "timeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 60000,
+ "default": 30000,
+ "description": "Request timeout in ms"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable webhook"
+ }
+ },
+ "required": [
+ "url",
+ "events"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Webhook configurations"
+ },
+ "rateLimitConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "fixed_window",
+ "sliding_window",
+ "token_bucket",
+ "leaky_bucket"
+ ],
+ "description": "Rate limiting strategy",
+ "default": "token_bucket"
+ },
+ "maxRequests": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Maximum requests per window"
+ },
+ "windowSeconds": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Time window in seconds"
+ },
+ "burstCapacity": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Burst capacity"
+ },
+ "respectUpstreamLimits": {
+ "type": "boolean",
+ "default": true,
+ "description": "Respect external rate limit headers"
+ },
+ "rateLimitHeaders": {
+ "type": "object",
+ "properties": {
+ "remaining": {
+ "type": "string",
+ "default": "X-RateLimit-Remaining",
+ "description": "Header for remaining requests"
+ },
+ "limit": {
+ "type": "string",
+ "default": "X-RateLimit-Limit",
+ "description": "Header for rate limit"
+ },
+ "reset": {
+ "type": "string",
+ "default": "X-RateLimit-Reset",
+ "description": "Header for reset time"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Custom rate limit headers"
+ }
+ },
+ "required": [
+ "maxRequests",
+ "windowSeconds"
+ ],
+ "additionalProperties": false,
+ "description": "Rate limiting configuration"
+ },
+ "retryConfig": {
+ "type": "object",
+ "properties": {
+ "strategy": {
+ "type": "string",
+ "enum": [
+ "exponential_backoff",
+ "linear_backoff",
+ "fixed_delay",
+ "no_retry"
+ ],
+ "description": "Retry strategy",
+ "default": "exponential_backoff"
+ },
+ "maxAttempts": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 10,
+ "default": 3,
+ "description": "Maximum retry attempts"
+ },
+ "initialDelayMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 1000,
+ "description": "Initial retry delay in ms"
+ },
+ "maxDelayMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 60000,
+ "description": "Maximum retry delay in ms"
+ },
+ "backoffMultiplier": {
+ "type": "number",
+ "minimum": 1,
+ "default": 2,
+ "description": "Exponential backoff multiplier"
+ },
+ "retryableStatusCodes": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ },
+ "default": [
+ 408,
+ 429,
+ 500,
+ 502,
+ 503,
+ 504
+ ],
+ "description": "HTTP status codes to retry"
+ },
+ "retryOnNetworkError": {
+ "type": "boolean",
+ "default": true,
+ "description": "Retry on network errors"
+ },
+ "jitter": {
+ "type": "boolean",
+ "default": true,
+ "description": "Add jitter to retry delays"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Retry configuration"
+ },
+ "connectionTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 300000,
+ "default": 30000,
+ "description": "Connection timeout in ms"
+ },
+ "requestTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 300000,
+ "default": 30000,
+ "description": "Request timeout in ms"
+ },
+ "status": {
+ "type": "string",
+ "enum": [
+ "active",
+ "inactive",
+ "error",
+ "configuring"
+ ],
+ "description": "Connector status",
+ "default": "inactive"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable connector"
+ },
+ "metadata": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Custom connector metadata"
+ },
+ "provider": {
+ "type": "string",
+ "enum": [
+ "salesforce",
+ "hubspot",
+ "stripe",
+ "shopify",
+ "zendesk",
+ "intercom",
+ "mailchimp",
+ "slack",
+ "microsoft_dynamics",
+ "servicenow",
+ "netsuite",
+ "custom"
+ ],
+ "description": "SaaS provider type"
+ },
+ "baseUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "API base URL"
+ },
+ "apiVersion": {
+ "type": "object",
+ "properties": {
+ "version": {
+ "type": "string",
+ "description": "API version (e.g., \"v2\", \"2023-10-01\")"
+ },
+ "isDefault": {
+ "type": "boolean",
+ "default": false,
+ "description": "Is this the default version"
+ },
+ "deprecationDate": {
+ "type": "string",
+ "description": "API version deprecation date (ISO 8601)"
+ },
+ "sunsetDate": {
+ "type": "string",
+ "description": "API version sunset date (ISO 8601)"
+ }
+ },
+ "required": [
+ "version"
+ ],
+ "additionalProperties": false,
+ "description": "API version configuration"
+ },
+ "objectTypes": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Object type name (snake_case)"
+ },
+ "label": {
+ "type": "string",
+ "description": "Display label"
+ },
+ "apiName": {
+ "type": "string",
+ "description": "API name in external system"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable sync for this object"
+ },
+ "supportsCreate": {
+ "type": "boolean",
+ "default": true,
+ "description": "Supports record creation"
+ },
+ "supportsUpdate": {
+ "type": "boolean",
+ "default": true,
+ "description": "Supports record updates"
+ },
+ "supportsDelete": {
+ "type": "boolean",
+ "default": true,
+ "description": "Supports record deletion"
+ },
+ "fieldMappings": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sourceField": {
+ "type": "string",
+ "description": "Field name in external system"
+ },
+ "targetField": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Field name in ObjectStack (snake_case)"
+ },
+ "dataType": {
+ "type": "string",
+ "enum": [
+ "string",
+ "number",
+ "boolean",
+ "date",
+ "datetime",
+ "json",
+ "array"
+ ],
+ "description": "Target data type"
+ },
+ "required": {
+ "type": "boolean",
+ "default": false,
+ "description": "Field is required"
+ },
+ "defaultValue": {
+ "description": "Default value"
+ },
+ "transform": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "uppercase",
+ "lowercase",
+ "trim",
+ "date_format",
+ "number_format",
+ "custom"
+ ],
+ "description": "Transformation type"
+ },
+ "params": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Transformation parameters"
+ },
+ "function": {
+ "type": "string",
+ "description": "Custom JavaScript function for transformation"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "description": "Field transformation"
+ },
+ "syncMode": {
+ "type": "string",
+ "enum": [
+ "read_only",
+ "write_only",
+ "bidirectional"
+ ],
+ "default": "bidirectional",
+ "description": "Sync mode"
+ }
+ },
+ "required": [
+ "sourceField",
+ "targetField"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Object-specific field mappings"
+ }
+ },
+ "required": [
+ "name",
+ "label",
+ "apiName"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Syncable object types"
+ },
+ "oauthSettings": {
+ "type": "object",
+ "properties": {
+ "scopes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Required OAuth scopes"
+ },
+ "refreshTokenUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "Token refresh endpoint"
+ },
+ "revokeTokenUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "Token revocation endpoint"
+ },
+ "autoRefresh": {
+ "type": "boolean",
+ "default": true,
+ "description": "Automatically refresh expired tokens"
+ }
+ },
+ "required": [
+ "scopes"
+ ],
+ "additionalProperties": false,
+ "description": "OAuth-specific configuration"
+ },
+ "paginationConfig": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "cursor",
+ "offset",
+ "page"
+ ],
+ "default": "cursor",
+ "description": "Pagination type"
+ },
+ "defaultPageSize": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 1000,
+ "default": 100,
+ "description": "Default page size"
+ },
+ "maxPageSize": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 10000,
+ "default": 1000,
+ "description": "Maximum page size"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Pagination configuration"
+ },
+ "sandboxConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Use sandbox environment"
+ },
+ "baseUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "Sandbox API base URL"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Sandbox environment configuration"
+ },
+ "customHeaders": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Custom HTTP headers for all requests"
+ }
+ },
+ "required": [
+ "name",
+ "label",
+ "type",
+ "authentication",
+ "provider",
+ "baseUrl",
+ "objectTypes"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/SaasObjectType.json b/packages/spec/json-schema/integration/SaasObjectType.json
new file mode 100644
index 000000000..def5803c5
--- /dev/null
+++ b/packages/spec/json-schema/integration/SaasObjectType.json
@@ -0,0 +1,135 @@
+{
+ "$ref": "#/definitions/SaasObjectType",
+ "definitions": {
+ "SaasObjectType": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Object type name (snake_case)"
+ },
+ "label": {
+ "type": "string",
+ "description": "Display label"
+ },
+ "apiName": {
+ "type": "string",
+ "description": "API name in external system"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable sync for this object"
+ },
+ "supportsCreate": {
+ "type": "boolean",
+ "default": true,
+ "description": "Supports record creation"
+ },
+ "supportsUpdate": {
+ "type": "boolean",
+ "default": true,
+ "description": "Supports record updates"
+ },
+ "supportsDelete": {
+ "type": "boolean",
+ "default": true,
+ "description": "Supports record deletion"
+ },
+ "fieldMappings": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sourceField": {
+ "type": "string",
+ "description": "Field name in external system"
+ },
+ "targetField": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Field name in ObjectStack (snake_case)"
+ },
+ "dataType": {
+ "type": "string",
+ "enum": [
+ "string",
+ "number",
+ "boolean",
+ "date",
+ "datetime",
+ "json",
+ "array"
+ ],
+ "description": "Target data type"
+ },
+ "required": {
+ "type": "boolean",
+ "default": false,
+ "description": "Field is required"
+ },
+ "defaultValue": {
+ "description": "Default value"
+ },
+ "transform": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "uppercase",
+ "lowercase",
+ "trim",
+ "date_format",
+ "number_format",
+ "custom"
+ ],
+ "description": "Transformation type"
+ },
+ "params": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Transformation parameters"
+ },
+ "function": {
+ "type": "string",
+ "description": "Custom JavaScript function for transformation"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "description": "Field transformation"
+ },
+ "syncMode": {
+ "type": "string",
+ "enum": [
+ "read_only",
+ "write_only",
+ "bidirectional"
+ ],
+ "default": "bidirectional",
+ "description": "Sync mode"
+ }
+ },
+ "required": [
+ "sourceField",
+ "targetField"
+ ],
+ "additionalProperties": false
+ },
+ "description": "Object-specific field mappings"
+ }
+ },
+ "required": [
+ "name",
+ "label",
+ "apiName"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/SaasProvider.json b/packages/spec/json-schema/integration/SaasProvider.json
new file mode 100644
index 000000000..d73280ee2
--- /dev/null
+++ b/packages/spec/json-schema/integration/SaasProvider.json
@@ -0,0 +1,24 @@
+{
+ "$ref": "#/definitions/SaasProvider",
+ "definitions": {
+ "SaasProvider": {
+ "type": "string",
+ "enum": [
+ "salesforce",
+ "hubspot",
+ "stripe",
+ "shopify",
+ "zendesk",
+ "intercom",
+ "mailchimp",
+ "slack",
+ "microsoft_dynamics",
+ "servicenow",
+ "netsuite",
+ "custom"
+ ],
+ "description": "SaaS provider type"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/SamlAuth.json b/packages/spec/json-schema/integration/SamlAuth.json
new file mode 100644
index 000000000..8994c177b
--- /dev/null
+++ b/packages/spec/json-schema/integration/SamlAuth.json
@@ -0,0 +1,64 @@
+{
+ "$ref": "#/definitions/SamlAuth",
+ "definitions": {
+ "SamlAuth": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "saml",
+ "description": "Authentication type"
+ },
+ "entryPoint": {
+ "type": "string",
+ "format": "uri",
+ "description": "SAML IdP entry point URL"
+ },
+ "issuer": {
+ "type": "string",
+ "description": "SAML service provider issuer"
+ },
+ "certificate": {
+ "type": "string",
+ "description": "SAML IdP certificate (X.509)"
+ },
+ "privateKey": {
+ "type": "string",
+ "description": "SAML service provider private key"
+ },
+ "callbackUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "SAML assertion consumer service URL"
+ },
+ "signatureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "sha1",
+ "sha256",
+ "sha512"
+ ],
+ "default": "sha256",
+ "description": "SAML signature algorithm"
+ },
+ "wantAssertionsSigned": {
+ "type": "boolean",
+ "default": true,
+ "description": "Require signed SAML assertions"
+ },
+ "identifierFormat": {
+ "type": "string",
+ "description": "SAML NameID format"
+ }
+ },
+ "required": [
+ "type",
+ "entryPoint",
+ "issuer",
+ "certificate"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/SslConfig.json b/packages/spec/json-schema/integration/SslConfig.json
new file mode 100644
index 000000000..27688e971
--- /dev/null
+++ b/packages/spec/json-schema/integration/SslConfig.json
@@ -0,0 +1,34 @@
+{
+ "$ref": "#/definitions/SslConfig",
+ "definitions": {
+ "SslConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable SSL/TLS"
+ },
+ "rejectUnauthorized": {
+ "type": "boolean",
+ "default": true,
+ "description": "Reject unauthorized certificates"
+ },
+ "ca": {
+ "type": "string",
+ "description": "Certificate Authority certificate"
+ },
+ "cert": {
+ "type": "string",
+ "description": "Client certificate"
+ },
+ "key": {
+ "type": "string",
+ "description": "Client private key"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/StorageBucket.json b/packages/spec/json-schema/integration/StorageBucket.json
new file mode 100644
index 000000000..a42780be9
--- /dev/null
+++ b/packages/spec/json-schema/integration/StorageBucket.json
@@ -0,0 +1,99 @@
+{
+ "$ref": "#/definitions/StorageBucket",
+ "definitions": {
+ "StorageBucket": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Bucket identifier in ObjectStack (snake_case)"
+ },
+ "label": {
+ "type": "string",
+ "description": "Display label"
+ },
+ "bucketName": {
+ "type": "string",
+ "description": "Actual bucket/container name in storage system"
+ },
+ "region": {
+ "type": "string",
+ "description": "Storage region"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable sync for this bucket"
+ },
+ "prefix": {
+ "type": "string",
+ "description": "Prefix/path within bucket"
+ },
+ "accessPattern": {
+ "type": "string",
+ "enum": [
+ "public_read",
+ "private",
+ "authenticated_read",
+ "bucket_owner_read",
+ "bucket_owner_full"
+ ],
+ "description": "Access pattern"
+ },
+ "fileFilters": {
+ "type": "object",
+ "properties": {
+ "includePatterns": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "File patterns to include (glob)"
+ },
+ "excludePatterns": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "File patterns to exclude (glob)"
+ },
+ "minFileSize": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Minimum file size in bytes"
+ },
+ "maxFileSize": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Maximum file size in bytes"
+ },
+ "allowedExtensions": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Allowed file extensions"
+ },
+ "blockedExtensions": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Blocked file extensions"
+ }
+ },
+ "additionalProperties": false,
+ "description": "File filter configuration"
+ }
+ },
+ "required": [
+ "name",
+ "label",
+ "bucketName"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/SyncStrategy.json b/packages/spec/json-schema/integration/SyncStrategy.json
new file mode 100644
index 000000000..f48df7c84
--- /dev/null
+++ b/packages/spec/json-schema/integration/SyncStrategy.json
@@ -0,0 +1,16 @@
+{
+ "$ref": "#/definitions/SyncStrategy",
+ "definitions": {
+ "SyncStrategy": {
+ "type": "string",
+ "enum": [
+ "full",
+ "incremental",
+ "upsert",
+ "append_only"
+ ],
+ "description": "Synchronization strategy"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/TopicQueue.json b/packages/spec/json-schema/integration/TopicQueue.json
new file mode 100644
index 000000000..0860da236
--- /dev/null
+++ b/packages/spec/json-schema/integration/TopicQueue.json
@@ -0,0 +1,252 @@
+{
+ "$ref": "#/definitions/TopicQueue",
+ "definitions": {
+ "TopicQueue": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "pattern": "^[a-z_][a-z0-9_]*$",
+ "description": "Topic/queue identifier in ObjectStack (snake_case)"
+ },
+ "label": {
+ "type": "string",
+ "description": "Display label"
+ },
+ "topicName": {
+ "type": "string",
+ "description": "Actual topic/queue name in message queue system"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable sync for this topic/queue"
+ },
+ "mode": {
+ "type": "string",
+ "enum": [
+ "consumer",
+ "producer",
+ "both"
+ ],
+ "default": "both",
+ "description": "Consumer, producer, or both"
+ },
+ "messageFormat": {
+ "type": "string",
+ "enum": [
+ "json",
+ "xml",
+ "protobuf",
+ "avro",
+ "text",
+ "binary"
+ ],
+ "description": "Message format/serialization",
+ "default": "json"
+ },
+ "partitions": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Number of partitions (for Kafka)"
+ },
+ "replicationFactor": {
+ "type": "number",
+ "minimum": 1,
+ "description": "Replication factor (for Kafka)"
+ },
+ "consumerConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable consumer"
+ },
+ "consumerGroup": {
+ "type": "string",
+ "description": "Consumer group ID"
+ },
+ "concurrency": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 100,
+ "default": 1,
+ "description": "Number of concurrent consumers"
+ },
+ "prefetchCount": {
+ "type": "number",
+ "minimum": 1,
+ "maximum": 1000,
+ "default": 10,
+ "description": "Prefetch count"
+ },
+ "ackMode": {
+ "type": "string",
+ "enum": [
+ "auto",
+ "manual",
+ "client"
+ ],
+ "description": "Message acknowledgment mode",
+ "default": "manual"
+ },
+ "autoCommit": {
+ "type": "boolean",
+ "default": false,
+ "description": "Auto-commit offsets"
+ },
+ "autoCommitIntervalMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 5000,
+ "description": "Auto-commit interval in ms"
+ },
+ "sessionTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "default": 30000,
+ "description": "Session timeout in ms"
+ },
+ "rebalanceTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "description": "Rebalance timeout in ms"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Consumer-specific configuration"
+ },
+ "producerConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable producer"
+ },
+ "acks": {
+ "type": "string",
+ "enum": [
+ "0",
+ "1",
+ "all"
+ ],
+ "default": "all",
+ "description": "Acknowledgment level"
+ },
+ "compressionType": {
+ "type": "string",
+ "enum": [
+ "none",
+ "gzip",
+ "snappy",
+ "lz4",
+ "zstd"
+ ],
+ "default": "none",
+ "description": "Compression type"
+ },
+ "batchSize": {
+ "type": "number",
+ "minimum": 1,
+ "default": 16384,
+ "description": "Batch size in bytes"
+ },
+ "lingerMs": {
+ "type": "number",
+ "minimum": 0,
+ "default": 0,
+ "description": "Linger time in ms"
+ },
+ "maxInFlightRequests": {
+ "type": "number",
+ "minimum": 1,
+ "default": 5,
+ "description": "Max in-flight requests"
+ },
+ "idempotence": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable idempotent producer"
+ },
+ "transactional": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable transactional producer"
+ },
+ "transactionTimeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "description": "Transaction timeout in ms"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Producer-specific configuration"
+ },
+ "dlqConfig": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable DLQ"
+ },
+ "queueName": {
+ "type": "string",
+ "description": "Dead letter queue/topic name"
+ },
+ "maxRetries": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 100,
+ "default": 3,
+ "description": "Max retries before DLQ"
+ },
+ "retryDelayMs": {
+ "type": "number",
+ "minimum": 0,
+ "default": 60000,
+ "description": "Retry delay in ms"
+ }
+ },
+ "required": [
+ "queueName"
+ ],
+ "additionalProperties": false,
+ "description": "Dead letter queue configuration"
+ },
+ "routingKey": {
+ "type": "string",
+ "description": "Routing key pattern"
+ },
+ "messageFilter": {
+ "type": "object",
+ "properties": {
+ "headers": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Filter by message headers"
+ },
+ "attributes": {
+ "type": "object",
+ "additionalProperties": {},
+ "description": "Filter by message attributes"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Message filter criteria"
+ }
+ },
+ "required": [
+ "name",
+ "label",
+ "topicName"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/WebhookConfig.json b/packages/spec/json-schema/integration/WebhookConfig.json
new file mode 100644
index 000000000..cccf0050c
--- /dev/null
+++ b/packages/spec/json-schema/integration/WebhookConfig.json
@@ -0,0 +1,98 @@
+{
+ "$ref": "#/definitions/WebhookConfig",
+ "definitions": {
+ "WebhookConfig": {
+ "type": "object",
+ "properties": {
+ "url": {
+ "type": "string",
+ "format": "uri",
+ "description": "Webhook endpoint URL"
+ },
+ "events": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "record.created",
+ "record.updated",
+ "record.deleted",
+ "sync.started",
+ "sync.completed",
+ "sync.failed",
+ "auth.expired",
+ "rate_limit.exceeded"
+ ],
+ "description": "Webhook event type"
+ },
+ "description": "Events to subscribe to"
+ },
+ "secret": {
+ "type": "string",
+ "description": "Secret for HMAC signature"
+ },
+ "signatureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "hmac_sha256",
+ "hmac_sha512",
+ "none"
+ ],
+ "description": "Webhook signature algorithm",
+ "default": "hmac_sha256"
+ },
+ "headers": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "description": "Custom HTTP headers"
+ },
+ "retryConfig": {
+ "type": "object",
+ "properties": {
+ "maxAttempts": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 10,
+ "default": 3,
+ "description": "Maximum retry attempts"
+ },
+ "backoffMultiplier": {
+ "type": "number",
+ "minimum": 1,
+ "default": 2,
+ "description": "Exponential backoff multiplier"
+ },
+ "initialDelayMs": {
+ "type": "number",
+ "minimum": 100,
+ "default": 1000,
+ "description": "Initial retry delay in ms"
+ }
+ },
+ "additionalProperties": false,
+ "description": "Retry configuration"
+ },
+ "timeoutMs": {
+ "type": "number",
+ "minimum": 1000,
+ "maximum": 60000,
+ "default": 30000,
+ "description": "Request timeout in ms"
+ },
+ "enabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable webhook"
+ }
+ },
+ "required": [
+ "url",
+ "events"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/WebhookEvent.json b/packages/spec/json-schema/integration/WebhookEvent.json
new file mode 100644
index 000000000..6deaf08e6
--- /dev/null
+++ b/packages/spec/json-schema/integration/WebhookEvent.json
@@ -0,0 +1,20 @@
+{
+ "$ref": "#/definitions/WebhookEvent",
+ "definitions": {
+ "WebhookEvent": {
+ "type": "string",
+ "enum": [
+ "record.created",
+ "record.updated",
+ "record.deleted",
+ "sync.started",
+ "sync.completed",
+ "sync.failed",
+ "auth.expired",
+ "rate_limit.exceeded"
+ ],
+ "description": "Webhook event type"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/json-schema/integration/WebhookSignatureAlgorithm.json b/packages/spec/json-schema/integration/WebhookSignatureAlgorithm.json
new file mode 100644
index 000000000..6d6ba3efd
--- /dev/null
+++ b/packages/spec/json-schema/integration/WebhookSignatureAlgorithm.json
@@ -0,0 +1,15 @@
+{
+ "$ref": "#/definitions/WebhookSignatureAlgorithm",
+ "definitions": {
+ "WebhookSignatureAlgorithm": {
+ "type": "string",
+ "enum": [
+ "hmac_sha256",
+ "hmac_sha512",
+ "none"
+ ],
+ "description": "Webhook signature algorithm"
+ }
+ },
+ "$schema": "http://json-schema.org/draft-07/schema#"
+}
\ No newline at end of file
diff --git a/packages/spec/src/index.ts b/packages/spec/src/index.ts
index 4e8c8fc99..c478621a9 100644
--- a/packages/spec/src/index.ts
+++ b/packages/spec/src/index.ts
@@ -52,6 +52,7 @@ export * as Hub from './hub';
export * as AI from './ai';
export * as API from './api';
export * as Automation from './automation';
+export * as Integration from './integration';
export {
defineStack,
diff --git a/packages/spec/src/integration/connector.test.ts b/packages/spec/src/integration/connector.test.ts
new file mode 100644
index 000000000..9886a1320
--- /dev/null
+++ b/packages/spec/src/integration/connector.test.ts
@@ -0,0 +1,624 @@
+import { describe, it, expect } from 'vitest';
+import {
+ // Authentication Schemas
+ ApiKeyAuthSchema,
+ OAuth2AuthSchema,
+ JwtAuthSchema,
+ SamlAuthSchema,
+ BasicAuthSchema,
+ BearerTokenAuthSchema,
+ NoAuthSchema,
+ AuthenticationSchema,
+
+ // Field Mapping
+ FieldMappingSchema,
+ FieldTransformSchema,
+
+ // Data Sync
+ DataSyncConfigSchema,
+ SyncStrategySchema,
+ ConflictResolutionSchema,
+
+ // Webhook
+ WebhookConfigSchema,
+ WebhookEventSchema,
+
+ // Rate Limiting & Retry
+ RateLimitConfigSchema,
+ RetryConfigSchema,
+
+ // Base Connector
+ ConnectorSchema,
+ ConnectorTypeSchema,
+ ConnectorStatusSchema,
+
+ // Types
+ type Connector,
+ type ApiKeyAuth,
+ type OAuth2Auth,
+ type FieldMapping,
+ type DataSyncConfig,
+ type WebhookConfig,
+} from './connector.zod';
+
+// ============================================================================
+// Authentication Schemas Tests
+// ============================================================================
+
+describe('ApiKeyAuthSchema', () => {
+ it('should accept valid API key authentication', () => {
+ const auth: ApiKeyAuth = {
+ type: 'api_key',
+ apiKey: 'test-api-key-12345',
+ headerName: 'X-API-Key',
+ };
+
+ expect(() => ApiKeyAuthSchema.parse(auth)).not.toThrow();
+ });
+
+ it('should accept API key with query parameter', () => {
+ const auth = {
+ type: 'api_key',
+ apiKey: 'test-key',
+ headerName: 'X-Custom-Key',
+ paramName: 'api_key',
+ };
+
+ const parsed = ApiKeyAuthSchema.parse(auth);
+ expect(parsed.paramName).toBe('api_key');
+ });
+
+ it('should use default header name', () => {
+ const auth = {
+ type: 'api_key',
+ apiKey: 'test-key',
+ };
+
+ const parsed = ApiKeyAuthSchema.parse(auth);
+ expect(parsed.headerName).toBe('X-API-Key');
+ });
+});
+
+describe('OAuth2AuthSchema', () => {
+ it('should accept valid OAuth2 configuration', () => {
+ const auth: OAuth2Auth = {
+ type: 'oauth2',
+ clientId: 'client-id',
+ clientSecret: 'client-secret',
+ authorizationUrl: 'https://auth.example.com/authorize',
+ tokenUrl: 'https://auth.example.com/token',
+ grantType: 'authorization_code',
+ };
+
+ expect(() => OAuth2AuthSchema.parse(auth)).not.toThrow();
+ });
+
+ it('should accept OAuth2 with scopes and refresh token', () => {
+ const auth = {
+ type: 'oauth2',
+ clientId: 'client-id',
+ clientSecret: 'client-secret',
+ authorizationUrl: 'https://auth.example.com/authorize',
+ tokenUrl: 'https://auth.example.com/token',
+ scopes: ['read', 'write'],
+ refreshToken: 'refresh-token-xyz',
+ grantType: 'client_credentials',
+ };
+
+ const parsed = OAuth2AuthSchema.parse(auth);
+ expect(parsed.scopes).toHaveLength(2);
+ expect(parsed.refreshToken).toBe('refresh-token-xyz');
+ });
+
+ it('should use default grant type', () => {
+ const auth = {
+ type: 'oauth2',
+ clientId: 'client-id',
+ clientSecret: 'client-secret',
+ authorizationUrl: 'https://auth.example.com/authorize',
+ tokenUrl: 'https://auth.example.com/token',
+ };
+
+ const parsed = OAuth2AuthSchema.parse(auth);
+ expect(parsed.grantType).toBe('authorization_code');
+ });
+});
+
+describe('JwtAuthSchema', () => {
+ it('should accept JWT with token', () => {
+ const auth = {
+ type: 'jwt',
+ token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
+ algorithm: 'HS256',
+ };
+
+ expect(() => JwtAuthSchema.parse(auth)).not.toThrow();
+ });
+
+ it('should accept JWT with secret key and claims', () => {
+ const auth = {
+ type: 'jwt',
+ secretKey: 'my-secret-key',
+ algorithm: 'HS256',
+ issuer: 'objectstack',
+ audience: 'api',
+ expiresIn: 3600,
+ claims: { role: 'admin' },
+ };
+
+ const parsed = JwtAuthSchema.parse(auth);
+ expect(parsed.claims).toEqual({ role: 'admin' });
+ });
+
+ it('should use default algorithm and expiry', () => {
+ const auth = {
+ type: 'jwt',
+ token: 'test-token',
+ };
+
+ const parsed = JwtAuthSchema.parse(auth);
+ expect(parsed.algorithm).toBe('HS256');
+ expect(parsed.expiresIn).toBe(3600);
+ });
+});
+
+describe('SamlAuthSchema', () => {
+ it('should accept valid SAML configuration', () => {
+ const auth = {
+ type: 'saml',
+ entryPoint: 'https://idp.example.com/sso',
+ issuer: 'objectstack-sp',
+ certificate: '-----BEGIN CERTIFICATE-----...',
+ signatureAlgorithm: 'sha256',
+ };
+
+ expect(() => SamlAuthSchema.parse(auth)).not.toThrow();
+ });
+
+ it('should use default values', () => {
+ const auth = {
+ type: 'saml',
+ entryPoint: 'https://idp.example.com/sso',
+ issuer: 'objectstack-sp',
+ certificate: 'cert-content',
+ };
+
+ const parsed = SamlAuthSchema.parse(auth);
+ expect(parsed.signatureAlgorithm).toBe('sha256');
+ expect(parsed.wantAssertionsSigned).toBe(true);
+ });
+});
+
+describe('AuthenticationSchema', () => {
+ it('should accept all authentication types via discriminated union', () => {
+ const apiKeyAuth = { type: 'api_key', apiKey: 'key' };
+ const oauth2Auth = {
+ type: 'oauth2',
+ clientId: 'id',
+ clientSecret: 'secret',
+ authorizationUrl: 'https://auth.example.com/authorize',
+ tokenUrl: 'https://auth.example.com/token',
+ };
+ const basicAuth = { type: 'basic', username: 'user', password: 'pass' };
+ const noAuth = { type: 'none' };
+
+ expect(() => AuthenticationSchema.parse(apiKeyAuth)).not.toThrow();
+ expect(() => AuthenticationSchema.parse(oauth2Auth)).not.toThrow();
+ expect(() => AuthenticationSchema.parse(basicAuth)).not.toThrow();
+ expect(() => AuthenticationSchema.parse(noAuth)).not.toThrow();
+ });
+});
+
+// ============================================================================
+// Field Mapping Tests
+// ============================================================================
+
+describe('FieldMappingSchema', () => {
+ it('should accept valid field mapping', () => {
+ const mapping: FieldMapping = {
+ sourceField: 'firstName',
+ targetField: 'first_name',
+ dataType: 'string',
+ syncMode: 'bidirectional',
+ };
+
+ expect(() => FieldMappingSchema.parse(mapping)).not.toThrow();
+ });
+
+ it('should validate target field snake_case format', () => {
+ expect(() => FieldMappingSchema.parse({
+ sourceField: 'field',
+ targetField: 'valid_field_name',
+ })).not.toThrow();
+
+ expect(() => FieldMappingSchema.parse({
+ sourceField: 'field',
+ targetField: 'InvalidField',
+ })).toThrow();
+ });
+
+ it('should accept field with transformation', () => {
+ const mapping = {
+ sourceField: 'name',
+ targetField: 'full_name',
+ transform: {
+ type: 'uppercase',
+ },
+ };
+
+ const parsed = FieldMappingSchema.parse(mapping);
+ expect(parsed.transform?.type).toBe('uppercase');
+ });
+
+ it('should use default values', () => {
+ const mapping = {
+ sourceField: 'field1',
+ targetField: 'field_1',
+ };
+
+ const parsed = FieldMappingSchema.parse(mapping);
+ expect(parsed.required).toBe(false);
+ expect(parsed.syncMode).toBe('bidirectional');
+ });
+});
+
+// ============================================================================
+// Data Sync Configuration Tests
+// ============================================================================
+
+describe('DataSyncConfigSchema', () => {
+ it('should accept valid sync configuration', () => {
+ const config: DataSyncConfig = {
+ strategy: 'incremental',
+ direction: 'bidirectional',
+ schedule: '0 */6 * * *',
+ realtimeSync: true,
+ conflictResolution: 'latest_wins',
+ batchSize: 1000,
+ deleteMode: 'soft_delete',
+ };
+
+ expect(() => DataSyncConfigSchema.parse(config)).not.toThrow();
+ });
+
+ it('should use default values', () => {
+ const config = {};
+
+ const parsed = DataSyncConfigSchema.parse(config);
+ expect(parsed.strategy).toBe('incremental');
+ expect(parsed.direction).toBe('import');
+ expect(parsed.realtimeSync).toBe(false);
+ expect(parsed.conflictResolution).toBe('latest_wins');
+ expect(parsed.batchSize).toBe(1000);
+ expect(parsed.deleteMode).toBe('soft_delete');
+ });
+
+ it('should validate batch size range', () => {
+ expect(() => DataSyncConfigSchema.parse({ batchSize: 0 })).toThrow();
+ expect(() => DataSyncConfigSchema.parse({ batchSize: 10001 })).toThrow();
+ expect(() => DataSyncConfigSchema.parse({ batchSize: 500 })).not.toThrow();
+ });
+});
+
+// ============================================================================
+// Webhook Configuration Tests
+// ============================================================================
+
+describe('WebhookConfigSchema', () => {
+ it('should accept valid webhook configuration', () => {
+ const webhook: WebhookConfig = {
+ url: 'https://api.example.com/webhooks',
+ events: ['record.created', 'record.updated'],
+ secret: 'webhook-secret',
+ signatureAlgorithm: 'hmac_sha256',
+ enabled: true,
+ };
+
+ expect(() => WebhookConfigSchema.parse(webhook)).not.toThrow();
+ });
+
+ it('should accept webhook with retry configuration', () => {
+ const webhook = {
+ url: 'https://api.example.com/webhooks',
+ events: ['sync.completed'],
+ retryConfig: {
+ maxAttempts: 3,
+ backoffMultiplier: 2,
+ initialDelayMs: 1000,
+ },
+ };
+
+ const parsed = WebhookConfigSchema.parse(webhook);
+ expect(parsed.retryConfig?.maxAttempts).toBe(3);
+ });
+
+ it('should use default values', () => {
+ const webhook = {
+ url: 'https://api.example.com/webhooks',
+ events: ['record.created'],
+ };
+
+ const parsed = WebhookConfigSchema.parse(webhook);
+ expect(parsed.signatureAlgorithm).toBe('hmac_sha256');
+ expect(parsed.timeoutMs).toBe(30000);
+ expect(parsed.enabled).toBe(true);
+ });
+});
+
+// ============================================================================
+// Rate Limiting & Retry Tests
+// ============================================================================
+
+describe('RateLimitConfigSchema', () => {
+ it('should accept valid rate limit configuration', () => {
+ const config = {
+ strategy: 'token_bucket',
+ maxRequests: 100,
+ windowSeconds: 60,
+ burstCapacity: 150,
+ respectUpstreamLimits: true,
+ };
+
+ expect(() => RateLimitConfigSchema.parse(config)).not.toThrow();
+ });
+
+ it('should use default values', () => {
+ const config = {
+ maxRequests: 100,
+ windowSeconds: 60,
+ };
+
+ const parsed = RateLimitConfigSchema.parse(config);
+ expect(parsed.strategy).toBe('token_bucket');
+ expect(parsed.respectUpstreamLimits).toBe(true);
+ });
+});
+
+describe('RetryConfigSchema', () => {
+ it('should accept valid retry configuration', () => {
+ const config = {
+ strategy: 'exponential_backoff',
+ maxAttempts: 3,
+ initialDelayMs: 1000,
+ maxDelayMs: 60000,
+ backoffMultiplier: 2,
+ retryableStatusCodes: [429, 500, 502, 503],
+ retryOnNetworkError: true,
+ jitter: true,
+ };
+
+ expect(() => RetryConfigSchema.parse(config)).not.toThrow();
+ });
+
+ it('should use default values', () => {
+ const config = {};
+
+ const parsed = RetryConfigSchema.parse(config);
+ expect(parsed.strategy).toBe('exponential_backoff');
+ expect(parsed.maxAttempts).toBe(3);
+ expect(parsed.initialDelayMs).toBe(1000);
+ expect(parsed.maxDelayMs).toBe(60000);
+ expect(parsed.backoffMultiplier).toBe(2);
+ expect(parsed.retryableStatusCodes).toEqual([408, 429, 500, 502, 503, 504]);
+ expect(parsed.retryOnNetworkError).toBe(true);
+ expect(parsed.jitter).toBe(true);
+ });
+
+ it('should validate max attempts range', () => {
+ expect(() => RetryConfigSchema.parse({ maxAttempts: -1 })).toThrow();
+ expect(() => RetryConfigSchema.parse({ maxAttempts: 11 })).toThrow();
+ expect(() => RetryConfigSchema.parse({ maxAttempts: 5 })).not.toThrow();
+ });
+});
+
+// ============================================================================
+// Base Connector Tests
+// ============================================================================
+
+describe('ConnectorSchema', () => {
+ it('should accept valid minimal connector', () => {
+ const connector: Connector = {
+ name: 'test_connector',
+ label: 'Test Connector',
+ type: 'api',
+ authentication: {
+ type: 'api_key',
+ apiKey: 'test-key',
+ },
+ status: 'inactive',
+ enabled: true,
+ };
+
+ expect(() => ConnectorSchema.parse(connector)).not.toThrow();
+ });
+
+ it('should validate connector name format (snake_case)', () => {
+ expect(() => ConnectorSchema.parse({
+ name: 'valid_connector_name',
+ label: 'Test',
+ type: 'saas',
+ authentication: { type: 'none' },
+ })).not.toThrow();
+
+ expect(() => ConnectorSchema.parse({
+ name: 'InvalidConnector',
+ label: 'Test',
+ type: 'saas',
+ authentication: { type: 'none' },
+ })).toThrow();
+ });
+
+ it('should accept connector with all fields', () => {
+ const connector = {
+ name: 'full_connector',
+ label: 'Full Connector',
+ type: 'saas',
+ description: 'A comprehensive connector',
+ icon: 'cloud',
+ authentication: {
+ type: 'oauth2',
+ clientId: 'client',
+ clientSecret: 'secret',
+ authorizationUrl: 'https://auth.example.com/authorize',
+ tokenUrl: 'https://auth.example.com/token',
+ },
+ syncConfig: {
+ strategy: 'incremental',
+ direction: 'bidirectional',
+ },
+ fieldMappings: [
+ {
+ sourceField: 'id',
+ targetField: 'external_id',
+ },
+ ],
+ webhooks: [
+ {
+ url: 'https://api.example.com/webhook',
+ events: ['record.created'],
+ },
+ ],
+ rateLimitConfig: {
+ maxRequests: 100,
+ windowSeconds: 60,
+ },
+ retryConfig: {
+ maxAttempts: 3,
+ },
+ status: 'active',
+ enabled: true,
+ metadata: {
+ version: '1.0',
+ },
+ };
+
+ const parsed = ConnectorSchema.parse(connector);
+ expect(parsed.description).toBe('A comprehensive connector');
+ expect(parsed.fieldMappings).toHaveLength(1);
+ expect(parsed.webhooks).toHaveLength(1);
+ });
+
+ it('should use default values', () => {
+ const connector = {
+ name: 'default_connector',
+ label: 'Default Connector',
+ type: 'database',
+ authentication: { type: 'none' },
+ };
+
+ const parsed = ConnectorSchema.parse(connector);
+ expect(parsed.connectionTimeoutMs).toBe(30000);
+ expect(parsed.requestTimeoutMs).toBe(30000);
+ expect(parsed.status).toBe('inactive');
+ expect(parsed.enabled).toBe(true);
+ });
+
+ it('should validate timeout ranges', () => {
+ expect(() => ConnectorSchema.parse({
+ name: 'test',
+ label: 'Test',
+ type: 'api',
+ authentication: { type: 'none' },
+ connectionTimeoutMs: 500,
+ })).toThrow();
+
+ expect(() => ConnectorSchema.parse({
+ name: 'test',
+ label: 'Test',
+ type: 'api',
+ authentication: { type: 'none' },
+ connectionTimeoutMs: 350000,
+ })).toThrow();
+
+ expect(() => ConnectorSchema.parse({
+ name: 'test',
+ label: 'Test',
+ type: 'api',
+ authentication: { type: 'none' },
+ connectionTimeoutMs: 5000,
+ })).not.toThrow();
+ });
+});
+
+describe('ConnectorTypeSchema', () => {
+ it('should accept all valid connector types', () => {
+ const types = ['saas', 'database', 'file_storage', 'message_queue', 'api', 'custom'];
+
+ types.forEach(type => {
+ expect(() => ConnectorTypeSchema.parse(type)).not.toThrow();
+ });
+ });
+
+ it('should reject invalid connector types', () => {
+ expect(() => ConnectorTypeSchema.parse('invalid_type')).toThrow();
+ });
+});
+
+describe('ConnectorStatusSchema', () => {
+ it('should accept all valid statuses', () => {
+ const statuses = ['active', 'inactive', 'error', 'configuring'];
+
+ statuses.forEach(status => {
+ expect(() => ConnectorStatusSchema.parse(status)).not.toThrow();
+ });
+ });
+});
+
+// ============================================================================
+// Integration Tests
+// ============================================================================
+
+describe('Connector Integration', () => {
+ it('should create a complete SaaS connector', () => {
+ const connector = {
+ name: 'salesforce_prod',
+ label: 'Salesforce Production',
+ type: 'saas',
+ description: 'Production Salesforce connector',
+ authentication: {
+ type: 'oauth2',
+ clientId: '${SF_CLIENT_ID}',
+ clientSecret: '${SF_CLIENT_SECRET}',
+ authorizationUrl: 'https://login.salesforce.com/services/oauth2/authorize',
+ tokenUrl: 'https://login.salesforce.com/services/oauth2/token',
+ scopes: ['api', 'refresh_token'],
+ },
+ syncConfig: {
+ strategy: 'incremental',
+ direction: 'bidirectional',
+ schedule: '0 */6 * * *',
+ realtimeSync: true,
+ batchSize: 200,
+ },
+ fieldMappings: [
+ {
+ sourceField: 'FirstName',
+ targetField: 'first_name',
+ dataType: 'string',
+ required: true,
+ },
+ {
+ sourceField: 'LastName',
+ targetField: 'last_name',
+ dataType: 'string',
+ required: true,
+ },
+ ],
+ rateLimitConfig: {
+ strategy: 'token_bucket',
+ maxRequests: 100,
+ windowSeconds: 20,
+ },
+ retryConfig: {
+ strategy: 'exponential_backoff',
+ maxAttempts: 3,
+ },
+ status: 'active',
+ enabled: true,
+ };
+
+ const parsed = ConnectorSchema.parse(connector);
+ expect(parsed.type).toBe('saas');
+ expect(parsed.fieldMappings).toHaveLength(2);
+ });
+});
diff --git a/packages/spec/src/integration/connector.zod.ts b/packages/spec/src/integration/connector.zod.ts
new file mode 100644
index 000000000..65bdb7396
--- /dev/null
+++ b/packages/spec/src/integration/connector.zod.ts
@@ -0,0 +1,645 @@
+import { z } from 'zod';
+
+/**
+ * Connector Protocol
+ *
+ * Defines the standard connector specification for external system integration.
+ * Connectors enable ObjectStack to sync data with SaaS apps, databases, file storage,
+ * and message queues through a unified protocol.
+ *
+ * This protocol supports multiple authentication strategies, bidirectional sync,
+ * field mapping, webhooks, and comprehensive rate limiting.
+ */
+
+// ============================================================================
+// Authentication Schemas
+// ============================================================================
+
+/**
+ * API Key Authentication Schema
+ */
+export const ApiKeyAuthSchema = z.object({
+ type: z.literal('api_key').describe('Authentication type'),
+ apiKey: z.string().describe('API key (typically from ENV)'),
+ headerName: z.string().default('X-API-Key').describe('HTTP header name for API key'),
+ paramName: z.string().optional().describe('Query parameter name (alternative to header)'),
+});
+
+export type ApiKeyAuth = z.infer;
+
+/**
+ * OAuth2 Authentication Schema
+ */
+export const OAuth2AuthSchema = z.object({
+ type: z.literal('oauth2').describe('Authentication type'),
+
+ clientId: z.string().describe('OAuth2 client ID'),
+ clientSecret: z.string().describe('OAuth2 client secret (typically from ENV)'),
+
+ authorizationUrl: z.string().url().describe('OAuth2 authorization endpoint'),
+ tokenUrl: z.string().url().describe('OAuth2 token endpoint'),
+
+ scopes: z.array(z.string()).optional().describe('Requested OAuth2 scopes'),
+
+ redirectUri: z.string().url().optional().describe('OAuth2 callback URL'),
+
+ grantType: z.enum([
+ 'authorization_code',
+ 'client_credentials',
+ 'password',
+ 'refresh_token',
+ ]).default('authorization_code').describe('OAuth2 grant type'),
+
+ refreshToken: z.string().optional().describe('Refresh token for token renewal'),
+
+ tokenExpiry: z.number().optional().describe('Token expiry timestamp'),
+});
+
+export type OAuth2Auth = z.infer;
+
+/**
+ * JWT Authentication Schema
+ */
+export const JwtAuthSchema = z.object({
+ type: z.literal('jwt').describe('Authentication type'),
+
+ token: z.string().optional().describe('Pre-generated JWT token'),
+
+ secretKey: z.string().optional().describe('Secret key for JWT signing'),
+
+ algorithm: z.enum([
+ 'HS256', 'HS384', 'HS512',
+ 'RS256', 'RS384', 'RS512',
+ 'ES256', 'ES384', 'ES512',
+ ]).default('HS256').describe('JWT signing algorithm'),
+
+ issuer: z.string().optional().describe('JWT issuer claim'),
+
+ audience: z.string().optional().describe('JWT audience claim'),
+
+ subject: z.string().optional().describe('JWT subject claim'),
+
+ expiresIn: z.number().default(3600).describe('Token expiry in seconds'),
+
+ claims: z.record(z.any()).optional().describe('Additional JWT claims'),
+});
+
+export type JwtAuth = z.infer;
+
+/**
+ * SAML Authentication Schema
+ */
+export const SamlAuthSchema = z.object({
+ type: z.literal('saml').describe('Authentication type'),
+
+ entryPoint: z.string().url().describe('SAML IdP entry point URL'),
+
+ issuer: z.string().describe('SAML service provider issuer'),
+
+ certificate: z.string().describe('SAML IdP certificate (X.509)'),
+
+ privateKey: z.string().optional().describe('SAML service provider private key'),
+
+ callbackUrl: z.string().url().optional().describe('SAML assertion consumer service URL'),
+
+ signatureAlgorithm: z.enum([
+ 'sha1',
+ 'sha256',
+ 'sha512',
+ ]).default('sha256').describe('SAML signature algorithm'),
+
+ wantAssertionsSigned: z.boolean().default(true).describe('Require signed SAML assertions'),
+
+ identifierFormat: z.string().optional().describe('SAML NameID format'),
+});
+
+export type SamlAuth = z.infer;
+
+/**
+ * Basic Authentication Schema
+ */
+export const BasicAuthSchema = z.object({
+ type: z.literal('basic').describe('Authentication type'),
+ username: z.string().describe('Username'),
+ password: z.string().describe('Password (typically from ENV)'),
+});
+
+export type BasicAuth = z.infer;
+
+/**
+ * Bearer Token Authentication Schema
+ */
+export const BearerTokenAuthSchema = z.object({
+ type: z.literal('bearer').describe('Authentication type'),
+ token: z.string().describe('Bearer token'),
+});
+
+export type BearerTokenAuth = z.infer;
+
+/**
+ * No Authentication Schema
+ */
+export const NoAuthSchema = z.object({
+ type: z.literal('none').describe('No authentication required'),
+});
+
+export type NoAuth = z.infer;
+
+/**
+ * Unified Authentication Configuration
+ * Discriminated union of all authentication methods
+ */
+export const AuthenticationSchema = z.discriminatedUnion('type', [
+ ApiKeyAuthSchema,
+ OAuth2AuthSchema,
+ JwtAuthSchema,
+ SamlAuthSchema,
+ BasicAuthSchema,
+ BearerTokenAuthSchema,
+ NoAuthSchema,
+]);
+
+export type Authentication = z.infer;
+
+// ============================================================================
+// Field Mapping Schema
+// ============================================================================
+
+/**
+ * Field Transformation Function
+ */
+export const FieldTransformSchema = z.object({
+ type: z.enum([
+ 'uppercase',
+ 'lowercase',
+ 'trim',
+ 'date_format',
+ 'number_format',
+ 'custom',
+ ]).describe('Transformation type'),
+
+ params: z.record(z.any()).optional().describe('Transformation parameters'),
+
+ function: z.string().optional().describe('Custom JavaScript function for transformation'),
+});
+
+export type FieldTransform = z.infer;
+
+/**
+ * Field Mapping Configuration
+ * Maps fields between ObjectStack and external system
+ */
+export const FieldMappingSchema = z.object({
+ /**
+ * Source field name (in external system)
+ */
+ sourceField: z.string().describe('Field name in external system'),
+
+ /**
+ * Target field name (in ObjectStack)
+ */
+ targetField: z.string().regex(/^[a-z_][a-z0-9_]*$/).describe('Field name in ObjectStack (snake_case)'),
+
+ /**
+ * Data type mapping
+ */
+ dataType: z.enum([
+ 'string',
+ 'number',
+ 'boolean',
+ 'date',
+ 'datetime',
+ 'json',
+ 'array',
+ ]).optional().describe('Target data type'),
+
+ /**
+ * Is this field required?
+ */
+ required: z.boolean().default(false).describe('Field is required'),
+
+ /**
+ * Default value if source is empty
+ */
+ defaultValue: z.any().optional().describe('Default value'),
+
+ /**
+ * Field transformation rules
+ */
+ transform: FieldTransformSchema.optional().describe('Field transformation'),
+
+ /**
+ * Bidirectional sync mode
+ */
+ syncMode: z.enum([
+ 'read_only', // Only sync from external to ObjectStack
+ 'write_only', // Only sync from ObjectStack to external
+ 'bidirectional', // Sync both ways
+ ]).default('bidirectional').describe('Sync mode'),
+});
+
+export type FieldMapping = z.infer;
+
+// ============================================================================
+// Data Synchronization Configuration
+// ============================================================================
+
+/**
+ * Sync Strategy Schema
+ */
+export const SyncStrategySchema = z.enum([
+ 'full', // Full refresh (delete all and re-import)
+ 'incremental', // Only sync changes since last sync
+ 'upsert', // Insert new, update existing
+ 'append_only', // Only insert new records
+]).describe('Synchronization strategy');
+
+export type SyncStrategy = z.infer;
+
+/**
+ * Conflict Resolution Strategy
+ */
+export const ConflictResolutionSchema = z.enum([
+ 'source_wins', // External system data takes precedence
+ 'target_wins', // ObjectStack data takes precedence
+ 'latest_wins', // Most recently modified wins
+ 'manual', // Flag for manual resolution
+]).describe('Conflict resolution strategy');
+
+export type ConflictResolution = z.infer;
+
+/**
+ * Data Synchronization Configuration
+ */
+export const DataSyncConfigSchema = z.object({
+ /**
+ * Sync strategy
+ */
+ strategy: SyncStrategySchema.optional().default('incremental'),
+
+ /**
+ * Sync direction
+ */
+ direction: z.enum([
+ 'import', // External → ObjectStack
+ 'export', // ObjectStack → External
+ 'bidirectional', // Both ways
+ ]).optional().default('import').describe('Sync direction'),
+
+ /**
+ * Sync frequency (cron expression)
+ */
+ schedule: z.string().optional().describe('Cron expression for scheduled sync'),
+
+ /**
+ * Enable real-time sync via webhooks
+ */
+ realtimeSync: z.boolean().optional().default(false).describe('Enable real-time sync'),
+
+ /**
+ * Field to track last sync timestamp
+ */
+ timestampField: z.string().optional().describe('Field to track last modification time'),
+
+ /**
+ * Conflict resolution strategy
+ */
+ conflictResolution: ConflictResolutionSchema.optional().default('latest_wins'),
+
+ /**
+ * Batch size for bulk operations
+ */
+ batchSize: z.number().min(1).max(10000).optional().default(1000).describe('Records per batch'),
+
+ /**
+ * Delete handling
+ */
+ deleteMode: z.enum([
+ 'hard_delete', // Permanently delete
+ 'soft_delete', // Mark as deleted
+ 'ignore', // Don't sync deletions
+ ]).optional().default('soft_delete').describe('Delete handling mode'),
+
+ /**
+ * Filter criteria for selective sync
+ */
+ filters: z.record(z.any()).optional().describe('Filter criteria for selective sync'),
+});
+
+export type DataSyncConfig = z.infer;
+
+// ============================================================================
+// Webhook Configuration
+// ============================================================================
+
+/**
+ * Webhook Event Schema
+ */
+export const WebhookEventSchema = z.enum([
+ 'record.created',
+ 'record.updated',
+ 'record.deleted',
+ 'sync.started',
+ 'sync.completed',
+ 'sync.failed',
+ 'auth.expired',
+ 'rate_limit.exceeded',
+]).describe('Webhook event type');
+
+export type WebhookEvent = z.infer;
+
+/**
+ * Webhook Signature Algorithm
+ */
+export const WebhookSignatureAlgorithmSchema = z.enum([
+ 'hmac_sha256',
+ 'hmac_sha512',
+ 'none',
+]).describe('Webhook signature algorithm');
+
+export type WebhookSignatureAlgorithm = z.infer;
+
+/**
+ * Webhook Configuration Schema
+ */
+export const WebhookConfigSchema = z.object({
+ /**
+ * Webhook endpoint URL
+ */
+ url: z.string().url().describe('Webhook endpoint URL'),
+
+ /**
+ * Events to listen for
+ */
+ events: z.array(WebhookEventSchema).describe('Events to subscribe to'),
+
+ /**
+ * Webhook secret for signature verification
+ */
+ secret: z.string().optional().describe('Secret for HMAC signature'),
+
+ /**
+ * Signature algorithm
+ */
+ signatureAlgorithm: WebhookSignatureAlgorithmSchema.optional().default('hmac_sha256'),
+
+ /**
+ * Custom headers to include in webhook requests
+ */
+ headers: z.record(z.string()).optional().describe('Custom HTTP headers'),
+
+ /**
+ * Retry configuration for failed webhook deliveries
+ */
+ retryConfig: z.object({
+ maxAttempts: z.number().min(0).max(10).optional().default(3).describe('Maximum retry attempts'),
+ backoffMultiplier: z.number().min(1).optional().default(2).describe('Exponential backoff multiplier'),
+ initialDelayMs: z.number().min(100).optional().default(1000).describe('Initial retry delay in ms'),
+ }).optional().describe('Retry configuration'),
+
+ /**
+ * Timeout for webhook requests
+ */
+ timeoutMs: z.number().min(1000).max(60000).optional().default(30000).describe('Request timeout in ms'),
+
+ /**
+ * Enable webhook
+ */
+ enabled: z.boolean().optional().default(true).describe('Enable webhook'),
+});
+
+export type WebhookConfig = z.infer;
+
+// ============================================================================
+// Rate Limiting and Retry Configuration
+// ============================================================================
+
+/**
+ * Rate Limiting Strategy
+ */
+export const RateLimitStrategySchema = z.enum([
+ 'fixed_window', // Fixed time window
+ 'sliding_window', // Sliding time window
+ 'token_bucket', // Token bucket algorithm
+ 'leaky_bucket', // Leaky bucket algorithm
+]).describe('Rate limiting strategy');
+
+export type RateLimitStrategy = z.infer;
+
+/**
+ * Rate Limiting Configuration
+ */
+export const RateLimitConfigSchema = z.object({
+ /**
+ * Rate limiting strategy
+ */
+ strategy: RateLimitStrategySchema.optional().default('token_bucket'),
+
+ /**
+ * Maximum requests per window
+ */
+ maxRequests: z.number().min(1).describe('Maximum requests per window'),
+
+ /**
+ * Time window in seconds
+ */
+ windowSeconds: z.number().min(1).describe('Time window in seconds'),
+
+ /**
+ * Burst capacity (for token bucket)
+ */
+ burstCapacity: z.number().min(1).optional().describe('Burst capacity'),
+
+ /**
+ * Respect external system rate limits
+ */
+ respectUpstreamLimits: z.boolean().optional().default(true).describe('Respect external rate limit headers'),
+
+ /**
+ * Custom rate limit headers to check
+ */
+ rateLimitHeaders: z.object({
+ remaining: z.string().optional().default('X-RateLimit-Remaining').describe('Header for remaining requests'),
+ limit: z.string().optional().default('X-RateLimit-Limit').describe('Header for rate limit'),
+ reset: z.string().optional().default('X-RateLimit-Reset').describe('Header for reset time'),
+ }).optional().describe('Custom rate limit headers'),
+});
+
+export type RateLimitConfig = z.infer;
+
+/**
+ * Retry Strategy
+ */
+export const RetryStrategySchema = z.enum([
+ 'exponential_backoff',
+ 'linear_backoff',
+ 'fixed_delay',
+ 'no_retry',
+]).describe('Retry strategy');
+
+export type RetryStrategy = z.infer;
+
+/**
+ * Retry Configuration
+ */
+export const RetryConfigSchema = z.object({
+ /**
+ * Retry strategy
+ */
+ strategy: RetryStrategySchema.optional().default('exponential_backoff'),
+
+ /**
+ * Maximum retry attempts
+ */
+ maxAttempts: z.number().min(0).max(10).optional().default(3).describe('Maximum retry attempts'),
+
+ /**
+ * Initial delay in milliseconds
+ */
+ initialDelayMs: z.number().min(100).optional().default(1000).describe('Initial retry delay in ms'),
+
+ /**
+ * Maximum delay in milliseconds
+ */
+ maxDelayMs: z.number().min(1000).optional().default(60000).describe('Maximum retry delay in ms'),
+
+ /**
+ * Backoff multiplier (for exponential backoff)
+ */
+ backoffMultiplier: z.number().min(1).optional().default(2).describe('Exponential backoff multiplier'),
+
+ /**
+ * HTTP status codes to retry
+ */
+ retryableStatusCodes: z.array(z.number()).optional().default([408, 429, 500, 502, 503, 504]).describe('HTTP status codes to retry'),
+
+ /**
+ * Retry on network errors
+ */
+ retryOnNetworkError: z.boolean().optional().default(true).describe('Retry on network errors'),
+
+ /**
+ * Jitter to add randomness to retry delays
+ */
+ jitter: z.boolean().optional().default(true).describe('Add jitter to retry delays'),
+});
+
+export type RetryConfig = z.infer;
+
+// ============================================================================
+// Base Connector Schema
+// ============================================================================
+
+/**
+ * Connector Type
+ */
+export const ConnectorTypeSchema = z.enum([
+ 'saas', // SaaS application connector
+ 'database', // Database connector
+ 'file_storage', // File storage connector
+ 'message_queue', // Message queue connector
+ 'api', // Generic REST/GraphQL API
+ 'custom', // Custom connector
+]).describe('Connector type');
+
+export type ConnectorType = z.infer;
+
+/**
+ * Connector Status
+ */
+export const ConnectorStatusSchema = z.enum([
+ 'active', // Connector is active and syncing
+ 'inactive', // Connector is configured but disabled
+ 'error', // Connector has errors
+ 'configuring', // Connector is being set up
+]).describe('Connector status');
+
+export type ConnectorStatus = z.infer;
+
+/**
+ * Base Connector Schema
+ * Core connector configuration shared across all connector types
+ */
+export const ConnectorSchema = z.object({
+ /**
+ * Machine name (snake_case)
+ */
+ name: z.string().regex(/^[a-z_][a-z0-9_]*$/).describe('Unique connector identifier'),
+
+ /**
+ * Human-readable label
+ */
+ label: z.string().describe('Display label'),
+
+ /**
+ * Connector type
+ */
+ type: ConnectorTypeSchema.describe('Connector type'),
+
+ /**
+ * Description
+ */
+ description: z.string().optional().describe('Connector description'),
+
+ /**
+ * Icon identifier
+ */
+ icon: z.string().optional().describe('Icon identifier'),
+
+ /**
+ * Authentication configuration
+ */
+ authentication: AuthenticationSchema.describe('Authentication configuration'),
+
+ /**
+ * Data synchronization configuration
+ */
+ syncConfig: DataSyncConfigSchema.optional().describe('Data sync configuration'),
+
+ /**
+ * Field mappings
+ */
+ fieldMappings: z.array(FieldMappingSchema).optional().describe('Field mapping rules'),
+
+ /**
+ * Webhook configuration
+ */
+ webhooks: z.array(WebhookConfigSchema).optional().describe('Webhook configurations'),
+
+ /**
+ * Rate limiting configuration
+ */
+ rateLimitConfig: RateLimitConfigSchema.optional().describe('Rate limiting configuration'),
+
+ /**
+ * Retry configuration
+ */
+ retryConfig: RetryConfigSchema.optional().describe('Retry configuration'),
+
+ /**
+ * Connection timeout in milliseconds
+ */
+ connectionTimeoutMs: z.number().min(1000).max(300000).optional().default(30000).describe('Connection timeout in ms'),
+
+ /**
+ * Request timeout in milliseconds
+ */
+ requestTimeoutMs: z.number().min(1000).max(300000).optional().default(30000).describe('Request timeout in ms'),
+
+ /**
+ * Connector status
+ */
+ status: ConnectorStatusSchema.optional().default('inactive').describe('Connector status'),
+
+ /**
+ * Enable connector
+ */
+ enabled: z.boolean().optional().default(true).describe('Enable connector'),
+
+ /**
+ * Custom metadata
+ */
+ metadata: z.record(z.any()).optional().describe('Custom connector metadata'),
+});
+
+export type Connector = z.infer;
diff --git a/packages/spec/src/integration/connector/database.zod.ts b/packages/spec/src/integration/connector/database.zod.ts
new file mode 100644
index 000000000..ff12bfd39
--- /dev/null
+++ b/packages/spec/src/integration/connector/database.zod.ts
@@ -0,0 +1,341 @@
+import { z } from 'zod';
+import {
+ ConnectorSchema,
+ FieldMappingSchema,
+} from '../connector.zod';
+
+/**
+ * Database Connector Protocol Template
+ *
+ * Specialized connector for database systems (PostgreSQL, MySQL, SQL Server, etc.)
+ * Extends the base connector with database-specific features like schema discovery,
+ * CDC (Change Data Capture), and connection pooling.
+ */
+
+/**
+ * Database Provider Types
+ */
+export const DatabaseProviderSchema = z.enum([
+ 'postgresql',
+ 'mysql',
+ 'mariadb',
+ 'mssql',
+ 'oracle',
+ 'mongodb',
+ 'redis',
+ 'cassandra',
+ 'snowflake',
+ 'bigquery',
+ 'redshift',
+ 'custom',
+]).describe('Database provider type');
+
+export type DatabaseProvider = z.infer;
+
+/**
+ * Database Connection Pool Configuration
+ */
+export const DatabasePoolConfigSchema = z.object({
+ min: z.number().min(0).default(2).describe('Minimum connections in pool'),
+ max: z.number().min(1).default(10).describe('Maximum connections in pool'),
+ idleTimeoutMs: z.number().min(1000).default(30000).describe('Idle connection timeout in ms'),
+ connectionTimeoutMs: z.number().min(1000).default(10000).describe('Connection establishment timeout in ms'),
+ acquireTimeoutMs: z.number().min(1000).default(30000).describe('Connection acquisition timeout in ms'),
+ evictionRunIntervalMs: z.number().min(1000).default(30000).describe('Connection eviction check interval in ms'),
+ testOnBorrow: z.boolean().default(true).describe('Test connection before use'),
+});
+
+export type DatabasePoolConfig = z.infer;
+
+/**
+ * SSL/TLS Configuration
+ */
+export const SslConfigSchema = z.object({
+ enabled: z.boolean().default(false).describe('Enable SSL/TLS'),
+ rejectUnauthorized: z.boolean().default(true).describe('Reject unauthorized certificates'),
+ ca: z.string().optional().describe('Certificate Authority certificate'),
+ cert: z.string().optional().describe('Client certificate'),
+ key: z.string().optional().describe('Client private key'),
+});
+
+export type SslConfig = z.infer;
+
+/**
+ * Change Data Capture (CDC) Configuration
+ */
+export const CdcConfigSchema = z.object({
+ enabled: z.boolean().default(false).describe('Enable CDC'),
+
+ method: z.enum([
+ 'log_based', // Transaction log parsing (e.g., PostgreSQL logical replication)
+ 'trigger_based', // Database triggers for change tracking
+ 'query_based', // Timestamp-based queries
+ 'custom', // Custom CDC implementation
+ ]).describe('CDC method'),
+
+ slotName: z.string().optional().describe('Replication slot name (for log-based CDC)'),
+
+ publicationName: z.string().optional().describe('Publication name (for PostgreSQL)'),
+
+ startPosition: z.string().optional().describe('Starting position/LSN for CDC stream'),
+
+ batchSize: z.number().min(1).max(10000).default(1000).describe('CDC batch size'),
+
+ pollIntervalMs: z.number().min(100).default(1000).describe('CDC polling interval in ms'),
+});
+
+export type CdcConfig = z.infer;
+
+/**
+ * Database Table Configuration
+ */
+export const DatabaseTableSchema = z.object({
+ name: z.string().regex(/^[a-z_][a-z0-9_]*$/).describe('Table name in ObjectStack (snake_case)'),
+ label: z.string().describe('Display label'),
+ schema: z.string().optional().describe('Database schema name'),
+ tableName: z.string().describe('Actual table name in database'),
+ primaryKey: z.string().describe('Primary key column'),
+ enabled: z.boolean().default(true).describe('Enable sync for this table'),
+ fieldMappings: z.array(FieldMappingSchema).optional().describe('Table-specific field mappings'),
+ whereClause: z.string().optional().describe('SQL WHERE clause for filtering'),
+});
+
+export type DatabaseTable = z.infer;
+
+/**
+ * Database Connector Configuration Schema
+ */
+export const DatabaseConnectorSchema = ConnectorSchema.extend({
+ type: z.literal('database'),
+
+ /**
+ * Database provider
+ */
+ provider: DatabaseProviderSchema.describe('Database provider type'),
+
+ /**
+ * Connection configuration
+ */
+ connectionConfig: z.object({
+ host: z.string().describe('Database host'),
+ port: z.number().min(1).max(65535).describe('Database port'),
+ database: z.string().describe('Database name'),
+ username: z.string().describe('Database username'),
+ password: z.string().describe('Database password (typically from ENV)'),
+ options: z.record(z.any()).optional().describe('Driver-specific connection options'),
+ }).describe('Database connection configuration'),
+
+ /**
+ * Connection pool configuration
+ */
+ poolConfig: DatabasePoolConfigSchema.optional().describe('Connection pool configuration'),
+
+ /**
+ * SSL/TLS configuration
+ */
+ sslConfig: SslConfigSchema.optional().describe('SSL/TLS configuration'),
+
+ /**
+ * Tables to sync
+ */
+ tables: z.array(DatabaseTableSchema).describe('Tables to sync'),
+
+ /**
+ * Change Data Capture configuration
+ */
+ cdcConfig: CdcConfigSchema.optional().describe('CDC configuration'),
+
+ /**
+ * Read replica configuration
+ */
+ readReplicaConfig: z.object({
+ enabled: z.boolean().default(false).describe('Use read replicas'),
+ hosts: z.array(z.object({
+ host: z.string().describe('Replica host'),
+ port: z.number().min(1).max(65535).describe('Replica port'),
+ weight: z.number().min(0).max(1).default(1).describe('Load balancing weight'),
+ })).describe('Read replica hosts'),
+ }).optional().describe('Read replica configuration'),
+
+ /**
+ * Query timeout
+ */
+ queryTimeoutMs: z.number().min(1000).max(300000).optional().default(30000).describe('Query timeout in ms'),
+
+ /**
+ * Enable query logging
+ */
+ enableQueryLogging: z.boolean().optional().default(false).describe('Enable SQL query logging'),
+});
+
+export type DatabaseConnector = z.infer;
+
+// ============================================================================
+// Helper Functions & Examples
+// ============================================================================
+
+/**
+ * Example: PostgreSQL Connector Configuration
+ */
+export const postgresConnectorExample = {
+ name: 'postgres_production',
+ label: 'Production PostgreSQL',
+ type: 'database',
+ provider: 'postgresql',
+ authentication: {
+ type: 'basic',
+ username: '${DB_USERNAME}',
+ password: '${DB_PASSWORD}',
+ },
+ connectionConfig: {
+ host: 'db.example.com',
+ port: 5432,
+ database: 'production',
+ username: '${DB_USERNAME}',
+ password: '${DB_PASSWORD}',
+ },
+ poolConfig: {
+ min: 2,
+ max: 20,
+ idleTimeoutMs: 30000,
+ connectionTimeoutMs: 10000,
+ acquireTimeoutMs: 30000,
+ evictionRunIntervalMs: 30000,
+ testOnBorrow: true,
+ },
+ sslConfig: {
+ enabled: true,
+ rejectUnauthorized: true,
+ },
+ tables: [
+ {
+ name: 'customer',
+ label: 'Customer',
+ schema: 'public',
+ tableName: 'customers',
+ primaryKey: 'id',
+ enabled: true,
+ },
+ {
+ name: 'order',
+ label: 'Order',
+ schema: 'public',
+ tableName: 'orders',
+ primaryKey: 'id',
+ enabled: true,
+ whereClause: 'status != \'archived\'',
+ },
+ ],
+ cdcConfig: {
+ enabled: true,
+ method: 'log_based',
+ slotName: 'objectstack_replication_slot',
+ publicationName: 'objectstack_publication',
+ batchSize: 1000,
+ pollIntervalMs: 1000,
+ },
+ syncConfig: {
+ strategy: 'incremental',
+ direction: 'bidirectional',
+ realtimeSync: true,
+ conflictResolution: 'latest_wins',
+ batchSize: 1000,
+ deleteMode: 'soft_delete',
+ },
+ status: 'active',
+ enabled: true,
+};
+
+/**
+ * Example: MongoDB Connector Configuration
+ */
+export const mongoConnectorExample = {
+ name: 'mongodb_analytics',
+ label: 'MongoDB Analytics',
+ type: 'database',
+ provider: 'mongodb',
+ authentication: {
+ type: 'basic',
+ username: '${MONGO_USERNAME}',
+ password: '${MONGO_PASSWORD}',
+ },
+ connectionConfig: {
+ host: 'mongodb.example.com',
+ port: 27017,
+ database: 'analytics',
+ username: '${MONGO_USERNAME}',
+ password: '${MONGO_PASSWORD}',
+ options: {
+ authSource: 'admin',
+ replicaSet: 'rs0',
+ },
+ },
+ tables: [
+ {
+ name: 'event',
+ label: 'Event',
+ tableName: 'events',
+ primaryKey: '_id',
+ enabled: true,
+ },
+ ],
+ cdcConfig: {
+ enabled: true,
+ method: 'log_based',
+ batchSize: 1000,
+ pollIntervalMs: 500,
+ },
+ syncConfig: {
+ strategy: 'incremental',
+ direction: 'import',
+ batchSize: 1000,
+ },
+ status: 'active',
+ enabled: true,
+};
+
+/**
+ * Example: Snowflake Connector Configuration
+ */
+export const snowflakeConnectorExample = {
+ name: 'snowflake_warehouse',
+ label: 'Snowflake Data Warehouse',
+ type: 'database',
+ provider: 'snowflake',
+ authentication: {
+ type: 'basic',
+ username: '${SNOWFLAKE_USERNAME}',
+ password: '${SNOWFLAKE_PASSWORD}',
+ },
+ connectionConfig: {
+ host: 'account.snowflakecomputing.com',
+ port: 443,
+ database: 'ANALYTICS_DB',
+ username: '${SNOWFLAKE_USERNAME}',
+ password: '${SNOWFLAKE_PASSWORD}',
+ options: {
+ warehouse: 'COMPUTE_WH',
+ schema: 'PUBLIC',
+ role: 'ANALYST',
+ },
+ },
+ tables: [
+ {
+ name: 'sales_summary',
+ label: 'Sales Summary',
+ schema: 'PUBLIC',
+ tableName: 'SALES_SUMMARY',
+ primaryKey: 'ID',
+ enabled: true,
+ },
+ ],
+ syncConfig: {
+ strategy: 'full',
+ direction: 'import',
+ schedule: '0 2 * * *', // Daily at 2 AM
+ batchSize: 5000,
+ },
+ queryTimeoutMs: 60000,
+ status: 'active',
+ enabled: true,
+};
diff --git a/packages/spec/src/integration/connector/file-storage.zod.ts b/packages/spec/src/integration/connector/file-storage.zod.ts
new file mode 100644
index 000000000..daa665023
--- /dev/null
+++ b/packages/spec/src/integration/connector/file-storage.zod.ts
@@ -0,0 +1,397 @@
+import { z } from 'zod';
+import {
+ ConnectorSchema,
+} from '../connector.zod';
+
+/**
+ * File Storage Connector Protocol Template
+ *
+ * Specialized connector for file storage systems (S3, Azure Blob, Google Cloud Storage, etc.)
+ * Extends the base connector with file-specific features like multipart uploads,
+ * versioning, and metadata extraction.
+ */
+
+/**
+ * File Storage Provider Types
+ */
+export const FileStorageProviderSchema = z.enum([
+ 's3', // Amazon S3
+ 'azure_blob', // Azure Blob Storage
+ 'gcs', // Google Cloud Storage
+ 'dropbox', // Dropbox
+ 'box', // Box
+ 'onedrive', // Microsoft OneDrive
+ 'google_drive', // Google Drive
+ 'sharepoint', // SharePoint
+ 'ftp', // FTP/SFTP
+ 'local', // Local file system
+ 'custom', // Custom file storage
+]).describe('File storage provider type');
+
+export type FileStorageProvider = z.infer;
+
+/**
+ * File Access Pattern
+ */
+export const FileAccessPatternSchema = z.enum([
+ 'public_read', // Public read access
+ 'private', // Private access
+ 'authenticated_read', // Requires authentication
+ 'bucket_owner_read', // Bucket owner has read access
+ 'bucket_owner_full', // Bucket owner has full control
+]).describe('File access pattern');
+
+export type FileAccessPattern = z.infer;
+
+/**
+ * File Metadata Configuration
+ */
+export const FileMetadataConfigSchema = z.object({
+ extractMetadata: z.boolean().default(true).describe('Extract file metadata'),
+
+ metadataFields: z.array(z.enum([
+ 'content_type',
+ 'file_size',
+ 'last_modified',
+ 'etag',
+ 'checksum',
+ 'creator',
+ 'created_at',
+ 'custom',
+ ])).optional().describe('Metadata fields to extract'),
+
+ customMetadata: z.record(z.string()).optional().describe('Custom metadata key-value pairs'),
+});
+
+export type FileMetadataConfig = z.infer;
+
+/**
+ * Multipart Upload Configuration
+ */
+export const MultipartUploadConfigSchema = z.object({
+ enabled: z.boolean().default(true).describe('Enable multipart uploads'),
+
+ partSize: z.number().min(5 * 1024 * 1024).default(5 * 1024 * 1024).describe('Part size in bytes (min 5MB)'),
+
+ maxConcurrentParts: z.number().min(1).max(10).default(5).describe('Maximum concurrent part uploads'),
+
+ threshold: z.number().min(5 * 1024 * 1024).default(100 * 1024 * 1024).describe('File size threshold for multipart upload in bytes'),
+});
+
+export type MultipartUploadConfig = z.infer;
+
+/**
+ * File Versioning Configuration
+ */
+export const FileVersioningConfigSchema = z.object({
+ enabled: z.boolean().default(false).describe('Enable file versioning'),
+
+ maxVersions: z.number().min(1).max(100).optional().describe('Maximum versions to retain'),
+
+ retentionDays: z.number().min(1).optional().describe('Version retention period in days'),
+});
+
+export type FileVersioningConfig = z.infer;
+
+/**
+ * File Filter Configuration
+ */
+export const FileFilterConfigSchema = z.object({
+ includePatterns: z.array(z.string()).optional().describe('File patterns to include (glob)'),
+
+ excludePatterns: z.array(z.string()).optional().describe('File patterns to exclude (glob)'),
+
+ minFileSize: z.number().min(0).optional().describe('Minimum file size in bytes'),
+
+ maxFileSize: z.number().min(1).optional().describe('Maximum file size in bytes'),
+
+ allowedExtensions: z.array(z.string()).optional().describe('Allowed file extensions'),
+
+ blockedExtensions: z.array(z.string()).optional().describe('Blocked file extensions'),
+});
+
+export type FileFilterConfig = z.infer;
+
+/**
+ * File Storage Bucket/Container Configuration
+ */
+export const StorageBucketSchema = z.object({
+ name: z.string().regex(/^[a-z_][a-z0-9_]*$/).describe('Bucket identifier in ObjectStack (snake_case)'),
+ label: z.string().describe('Display label'),
+ bucketName: z.string().describe('Actual bucket/container name in storage system'),
+ region: z.string().optional().describe('Storage region'),
+ enabled: z.boolean().default(true).describe('Enable sync for this bucket'),
+ prefix: z.string().optional().describe('Prefix/path within bucket'),
+ accessPattern: FileAccessPatternSchema.optional().describe('Access pattern'),
+ fileFilters: FileFilterConfigSchema.optional().describe('File filter configuration'),
+});
+
+export type StorageBucket = z.infer;
+
+/**
+ * File Storage Connector Configuration Schema
+ */
+export const FileStorageConnectorSchema = ConnectorSchema.extend({
+ type: z.literal('file_storage'),
+
+ /**
+ * File storage provider
+ */
+ provider: FileStorageProviderSchema.describe('File storage provider type'),
+
+ /**
+ * Storage configuration
+ */
+ storageConfig: z.object({
+ endpoint: z.string().url().optional().describe('Custom endpoint URL'),
+ region: z.string().optional().describe('Default region'),
+ pathStyle: z.boolean().optional().default(false).describe('Use path-style URLs (for S3-compatible)'),
+ }).optional().describe('Storage configuration'),
+
+ /**
+ * Buckets/containers to sync
+ */
+ buckets: z.array(StorageBucketSchema).describe('Buckets/containers to sync'),
+
+ /**
+ * File metadata configuration
+ */
+ metadataConfig: FileMetadataConfigSchema.optional().describe('Metadata extraction configuration'),
+
+ /**
+ * Multipart upload configuration
+ */
+ multipartConfig: MultipartUploadConfigSchema.optional().describe('Multipart upload configuration'),
+
+ /**
+ * File versioning configuration
+ */
+ versioningConfig: FileVersioningConfigSchema.optional().describe('File versioning configuration'),
+
+ /**
+ * Enable server-side encryption
+ */
+ encryption: z.object({
+ enabled: z.boolean().default(false).describe('Enable server-side encryption'),
+ algorithm: z.enum(['AES256', 'aws:kms', 'custom']).optional().describe('Encryption algorithm'),
+ kmsKeyId: z.string().optional().describe('KMS key ID (for aws:kms)'),
+ }).optional().describe('Encryption configuration'),
+
+ /**
+ * Lifecycle policy
+ */
+ lifecyclePolicy: z.object({
+ enabled: z.boolean().default(false).describe('Enable lifecycle policy'),
+ deleteAfterDays: z.number().min(1).optional().describe('Delete files after N days'),
+ archiveAfterDays: z.number().min(1).optional().describe('Archive files after N days'),
+ }).optional().describe('Lifecycle policy'),
+
+ /**
+ * Content processing configuration
+ */
+ contentProcessing: z.object({
+ extractText: z.boolean().default(false).describe('Extract text from documents'),
+ generateThumbnails: z.boolean().default(false).describe('Generate image thumbnails'),
+ thumbnailSizes: z.array(z.object({
+ width: z.number().min(1),
+ height: z.number().min(1),
+ })).optional().describe('Thumbnail sizes'),
+ virusScan: z.boolean().default(false).describe('Scan for viruses'),
+ }).optional().describe('Content processing configuration'),
+
+ /**
+ * Download/upload buffer size
+ */
+ bufferSize: z.number().min(1024).default(64 * 1024).describe('Buffer size in bytes'),
+
+ /**
+ * Enable transfer acceleration (for supported providers)
+ */
+ transferAcceleration: z.boolean().default(false).describe('Enable transfer acceleration'),
+});
+
+export type FileStorageConnector = z.infer;
+
+// ============================================================================
+// Helper Functions & Examples
+// ============================================================================
+
+/**
+ * Example: Amazon S3 Connector Configuration
+ */
+export const s3ConnectorExample = {
+ name: 's3_production_assets',
+ label: 'Production S3 Assets',
+ type: 'file_storage',
+ provider: 's3',
+ authentication: {
+ type: 'api_key',
+ apiKey: '${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}',
+ headerName: 'Authorization',
+ },
+ storageConfig: {
+ region: 'us-east-1',
+ pathStyle: false,
+ },
+ buckets: [
+ {
+ name: 'product_images',
+ label: 'Product Images',
+ bucketName: 'my-company-product-images',
+ region: 'us-east-1',
+ enabled: true,
+ prefix: 'products/',
+ accessPattern: 'public_read',
+ fileFilters: {
+ allowedExtensions: ['.jpg', '.jpeg', '.png', '.webp'],
+ maxFileSize: 10 * 1024 * 1024, // 10MB
+ },
+ },
+ {
+ name: 'customer_documents',
+ label: 'Customer Documents',
+ bucketName: 'my-company-customer-docs',
+ region: 'us-east-1',
+ enabled: true,
+ accessPattern: 'private',
+ fileFilters: {
+ allowedExtensions: ['.pdf', '.docx', '.xlsx'],
+ maxFileSize: 50 * 1024 * 1024, // 50MB
+ },
+ },
+ ],
+ metadataConfig: {
+ extractMetadata: true,
+ metadataFields: ['content_type', 'file_size', 'last_modified', 'etag'],
+ },
+ multipartConfig: {
+ enabled: true,
+ partSize: 5 * 1024 * 1024, // 5MB
+ maxConcurrentParts: 5,
+ threshold: 100 * 1024 * 1024, // 100MB
+ },
+ versioningConfig: {
+ enabled: true,
+ maxVersions: 10,
+ },
+ encryption: {
+ enabled: true,
+ algorithm: 'aws:kms',
+ kmsKeyId: '${AWS_KMS_KEY_ID}',
+ },
+ contentProcessing: {
+ extractText: true,
+ generateThumbnails: true,
+ thumbnailSizes: [
+ { width: 150, height: 150 },
+ { width: 300, height: 300 },
+ { width: 600, height: 600 },
+ ],
+ virusScan: true,
+ },
+ syncConfig: {
+ strategy: 'incremental',
+ direction: 'bidirectional',
+ realtimeSync: true,
+ conflictResolution: 'latest_wins',
+ batchSize: 100,
+ },
+ transferAcceleration: true,
+ status: 'active',
+ enabled: true,
+};
+
+/**
+ * Example: Google Drive Connector Configuration
+ */
+export const googleDriveConnectorExample = {
+ name: 'google_drive_team',
+ label: 'Google Drive Team Folder',
+ type: 'file_storage',
+ provider: 'google_drive',
+ authentication: {
+ type: 'oauth2',
+ clientId: '${GOOGLE_CLIENT_ID}',
+ clientSecret: '${GOOGLE_CLIENT_SECRET}',
+ authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
+ tokenUrl: 'https://oauth2.googleapis.com/token',
+ grantType: 'authorization_code',
+ scopes: ['https://www.googleapis.com/auth/drive.file'],
+ },
+ buckets: [
+ {
+ name: 'team_drive',
+ label: 'Team Drive',
+ bucketName: 'shared-team-drive',
+ enabled: true,
+ fileFilters: {
+ excludePatterns: ['*.tmp', '~$*'],
+ },
+ },
+ ],
+ metadataConfig: {
+ extractMetadata: true,
+ metadataFields: ['content_type', 'file_size', 'last_modified', 'creator', 'created_at'],
+ },
+ versioningConfig: {
+ enabled: true,
+ maxVersions: 5,
+ },
+ syncConfig: {
+ strategy: 'incremental',
+ direction: 'bidirectional',
+ realtimeSync: true,
+ conflictResolution: 'latest_wins',
+ batchSize: 50,
+ },
+ status: 'active',
+ enabled: true,
+};
+
+/**
+ * Example: Azure Blob Storage Connector Configuration
+ */
+export const azureBlobConnectorExample = {
+ name: 'azure_blob_storage',
+ label: 'Azure Blob Storage',
+ type: 'file_storage',
+ provider: 'azure_blob',
+ authentication: {
+ type: 'api_key',
+ apiKey: '${AZURE_STORAGE_ACCOUNT_KEY}',
+ headerName: 'x-ms-blob-type',
+ },
+ storageConfig: {
+ endpoint: 'https://myaccount.blob.core.windows.net',
+ },
+ buckets: [
+ {
+ name: 'archive_container',
+ label: 'Archive Container',
+ bucketName: 'archive',
+ enabled: true,
+ accessPattern: 'private',
+ },
+ ],
+ metadataConfig: {
+ extractMetadata: true,
+ metadataFields: ['content_type', 'file_size', 'last_modified', 'etag'],
+ },
+ encryption: {
+ enabled: true,
+ algorithm: 'AES256',
+ },
+ lifecyclePolicy: {
+ enabled: true,
+ archiveAfterDays: 90,
+ deleteAfterDays: 365,
+ },
+ syncConfig: {
+ strategy: 'incremental',
+ direction: 'import',
+ schedule: '0 1 * * *', // Daily at 1 AM
+ batchSize: 200,
+ },
+ status: 'active',
+ enabled: true,
+};
diff --git a/packages/spec/src/integration/connector/message-queue.zod.ts b/packages/spec/src/integration/connector/message-queue.zod.ts
new file mode 100644
index 000000000..4532aae11
--- /dev/null
+++ b/packages/spec/src/integration/connector/message-queue.zod.ts
@@ -0,0 +1,498 @@
+import { z } from 'zod';
+import {
+ ConnectorSchema,
+} from '../connector.zod';
+
+/**
+ * Message Queue Connector Protocol Template
+ *
+ * Specialized connector for message queue systems (RabbitMQ, Kafka, SQS, etc.)
+ * Extends the base connector with message queue-specific features like topics,
+ * consumer groups, and message acknowledgment patterns.
+ */
+
+/**
+ * Message Queue Provider Types
+ */
+export const MessageQueueProviderSchema = z.enum([
+ 'rabbitmq', // RabbitMQ
+ 'kafka', // Apache Kafka
+ 'redis_pubsub', // Redis Pub/Sub
+ 'redis_streams', // Redis Streams
+ 'aws_sqs', // Amazon SQS
+ 'aws_sns', // Amazon SNS
+ 'google_pubsub', // Google Cloud Pub/Sub
+ 'azure_service_bus', // Azure Service Bus
+ 'azure_event_hubs', // Azure Event Hubs
+ 'nats', // NATS
+ 'pulsar', // Apache Pulsar
+ 'activemq', // Apache ActiveMQ
+ 'custom', // Custom message queue
+]).describe('Message queue provider type');
+
+export type MessageQueueProvider = z.infer;
+
+/**
+ * Message Format
+ */
+export const MessageFormatSchema = z.enum([
+ 'json',
+ 'xml',
+ 'protobuf',
+ 'avro',
+ 'text',
+ 'binary',
+]).describe('Message format/serialization');
+
+export type MessageFormat = z.infer;
+
+/**
+ * Message Acknowledgment Mode
+ */
+export const AckModeSchema = z.enum([
+ 'auto', // Auto-acknowledge
+ 'manual', // Manual acknowledge after processing
+ 'client', // Client-controlled acknowledge
+]).describe('Message acknowledgment mode');
+
+export type AckMode = z.infer;
+
+/**
+ * Delivery Guarantee
+ */
+export const DeliveryGuaranteeSchema = z.enum([
+ 'at_most_once', // Fire and forget
+ 'at_least_once', // May deliver duplicates
+ 'exactly_once', // Guaranteed exactly once delivery
+]).describe('Message delivery guarantee');
+
+export type DeliveryGuarantee = z.infer;
+
+/**
+ * Consumer Configuration
+ */
+export const ConsumerConfigSchema = z.object({
+ enabled: z.boolean().optional().default(true).describe('Enable consumer'),
+
+ consumerGroup: z.string().optional().describe('Consumer group ID'),
+
+ concurrency: z.number().min(1).max(100).optional().default(1).describe('Number of concurrent consumers'),
+
+ prefetchCount: z.number().min(1).max(1000).optional().default(10).describe('Prefetch count'),
+
+ ackMode: AckModeSchema.optional().default('manual'),
+
+ autoCommit: z.boolean().optional().default(false).describe('Auto-commit offsets'),
+
+ autoCommitIntervalMs: z.number().min(100).optional().default(5000).describe('Auto-commit interval in ms'),
+
+ sessionTimeoutMs: z.number().min(1000).optional().default(30000).describe('Session timeout in ms'),
+
+ rebalanceTimeoutMs: z.number().min(1000).optional().describe('Rebalance timeout in ms'),
+});
+
+export type ConsumerConfig = z.infer;
+
+/**
+ * Producer Configuration
+ */
+export const ProducerConfigSchema = z.object({
+ enabled: z.boolean().optional().default(true).describe('Enable producer'),
+
+ acks: z.enum(['0', '1', 'all']).optional().default('all').describe('Acknowledgment level'),
+
+ compressionType: z.enum(['none', 'gzip', 'snappy', 'lz4', 'zstd']).optional().default('none').describe('Compression type'),
+
+ batchSize: z.number().min(1).optional().default(16384).describe('Batch size in bytes'),
+
+ lingerMs: z.number().min(0).optional().default(0).describe('Linger time in ms'),
+
+ maxInFlightRequests: z.number().min(1).optional().default(5).describe('Max in-flight requests'),
+
+ idempotence: z.boolean().optional().default(true).describe('Enable idempotent producer'),
+
+ transactional: z.boolean().optional().default(false).describe('Enable transactional producer'),
+
+ transactionTimeoutMs: z.number().min(1000).optional().describe('Transaction timeout in ms'),
+});
+
+export type ProducerConfig = z.infer;
+
+/**
+ * Dead Letter Queue Configuration
+ */
+export const DlqConfigSchema = z.object({
+ enabled: z.boolean().optional().default(false).describe('Enable DLQ'),
+
+ queueName: z.string().describe('Dead letter queue/topic name'),
+
+ maxRetries: z.number().min(0).max(100).optional().default(3).describe('Max retries before DLQ'),
+
+ retryDelayMs: z.number().min(0).optional().default(60000).describe('Retry delay in ms'),
+});
+
+export type DlqConfig = z.infer;
+
+/**
+ * Topic/Queue Configuration
+ */
+export const TopicQueueSchema = z.object({
+ name: z.string().regex(/^[a-z_][a-z0-9_]*$/).describe('Topic/queue identifier in ObjectStack (snake_case)'),
+ label: z.string().describe('Display label'),
+ topicName: z.string().describe('Actual topic/queue name in message queue system'),
+ enabled: z.boolean().optional().default(true).describe('Enable sync for this topic/queue'),
+
+ /**
+ * Consumer or Producer
+ */
+ mode: z.enum(['consumer', 'producer', 'both']).optional().default('both').describe('Consumer, producer, or both'),
+
+ /**
+ * Message format
+ */
+ messageFormat: MessageFormatSchema.optional().default('json'),
+
+ /**
+ * Partition/shard configuration
+ */
+ partitions: z.number().min(1).optional().describe('Number of partitions (for Kafka)'),
+
+ /**
+ * Replication factor
+ */
+ replicationFactor: z.number().min(1).optional().describe('Replication factor (for Kafka)'),
+
+ /**
+ * Consumer configuration
+ */
+ consumerConfig: ConsumerConfigSchema.optional().describe('Consumer-specific configuration'),
+
+ /**
+ * Producer configuration
+ */
+ producerConfig: ProducerConfigSchema.optional().describe('Producer-specific configuration'),
+
+ /**
+ * Dead letter queue configuration
+ */
+ dlqConfig: DlqConfigSchema.optional().describe('Dead letter queue configuration'),
+
+ /**
+ * Message routing key (for RabbitMQ)
+ */
+ routingKey: z.string().optional().describe('Routing key pattern'),
+
+ /**
+ * Message filter
+ */
+ messageFilter: z.object({
+ headers: z.record(z.string()).optional().describe('Filter by message headers'),
+ attributes: z.record(z.any()).optional().describe('Filter by message attributes'),
+ }).optional().describe('Message filter criteria'),
+});
+
+export type TopicQueue = z.infer;
+
+/**
+ * Message Queue Connector Configuration Schema
+ */
+export const MessageQueueConnectorSchema = ConnectorSchema.extend({
+ type: z.literal('message_queue'),
+
+ /**
+ * Message queue provider
+ */
+ provider: MessageQueueProviderSchema.describe('Message queue provider type'),
+
+ /**
+ * Broker configuration
+ */
+ brokerConfig: z.object({
+ brokers: z.array(z.string()).describe('Broker addresses (host:port)'),
+ clientId: z.string().optional().describe('Client ID'),
+ connectionTimeoutMs: z.number().min(1000).optional().default(30000).describe('Connection timeout in ms'),
+ requestTimeoutMs: z.number().min(1000).optional().default(30000).describe('Request timeout in ms'),
+ }).describe('Broker connection configuration'),
+
+ /**
+ * Topics/queues to sync
+ */
+ topics: z.array(TopicQueueSchema).describe('Topics/queues to sync'),
+
+ /**
+ * Delivery guarantee
+ */
+ deliveryGuarantee: DeliveryGuaranteeSchema.optional().default('at_least_once'),
+
+ /**
+ * SSL/TLS configuration
+ */
+ sslConfig: z.object({
+ enabled: z.boolean().optional().default(false).describe('Enable SSL/TLS'),
+ rejectUnauthorized: z.boolean().optional().default(true).describe('Reject unauthorized certificates'),
+ ca: z.string().optional().describe('CA certificate'),
+ cert: z.string().optional().describe('Client certificate'),
+ key: z.string().optional().describe('Client private key'),
+ }).optional().describe('SSL/TLS configuration'),
+
+ /**
+ * SASL authentication (for Kafka)
+ */
+ saslConfig: z.object({
+ mechanism: z.enum(['plain', 'scram-sha-256', 'scram-sha-512', 'aws']).describe('SASL mechanism'),
+ username: z.string().optional().describe('SASL username'),
+ password: z.string().optional().describe('SASL password'),
+ }).optional().describe('SASL authentication configuration'),
+
+ /**
+ * Schema registry configuration (for Kafka/Avro)
+ */
+ schemaRegistry: z.object({
+ url: z.string().url().describe('Schema registry URL'),
+ auth: z.object({
+ username: z.string().optional(),
+ password: z.string().optional(),
+ }).optional(),
+ }).optional().describe('Schema registry configuration'),
+
+ /**
+ * Message ordering
+ */
+ preserveOrder: z.boolean().optional().default(true).describe('Preserve message ordering'),
+
+ /**
+ * Enable metrics
+ */
+ enableMetrics: z.boolean().optional().default(true).describe('Enable message queue metrics'),
+
+ /**
+ * Enable distributed tracing
+ */
+ enableTracing: z.boolean().optional().default(false).describe('Enable distributed tracing'),
+});
+
+export type MessageQueueConnector = z.infer;
+
+// ============================================================================
+// Helper Functions & Examples
+// ============================================================================
+
+/**
+ * Example: Apache Kafka Connector Configuration
+ */
+export const kafkaConnectorExample = {
+ name: 'kafka_production',
+ label: 'Production Kafka Cluster',
+ type: 'message_queue',
+ provider: 'kafka',
+ authentication: {
+ type: 'none',
+ },
+ brokerConfig: {
+ brokers: ['kafka-1.example.com:9092', 'kafka-2.example.com:9092', 'kafka-3.example.com:9092'],
+ clientId: 'objectstack-client',
+ connectionTimeoutMs: 30000,
+ requestTimeoutMs: 30000,
+ },
+ topics: [
+ {
+ name: 'order_events',
+ label: 'Order Events',
+ topicName: 'orders',
+ enabled: true,
+ mode: 'consumer',
+ messageFormat: 'json',
+ partitions: 10,
+ replicationFactor: 3,
+ consumerConfig: {
+ enabled: true,
+ consumerGroup: 'objectstack-consumer-group',
+ concurrency: 5,
+ prefetchCount: 100,
+ ackMode: 'manual',
+ autoCommit: false,
+ sessionTimeoutMs: 30000,
+ },
+ dlqConfig: {
+ enabled: true,
+ queueName: 'orders-dlq',
+ maxRetries: 3,
+ retryDelayMs: 60000,
+ },
+ },
+ {
+ name: 'user_activity',
+ label: 'User Activity',
+ topicName: 'user-activity',
+ enabled: true,
+ mode: 'producer',
+ messageFormat: 'json',
+ partitions: 5,
+ replicationFactor: 3,
+ producerConfig: {
+ enabled: true,
+ acks: 'all',
+ compressionType: 'snappy',
+ batchSize: 16384,
+ lingerMs: 10,
+ maxInFlightRequests: 5,
+ idempotence: true,
+ },
+ },
+ ],
+ deliveryGuarantee: 'at_least_once',
+ saslConfig: {
+ mechanism: 'scram-sha-256',
+ username: '${KAFKA_USERNAME}',
+ password: '${KAFKA_PASSWORD}',
+ },
+ sslConfig: {
+ enabled: true,
+ rejectUnauthorized: true,
+ },
+ preserveOrder: true,
+ enableMetrics: true,
+ enableTracing: true,
+ status: 'active',
+ enabled: true,
+};
+
+/**
+ * Example: RabbitMQ Connector Configuration
+ */
+export const rabbitmqConnectorExample = {
+ name: 'rabbitmq_events',
+ label: 'RabbitMQ Event Bus',
+ type: 'message_queue',
+ provider: 'rabbitmq',
+ authentication: {
+ type: 'basic',
+ username: '${RABBITMQ_USERNAME}',
+ password: '${RABBITMQ_PASSWORD}',
+ },
+ brokerConfig: {
+ brokers: ['amqp://rabbitmq.example.com:5672'],
+ clientId: 'objectstack-rabbitmq-client',
+ },
+ topics: [
+ {
+ name: 'notifications',
+ label: 'Notifications',
+ topicName: 'notifications',
+ enabled: true,
+ mode: 'both',
+ messageFormat: 'json',
+ routingKey: 'notification.*',
+ consumerConfig: {
+ enabled: true,
+ prefetchCount: 10,
+ ackMode: 'manual',
+ },
+ producerConfig: {
+ enabled: true,
+ },
+ dlqConfig: {
+ enabled: true,
+ queueName: 'notifications-dlq',
+ maxRetries: 3,
+ retryDelayMs: 30000,
+ },
+ },
+ ],
+ deliveryGuarantee: 'at_least_once',
+ status: 'active',
+ enabled: true,
+};
+
+/**
+ * Example: AWS SQS Connector Configuration
+ */
+export const sqsConnectorExample = {
+ name: 'aws_sqs_queue',
+ label: 'AWS SQS Queue',
+ type: 'message_queue',
+ provider: 'aws_sqs',
+ authentication: {
+ type: 'api_key',
+ apiKey: '${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}',
+ headerName: 'Authorization',
+ },
+ brokerConfig: {
+ brokers: ['https://sqs.us-east-1.amazonaws.com'],
+ },
+ topics: [
+ {
+ name: 'task_queue',
+ label: 'Task Queue',
+ topicName: 'task-queue',
+ enabled: true,
+ mode: 'consumer',
+ messageFormat: 'json',
+ consumerConfig: {
+ enabled: true,
+ concurrency: 10,
+ prefetchCount: 10,
+ ackMode: 'manual',
+ },
+ dlqConfig: {
+ enabled: true,
+ queueName: 'task-queue-dlq',
+ maxRetries: 3,
+ retryDelayMs: 120000,
+ },
+ },
+ ],
+ deliveryGuarantee: 'at_least_once',
+ retryConfig: {
+ strategy: 'exponential_backoff',
+ maxAttempts: 3,
+ initialDelayMs: 1000,
+ maxDelayMs: 60000,
+ backoffMultiplier: 2,
+ },
+ status: 'active',
+ enabled: true,
+};
+
+/**
+ * Example: Google Cloud Pub/Sub Connector Configuration
+ */
+export const pubsubConnectorExample = {
+ name: 'gcp_pubsub',
+ label: 'Google Cloud Pub/Sub',
+ type: 'message_queue',
+ provider: 'google_pubsub',
+ authentication: {
+ type: 'oauth2',
+ clientId: '${GCP_CLIENT_ID}',
+ clientSecret: '${GCP_CLIENT_SECRET}',
+ authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
+ tokenUrl: 'https://oauth2.googleapis.com/token',
+ grantType: 'client_credentials',
+ scopes: ['https://www.googleapis.com/auth/pubsub'],
+ },
+ brokerConfig: {
+ brokers: ['pubsub.googleapis.com'],
+ },
+ topics: [
+ {
+ name: 'analytics_events',
+ label: 'Analytics Events',
+ topicName: 'projects/my-project/topics/analytics-events',
+ enabled: true,
+ mode: 'both',
+ messageFormat: 'json',
+ consumerConfig: {
+ enabled: true,
+ consumerGroup: 'objectstack-subscription',
+ concurrency: 5,
+ prefetchCount: 100,
+ ackMode: 'manual',
+ },
+ },
+ ],
+ deliveryGuarantee: 'at_least_once',
+ enableMetrics: true,
+ status: 'active',
+ enabled: true,
+};
diff --git a/packages/spec/src/integration/connector/saas.zod.ts b/packages/spec/src/integration/connector/saas.zod.ts
new file mode 100644
index 000000000..4f003b8a2
--- /dev/null
+++ b/packages/spec/src/integration/connector/saas.zod.ts
@@ -0,0 +1,248 @@
+import { z } from 'zod';
+import {
+ ConnectorSchema,
+ FieldMappingSchema,
+} from '../connector.zod';
+
+/**
+ * SaaS Connector Protocol Template
+ *
+ * Specialized connector for SaaS applications (Salesforce, HubSpot, Stripe, etc.)
+ * Extends the base connector with SaaS-specific features like OAuth flows,
+ * object type discovery, and API version management.
+ */
+
+/**
+ * SaaS Provider Types
+ */
+export const SaasProviderSchema = z.enum([
+ 'salesforce',
+ 'hubspot',
+ 'stripe',
+ 'shopify',
+ 'zendesk',
+ 'intercom',
+ 'mailchimp',
+ 'slack',
+ 'microsoft_dynamics',
+ 'servicenow',
+ 'netsuite',
+ 'custom',
+]).describe('SaaS provider type');
+
+export type SaasProvider = z.infer;
+
+/**
+ * API Version Configuration
+ */
+export const ApiVersionConfigSchema = z.object({
+ version: z.string().describe('API version (e.g., "v2", "2023-10-01")'),
+ isDefault: z.boolean().default(false).describe('Is this the default version'),
+ deprecationDate: z.string().optional().describe('API version deprecation date (ISO 8601)'),
+ sunsetDate: z.string().optional().describe('API version sunset date (ISO 8601)'),
+});
+
+export type ApiVersionConfig = z.infer;
+
+/**
+ * SaaS Object Type Schema
+ * Represents a syncable entity in the SaaS system (e.g., Account, Contact, Deal)
+ */
+export const SaasObjectTypeSchema = z.object({
+ name: z.string().regex(/^[a-z_][a-z0-9_]*$/).describe('Object type name (snake_case)'),
+ label: z.string().describe('Display label'),
+ apiName: z.string().describe('API name in external system'),
+ enabled: z.boolean().default(true).describe('Enable sync for this object'),
+ supportsCreate: z.boolean().default(true).describe('Supports record creation'),
+ supportsUpdate: z.boolean().default(true).describe('Supports record updates'),
+ supportsDelete: z.boolean().default(true).describe('Supports record deletion'),
+ fieldMappings: z.array(FieldMappingSchema).optional().describe('Object-specific field mappings'),
+});
+
+export type SaasObjectType = z.infer;
+
+/**
+ * SaaS Connector Configuration Schema
+ */
+export const SaasConnectorSchema = ConnectorSchema.extend({
+ type: z.literal('saas'),
+
+ /**
+ * SaaS provider
+ */
+ provider: SaasProviderSchema.describe('SaaS provider type'),
+
+ /**
+ * Base URL for API requests
+ */
+ baseUrl: z.string().url().describe('API base URL'),
+
+ /**
+ * API version configuration
+ */
+ apiVersion: ApiVersionConfigSchema.optional().describe('API version configuration'),
+
+ /**
+ * Supported object types to sync
+ */
+ objectTypes: z.array(SaasObjectTypeSchema).describe('Syncable object types'),
+
+ /**
+ * OAuth-specific settings
+ */
+ oauthSettings: z.object({
+ scopes: z.array(z.string()).describe('Required OAuth scopes'),
+ refreshTokenUrl: z.string().url().optional().describe('Token refresh endpoint'),
+ revokeTokenUrl: z.string().url().optional().describe('Token revocation endpoint'),
+ autoRefresh: z.boolean().default(true).describe('Automatically refresh expired tokens'),
+ }).optional().describe('OAuth-specific configuration'),
+
+ /**
+ * Pagination settings
+ */
+ paginationConfig: z.object({
+ type: z.enum(['cursor', 'offset', 'page']).default('cursor').describe('Pagination type'),
+ defaultPageSize: z.number().min(1).max(1000).default(100).describe('Default page size'),
+ maxPageSize: z.number().min(1).max(10000).default(1000).describe('Maximum page size'),
+ }).optional().describe('Pagination configuration'),
+
+ /**
+ * Sandbox/test environment settings
+ */
+ sandboxConfig: z.object({
+ enabled: z.boolean().default(false).describe('Use sandbox environment'),
+ baseUrl: z.string().url().optional().describe('Sandbox API base URL'),
+ }).optional().describe('Sandbox environment configuration'),
+
+ /**
+ * Custom request headers
+ */
+ customHeaders: z.record(z.string()).optional().describe('Custom HTTP headers for all requests'),
+});
+
+export type SaasConnector = z.infer;
+
+// ============================================================================
+// Helper Functions & Examples
+// ============================================================================
+
+/**
+ * Example: Salesforce Connector Configuration
+ */
+export const salesforceConnectorExample = {
+ name: 'salesforce_production',
+ label: 'Salesforce Production',
+ type: 'saas',
+ provider: 'salesforce',
+ baseUrl: 'https://example.my.salesforce.com',
+ apiVersion: {
+ version: 'v59.0',
+ isDefault: true,
+ },
+ authentication: {
+ type: 'oauth2',
+ clientId: '${SALESFORCE_CLIENT_ID}',
+ clientSecret: '${SALESFORCE_CLIENT_SECRET}',
+ authorizationUrl: 'https://login.salesforce.com/services/oauth2/authorize',
+ tokenUrl: 'https://login.salesforce.com/services/oauth2/token',
+ grantType: 'authorization_code',
+ scopes: ['api', 'refresh_token', 'offline_access'],
+ },
+ objectTypes: [
+ {
+ name: 'account',
+ label: 'Account',
+ apiName: 'Account',
+ enabled: true,
+ supportsCreate: true,
+ supportsUpdate: true,
+ supportsDelete: true,
+ },
+ {
+ name: 'contact',
+ label: 'Contact',
+ apiName: 'Contact',
+ enabled: true,
+ supportsCreate: true,
+ supportsUpdate: true,
+ supportsDelete: true,
+ },
+ ],
+ syncConfig: {
+ strategy: 'incremental',
+ direction: 'bidirectional',
+ schedule: '0 */6 * * *', // Every 6 hours
+ realtimeSync: true,
+ conflictResolution: 'latest_wins',
+ batchSize: 200,
+ deleteMode: 'soft_delete',
+ },
+ rateLimitConfig: {
+ strategy: 'token_bucket',
+ maxRequests: 100,
+ windowSeconds: 20,
+ respectUpstreamLimits: true,
+ },
+ retryConfig: {
+ strategy: 'exponential_backoff',
+ maxAttempts: 3,
+ initialDelayMs: 1000,
+ maxDelayMs: 30000,
+ backoffMultiplier: 2,
+ retryableStatusCodes: [408, 429, 500, 502, 503, 504],
+ retryOnNetworkError: true,
+ jitter: true,
+ },
+ status: 'active',
+ enabled: true,
+};
+
+/**
+ * Example: HubSpot Connector Configuration
+ */
+export const hubspotConnectorExample = {
+ name: 'hubspot_crm',
+ label: 'HubSpot CRM',
+ type: 'saas',
+ provider: 'hubspot',
+ baseUrl: 'https://api.hubapi.com',
+ authentication: {
+ type: 'api_key',
+ apiKey: '${HUBSPOT_API_KEY}',
+ headerName: 'Authorization',
+ },
+ objectTypes: [
+ {
+ name: 'company',
+ label: 'Company',
+ apiName: 'companies',
+ enabled: true,
+ supportsCreate: true,
+ supportsUpdate: true,
+ supportsDelete: true,
+ },
+ {
+ name: 'deal',
+ label: 'Deal',
+ apiName: 'deals',
+ enabled: true,
+ supportsCreate: true,
+ supportsUpdate: true,
+ supportsDelete: true,
+ },
+ ],
+ syncConfig: {
+ strategy: 'incremental',
+ direction: 'import',
+ schedule: '0 */4 * * *', // Every 4 hours
+ conflictResolution: 'source_wins',
+ batchSize: 100,
+ },
+ rateLimitConfig: {
+ strategy: 'token_bucket',
+ maxRequests: 100,
+ windowSeconds: 10,
+ },
+ status: 'active',
+ enabled: true,
+};
diff --git a/packages/spec/src/integration/index.ts b/packages/spec/src/integration/index.ts
new file mode 100644
index 000000000..e513e4418
--- /dev/null
+++ b/packages/spec/src/integration/index.ts
@@ -0,0 +1,18 @@
+/**
+ * Integration Protocol Exports
+ *
+ * External System Connection Protocols
+ * - Connector configurations for SaaS, databases, file storage, message queues
+ * - Authentication methods (OAuth2, API Key, JWT, SAML)
+ * - Data synchronization and field mapping
+ * - Webhooks, rate limiting, and retry strategies
+ */
+
+// Core Connector Protocol
+export * from './connector.zod';
+
+// Connector Templates
+export * from './connector/saas.zod';
+export * from './connector/database.zod';
+export * from './connector/file-storage.zod';
+export * from './connector/message-queue.zod';
diff --git a/packages/spec/src/system/index.ts b/packages/spec/src/system/index.ts
index e1cc8f019..8764ca28b 100644
--- a/packages/spec/src/system/index.ts
+++ b/packages/spec/src/system/index.ts
@@ -34,3 +34,4 @@ export * from './data-engine.zod';
// Note: Auth, Identity, Policy, Role, Organization moved to @objectstack/spec/auth
// Note: Territory moved to @objectstack/spec/permission
+// Note: Connector Protocol moved to @objectstack/spec/integration