airbyte-cdk 6.61.1__py3-none-any.whl → 6.61.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. airbyte_cdk/__init__.py +0 -2
  2. airbyte_cdk/connector_builder/connector_builder_handler.py +7 -5
  3. airbyte_cdk/connector_builder/main.py +4 -2
  4. airbyte_cdk/connector_builder/test_reader/reader.py +10 -8
  5. airbyte_cdk/legacy/__init__.py +1 -0
  6. airbyte_cdk/legacy/sources/__init__.py +1 -0
  7. airbyte_cdk/legacy/sources/declarative/__init__.py +1 -0
  8. airbyte_cdk/legacy/sources/declarative/incremental/__init__.py +1 -0
  9. airbyte_cdk/{sources → legacy/sources}/declarative/manifest_declarative_source.py +1 -1
  10. airbyte_cdk/manifest_server/Dockerfile +45 -0
  11. airbyte_cdk/manifest_server/README.md +142 -0
  12. airbyte_cdk/manifest_server/__init__.py +3 -0
  13. airbyte_cdk/manifest_server/api_models/__init__.py +49 -0
  14. airbyte_cdk/manifest_server/api_models/capabilities.py +7 -0
  15. airbyte_cdk/manifest_server/api_models/dicts.py +17 -0
  16. airbyte_cdk/manifest_server/api_models/manifest.py +73 -0
  17. airbyte_cdk/manifest_server/api_models/stream.py +76 -0
  18. airbyte_cdk/manifest_server/app.py +17 -0
  19. airbyte_cdk/manifest_server/auth.py +43 -0
  20. airbyte_cdk/manifest_server/cli/__init__.py +5 -0
  21. airbyte_cdk/manifest_server/cli/_common.py +28 -0
  22. airbyte_cdk/manifest_server/cli/_info.py +30 -0
  23. airbyte_cdk/manifest_server/cli/_openapi.py +43 -0
  24. airbyte_cdk/manifest_server/cli/_start.py +38 -0
  25. airbyte_cdk/manifest_server/cli/run.py +59 -0
  26. airbyte_cdk/manifest_server/command_processor/__init__.py +0 -0
  27. airbyte_cdk/manifest_server/command_processor/processor.py +122 -0
  28. airbyte_cdk/manifest_server/command_processor/utils.py +99 -0
  29. airbyte_cdk/manifest_server/main.py +24 -0
  30. airbyte_cdk/manifest_server/openapi.yaml +641 -0
  31. airbyte_cdk/manifest_server/routers/__init__.py +0 -0
  32. airbyte_cdk/manifest_server/routers/capabilities.py +25 -0
  33. airbyte_cdk/manifest_server/routers/health.py +13 -0
  34. airbyte_cdk/manifest_server/routers/manifest.py +155 -0
  35. airbyte_cdk/sources/declarative/concurrent_declarative_source.py +507 -24
  36. airbyte_cdk/sources/declarative/incremental/__init__.py +4 -4
  37. airbyte_cdk/sources/declarative/incremental/per_partition_with_global.py +4 -4
  38. airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +12 -0
  39. airbyte_cdk/sources/declarative/retrievers/retriever.py +1 -2
  40. airbyte_cdk/sources/streams/http/http_client.py +21 -0
  41. {airbyte_cdk-6.61.1.dist-info → airbyte_cdk-6.61.3.dist-info}/METADATA +4 -1
  42. {airbyte_cdk-6.61.1.dist-info → airbyte_cdk-6.61.3.dist-info}/RECORD +48 -19
  43. {airbyte_cdk-6.61.1.dist-info → airbyte_cdk-6.61.3.dist-info}/entry_points.txt +1 -0
  44. /airbyte_cdk/{sources → legacy/sources}/declarative/declarative_source.py +0 -0
  45. /airbyte_cdk/{sources → legacy/sources}/declarative/incremental/per_partition_cursor.py +0 -0
  46. {airbyte_cdk-6.61.1.dist-info → airbyte_cdk-6.61.3.dist-info}/LICENSE.txt +0 -0
  47. {airbyte_cdk-6.61.1.dist-info → airbyte_cdk-6.61.3.dist-info}/LICENSE_SHORT +0 -0
  48. {airbyte_cdk-6.61.1.dist-info → airbyte_cdk-6.61.3.dist-info}/WHEEL +0 -0
