service-forge 0.1.24__py3-none-any.whl → 0.1.27__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.

Potentially problematic release.


This version of service-forge might be problematic. Click here for more details.

@@ -3,7 +3,7 @@ import uvicorn
3
3
  from fastapi import APIRouter
4
4
  from loguru import logger
5
5
  from urllib.parse import urlparse
6
- from fastapi import HTTPException, Request
6
+ from fastapi import HTTPException, Request, WebSocket, WebSocketException
7
7
  from fastapi.middleware.cors import CORSMiddleware
8
8
  from fastapi.openapi.utils import get_openapi
9
9
  from service_forge.api.routers.websocket.websocket_router import websocket_router
@@ -36,6 +36,88 @@ def is_trusted_origin(origin_host: str, host: str, trusted_root: str = "ring.shi
36
36
  )
37
37
 
38
38
 
39
+ def validate_auth_from_headers(
40
+ headers: dict,
41
+ origin: str | None,
42
+ scheme: str,
43
+ host: str,
44
+ trusted_domain: str = "ring.shiweinan.com",
45
+ ) -> tuple[str | None, str | None]:
46
+ """
47
+ Validate authentication from headers and return user_id and token.
48
+
49
+ Args:
50
+ headers: Dictionary of headers (can be from Request or WebSocket)
51
+ origin: Origin header value
52
+ scheme: URL scheme (http/https/ws/wss)
53
+ host: Host header value
54
+ trusted_domain: Trusted domain for origin validation
55
+
56
+ Returns:
57
+ tuple: (user_id, auth_token) - user_id can be None if not authenticated and not same origin
58
+ """
59
+ is_same_origin = False
60
+
61
+ logger.debug(f"origin {origin}, host:{host}")
62
+
63
+ if origin and host:
64
+ try:
65
+ parsed_origin = urlparse(origin)
66
+ parsed_host = urlparse(f"{scheme}://{host}")
67
+ is_same_origin = (
68
+ parsed_origin.hostname == parsed_host.hostname
69
+ and parsed_origin.port == parsed_host.port
70
+ and is_trusted_origin(parsed_origin.hostname, parsed_host.hostname, trusted_domain)
71
+ )
72
+ except Exception:
73
+ pass
74
+
75
+ user_id = headers.get("X-User-ID")
76
+ token = headers.get("X-User-Token")
77
+
78
+ if not is_same_origin:
79
+ # For cross-origin requests, user_id is required
80
+ if not user_id:
81
+ return None, None
82
+ return user_id, token
83
+ else:
84
+ # For same-origin requests, user_id defaults to "0" if not provided
85
+ return user_id if user_id else "0", token
86
+
87
+
88
+ async def authenticate_websocket(
89
+ websocket: WebSocket,
90
+ trusted_domain: str = "ring.shiweinan.com",
91
+ ) -> None:
92
+ """
93
+ Authenticate WebSocket connection and set user_id and auth_token in websocket.state.
94
+
95
+ Args:
96
+ websocket: WebSocket instance
97
+ trusted_domain: Trusted domain for origin validation
98
+
99
+ Raises:
100
+ WebSocketException: If authentication fails
101
+ """
102
+ origin = websocket.headers.get("origin") or websocket.headers.get("referer")
103
+ scheme = websocket.url.scheme
104
+ host = websocket.headers.get("host", "")
105
+
106
+ user_id, token = validate_auth_from_headers(
107
+ websocket.headers,
108
+ origin,
109
+ scheme,
110
+ host,
111
+ trusted_domain,
112
+ )
113
+
114
+ if user_id is None:
115
+ raise WebSocketException(code=1008, reason="Unauthorized")
116
+
117
+ websocket.state.user_id = user_id
118
+ websocket.state.auth_token = token
119
+
120
+
39
121
  def create_app(
40
122
  app: FastAPI | None = None,
41
123
  routers: list[APIRouter] | None = None,
@@ -77,6 +159,10 @@ def create_app(
77
159
  for router in routers:
78
160
  app.include_router(router)
79
161
 
162
+ # Store auth configuration in app.state for WebSocket endpoints to access
163
+ app.state.enable_auth_middleware = enable_auth_middleware
164
+ app.state.trusted_domain = trusted_domain
165
+
80
166
  # Always include WebSocket router
81
167
  app.include_router(websocket_router)
82
168
 
@@ -100,31 +186,20 @@ def create_app(
100
186
  origin = request.headers.get("origin") or request.headers.get("referer")
101
187
  scheme = request.url.scheme
102
188
  host = request.headers.get("host", "")
103
- is_same_origin = False
104
189
 
105
- logger.debug(f"origin {origin}, host:{host}")
190
+ user_id, token = validate_auth_from_headers(
191
+ request.headers,
192
+ origin,
193
+ scheme,
194
+ host,
195
+ trusted_domain,
196
+ )
197
+
198
+ if user_id is None:
199
+ raise HTTPException(status_code=401, detail="Unauthorized")
106
200
 
107
- if origin and host:
108
- try:
109
- parsed_origin = urlparse(origin)
110
- parsed_host = urlparse(f"{scheme}://{host}")
111
- is_same_origin = (
112
- parsed_origin.hostname == parsed_host.hostname
113
- and parsed_origin.port == parsed_host.port
114
- and is_trusted_origin(parsed_origin.hostname, parsed_host.hostname, trusted_domain)
115
- )
116
- except Exception:
117
- pass # If parsing fails, continue with default behavior
118
- if not is_same_origin:
119
- headers = request.headers
120
- user_id = headers.get("X-User-ID")
121
- if not user_id:
122
- raise HTTPException(status_code=401, detail="Unauthorized")
123
-
124
- request.state.user_id = user_id
125
- else:
126
- # Same-origin requests can skip auth, but still set default user_id
127
- request.state.user_id = "0" # Can be None or default value as needed
201
+ request.state.user_id = user_id
202
+ request.state.auth_token = token
128
203
 
129
204
  return await call_next(request)
130
205
 
@@ -147,6 +222,7 @@ async def start_fastapi_server(host: str, port: int):
147
222
 
148
223
  try:
149
224
  metadata = load_metadata("sf-meta.yaml")
150
- fastapi_app = create_app(enable_auth_middleware=False, root_path=f"/api/v1/{get_service_url_name(metadata.name, metadata.version)}")
225
+ fastapi_app = create_app(enable_auth_middleware=metadata.enable_auth_middleware, root_path=f"/api/v1/{get_service_url_name(metadata.name, metadata.version)}")
151
226
  except Exception as e:
152
- fastapi_app = create_app(enable_auth_middleware=False, root_path=None)
227
+ logger.warning(f"Failed to load metadata, using default configuration: {e}")
228
+ fastapi_app = create_app(enable_auth_middleware=True, root_path=None)
@@ -9,6 +9,19 @@ websocket_router = APIRouter()
9
9
 
10
10
  @websocket_router.websocket("/sdk/ws")
11
11
  async def sdk_websocket_endpoint(websocket: WebSocket):
12
+ # Authenticate WebSocket connection before accepting
13
+ # Get trusted_domain from app.state if available
14
+ # trusted_domain = getattr(websocket.app.state, "trusted_domain", "ring.shiweinan.com")
15
+ # enable_auth = getattr(websocket.app.state, "enable_auth_middleware", True)
16
+
17
+ # if enable_auth:
18
+ # from service_forge.api.http_api import authenticate_websocket
19
+ # await authenticate_websocket(websocket, trusted_domain)
20
+ # else:
21
+ # # If auth is disabled, set default values
22
+ # websocket.state.user_id = websocket.headers.get("X-User-ID", "0")
23
+ # websocket.state.auth_token = websocket.headers.get("X-User-Token")
24
+
12
25
  await websocket.accept()
13
26
  try:
14
27
  while True:
service_forge/service.py CHANGED
@@ -4,6 +4,7 @@ import os
4
4
  import asyncio
5
5
  import threading
6
6
  import uuid
7
+ from importlib.metadata import version
7
8
  from loguru import logger
8
9
  from typing import Callable, AsyncIterator, Awaitable, Any, TYPE_CHECKING
9
10
  from service_forge.workflow.node import node_register
@@ -260,6 +261,12 @@ class Service:
260
261
 
261
262
  @staticmethod
262
263
  def from_config(metadata: SfMetadata, service_env: dict[str, Any] = None, config: ServiceConfig = None) -> Service:
264
+ try:
265
+ service_forge_version = version("service-forge")
266
+ logger.info(f"service-forge version: {service_forge_version}")
267
+ except Exception as e:
268
+ logger.warning(f"Failed to get service-forge version: {e}")
269
+
263
270
  if config is not None:
264
271
  config_path = None
265
272
  else:
@@ -133,9 +133,14 @@ class Injector:
133
133
  f.write(new_content)
134
134
 
135
135
  def inject(self) -> None:
136
- self.inject_deployment()
137
- self.inject_service_config()
138
- self.inject_ingress()
139
- self.inject_dockerfile()
140
- self.inject_pyproject_toml()
141
- self.clear_start_sh()
136
+ if self.metadata.inject.deployment:
137
+ self.inject_deployment()
138
+ if self.metadata.inject.service_config:
139
+ self.inject_service_config()
140
+ if self.metadata.inject.ingress:
141
+ self.inject_ingress()
142
+ if self.metadata.inject.dockerfile:
143
+ self.inject_dockerfile()
144
+ if self.metadata.inject.pyproject_toml:
145
+ self.inject_pyproject_toml()
146
+ self.clear_start_sh()
@@ -1,30 +1,29 @@
1
- from omegaconf import OmegaConf
1
+ from __future__ import annotations
2
+ import yaml
3
+ from pydantic import BaseModel
2
4
 
3
- class SfMetadata:
4
- def __init__(
5
- self,
6
- name: str,
7
- version: str,
8
- description: str,
9
- service_config: str,
10
- config_only: bool,
11
- env: list[dict],
12
- ) -> None:
13
- self.name = name
14
- self.version = version
15
- self.description = description
16
- self.service_config = service_config
17
- self.config_only = config_only
18
- self.env = env
5
+ class SfMetadataInject(BaseModel):
6
+ deployment: bool = True
7
+ service_config: bool = True
8
+ ingress: bool = True
9
+ dockerfile: bool = True
10
+ pyproject_toml: bool = True
11
+
12
+ class SfMetadata(BaseModel):
13
+ name: str
14
+ version: str
15
+ description: str
16
+ service_config: str
17
+ config_only: bool
18
+ env: list[dict]
19
+ inject: SfMetadataInject = SfMetadataInject()
20
+ enable_auth_middleware: bool = True
21
+
22
+ @classmethod
23
+ def from_yaml_file(cls, filepath: str) -> SfMetadata:
24
+ with open(filepath, 'r', encoding='utf-8') as f:
25
+ data = yaml.safe_load(f)
26
+ return cls(**data)
19
27
 
20
28
  def load_metadata(path: str) -> SfMetadata:
21
- with open(path, 'r') as file:
22
- data = OmegaConf.load(file)
23
- return SfMetadata(
24
- name=data.get('name'),
25
- version=data.get('version'),
26
- description=data.get('description'),
27
- service_config=data.get('service_config'),
28
- config_only=data.get('config_only'),
29
- env=data.get('env', []),
30
- )
29
+ return SfMetadata.from_yaml_file(path)
@@ -2,7 +2,6 @@ import typer
2
2
  from pathlib import Path
3
3
  from typing import Callable, TypeVar, Any
4
4
  from service_forge.sft.util.logger import log_error, log_info
5
- from service_forge.sft.config.sf_metadata import load_metadata, SfMetadata
6
5
 
7
6
  T = TypeVar('T')
8
7
 
@@ -26,6 +26,7 @@ class FastAPITrigger(Trigger):
26
26
  DEFAULT_OUTPUT_PORTS = [
27
27
  Port("trigger", bool),
28
28
  Port("user_id", int),
29
+ Port("token", str),
29
30
  Port("data", Any),
30
31
  ]
31
32
 
@@ -72,6 +73,7 @@ class FastAPITrigger(Trigger):
72
73
  self.trigger_queue.put_nowait({
73
74
  "id": task_id,
74
75
  "user_id": getattr(request.state, "user_id", None),
76
+ "token": getattr(request.state, "auth_token", None),
75
77
  "data": converted_data,
76
78
  })
77
79
 
@@ -169,6 +171,7 @@ class FastAPITrigger(Trigger):
169
171
  try:
170
172
  trigger = await self.trigger_queue.get()
171
173
  self.prepare_output_edges(self.get_output_port_by_name('user_id'), trigger['user_id'])
174
+ self.prepare_output_edges(self.get_output_port_by_name('token'), trigger['token'])
172
175
  self.prepare_output_edges(self.get_output_port_by_name('data'), trigger['data'])
173
176
  yield self.trigger(trigger['id'])
174
177
  except Exception as e:
@@ -9,6 +9,7 @@ from fastapi import FastAPI, WebSocket, WebSocketDisconnect
9
9
  from service_forge.workflow.port import Port
10
10
  from google.protobuf.message import Message
11
11
  from google.protobuf.json_format import MessageToJson
12
+ from service_forge.api.http_api import authenticate_websocket
12
13
 
13
14
  class WebSocketAPITrigger(Trigger):
14
15
  DEFAULT_INPUT_PORTS = [
@@ -19,6 +20,8 @@ class WebSocketAPITrigger(Trigger):
19
20
 
20
21
  DEFAULT_OUTPUT_PORTS = [
21
22
  Port("trigger", bool),
23
+ Port("user_id", int),
24
+ Port("token", str),
22
25
  Port("data", Any),
23
26
  ]
24
27
 
@@ -36,6 +39,20 @@ class WebSocketAPITrigger(Trigger):
36
39
  )
37
40
  return result
38
41
 
42
+ async def send_message(
43
+ self,
44
+ websocket: WebSocket,
45
+ type: str,
46
+ task_id: uuid.UUID,
47
+ data: Any,
48
+ ):
49
+ message = {
50
+ "type": type,
51
+ "task_id": str(task_id),
52
+ "data": data
53
+ }
54
+ await websocket.send_text(json.dumps(message))
55
+
39
56
  async def handle_stream_output(
40
57
  self,
41
58
  websocket: WebSocket,
@@ -46,12 +63,7 @@ class WebSocketAPITrigger(Trigger):
46
63
  item = await self.stream_queues[task_id].get()
47
64
 
48
65
  if item.is_error:
49
- error_response = {
50
- "type": "stream_error",
51
- "task_id": str(task_id),
52
- "detail": str(item.result)
53
- }
54
- await websocket.send_text(json.dumps(error_response))
66
+ await self.send_message(websocket, "stream_error", task_id, str(item.result))
55
67
  break
56
68
 
57
69
  if item.is_end:
@@ -65,18 +77,9 @@ class WebSocketAPITrigger(Trigger):
65
77
  data = serialized
66
78
  else:
67
79
  data = serialized
68
-
69
- end_response = {
70
- "type": "stream_end",
71
- "task_id": str(task_id),
72
- "data": data
73
- }
80
+ await self.send_message(websocket, "stream_end", task_id, data)
74
81
  else:
75
- end_response = {
76
- "type": "stream_end",
77
- "task_id": str(task_id)
78
- }
79
- await websocket.send_text(json.dumps(end_response))
82
+ await self.send_message(websocket, "stream_end", task_id, None)
80
83
  break
81
84
 
82
85
  # Send stream data
@@ -89,23 +92,10 @@ class WebSocketAPITrigger(Trigger):
89
92
  else:
90
93
  data = serialized
91
94
 
92
- stream_response = {
93
- "type": "stream",
94
- "task_id": str(task_id),
95
- "data": data
96
- }
97
- await websocket.send_text(json.dumps(stream_response))
95
+ await self.send_message(websocket, "stream", task_id, data)
98
96
  except Exception as e:
99
97
  logger.error(f"Error handling stream output for task {task_id}: {e}")
100
- error_response = {
101
- "type": "stream_error",
102
- "task_id": str(task_id),
103
- "detail": str(e)
104
- }
105
- try:
106
- await websocket.send_text(json.dumps(error_response))
107
- except Exception:
108
- pass
98
+ await self.send_message(websocket, "stream_error", task_id, str(e))
109
99
  finally:
110
100
  if task_id in self.stream_queues:
111
101
  del self.stream_queues[task_id]
@@ -120,6 +110,8 @@ class WebSocketAPITrigger(Trigger):
120
110
  self.result_queues[task_id] = asyncio.Queue()
121
111
  self.stream_queues[task_id] = asyncio.Queue()
122
112
 
113
+ logger.info('user_id', getattr(websocket.state, "user_id", None), 'token', getattr(websocket.state, "auth_token", None))
114
+
123
115
  if data_type is Any:
124
116
  converted_data = message_data
125
117
  else:
@@ -136,6 +128,8 @@ class WebSocketAPITrigger(Trigger):
136
128
 
137
129
  self.trigger_queue.put_nowait({
138
130
  "id": task_id,
131
+ "user_id": getattr(websocket.state, "user_id", None),
132
+ "token": getattr(websocket.state, "auth_token", None),
139
133
  "data": converted_data,
140
134
  })
141
135
 
@@ -143,6 +137,18 @@ class WebSocketAPITrigger(Trigger):
143
137
 
144
138
  def _setup_websocket(self, app: FastAPI, path: str, data_type: type) -> None:
145
139
  async def websocket_handler(websocket: WebSocket):
140
+ # Authenticate WebSocket connection before accepting
141
+ # Get trusted_domain from app.state if available
142
+ trusted_domain = getattr(app.state, "trusted_domain", "ring.shiweinan.com")
143
+ enable_auth = getattr(app.state, "enable_auth_middleware", True)
144
+
145
+ if enable_auth:
146
+ await authenticate_websocket(websocket, trusted_domain)
147
+ else:
148
+ # If auth is disabled, set default values
149
+ websocket.state.user_id = websocket.headers.get("X-User-ID", "0")
150
+ websocket.state.auth_token = websocket.headers.get("X-User-Token")
151
+
146
152
  await websocket.accept()
147
153
 
148
154
  try:
@@ -178,6 +184,8 @@ class WebSocketAPITrigger(Trigger):
178
184
  while True:
179
185
  try:
180
186
  trigger = await self.trigger_queue.get()
187
+ self.prepare_output_edges(self.get_output_port_by_name('user_id'), trigger['user_id'])
188
+ self.prepare_output_edges(self.get_output_port_by_name('token'), trigger['token'])
181
189
  self.prepare_output_edges(self.get_output_port_by_name('data'), trigger['data'])
182
190
  yield self.trigger(trigger['id'])
183
191
  except Exception as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: service-forge
3
- Version: 0.1.24
3
+ Version: 0.1.27
4
4
  Summary: Add your description here
5
5
  Author-email: euxcet <zcc.qwer@gmail.com>
6
6
  Requires-Python: >=3.11
@@ -1,16 +1,16 @@
1
1
  service_forge/current_service.py,sha256=0YKm7nQiXzUUAc1ToCcbG1QPJfOSNKcOHUpyJ4E3xrY,342
2
- service_forge/service.py,sha256=rZZ7-BXTTCrc6KqnONnKpg-bRs5JCfDTvMrl4K26vbE,12633
2
+ service_forge/service.py,sha256=lHsZraEH6Ze20QO5v6iW1MO8src8T8JKLFRBXtd0LD0,12933
3
3
  service_forge/service_config.py,sha256=zsTdCZ1peMAotjGEVypPos7d-gjwrYoB9x_12g95G4g,1242
4
4
  service_forge/api/deprecated_websocket_api.py,sha256=E36-fpUPxzMJ2YGlCPeqwRbryk2FMMbQD_pbb8k1FYI,3343
5
5
  service_forge/api/deprecated_websocket_manager.py,sha256=Xiwg3zwXRVi63sXmVH-TgbpL2XH_djyLeo96STm4cNM,16757
6
- service_forge/api/http_api.py,sha256=XnEQ45zuWQV1zrSL9vd3USUh47ymkVc4w_1SoFlNdl8,5648
6
+ service_forge/api/http_api.py,sha256=8vcN7oyxwTwu_w1f-Egh2XrFWsm-ci5_gk7KsQiP1iM,7673
7
7
  service_forge/api/http_api_doc.py,sha256=ASlxvsIiUzDcMhVoumRjt9CfEMbh0O1U4ZLC9eobLF8,20235
8
8
  service_forge/api/kafka_api.py,sha256=PInx2ZzKJRON7EaJFWroXkiOt_UeZY7WE6qK03gq4ak,4599
9
9
  service_forge/api/task_manager.py,sha256=9Lk-NV4cBnuv9b8V6GVLWJJ4MCiAwCp5TVAwmYgqXbs,5269
10
10
  service_forge/api/routers/feedback/feedback_router.py,sha256=JOJI6kaQYapg4__iA6Eo26_9su48p7R2Kpn422nbsxw,5640
11
11
  service_forge/api/routers/service/service_router.py,sha256=hGOT-ScnXR7agHp-F9OFGWiPFjG9f3gl7NBsnayW3JI,5088
12
12
  service_forge/api/routers/websocket/websocket_manager.py,sha256=j1AFqzXQhZZyaLQwhvZefXAS-zCOPzLcRMDEuusv6V0,3605
13
- service_forge/api/routers/websocket/websocket_router.py,sha256=V0B7eQP8toO94-WbTrGraadXD3qeZ9lnKFcxwx6kLgM,3777
13
+ service_forge/api/routers/websocket/websocket_router.py,sha256=sPDJriEpD2mqu4508cOaWK7u040sgOdaUFlyiBqCSgc,4447
14
14
  service_forge/db/__init__.py,sha256=EWLhH8bYsMOvRF_YXF6FgL3irKA6GZeLxSGvWDRM6f8,85
15
15
  service_forge/db/database.py,sha256=WKtZ0MoOnbMw54ohfs9zKsrOZ5_qenLvXkAV_Gr2WOs,10068
16
16
  service_forge/db/migrations/feedback_migration.py,sha256=-zQ71TsOlWmQPQo1NKSIu3C1T47v3cfD6IAQ5HE_ffk,4845
@@ -30,15 +30,15 @@ service_forge/sft/cmd/remote_deploy.py,sha256=AStAlbqGD7XeZFhL0fx2j12YWP_MVbdURb
30
30
  service_forge/sft/cmd/remote_list_tars.py,sha256=mx6hkNnu0ySMyBX2Qi6blKMj5xnNnrmXq3VD_nERlmw,4176
31
31
  service_forge/sft/cmd/service_command.py,sha256=69GMMN61KtuoEFuYzFJ74ivNt8RX8q0I6rbePfJfEwQ,5538
32
32
  service_forge/sft/cmd/upload_service.py,sha256=86PvvJSXCZKH4BU6rLytuc45grX-sRnQnOHCo9zUaPY,1232
33
- service_forge/sft/config/injector.py,sha256=-eU21Ob09ond9pwHVkjklAd5_qLWWbbf0b91iCg2Kwk,6335
33
+ service_forge/sft/config/injector.py,sha256=V79AW1W_LyU-Hn2QgJlLyTt8tdI3J1t1jS3wRoXfbSo,6581
34
34
  service_forge/sft/config/injector_default_files.py,sha256=f7mNJ5Y9yb4e9kjLn414WiQoZrOue9ok_hq_POG4I2o,2717
35
- service_forge/sft/config/sf_metadata.py,sha256=Y9akhSCgOd11-oqRs3LIs8FL9pvWNw6hyy57fuFcBhc,866
35
+ service_forge/sft/config/sf_metadata.py,sha256=RruOe3_6JdxLnzMbmdnOcncxwnmATR-1q3Cn8R9d5eE,782
36
36
  service_forge/sft/config/sft_config.py,sha256=MgurtgbcSmyXbGlVX3NG84KD4Hst1gZWHdF9a8zi-6U,7707
37
37
  service_forge/sft/file/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
38
  service_forge/sft/file/ignore_pattern.py,sha256=UrVmR83wOx51XHFcZDTPp15dGYcvMTE5W1m07-SvHpw,2521
39
39
  service_forge/sft/file/sft_file_manager.py,sha256=poIM77tZZg7vfwBdCsdQctBbCczVLQePdTwVINEABvE,4337
40
40
  service_forge/sft/kubernetes/kubernetes_manager.py,sha256=IF2_X9U-k5Dx7EZuGrJ9lZ85ltbilrrZDfsl8qFyTu4,11339
41
- service_forge/sft/util/assert_util.py,sha256=8HreVkOzs9_ClKiFqG4qsFn_yyDLo5uXYhYUPXlmDjM,828
41
+ service_forge/sft/util/assert_util.py,sha256=6XVTsXKxg92ww3heWzuMvTbybGuw1cmTqWqfiSbPAcY,753
42
42
  service_forge/sft/util/logger.py,sha256=0Hi74IoxshE-wBgvBa2EZPXYj37tTrUYwlOBd9UMMMs,502
43
43
  service_forge/sft/util/name_util.py,sha256=WSYHM6c7SZULXCFON7nmGqsvAPPs_wavd6QjCa4UbRQ,301
44
44
  service_forge/sft/util/yaml_utils.py,sha256=9OhJNQlzj_C1NeQoUZVF8qpDovrE7RDWtNXe-H7tuNA,1703
@@ -74,12 +74,12 @@ service_forge/workflow/nodes/test/if_console_input_node.py,sha256=CtKHkFqr8PN974
74
74
  service_forge/workflow/nodes/test/time_consuming_node.py,sha256=gB2qw2DdjRf82z1158u36nSnCHrheHaxscAzPRnXNyk,1813
75
75
  service_forge/workflow/triggers/__init__.py,sha256=iQ0WEYu6JgL191Y9XslMhZ7jS7JO8bL3SZ9YqIw5LCM,269
76
76
  service_forge/workflow/triggers/a2a_api_trigger.py,sha256=Oaw3vRLA8fWZUIQ-h33dYmojmjp4mwNF_0LHqQ_4mZQ,8583
77
- service_forge/workflow/triggers/fast_api_trigger.py,sha256=8BF0A8gdcKeiP3cyF_dF0T3MH7bXnnZRCa_h5hx9kQ4,7513
77
+ service_forge/workflow/triggers/fast_api_trigger.py,sha256=bAtnuNkUcB5rApXj7x3oBscdavUnDGTb7lE9OpmtauE,7705
78
78
  service_forge/workflow/triggers/kafka_api_trigger.py,sha256=Zv8J75Rmg1-xqxHwpBMBhsm_TWX8p3_rqldk2RVSwVc,1561
79
79
  service_forge/workflow/triggers/once_trigger.py,sha256=YmzSQBoKE-8liNFIoDCqi2UdqhHujizsXVDft81_8jA,572
80
80
  service_forge/workflow/triggers/period_trigger.py,sha256=JFX3yBjKqoRP55jiulaSG_SPO-zWLMcwEb1BwcKsWUM,767
81
- service_forge/workflow/triggers/websocket_api_trigger.py,sha256=JjRYb0VM_em90_w3QEErgxMDBCaBHCrSBhTaV4Fl4HY,6894
82
- service_forge-0.1.24.dist-info/METADATA,sha256=tOQocyV5Smmw3sdoR6k-0MBwB-C0eaMGlG2hRDGj4AY,2308
83
- service_forge-0.1.24.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
84
- service_forge-0.1.24.dist-info/entry_points.txt,sha256=WHntHW7GAyKQUEeMcMvHDZ7_xAb0-cZeAK4iJeu9lm8,51
85
- service_forge-0.1.24.dist-info/RECORD,,
81
+ service_forge/workflow/triggers/websocket_api_trigger.py,sha256=JmA0NkOjbskvP6j7Oook2VkHvY4r4OdX6CBih7D5NBg,7588
82
+ service_forge-0.1.27.dist-info/METADATA,sha256=8_qXSBKj6S4P15B2mJW1ZXy1I4d6AT4YXOJPtasMTOw,2308
83
+ service_forge-0.1.27.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
84
+ service_forge-0.1.27.dist-info/entry_points.txt,sha256=WHntHW7GAyKQUEeMcMvHDZ7_xAb0-cZeAK4iJeu9lm8,51
85
+ service_forge-0.1.27.dist-info/RECORD,,