feat: 支持 v2 插件、独立前端和签名制品发布 (#130)

* feat: 支持 v2 插件、原生扩展与签名发布

* fix: 修复测试

* feat: 增强宿主 SDK、运行观测与制品维护能力

* feat: 增强文件传输、配置观测与本地开发能力

* feat: 支持 SSE 实时事件流并完善开发脚手架

* feat: 完善长连接鉴权复核与关闭回收

* feat: 增强生命周期与任务关闭可靠性

* feat: 收紧健康检查契约并补齐前端与真实网络验收

* feat: 增加SDK溯源与离线更新工具并验证跨版本兼容

* feat: 增加持久化业务示例与受控 Python 交付

* feat: 增加统一运行诊断与多worker状态观测

* feat: 增加固定目标发布等待与自动验收

* fix: 修复多环境插件部署前缀与代理配置不一致

* fix: 修复测试
This commit is contained in:
insistence
2026-10-09 23:49:45 +08:00
committed by GitHub
parent a89aec54aa
commit 4bd83bc7cd
287 changed files with 41945 additions and 331 deletions
@@ -0,0 +1,79 @@
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
from typing import Any
from fastapi import FastAPI, HTTPException, Request
from pydantic import BaseModel, Field
from plugins.core.sdk import PluginDefinition, PluginHostContext, PluginRequestContext, plugin_endpoint
class EchoBody(BaseModel):
"""
SDK 请求体模型,约束示例消息长度。
"""
message: str = Field(min_length=1, max_length=200)
async def echo(context: PluginRequestContext) -> dict[str, Any]:
return {**context.request.to_payload(), 'requestId': context.request_id}
def create_plugin(host: PluginHostContext) -> PluginDefinition:
"""
声明子应用工厂,资源初始化交给子应用生命周期。
:param host: 宿主提供的插件上下文
:return: 插件能力声明
"""
return PluginDefinition(app_factory=create_app)
def create_app(host: PluginHostContext) -> FastAPI:
"""
为当前 worker 创建独立的 ASGI 子应用。
:param host: 宿主提供的插件上下文
:return: 包含权限检查和生命周期管理的子应用
"""
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[dict[str, str], None]:
"""
演示插件自有资源的启动与关闭。
:param app: 正在启动或关闭的 ASGI 子应用
:return: 可供请求访问的生命周期状态
"""
host.logger.info('ASGI 示例启动')
try:
yield {'message': '子应用资源已就绪'}
finally:
host.logger.info('ASGI 示例关闭')
app = FastAPI(title='ASGI 插件示例', lifespan=lifespan, docs_url=None, redoc_url=None)
@app.get(
'/api/info',
summary='获取ASGI插件信息接口',
description='用于获取当前插件标识、宿主API版本和子应用资源状态',
)
async def info(request: Request) -> dict[str, str]:
context = request.state.plugin_context
try:
context.require_permission('asgi_demo:view')
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
return {'pluginId': host.plugin_id, 'hostApiVersion': host.api_version, 'message': request.state.message}
app.add_api_route(
'/api/echo/{item_id}',
plugin_endpoint(echo, permission='asgi_demo:view', body_model=EchoBody),
methods=['POST'],
summary='验证ASGI插件请求上下文接口',
description='返回校验后的请求体、路径参数、多值查询参数与宿主追踪标识',
response_model=dict[str, Any],
)
return app