airbyte_cdk/__init__.py CHANGED
@@ -107,7 +107,6 @@ from .sources.declarative.extractors.record_extractor import RecordExtractor
107
107
  from .sources.declarative.extractors.record_filter import RecordFilter
108
108
  from .sources.declarative.incremental import DatetimeBasedCursor
109
109
  from .sources.declarative.interpolation import InterpolatedBoolean, InterpolatedString
110
- from .sources.declarative.manifest_declarative_source import ManifestDeclarativeSource
111
110
  from .sources.declarative.migrations.legacy_to_per_partition_state_migration import (
112
111
  LegacyToPerPartitionStateMigration,
113
112
  )
@@ -253,7 +252,6 @@ __all__ = [
253
252
  "JsonDecoder",
254
253
  "JsonFileSchemaLoader",
255
254
  "LegacyToPerPartitionStateMigration",
256
- "ManifestDeclarativeSource",
257
255
  "MinMaxDatetime",
258
256
  "NoAuth",
259
257
  "OffsetIncrement",
@@ -19,8 +19,6 @@ from airbyte_cdk.sources.declarative.concurrent_declarative_source import (
19
19
  ConcurrentDeclarativeSource,
20
20
  TestLimits,
21
21
  )
22
- from airbyte_cdk.sources.declarative.declarative_source import DeclarativeSource
23
- from airbyte_cdk.sources.declarative.manifest_declarative_source import ManifestDeclarativeSource
24
22
  from airbyte_cdk.utils.airbyte_secrets_utils import filter_secrets
25
23
  from airbyte_cdk.utils.datetime_helpers import ab_datetime_now
26
24
  from airbyte_cdk.utils.traced_exception import AirbyteTracedException
@@ -90,7 +88,7 @@ def create_source(
90
88
 
91
89
 
92
90
  def read_stream(
93
- source: DeclarativeSource,
91
+ source: ConcurrentDeclarativeSource[Optional[List[AirbyteStateMessage]]],
94
92
  config: Mapping[str, Any],
95
93
  configured_catalog: ConfiguredAirbyteCatalog,
96
94
  state: List[AirbyteStateMessage],
@@ -128,7 +126,9 @@ def read_stream(
128
126
  return error.as_airbyte_message()
129
127
 
130
128
 
131
- def resolve_manifest(source: ManifestDeclarativeSource) -> AirbyteMessage:
129
+ def resolve_manifest(
130
+ source: ConcurrentDeclarativeSource[Optional[List[AirbyteStateMessage]]],
131
+ ) -> AirbyteMessage:
132
132
  try:
133
133
  return AirbyteMessage(
134
134
  type=Type.RECORD,
@@ -145,7 +145,9 @@ def resolve_manifest(source: ManifestDeclarativeSource) -> AirbyteMessage:
145
145
  return error.as_airbyte_message()
146
146
 
147
147
 
148
- def full_resolve_manifest(source: ManifestDeclarativeSource, limits: TestLimits) -> AirbyteMessage:
148
+ def full_resolve_manifest(
149
+ source: ConcurrentDeclarativeSource[Optional[List[AirbyteStateMessage]]], limits: TestLimits
150
+ ) -> AirbyteMessage:
149
151
  try:
150
152
  manifest = {**source.resolved_manifest}
151
153
  streams = manifest.get("streams", [])
@@ -25,7 +25,9 @@ from airbyte_cdk.models import (
25
25
  ConfiguredAirbyteCatalog,
26
26
  ConfiguredAirbyteCatalogSerializer,
27
27
  )
28
- from airbyte_cdk.sources.declarative.manifest_declarative_source import ManifestDeclarativeSource
28
+ from airbyte_cdk.sources.declarative.concurrent_declarative_source import (
29
+ ConcurrentDeclarativeSource,
30
+ )
29
31
  from airbyte_cdk.sources.source import Source
30
32
  from airbyte_cdk.utils.traced_exception import AirbyteTracedException
31
33
 
@@ -68,7 +70,7 @@ def get_config_and_catalog_from_args(
68
70
 
69
71
 
70
72
  def handle_connector_builder_request(
71
- source: ManifestDeclarativeSource,
73
+ source: ConcurrentDeclarativeSource[Optional[List[AirbyteStateMessage]]],
72
74
  command: str,
73
75
  config: Mapping[str, Any],
74
76
  catalog: Optional[ConfiguredAirbyteCatalog],
@@ -23,7 +23,9 @@ from airbyte_cdk.models import (
23
23
  ConfiguredAirbyteCatalog,
24
24
  TraceType,
25
25
  )
26
- from airbyte_cdk.sources.declarative.declarative_source import DeclarativeSource
26
+ from airbyte_cdk.sources.declarative.concurrent_declarative_source import (
27
+ ConcurrentDeclarativeSource,
28
+ )
27
29
  from airbyte_cdk.utils import AirbyteTracedException
28
30
  from airbyte_cdk.utils.datetime_format_inferrer import DatetimeFormatInferrer
29
31
  from airbyte_cdk.utils.schema_inferrer import (
@@ -55,7 +57,7 @@ class TestReader:
55
57
  that contains slices of data, log messages, auxiliary requests, and any inferred schema or datetime formats.
56
58
 
57
59
  Parameters:
58
- source (DeclarativeSource): The data source to read from.
60
+ source (ConcurrentDeclarativeSource): The data source to read from.
59
61
  config (Mapping[str, Any]): Configuration parameters for the source.
60
62
  configured_catalog (ConfiguredAirbyteCatalog): Catalog containing stream configuration.
61
63
  state (List[AirbyteStateMessage]): Current state information for the read.
@@ -83,7 +85,7 @@ class TestReader:
83
85
 
84
86
  def run_test_read(
85
87
  self,
86
- source: DeclarativeSource,
88
+ source: ConcurrentDeclarativeSource[Optional[List[AirbyteStateMessage]]],
87
89
  config: Mapping[str, Any],
88
90
  configured_catalog: ConfiguredAirbyteCatalog,
89
91
  stream_name: str,
@@ -94,7 +96,7 @@ class TestReader:
94
96
  Run a test read for the connector by reading from a single stream and inferring schema and datetime formats.
95
97
 
96
98
  Parameters:
97
- source (DeclarativeSource): The source instance providing the streams.
99
+ source (ConcurrentDeclarativeSource): The source instance providing the streams.
98
100
  config (Mapping[str, Any]): The configuration settings to use for reading.
99
101
  configured_catalog (ConfiguredAirbyteCatalog): The catalog specifying the stream configuration.
100
102
  state (List[AirbyteStateMessage]): A list of state messages to resume the read.
@@ -126,7 +128,7 @@ class TestReader:
126
128
  if stream
127
129
  else None,
128
130
  self._cursor_field_to_nested_and_composite_field(stream.cursor_field)
129
- if stream
131
+ if stream and stream.cursor_field
130
132
  else None,
131
133
  )
132
134
  datetime_format_inferrer = DatetimeFormatInferrer()
@@ -381,13 +383,13 @@ class TestReader:
381
383
 
382
384
  def _read_stream(
383
385
  self,
384
- source: DeclarativeSource,
386
+ source: ConcurrentDeclarativeSource[Optional[List[AirbyteStateMessage]]],
385
387
  config: Mapping[str, Any],
386
388
  configured_catalog: ConfiguredAirbyteCatalog,
387
389
  state: List[AirbyteStateMessage],
388
390
  ) -> Iterator[AirbyteMessage]:
389
391
  """
390
- Reads messages from the given DeclarativeSource using an AirbyteEntrypoint.
392
+ Reads messages from the given ConcurrentDeclarativeSource using an AirbyteEntrypoint.
391
393
 
392
394
  This method attempts to yield messages from the source's read generator. If the generator
393
395
  raises an AirbyteTracedException, it checks whether the exception message indicates a non-actionable
@@ -396,7 +398,7 @@ class TestReader:
396
398
  wrapped into an AirbyteTracedException, and yielded as an AirbyteMessage.
397
399
 
398
400
  Parameters:
399
- source (DeclarativeSource): The source object that provides data reading logic.
401
+ source (ConcurrentDeclarativeSource): The source object that provides data reading logic.
400
402
  config (Mapping[str, Any]): The configuration dictionary for the source.
401
403
  configured_catalog (ConfiguredAirbyteCatalog): The catalog defining the streams and their configurations.
402
404
  state (List[AirbyteStateMessage]): A list representing the current state for incremental sync.
@@ -0,0 +1 @@
1
+ # Copyright (c) 2025 Airbyte, Inc., all rights reserved.
@@ -0,0 +1 @@
1
+ # Copyright (c) 2025 Airbyte, Inc., all rights reserved.
@@ -0,0 +1 @@
1
+ # Copyright (c) 2025 Airbyte, Inc., all rights reserved.
@@ -0,0 +1 @@
1
+ # Copyright (c) 2025 Airbyte, Inc., all rights reserved.
@@ -20,6 +20,7 @@ from airbyte_cdk.config_observation import create_connector_config_control_messa
20
20
  from airbyte_cdk.connector_builder.models import (
21
21
  LogMessage as ConnectorBuilderLogMessage,
22
22
  )
23
+ from airbyte_cdk.legacy.sources.declarative.declarative_source import DeclarativeSource
23
24
  from airbyte_cdk.manifest_migrations.migration_handler import (
24
25
  ManifestMigrationHandler,
25
26
  )
@@ -34,7 +35,6 @@ from airbyte_cdk.models import (
34
35
  from airbyte_cdk.models.airbyte_protocol_serializers import AirbyteMessageSerializer
35
36
  from airbyte_cdk.sources.declarative.checks import COMPONENTS_CHECKER_TYPE_MAPPING
36
37
  from airbyte_cdk.sources.declarative.checks.connection_checker import ConnectionChecker
37
- from airbyte_cdk.sources.declarative.declarative_source import DeclarativeSource
38
38
  from airbyte_cdk.sources.declarative.interpolation import InterpolatedBoolean
39
39
  from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
40
40
  ConditionalStreams as ConditionalStreamsModel,
@@ -0,0 +1,45 @@
1
+ # Dockerfile for the Airbyte Manifest Server.
2
+ #
3
+ # This Dockerfile should be built from the root of the repository.
4
+ #
5
+ # Example:
6
+ # docker build -f airbyte_cdk/manifest_server/Dockerfile -t airbyte/manifest-server .
7
+
8
+ FROM python:3.12-slim-bookworm
9
+
10
+ # Install git (needed for dynamic versioning) and poetry
11
+ RUN apt-get update && \
12
+ apt-get install -y git && \
13
+ rm -rf /var/lib/apt/lists/* && \
14
+ pip install poetry==1.8.3
15
+
16
+ # Configure poetry to not create virtual environments and disable interactive mode
17
+ ENV POETRY_NO_INTERACTION=1 \
18
+ POETRY_CACHE_DIR=/tmp/poetry_cache
19
+
20
+ WORKDIR /app
21
+
22
+ # Copy poetry files (build from project root)
23
+ COPY pyproject.toml poetry.lock ./
24
+
25
+ # Copy the project source code (needed for dynamic versioning)
26
+ COPY . /app
27
+
28
+ # Install dependencies and package directly to system Python
29
+ RUN --mount=type=cache,target=$POETRY_CACHE_DIR \
30
+ poetry config virtualenvs.create false && \
31
+ poetry install --extras manifest-server
32
+
33
+ # Create a non-root user and group
34
+ RUN groupadd --gid 1000 airbyte && \
35
+ useradd --uid 1000 --gid airbyte --shell /bin/bash --create-home airbyte
36
+
37
+ # Change ownership
38
+ RUN chown -R airbyte:airbyte /app
39
+
40
+ # Run app as non-root user
41
+ USER airbyte:airbyte
42
+
43
+ EXPOSE 8080
44
+
45
+ CMD ["uvicorn", "airbyte_cdk.manifest_server.app:app", "--host", "0.0.0.0", "--port", "8080"]
@@ -0,0 +1,142 @@
1
+ # Manifest Server
2
+
3
+ An HTTP server for running Airbyte declarative connectors via their manifest files.
4
+
5
+ ## Quick Start
6
+
7
+ ### Installation
8
+
9
+ The manifest server is available as an extra dependency:
10
+
11
+ ```bash
12
+ # Using Poetry (preferred)
13
+ poetry install --extras manifest-server
14
+
15
+ # Using pip
16
+ pip install airbyte-cdk[manifest-server]
17
+
18
+ # Using uv
19
+ uv pip install 'airbyte-cdk[manifest-server]'
20
+ ```
21
+
22
+ ### Running the Server
23
+
24
+ ```bash
25
+ # Start the server (default port 8000)
26
+ manifest-server start
27
+
28
+ # Start on a specific port
29
+ manifest-server start --port 8080
30
+
31
+ # Or using Python module
32
+ python -m airbyte_cdk.manifest_server.cli.run start
33
+ ```
34
+
35
+ The server will start on `http://localhost:8000` by default.
36
+
37
+ ## API Endpoints
38
+
39
+ ### `/v1/manifest/test_read`
40
+ Test reading from a specific stream in the manifest.
41
+
42
+ **POST** - Test stream reading with configurable limits for records, pages, and slices.
43
+
44
+ ### `/v1/manifest/check`
45
+ Check configuration against a manifest.
46
+
47
+ **POST** - Validates connector configuration and returns success/failure status with message.
48
+
49
+ ### `/v1/manifest/discover`
50
+ Discover streams from a manifest.
51
+
52
+ **POST** - Returns the catalog of available streams from the manifest.
53
+
54
+ ### `/v1/manifest/resolve`
55
+ Resolve a manifest to its final configuration.
56
+
57
+ **POST** - Returns the resolved manifest without dynamic stream generation.
58
+
59
+ ### `/v1/manifest/full_resolve`
60
+ Fully resolve a manifest including dynamic streams.
61
+
62
+ **POST** - Generates dynamic streams up to specified limits and includes them in the resolved manifest.
63
+
64
+ ## Custom Components
65
+
66
+ The manifest server supports custom Python components, but this feature is **disabled by default** for security reasons.
67
+
68
+ ### Enabling Custom Components
69
+
70
+ To allow custom Python components in your manifest files, set the environment variable:
71
+ ```bash
72
+ export AIRBYTE_ENABLE_UNSAFE_CODE=true
73
+ ```
74
+
75
+ ## Authentication
76
+
77
+ The manifest server supports optional JWT bearer token authentication:
78
+
79
+ ### Configuration
80
+ Set the environment variable to enable authentication:
81
+ ```bash
82
+ export AB_JWT_SIGNATURE_SECRET="your-jwt-secret-key"
83
+ ```
84
+
85
+ ### Usage
86
+ When authentication is enabled, include a valid JWT token in the Authorization header:
87
+ ```bash
88
+ curl -H "Authorization: Bearer <your-jwt-token>" \
89
+ http://localhost:8000/v1/manifest/test_read
90
+ ```
91
+
92
+ ### Behavior
93
+ - **Without `AB_JWT_SIGNATURE_SECRET`**: All requests pass through
94
+ - **With `AB_JWT_SIGNATURE_SECRET`**: Requires valid JWT bearer token using HS256 algorithm
95
+
96
+ ## OpenAPI Specification
97
+
98
+ The manifest server provides an OpenAPI specification for API client generation:
99
+
100
+ ### Generating the OpenAPI Spec
101
+ ```bash
102
+ # Generate OpenAPI YAML (default location)
103
+ manifest-server generate-openapi
104
+
105
+ # Generate to custom location
106
+ manifest-server generate-openapi --output /path/to/openapi.yaml
107
+ ```
108
+
109
+ The generated OpenAPI specification is consumed by other applications and tools to:
110
+ - Generate API clients in various programming languages
111
+ - Create SDK bindings for the manifest server
112
+ - Provide API documentation and validation
113
+ - Enable integration with API development tools
114
+
115
+ ### Interactive API Documentation
116
+
117
+ When running, interactive API documentation is available at:
118
+ - Swagger UI: `http://localhost:8000/docs`
119
+ - ReDoc: `http://localhost:8000/redoc`
120
+
121
+ ## Testing
122
+
123
+ Run the manifest server tests from the repository root:
124
+
125
+ ```bash
126
+ # Run all manifest server tests
127
+ poetry run pytest unit_tests/manifest_server/ -v
128
+ ```
129
+
130
+ ## Docker
131
+
132
+ The manifest server can be containerized using the included Dockerfile. Build from the repository root:
133
+
134
+ ```bash
135
+ # Build from repository root (not from manifest_server subdirectory)
136
+ docker build -f airbyte_cdk/manifest_server/Dockerfile -t manifest-server .
137
+
138
+ # Run the container
139
+ docker run -p 8080:8080 manifest-server
140
+ ```
141
+
142
+ Note: The container runs on port 8080 by default.
@@ -0,0 +1,3 @@
1
+ """
2
+ .. include:: ./README.md
3
+ """
@@ -0,0 +1,49 @@
1
+ """
2
+ API Models for the Manifest Server Service.
3
+
4
+ This package contains all Pydantic models used for API requests and responses.
5
+ """
6
+
7
+ from .dicts import ConnectorConfig, Manifest
8
+ from .manifest import (
9
+ CheckRequest,
10
+ CheckResponse,
11
+ DiscoverRequest,
12
+ DiscoverResponse,
13
+ FullResolveRequest,
14
+ ManifestResponse,
15
+ ResolveRequest,
16
+ StreamTestReadRequest,
17
+ )
18
+ from .stream import (
19
+ AuxiliaryRequest,
20
+ HttpRequest,
21
+ HttpResponse,
22
+ LogMessage,
23
+ StreamReadPages,
24
+ StreamReadResponse,
25
+ StreamReadSlices,
26
+ )
27
+
28
+ __all__ = [
29
+ # Typed Dicts
30
+ "ConnectorConfig",
31
+ "Manifest",
32
+ # Manifest request/response models
33
+ "FullResolveRequest",
34
+ "ManifestResponse",
35
+ "StreamTestReadRequest",
36
+ "ResolveRequest",
37
+ "CheckRequest",
38
+ "CheckResponse",
39
+ "DiscoverRequest",
40
+ "DiscoverResponse",
41
+ # Stream models
42
+ "AuxiliaryRequest",
43
+ "HttpRequest",
44
+ "HttpResponse",
45
+ "LogMessage",
46
+ "StreamReadResponse",
47
+ "StreamReadPages",
48
+ "StreamReadSlices",
49
+ ]
@@ -0,0 +1,7 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class CapabilitiesResponse(BaseModel):
5
+ """Capabilities of the manifest server."""
6
+
7
+ custom_code_execution: bool
@@ -0,0 +1,17 @@
1
+ """
2
+ Common API models shared across different endpoints.
3
+ """
4
+
5
+ from pydantic import BaseModel, ConfigDict
6
+
7
+
8
+ class Manifest(BaseModel):
9
+ """Base manifest model. Allows client generation to replace with proper JsonNode types."""
10
+
11
+ model_config = ConfigDict(extra="allow")
12
+
13
+
14
+ class ConnectorConfig(BaseModel):
15
+ """Base connector configuration model. Allows client generation to replace with proper JsonNode types."""
16
+
17
+ model_config = ConfigDict(extra="allow")
@@ -0,0 +1,73 @@
1
+ """
2
+ Manifest-related API models.
3
+
4
+ These models define the request and response structures for manifest operations
5
+ like reading, resolving, and full resolution.
6
+ """
7
+
8
+ from typing import Any, List, Optional
9
+
10
+ from airbyte_protocol_dataclasses.models import AirbyteCatalog
11
+ from pydantic import BaseModel, Field
12
+
13
+ from .dicts import ConnectorConfig, Manifest
14
+
15
+
16
+ class StreamTestReadRequest(BaseModel):
17
+ """Request to test read from a specific stream."""
18
+
19
+ manifest: Manifest
20
+ config: ConnectorConfig
21
+ stream_name: str
22
+ state: List[Any] = Field(default_factory=list)
23
+ custom_components_code: Optional[str] = None
24
+ record_limit: int = Field(default=100, ge=1, le=5000)
25
+ page_limit: int = Field(default=5, ge=1, le=20)
26
+ slice_limit: int = Field(default=5, ge=1, le=20)
27
+
28
+
29
+ class CheckRequest(BaseModel):
30
+ """Request to check a manifest."""
31
+
32
+ manifest: Manifest
33
+ config: ConnectorConfig
34
+
35
+
36
+ class CheckResponse(BaseModel):
37
+ """Response to check a manifest."""
38
+
39
+ success: bool
40
+ message: Optional[str] = None
41
+
42
+
43
+ class DiscoverRequest(BaseModel):
44
+ """Request to discover a manifest."""
45
+
46
+ manifest: Manifest
47
+ config: ConnectorConfig
48
+
49
+
50
+ class DiscoverResponse(BaseModel):
51
+ """Response to discover a manifest."""
52
+
53
+ catalog: AirbyteCatalog
54
+
55
+
56
+ class ResolveRequest(BaseModel):
57
+ """Request to resolve a manifest."""
58
+
59
+ manifest: Manifest
60
+
61
+
62
+ class ManifestResponse(BaseModel):
63
+ """Response containing a manifest."""
64
+
65
+ manifest: Manifest
66
+
67
+
68
+ class FullResolveRequest(BaseModel):
69
+ """Request to fully resolve a manifest."""
70
+
71
+ manifest: Manifest
72
+ config: ConnectorConfig
73
+ stream_limit: int = Field(default=100, ge=1, le=100)
@@ -0,0 +1,76 @@
1
+ """
2
+ Stream-related API models.
3
+
4
+ These models define the structure for stream reading operations and responses.
5
+ They accurately reflect the runtime types returned by the CDK, particularly
6
+ fixing type mismatches like slice_descriptor being a string rather than an object.
7
+ """
8
+
9
+ from typing import Any, Dict, List, Optional
10
+
11
+ from pydantic import BaseModel
12
+
13
+
14
+ class HttpRequest(BaseModel):
15
+ """HTTP request details."""
16
+
17
+ url: str
18
+ headers: Optional[Dict[str, Any]]
19
+ http_method: str
20
+ body: Optional[str] = None
21
+
22
+
23
+ class HttpResponse(BaseModel):
24
+ """HTTP response details."""
25
+
26
+ status: int
27
+ body: Optional[str] = None
28
+ headers: Optional[Dict[str, Any]] = None
29
+
30
+
31
+ class LogMessage(BaseModel):
32
+ """Log message from stream processing."""
33
+
34
+ message: str
35
+ level: str
36
+ internal_message: Optional[str] = None
37
+ stacktrace: Optional[str] = None
38
+
39
+
40
+ class AuxiliaryRequest(BaseModel):
41
+ """Auxiliary HTTP request made during stream processing."""
42
+
43
+ title: str
44
+ type: str
45
+ description: str
46
+ request: HttpRequest
47
+ response: HttpResponse
48
+
49
+
50
+ class StreamReadPages(BaseModel):
51
+ """Pages of data read from a stream slice."""
52
+
53
+ records: List[object]
54
+ request: Optional[HttpRequest] = None
55
+ response: Optional[HttpResponse] = None
56
+
57
+
58
+ class StreamReadSlices(BaseModel):
59
+ """Slices of data read from a stream."""
60
+
61
+ pages: List[StreamReadPages]
62
+ slice_descriptor: Optional[str] # This is actually a string at runtime, not Dict[str, Any]
63
+ state: Optional[List[Dict[str, Any]]] = None
64
+ auxiliary_requests: Optional[List[AuxiliaryRequest]] = None
65
+
66
+
67
+ class StreamReadResponse(BaseModel):
68
+ """Complete stream read response with properly typed fields."""
69
+
70
+ logs: List[LogMessage]
71
+ slices: List[StreamReadSlices]
72
+ test_read_limit_reached: bool
73
+ auxiliary_requests: List[AuxiliaryRequest]
74
+ inferred_schema: Optional[Dict[str, Any]]
75
+ inferred_datetime_formats: Optional[Dict[str, str]]
76
+ latest_config_update: Optional[Dict[str, Any]]
@@ -0,0 +1,17 @@
1
+ from fastapi import FastAPI
2
+
3
+ from .routers import capabilities, health, manifest
4
+
5
+ app = FastAPI(
6
+ title="Manifest Server",
7
+ description="A service for running low-code Airbyte connectors",
8
+ version="0.1.0",
9
+ contact={
10
+ "name": "Airbyte",
11
+ "url": "https://airbyte.com",
12
+ },
13
+ )
14
+
15
+ app.include_router(health.router)
16
+ app.include_router(capabilities.router)
17
+ app.include_router(manifest.router, prefix="/v1")
@@ -0,0 +1,43 @@
1
+ import os
2
+ from typing import Optional
3
+
4
+ import jwt
5
+ from fastapi import HTTPException, Security, status
6
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
7
+
8
+ security = HTTPBearer(auto_error=False)
9
+
10
+
11
+ def verify_jwt_token(
12
+ credentials: Optional[HTTPAuthorizationCredentials] = Security(security),
13
+ ) -> None:
14
+ """
15
+ Verify JWT token if AB_JWT_SIGNATURE_SECRET is set, otherwise allow through.
16
+
17
+ Args:
18
+ credentials: Bearer token credentials from request header
19
+
20
+ Raises:
21
+ HTTPException: If token is invalid or missing when secret is configured
22
+ """
23
+ jwt_secret = os.getenv("AB_JWT_SIGNATURE_SECRET")
24
+
25
+ # If no secret is configured, allow all requests through
26
+ if not jwt_secret:
27
+ return
28
+
29
+ if not credentials:
30
+ raise HTTPException(
31
+ status_code=status.HTTP_401_UNAUTHORIZED,
32
+ detail="Bearer token required",
33
+ headers={"WWW-Authenticate": "Bearer"},
34
+ )
35
+
36
+ try:
37
+ jwt.decode(credentials.credentials, jwt_secret, algorithms=["HS256"])
38
+ except jwt.InvalidTokenError:
39
+ raise HTTPException(
40
+ status_code=status.HTTP_401_UNAUTHORIZED,
41
+ detail="Invalid token",
42
+ headers={"WWW-Authenticate": "Bearer"},
43
+ )
@@ -0,0 +1,5 @@
1
+ # Copyright (c) 2025 Airbyte, Inc., all rights reserved.
2
+ """The `airbyte_cdk.manifest_server.cli` module provides a standalone CLI for the Airbyte CDK Manifest Server.
3
+
4
+ This CLI enables running a FastAPI server for managing and executing Airbyte declarative manifests.
5
+ """