airbyte-cdk 6.60.15__py3-none-any.whl → 6.60.16.post40.dev17219503797__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.
- airbyte_cdk/connector_builder/connector_builder_handler.py +32 -36
- airbyte_cdk/connector_builder/main.py +3 -3
- airbyte_cdk/connector_builder/test_reader/helpers.py +24 -2
- airbyte_cdk/connector_builder/test_reader/message_grouper.py +1 -1
- airbyte_cdk/manifest_server/Dockerfile +45 -0
- airbyte_cdk/manifest_server/README.md +142 -0
- airbyte_cdk/manifest_server/__init__.py +3 -0
- airbyte_cdk/manifest_server/api_models/__init__.py +41 -0
- airbyte_cdk/manifest_server/api_models/capabilities.py +7 -0
- airbyte_cdk/manifest_server/api_models/dicts.py +17 -0
- airbyte_cdk/manifest_server/api_models/manifest.py +73 -0
- airbyte_cdk/manifest_server/api_models/stream.py +76 -0
- airbyte_cdk/manifest_server/app.py +17 -0
- airbyte_cdk/manifest_server/auth.py +43 -0
- airbyte_cdk/manifest_server/cli/__init__.py +5 -0
- airbyte_cdk/manifest_server/cli/_common.py +28 -0
- airbyte_cdk/manifest_server/cli/_info.py +30 -0
- airbyte_cdk/manifest_server/cli/_openapi.py +43 -0
- airbyte_cdk/manifest_server/cli/_start.py +38 -0
- airbyte_cdk/manifest_server/cli/run.py +59 -0
- airbyte_cdk/manifest_server/command_processor/__init__.py +0 -0
- airbyte_cdk/manifest_server/command_processor/processor.py +151 -0
- airbyte_cdk/manifest_server/command_processor/utils.py +76 -0
- airbyte_cdk/manifest_server/main.py +24 -0
- airbyte_cdk/manifest_server/openapi.yaml +641 -0
- airbyte_cdk/manifest_server/routers/__init__.py +0 -0
- airbyte_cdk/manifest_server/routers/capabilities.py +25 -0
- airbyte_cdk/manifest_server/routers/health.py +13 -0
- airbyte_cdk/manifest_server/routers/manifest.py +137 -0
- airbyte_cdk/sources/concurrent_source/concurrent_read_processor.py +15 -22
- airbyte_cdk/sources/concurrent_source/concurrent_source.py +30 -18
- airbyte_cdk/sources/declarative/concurrent_declarative_source.py +73 -3
- airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +66 -39
- airbyte_cdk/sources/declarative/stream_slicers/declarative_partition_generator.py +42 -4
- airbyte_cdk/sources/declarative/stream_slicers/stream_slicer_test_read_decorator.py +2 -2
- airbyte_cdk/sources/message/concurrent_repository.py +47 -0
- airbyte_cdk/sources/streams/concurrent/cursor.py +23 -7
- airbyte_cdk/sources/streams/concurrent/partition_reader.py +46 -5
- airbyte_cdk/sources/streams/concurrent/partitions/types.py +7 -1
- airbyte_cdk/sources/streams/http/http_client.py +4 -1
- airbyte_cdk/sources/utils/slice_logger.py +4 -0
- {airbyte_cdk-6.60.15.dist-info → airbyte_cdk-6.60.16.post40.dev17219503797.dist-info}/METADATA +4 -1
- {airbyte_cdk-6.60.15.dist-info → airbyte_cdk-6.60.16.post40.dev17219503797.dist-info}/RECORD +47 -21
- {airbyte_cdk-6.60.15.dist-info → airbyte_cdk-6.60.16.post40.dev17219503797.dist-info}/entry_points.txt +1 -0
- {airbyte_cdk-6.60.15.dist-info → airbyte_cdk-6.60.16.post40.dev17219503797.dist-info}/LICENSE.txt +0 -0
- {airbyte_cdk-6.60.15.dist-info → airbyte_cdk-6.60.16.post40.dev17219503797.dist-info}/LICENSE_SHORT +0 -0
- {airbyte_cdk-6.60.15.dist-info → airbyte_cdk-6.60.16.post40.dev17219503797.dist-info}/WHEEL +0 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
|
2
|
+
"""Common utilities for manifest server CLI commands."""
|
3
|
+
|
4
|
+
import sys
|
5
|
+
|
6
|
+
import rich_click as click
|
7
|
+
|
8
|
+
# Import server dependencies with graceful fallback
|
9
|
+
try:
|
10
|
+
import fastapi # noqa: F401
|
11
|
+
import uvicorn # noqa: F401
|
12
|
+
|
13
|
+
FASTAPI_AVAILABLE = True
|
14
|
+
except ImportError:
|
15
|
+
FASTAPI_AVAILABLE = False
|
16
|
+
|
17
|
+
|
18
|
+
def check_manifest_server_dependencies() -> None:
|
19
|
+
"""Check if manifest-server dependencies are installed."""
|
20
|
+
if not FASTAPI_AVAILABLE:
|
21
|
+
click.echo(
|
22
|
+
"❌ Manifest runner dependencies not found. Please install with:\n\n"
|
23
|
+
" pip install airbyte-cdk[manifest-server]\n"
|
24
|
+
" # or\n"
|
25
|
+
" poetry install --extras manifest-server\n",
|
26
|
+
err=True,
|
27
|
+
)
|
28
|
+
sys.exit(1)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
|
2
|
+
"""Info command for the manifest server CLI."""
|
3
|
+
|
4
|
+
from typing import Any, Optional
|
5
|
+
|
6
|
+
import rich_click as click
|
7
|
+
|
8
|
+
# Import server dependencies with graceful fallback
|
9
|
+
fastapi: Optional[Any] = None
|
10
|
+
uvicorn: Optional[Any] = None
|
11
|
+
|
12
|
+
try:
|
13
|
+
import fastapi # type: ignore[no-redef]
|
14
|
+
import uvicorn # type: ignore[no-redef]
|
15
|
+
|
16
|
+
FASTAPI_AVAILABLE = True
|
17
|
+
except ImportError:
|
18
|
+
FASTAPI_AVAILABLE = False
|
19
|
+
|
20
|
+
|
21
|
+
@click.command()
|
22
|
+
def info() -> None:
|
23
|
+
"""Show manifest server information and status."""
|
24
|
+
if FASTAPI_AVAILABLE and fastapi is not None and uvicorn is not None:
|
25
|
+
click.echo("✅ Manifest runner dependencies are installed")
|
26
|
+
click.echo(f" FastAPI version: {fastapi.__version__}")
|
27
|
+
click.echo(f" Uvicorn version: {uvicorn.__version__}")
|
28
|
+
else:
|
29
|
+
click.echo("❌ Manifest runner dependencies not installed")
|
30
|
+
click.echo(" Install with: pip install airbyte-cdk[manifest-server]")
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
|
2
|
+
"""Generate OpenAPI command for the manifest server CLI."""
|
3
|
+
|
4
|
+
from pathlib import Path
|
5
|
+
|
6
|
+
import rich_click as click
|
7
|
+
from yaml import dump
|
8
|
+
|
9
|
+
from ._common import check_manifest_server_dependencies
|
10
|
+
|
11
|
+
|
12
|
+
@click.command("generate-openapi")
|
13
|
+
@click.option(
|
14
|
+
"--output",
|
15
|
+
"-o",
|
16
|
+
default="airbyte_cdk/manifest_server/openapi.yaml",
|
17
|
+
help="Output path for the OpenAPI YAML file",
|
18
|
+
show_default=True,
|
19
|
+
)
|
20
|
+
def generate_openapi(output: str) -> None:
|
21
|
+
"""Generate OpenAPI YAML specification for the manifest server."""
|
22
|
+
check_manifest_server_dependencies()
|
23
|
+
|
24
|
+
# Import the FastAPI app
|
25
|
+
from airbyte_cdk.manifest_server.app import app
|
26
|
+
|
27
|
+
# Get OpenAPI schema
|
28
|
+
openapi_schema = app.openapi()
|
29
|
+
|
30
|
+
# Ensure output directory exists
|
31
|
+
output_path = Path(output)
|
32
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
33
|
+
|
34
|
+
# Write YAML file with header comment
|
35
|
+
with open(output_path, "w") as f:
|
36
|
+
f.write("# This file is auto-generated. Do not edit manually.\n")
|
37
|
+
f.write("# To regenerate, run: manifest-server generate-openapi\n")
|
38
|
+
f.write("\n")
|
39
|
+
dump(openapi_schema, f, default_flow_style=False, sort_keys=False)
|
40
|
+
|
41
|
+
click.echo(f"✅ OpenAPI YAML generated at: {output_path}")
|
42
|
+
click.echo(f" Title: {openapi_schema.get('info', {}).get('title', 'N/A')}")
|
43
|
+
click.echo(f" Version: {openapi_schema.get('info', {}).get('version', 'N/A')}")
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
|
2
|
+
"""Start command for the manifest server CLI."""
|
3
|
+
|
4
|
+
import rich_click as click
|
5
|
+
|
6
|
+
from ._common import check_manifest_server_dependencies
|
7
|
+
|
8
|
+
|
9
|
+
@click.command()
|
10
|
+
@click.option(
|
11
|
+
"--host",
|
12
|
+
default="127.0.0.1",
|
13
|
+
help="Host to bind the server to",
|
14
|
+
show_default=True,
|
15
|
+
)
|
16
|
+
@click.option(
|
17
|
+
"--port",
|
18
|
+
default=8000,
|
19
|
+
help="Port to bind the server to",
|
20
|
+
show_default=True,
|
21
|
+
)
|
22
|
+
@click.option(
|
23
|
+
"--reload",
|
24
|
+
is_flag=True,
|
25
|
+
help="Enable auto-reload for development",
|
26
|
+
)
|
27
|
+
def start(host: str, port: int, reload: bool) -> None:
|
28
|
+
"""Start the FastAPI manifest server server."""
|
29
|
+
check_manifest_server_dependencies()
|
30
|
+
|
31
|
+
# Import and use the main server function
|
32
|
+
from airbyte_cdk.manifest_server.main import run_server
|
33
|
+
|
34
|
+
run_server(
|
35
|
+
host=host,
|
36
|
+
port=port,
|
37
|
+
reload=reload,
|
38
|
+
)
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
|
2
|
+
"""Standalone CLI for the Airbyte CDK Manifest Server.
|
3
|
+
|
4
|
+
This CLI provides commands for running and managing the manifest server server.
|
5
|
+
|
6
|
+
**Installation:**
|
7
|
+
|
8
|
+
To use the manifest-server functionality, install the CDK with the manifest-server extra:
|
9
|
+
|
10
|
+
```bash
|
11
|
+
pip install airbyte-cdk[manifest-server]
|
12
|
+
# or
|
13
|
+
poetry install --extras manifest-server
|
14
|
+
```
|
15
|
+
|
16
|
+
**Usage:**
|
17
|
+
|
18
|
+
```bash
|
19
|
+
manifest-server start --port 8000
|
20
|
+
manifest-server info
|
21
|
+
manifest-server --help
|
22
|
+
```
|
23
|
+
"""
|
24
|
+
|
25
|
+
import rich_click as click
|
26
|
+
|
27
|
+
from ._info import info
|
28
|
+
from ._openapi import generate_openapi
|
29
|
+
from ._start import start
|
30
|
+
|
31
|
+
|
32
|
+
@click.group(
|
33
|
+
help=__doc__.replace("\n", "\n\n"), # Render docstring as help text (markdown)
|
34
|
+
invoke_without_command=True,
|
35
|
+
)
|
36
|
+
@click.pass_context
|
37
|
+
def cli(
|
38
|
+
ctx: click.Context,
|
39
|
+
) -> None:
|
40
|
+
"""Airbyte Manifest Server CLI."""
|
41
|
+
|
42
|
+
if ctx.invoked_subcommand is None:
|
43
|
+
# If no subcommand is provided, show the help message.
|
44
|
+
click.echo(ctx.get_help())
|
45
|
+
ctx.exit()
|
46
|
+
|
47
|
+
|
48
|
+
cli.add_command(start)
|
49
|
+
cli.add_command(info)
|
50
|
+
cli.add_command(generate_openapi)
|
51
|
+
|
52
|
+
|
53
|
+
def run() -> None:
|
54
|
+
"""Entry point for the manifest-server CLI."""
|
55
|
+
cli()
|
56
|
+
|
57
|
+
|
58
|
+
if __name__ == "__main__":
|
59
|
+
run()
|
File without changes
|
@@ -0,0 +1,151 @@
|
|
1
|
+
import logging
|
2
|
+
from typing import Any, Dict, Iterable, List, Mapping, Optional, Tuple
|
3
|
+
|
4
|
+
from airbyte_protocol_dataclasses.models import (
|
5
|
+
AirbyteCatalog,
|
6
|
+
AirbyteConnectionStatus,
|
7
|
+
AirbyteMessage,
|
8
|
+
Status,
|
9
|
+
TraceType,
|
10
|
+
)
|
11
|
+
from airbyte_protocol_dataclasses.models import Type as AirbyteMessageType
|
12
|
+
from fastapi import HTTPException
|
13
|
+
|
14
|
+
from airbyte_cdk.connector_builder.models import StreamRead
|
15
|
+
from airbyte_cdk.connector_builder.test_reader import TestReader
|
16
|
+
from airbyte_cdk.entrypoint import AirbyteEntrypoint
|
17
|
+
from airbyte_cdk.models import (
|
18
|
+
AirbyteStateMessage,
|
19
|
+
ConfiguredAirbyteCatalog,
|
20
|
+
)
|
21
|
+
from airbyte_cdk.sources.declarative.manifest_declarative_source import (
|
22
|
+
ManifestDeclarativeSource,
|
23
|
+
)
|
24
|
+
|
25
|
+
|
26
|
+
class ManifestCommandProcessor:
|
27
|
+
_source: ManifestDeclarativeSource
|
28
|
+
_logger = logging.getLogger("airbyte.manifest-server")
|
29
|
+
|
30
|
+
def __init__(self, source: ManifestDeclarativeSource) -> None:
|
31
|
+
self._source = source
|
32
|
+
|
33
|
+
def test_read(
|
34
|
+
self,
|
35
|
+
config: Mapping[str, Any],
|
36
|
+
catalog: ConfiguredAirbyteCatalog,
|
37
|
+
state: List[AirbyteStateMessage],
|
38
|
+
record_limit: int,
|
39
|
+
page_limit: int,
|
40
|
+
slice_limit: int,
|
41
|
+
) -> StreamRead:
|
42
|
+
"""
|
43
|
+
Test the read method of the source.
|
44
|
+
"""
|
45
|
+
|
46
|
+
test_read_handler = TestReader(
|
47
|
+
max_pages_per_slice=page_limit,
|
48
|
+
max_slices=slice_limit,
|
49
|
+
max_record_limit=record_limit,
|
50
|
+
)
|
51
|
+
|
52
|
+
stream_read = test_read_handler.run_test_read(
|
53
|
+
source=self._source,
|
54
|
+
config=config,
|
55
|
+
configured_catalog=catalog,
|
56
|
+
state=state,
|
57
|
+
stream_name=catalog.streams[0].stream.name,
|
58
|
+
record_limit=record_limit,
|
59
|
+
)
|
60
|
+
|
61
|
+
return stream_read
|
62
|
+
|
63
|
+
def check_connection(
|
64
|
+
self,
|
65
|
+
config: Mapping[str, Any],
|
66
|
+
) -> Tuple[bool, str]:
|
67
|
+
"""
|
68
|
+
Check the connection to the source.
|
69
|
+
"""
|
70
|
+
|
71
|
+
spec = self._source.spec(self._logger)
|
72
|
+
messages = AirbyteEntrypoint(source=self._source).check(spec, config)
|
73
|
+
messages_by_type = self._get_messages_by_type(messages)
|
74
|
+
self._raise_on_trace_message(messages_by_type)
|
75
|
+
connection_status = self._get_connection_status(messages_by_type)
|
76
|
+
|
77
|
+
if connection_status:
|
78
|
+
return connection_status.status == Status.SUCCEEDED, connection_status.message
|
79
|
+
return False, "Connection check failed"
|
80
|
+
|
81
|
+
def discover(
|
82
|
+
self,
|
83
|
+
config: Mapping[str, Any],
|
84
|
+
) -> Optional[AirbyteCatalog]:
|
85
|
+
"""
|
86
|
+
Discover the catalog from the source.
|
87
|
+
"""
|
88
|
+
spec = self._source.spec(self._logger)
|
89
|
+
messages = AirbyteEntrypoint(source=self._source).discover(spec, config)
|
90
|
+
messages_by_type = self._get_messages_by_type(messages)
|
91
|
+
self._raise_on_trace_message(messages_by_type)
|
92
|
+
return self._get_catalog(messages_by_type)
|
93
|
+
|
94
|
+
def _get_messages_by_type(
|
95
|
+
self,
|
96
|
+
messages: Iterable[AirbyteMessage],
|
97
|
+
) -> Dict[str, List[AirbyteMessage]]:
|
98
|
+
"""
|
99
|
+
Group messages by type.
|
100
|
+
"""
|
101
|
+
grouped: Dict[str, List[AirbyteMessage]] = {}
|
102
|
+
for message in messages:
|
103
|
+
msg_type = message.type
|
104
|
+
if msg_type not in grouped:
|
105
|
+
grouped[msg_type] = []
|
106
|
+
grouped[msg_type].append(message)
|
107
|
+
return grouped
|
108
|
+
|
109
|
+
def _get_connection_status(
|
110
|
+
self,
|
111
|
+
messages_by_type: Mapping[str, List[AirbyteMessage]],
|
112
|
+
) -> Optional[AirbyteConnectionStatus]:
|
113
|
+
"""
|
114
|
+
Get the connection status from the messages.
|
115
|
+
"""
|
116
|
+
messages = messages_by_type.get(AirbyteMessageType.CONNECTION_STATUS)
|
117
|
+
return messages[-1].connectionStatus if messages else None
|
118
|
+
|
119
|
+
def _get_catalog(
|
120
|
+
self,
|
121
|
+
messages_by_type: Mapping[str, List[AirbyteMessage]],
|
122
|
+
) -> Optional[AirbyteCatalog]:
|
123
|
+
"""
|
124
|
+
Get the catalog from the messages.
|
125
|
+
"""
|
126
|
+
messages = messages_by_type.get(AirbyteMessageType.CATALOG)
|
127
|
+
return messages[-1].catalog if messages else None
|
128
|
+
|
129
|
+
def _raise_on_trace_message(
|
130
|
+
self,
|
131
|
+
messages_by_type: Mapping[str, List[AirbyteMessage]],
|
132
|
+
) -> None:
|
133
|
+
"""
|
134
|
+
Raise an exception if a trace message is found.
|
135
|
+
"""
|
136
|
+
messages = [
|
137
|
+
message
|
138
|
+
for message in messages_by_type.get(AirbyteMessageType.TRACE, [])
|
139
|
+
if message.trace.type == TraceType.ERROR
|
140
|
+
]
|
141
|
+
if messages:
|
142
|
+
error_message = messages[-1].trace.error.message
|
143
|
+
self._logger.warning(
|
144
|
+
"Error response from CDK: %s\n%s",
|
145
|
+
error_message,
|
146
|
+
messages[-1].trace.error.stack_trace,
|
147
|
+
)
|
148
|
+
raise HTTPException(
|
149
|
+
status_code=422,
|
150
|
+
detail=f"AirbyteTraceMessage response from CDK: {error_message}",
|
151
|
+
)
|
@@ -0,0 +1,76 @@
|
|
1
|
+
from typing import Any, Mapping, Optional
|
2
|
+
|
3
|
+
from airbyte_cdk.models import (
|
4
|
+
AirbyteStream,
|
5
|
+
ConfiguredAirbyteCatalog,
|
6
|
+
ConfiguredAirbyteStream,
|
7
|
+
DestinationSyncMode,
|
8
|
+
SyncMode,
|
9
|
+
)
|
10
|
+
from airbyte_cdk.sources.declarative.manifest_declarative_source import (
|
11
|
+
ManifestDeclarativeSource,
|
12
|
+
)
|
13
|
+
from airbyte_cdk.sources.declarative.parsers.model_to_component_factory import (
|
14
|
+
ModelToComponentFactory,
|
15
|
+
)
|
16
|
+
|
17
|
+
SHOULD_NORMALIZE_KEY = "__should_normalize"
|
18
|
+
SHOULD_MIGRATE_KEY = "__should_migrate"
|
19
|
+
|
20
|
+
|
21
|
+
def build_catalog(stream_name: str) -> ConfiguredAirbyteCatalog:
|
22
|
+
return ConfiguredAirbyteCatalog(
|
23
|
+
streams=[
|
24
|
+
ConfiguredAirbyteStream(
|
25
|
+
stream=AirbyteStream(
|
26
|
+
name=stream_name,
|
27
|
+
json_schema={},
|
28
|
+
supported_sync_modes=[SyncMode.full_refresh, SyncMode.incremental],
|
29
|
+
),
|
30
|
+
sync_mode=SyncMode.incremental,
|
31
|
+
destination_sync_mode=DestinationSyncMode.overwrite,
|
32
|
+
)
|
33
|
+
]
|
34
|
+
)
|
35
|
+
|
36
|
+
|
37
|
+
def should_migrate_manifest(manifest: Mapping[str, Any]) -> bool:
|
38
|
+
"""
|
39
|
+
Determines whether the manifest should be migrated,
|
40
|
+
based on the presence of the "__should_migrate" key.
|
41
|
+
|
42
|
+
This flag is set by the UI.
|
43
|
+
"""
|
44
|
+
return manifest.get(SHOULD_MIGRATE_KEY, False)
|
45
|
+
|
46
|
+
|
47
|
+
def should_normalize_manifest(manifest: Mapping[str, Any]) -> bool:
|
48
|
+
"""
|
49
|
+
Determines whether the manifest should be normalized,
|
50
|
+
based on the presence of the "__should_normalize" key.
|
51
|
+
|
52
|
+
This flag is set by the UI.
|
53
|
+
"""
|
54
|
+
return manifest.get(SHOULD_NORMALIZE_KEY, False)
|
55
|
+
|
56
|
+
|
57
|
+
def build_source(
|
58
|
+
manifest: Mapping[str, Any],
|
59
|
+
config: Mapping[str, Any],
|
60
|
+
page_limit: Optional[int] = None,
|
61
|
+
slice_limit: Optional[int] = None,
|
62
|
+
) -> ManifestDeclarativeSource:
|
63
|
+
return ManifestDeclarativeSource(
|
64
|
+
source_config=manifest,
|
65
|
+
config=config,
|
66
|
+
normalize_manifest=should_normalize_manifest(manifest),
|
67
|
+
migrate_manifest=should_migrate_manifest(manifest),
|
68
|
+
emit_connector_builder_messages=True,
|
69
|
+
component_factory=ModelToComponentFactory(
|
70
|
+
emit_connector_builder_messages=True,
|
71
|
+
limit_pages_fetched_per_slice=page_limit,
|
72
|
+
limit_slices_fetched=slice_limit,
|
73
|
+
disable_retries=True,
|
74
|
+
disable_cache=True,
|
75
|
+
),
|
76
|
+
)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
|
2
|
+
"""Main entry point for the Airbyte Manifest Server server."""
|
3
|
+
|
4
|
+
import uvicorn
|
5
|
+
|
6
|
+
|
7
|
+
def run_server(
|
8
|
+
host: str = "127.0.0.1", port: int = 8000, reload: bool = False, log_level: str = "info"
|
9
|
+
) -> None:
|
10
|
+
"""Run the FastAPI server."""
|
11
|
+
|
12
|
+
print(f"🚀 Starting Airbyte CDK Manifest Server on {host}:{port}")
|
13
|
+
|
14
|
+
uvicorn.run(
|
15
|
+
"airbyte_cdk.manifest_server.app:app",
|
16
|
+
host=host,
|
17
|
+
port=port,
|
18
|
+
reload=reload,
|
19
|
+
log_level=log_level,
|
20
|
+
)
|
21
|
+
|
22
|
+
|
23
|
+
if __name__ == "__main__":
|
24
|
+
run_server()
|