django-cfg 1.4.62__py3-none-any.whl → 1.4.64__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 django-cfg might be problematic. Click here for more details.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/accounts/services/otp_service.py +3 -14
- django_cfg/apps/centrifugo/__init__.py +57 -0
- django_cfg/apps/centrifugo/admin/__init__.py +13 -0
- django_cfg/apps/centrifugo/admin/centrifugo_log.py +249 -0
- django_cfg/apps/centrifugo/admin/config.py +82 -0
- django_cfg/apps/centrifugo/apps.py +31 -0
- django_cfg/apps/centrifugo/codegen/IMPLEMENTATION_SUMMARY.md +475 -0
- django_cfg/apps/centrifugo/codegen/README.md +242 -0
- django_cfg/apps/centrifugo/codegen/USAGE.md +616 -0
- django_cfg/apps/centrifugo/codegen/__init__.py +19 -0
- django_cfg/apps/centrifugo/codegen/discovery.py +246 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/__init__.py +5 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/generator.py +174 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/README.md.j2 +182 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/client.go.j2 +64 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/go.mod.j2 +10 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2 +300 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2.old +267 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/types.go.j2 +16 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/__init__.py +7 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/generator.py +241 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/README.md.j2 +128 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/__init__.py.j2 +22 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/client.py.j2 +73 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/models.py.j2 +19 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/requirements.txt.j2 +8 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/rpc_client.py.j2 +193 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/__init__.py +5 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/generator.py +124 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/README.md.j2 +38 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/client.ts.j2 +25 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/index.ts.j2 +12 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/package.json.j2 +13 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/rpc-client.ts.j2 +137 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/tsconfig.json.j2 +14 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/types.ts.j2 +9 -0
- django_cfg/apps/centrifugo/codegen/utils/__init__.py +37 -0
- django_cfg/apps/centrifugo/codegen/utils/naming.py +155 -0
- django_cfg/apps/centrifugo/codegen/utils/type_converter.py +349 -0
- django_cfg/apps/centrifugo/decorators.py +137 -0
- django_cfg/apps/centrifugo/management/__init__.py +1 -0
- django_cfg/apps/centrifugo/management/commands/__init__.py +1 -0
- django_cfg/apps/centrifugo/management/commands/generate_centrifugo_clients.py +254 -0
- django_cfg/apps/centrifugo/managers/__init__.py +12 -0
- django_cfg/apps/centrifugo/managers/centrifugo_log.py +264 -0
- django_cfg/apps/centrifugo/migrations/0001_initial.py +164 -0
- django_cfg/apps/centrifugo/migrations/__init__.py +3 -0
- django_cfg/apps/centrifugo/models/__init__.py +11 -0
- django_cfg/apps/centrifugo/models/centrifugo_log.py +210 -0
- django_cfg/apps/centrifugo/registry.py +106 -0
- django_cfg/apps/centrifugo/router.py +125 -0
- django_cfg/apps/centrifugo/serializers/__init__.py +40 -0
- django_cfg/apps/centrifugo/serializers/admin_api.py +264 -0
- django_cfg/apps/centrifugo/serializers/channels.py +26 -0
- django_cfg/apps/centrifugo/serializers/health.py +17 -0
- django_cfg/apps/centrifugo/serializers/publishes.py +16 -0
- django_cfg/apps/centrifugo/serializers/stats.py +21 -0
- django_cfg/apps/centrifugo/services/__init__.py +12 -0
- django_cfg/apps/centrifugo/services/client/__init__.py +29 -0
- django_cfg/apps/centrifugo/services/client/client.py +582 -0
- django_cfg/apps/centrifugo/services/client/config.py +236 -0
- django_cfg/apps/centrifugo/services/client/exceptions.py +212 -0
- django_cfg/apps/centrifugo/services/config_helper.py +63 -0
- django_cfg/apps/centrifugo/services/dashboard_notifier.py +157 -0
- django_cfg/apps/centrifugo/services/logging.py +677 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/css/dashboard.css +260 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_channels.mjs +313 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_testing.mjs +803 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/main.mjs +333 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/overview.mjs +432 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/testing.mjs +33 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/websocket.mjs +210 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/channels_content.html +46 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/live_channels_content.html +123 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/overview_content.html +45 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/publishes_content.html +84 -0
- django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/stat_cards.html +23 -20
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/system_status.html +91 -0
- django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/tab_navigation.html +15 -15
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/testing_tools.html +415 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/layout/base.html +61 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/pages/dashboard.html +58 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/tags/connection_script.html +48 -0
- django_cfg/apps/centrifugo/templatetags/__init__.py +1 -0
- django_cfg/apps/centrifugo/templatetags/centrifugo_tags.py +81 -0
- django_cfg/apps/centrifugo/urls.py +31 -0
- django_cfg/apps/{ipc → centrifugo}/urls_admin.py +4 -4
- django_cfg/apps/centrifugo/views/__init__.py +15 -0
- django_cfg/apps/centrifugo/views/admin_api.py +380 -0
- django_cfg/apps/centrifugo/views/dashboard.py +15 -0
- django_cfg/apps/centrifugo/views/monitoring.py +286 -0
- django_cfg/apps/centrifugo/views/testing_api.py +422 -0
- django_cfg/apps/support/utils/support_email_service.py +5 -18
- django_cfg/apps/tasks/templates/tasks/layout/base.html +0 -2
- django_cfg/apps/urls.py +5 -5
- django_cfg/core/base/config_model.py +4 -44
- django_cfg/core/builders/apps_builder.py +2 -2
- django_cfg/core/generation/integration_generators/third_party.py +8 -8
- django_cfg/core/utils/__init__.py +5 -0
- django_cfg/core/utils/url_helpers.py +73 -0
- django_cfg/modules/base.py +7 -7
- django_cfg/modules/django_client/core/__init__.py +2 -1
- django_cfg/modules/django_client/core/config/config.py +8 -0
- django_cfg/modules/django_client/core/generator/__init__.py +42 -2
- django_cfg/modules/django_client/core/generator/go/__init__.py +14 -0
- django_cfg/modules/django_client/core/generator/go/client_generator.py +124 -0
- django_cfg/modules/django_client/core/generator/go/files_generator.py +133 -0
- django_cfg/modules/django_client/core/generator/go/generator.py +203 -0
- django_cfg/modules/django_client/core/generator/go/models_generator.py +304 -0
- django_cfg/modules/django_client/core/generator/go/naming.py +193 -0
- django_cfg/modules/django_client/core/generator/go/operations_generator.py +134 -0
- django_cfg/modules/django_client/core/generator/go/templates/Makefile.j2 +38 -0
- django_cfg/modules/django_client/core/generator/go/templates/README.md.j2 +55 -0
- django_cfg/modules/django_client/core/generator/go/templates/client.go.j2 +122 -0
- django_cfg/modules/django_client/core/generator/go/templates/enums.go.j2 +49 -0
- django_cfg/modules/django_client/core/generator/go/templates/errors.go.j2 +182 -0
- django_cfg/modules/django_client/core/generator/go/templates/go.mod.j2 +6 -0
- django_cfg/modules/django_client/core/generator/go/templates/main_client.go.j2 +60 -0
- django_cfg/modules/django_client/core/generator/go/templates/middleware.go.j2 +388 -0
- django_cfg/modules/django_client/core/generator/go/templates/models.go.j2 +28 -0
- django_cfg/modules/django_client/core/generator/go/templates/operations_client.go.j2 +142 -0
- django_cfg/modules/django_client/core/generator/go/templates/validation.go.j2 +217 -0
- django_cfg/modules/django_client/core/generator/go/type_mapper.py +380 -0
- django_cfg/modules/django_client/management/commands/generate_client.py +53 -3
- django_cfg/modules/django_client/system/generate_mjs_clients.py +3 -1
- django_cfg/modules/django_client/system/schema_parser.py +5 -1
- django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +1 -0
- django_cfg/modules/django_twilio/sendgrid_service.py +7 -4
- django_cfg/modules/django_unfold/dashboard.py +25 -19
- django_cfg/pyproject.toml +1 -1
- django_cfg/registry/core.py +2 -0
- django_cfg/registry/modules.py +2 -2
- django_cfg/static/js/api/centrifugo/client.mjs +164 -0
- django_cfg/static/js/api/centrifugo/index.mjs +13 -0
- django_cfg/static/js/api/index.mjs +5 -5
- django_cfg/static/js/api/types.mjs +89 -26
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/METADATA +1 -1
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/RECORD +142 -70
- django_cfg/apps/ipc/README.md +0 -346
- django_cfg/apps/ipc/RPC_LOGGING.md +0 -321
- django_cfg/apps/ipc/TESTING.md +0 -539
- django_cfg/apps/ipc/__init__.py +0 -60
- django_cfg/apps/ipc/admin.py +0 -232
- django_cfg/apps/ipc/apps.py +0 -98
- django_cfg/apps/ipc/migrations/0001_initial.py +0 -137
- django_cfg/apps/ipc/migrations/0002_rpclog_is_event.py +0 -23
- django_cfg/apps/ipc/migrations/__init__.py +0 -0
- django_cfg/apps/ipc/models.py +0 -229
- django_cfg/apps/ipc/serializers/__init__.py +0 -29
- django_cfg/apps/ipc/serializers/serializers.py +0 -343
- django_cfg/apps/ipc/services/__init__.py +0 -7
- django_cfg/apps/ipc/services/client/__init__.py +0 -23
- django_cfg/apps/ipc/services/client/client.py +0 -621
- django_cfg/apps/ipc/services/client/config.py +0 -214
- django_cfg/apps/ipc/services/client/exceptions.py +0 -201
- django_cfg/apps/ipc/services/logging.py +0 -239
- django_cfg/apps/ipc/services/monitor.py +0 -466
- django_cfg/apps/ipc/services/rpc_log_consumer.py +0 -330
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/main.mjs +0 -269
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/overview.mjs +0 -259
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/testing.mjs +0 -375
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard.mjs.old +0 -441
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/methods_content.html +0 -22
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/notifications_content.html +0 -9
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/overview_content.html +0 -9
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/requests_content.html +0 -23
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/system_status.html +0 -47
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/testing_tools.html +0 -184
- django_cfg/apps/ipc/templates/django_cfg_ipc/layout/base.html +0 -71
- django_cfg/apps/ipc/templates/django_cfg_ipc/pages/dashboard.html +0 -56
- django_cfg/apps/ipc/urls.py +0 -23
- django_cfg/apps/ipc/views/__init__.py +0 -13
- django_cfg/apps/ipc/views/dashboard.py +0 -15
- django_cfg/apps/ipc/views/monitoring.py +0 -251
- django_cfg/apps/ipc/views/testing.py +0 -285
- django_cfg/static/js/api/ipc/client.mjs +0 -114
- django_cfg/static/js/api/ipc/index.mjs +0 -13
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TypeScript thin wrapper client generator.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import List, Type
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
|
10
|
+
|
|
11
|
+
from ...discovery import RPCMethodInfo
|
|
12
|
+
from ...utils import to_typescript_method_name, pydantic_to_typescript
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TypeScriptThinGenerator:
|
|
18
|
+
"""Generator for TypeScript thin wrapper clients."""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
methods: List[RPCMethodInfo],
|
|
23
|
+
models: List[Type[BaseModel]],
|
|
24
|
+
output_dir: Path,
|
|
25
|
+
):
|
|
26
|
+
self.methods = methods
|
|
27
|
+
self.models = models
|
|
28
|
+
self.output_dir = Path(output_dir)
|
|
29
|
+
|
|
30
|
+
templates_dir = Path(__file__).parent / "templates"
|
|
31
|
+
self.jinja_env = Environment(
|
|
32
|
+
loader=FileSystemLoader(str(templates_dir)),
|
|
33
|
+
autoescape=select_autoescape(),
|
|
34
|
+
trim_blocks=True,
|
|
35
|
+
lstrip_blocks=True,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def generate(self):
|
|
39
|
+
"""Generate all TypeScript files."""
|
|
40
|
+
self.output_dir.mkdir(parents=True, exist_ok=True)
|
|
41
|
+
|
|
42
|
+
self._generate_types()
|
|
43
|
+
self._generate_rpc_client()
|
|
44
|
+
self._generate_client()
|
|
45
|
+
self._generate_index()
|
|
46
|
+
self._generate_package_json()
|
|
47
|
+
self._generate_tsconfig()
|
|
48
|
+
self._generate_readme()
|
|
49
|
+
|
|
50
|
+
logger.info(f"✅ Generated TypeScript client in {self.output_dir}")
|
|
51
|
+
|
|
52
|
+
def _generate_types(self):
|
|
53
|
+
"""Generate types.ts file."""
|
|
54
|
+
template = self.jinja_env.get_template("types.ts.j2")
|
|
55
|
+
|
|
56
|
+
types_data = []
|
|
57
|
+
for model in self.models:
|
|
58
|
+
ts_interface = pydantic_to_typescript(model)
|
|
59
|
+
types_data.append({
|
|
60
|
+
'name': model.__name__,
|
|
61
|
+
'code': ts_interface,
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
content = template.render(types=types_data)
|
|
65
|
+
(self.output_dir / "types.ts").write_text(content)
|
|
66
|
+
|
|
67
|
+
def _generate_rpc_client(self):
|
|
68
|
+
"""Generate rpc-client.ts base class."""
|
|
69
|
+
template = self.jinja_env.get_template("rpc-client.ts.j2")
|
|
70
|
+
content = template.render()
|
|
71
|
+
(self.output_dir / "rpc-client.ts").write_text(content)
|
|
72
|
+
|
|
73
|
+
def _generate_client(self):
|
|
74
|
+
"""Generate client.ts thin wrapper."""
|
|
75
|
+
template = self.jinja_env.get_template("client.ts.j2")
|
|
76
|
+
|
|
77
|
+
methods_data = []
|
|
78
|
+
for method in self.methods:
|
|
79
|
+
param_type = method.param_type.__name__ if method.param_type else "any"
|
|
80
|
+
return_type = method.return_type.__name__ if method.return_type else "any"
|
|
81
|
+
method_name_ts = to_typescript_method_name(method.name)
|
|
82
|
+
|
|
83
|
+
methods_data.append({
|
|
84
|
+
'name': method.name,
|
|
85
|
+
'name_ts': method_name_ts,
|
|
86
|
+
'param_type': param_type,
|
|
87
|
+
'return_type': return_type,
|
|
88
|
+
'docstring': method.docstring or f"Call {method.name} RPC method",
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
model_names = [m.__name__ for m in self.models]
|
|
92
|
+
|
|
93
|
+
content = template.render(methods=methods_data, models=model_names)
|
|
94
|
+
(self.output_dir / "client.ts").write_text(content)
|
|
95
|
+
|
|
96
|
+
def _generate_index(self):
|
|
97
|
+
"""Generate index.ts file."""
|
|
98
|
+
template = self.jinja_env.get_template("index.ts.j2")
|
|
99
|
+
model_names = [m.__name__ for m in self.models]
|
|
100
|
+
content = template.render(models=model_names)
|
|
101
|
+
(self.output_dir / "index.ts").write_text(content)
|
|
102
|
+
|
|
103
|
+
def _generate_package_json(self):
|
|
104
|
+
"""Generate package.json file."""
|
|
105
|
+
template = self.jinja_env.get_template("package.json.j2")
|
|
106
|
+
content = template.render()
|
|
107
|
+
(self.output_dir / "package.json").write_text(content)
|
|
108
|
+
|
|
109
|
+
def _generate_tsconfig(self):
|
|
110
|
+
"""Generate tsconfig.json file."""
|
|
111
|
+
template = self.jinja_env.get_template("tsconfig.json.j2")
|
|
112
|
+
content = template.render()
|
|
113
|
+
(self.output_dir / "tsconfig.json").write_text(content)
|
|
114
|
+
|
|
115
|
+
def _generate_readme(self):
|
|
116
|
+
"""Generate README.md file."""
|
|
117
|
+
template = self.jinja_env.get_template("README.md.j2")
|
|
118
|
+
methods_data = [{'name': m.name, 'name_ts': to_typescript_method_name(m.name)} for m in self.methods[:3]]
|
|
119
|
+
model_names = [m.__name__ for m in self.models]
|
|
120
|
+
content = template.render(methods=methods_data, models=model_names)
|
|
121
|
+
(self.output_dir / "README.md").write_text(content)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
__all__ = ['TypeScriptThinGenerator']
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Generated TypeScript Client
|
|
2
|
+
|
|
3
|
+
Auto-generated type-safe TypeScript client for Centrifugo WebSocket RPC.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install centrifuge
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { CentrifugoRPCClient, APIClient } from './client';
|
|
15
|
+
|
|
16
|
+
async function main() {
|
|
17
|
+
const rpc = new CentrifugoRPCClient(
|
|
18
|
+
'ws://localhost:8000/connection/websocket',
|
|
19
|
+
'your-jwt-token',
|
|
20
|
+
'user-123'
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
await rpc.connect();
|
|
24
|
+
|
|
25
|
+
const api = new APIClient(rpc);
|
|
26
|
+
|
|
27
|
+
{% if methods %}
|
|
28
|
+
{% for method in methods %}
|
|
29
|
+
const result = await api.{{ method.name_ts }}(params);
|
|
30
|
+
{% endfor %}
|
|
31
|
+
{% endif %}
|
|
32
|
+
|
|
33
|
+
await rpc.disconnect();
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
**Generated by django_cfg.apps.centrifugo.codegen**
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated API Client
|
|
3
|
+
* Auto-generated thin wrapper - DO NOT EDIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { CentrifugoRPCClient } from './rpc-client';
|
|
7
|
+
{% if models %}
|
|
8
|
+
import type {
|
|
9
|
+
{% for model_name in models | unique | sort %} {{ model_name }},
|
|
10
|
+
{% endfor %}} from './types';
|
|
11
|
+
{% endif %}
|
|
12
|
+
|
|
13
|
+
export class APIClient {
|
|
14
|
+
constructor(private rpc: CentrifugoRPCClient) {}
|
|
15
|
+
|
|
16
|
+
{% for method in methods %}
|
|
17
|
+
/**
|
|
18
|
+
* {{ method.docstring.split('\n')[0] if method.docstring else 'No description' }}
|
|
19
|
+
*/
|
|
20
|
+
async {{ method.name_ts }}(params: {{ method.param_type }}): Promise<{{ method.return_type }}> {
|
|
21
|
+
return this.rpc.call<{{ method.return_type }}>('{{ method.name }}', params);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
{% endfor %}
|
|
25
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated TypeScript Client Package
|
|
3
|
+
* Auto-generated - DO NOT EDIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { CentrifugoRPCClient } from './rpc-client';
|
|
7
|
+
export { APIClient } from './client';
|
|
8
|
+
{% if models %}
|
|
9
|
+
export type {
|
|
10
|
+
{% for model_name in models | unique | sort %} {{ model_name }},
|
|
11
|
+
{% endfor %}} from './types';
|
|
12
|
+
{% endif %}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "centrifugo-client",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Generated Centrifugo WebSocket RPC client",
|
|
5
|
+
"main": "index.ts",
|
|
6
|
+
"types": "index.ts",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"centrifuge": "^5.0.0"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"typescript": "^5.0.0"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Centrifugo RPC Client
|
|
3
|
+
*
|
|
4
|
+
* Handles WebSocket connection and RPC call correlation.
|
|
5
|
+
* Auto-generated - DO NOT EDIT
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Centrifuge } from 'centrifuge';
|
|
9
|
+
|
|
10
|
+
export class CentrifugoRPCClient {
|
|
11
|
+
private centrifuge: Centrifuge;
|
|
12
|
+
private subscription: any;
|
|
13
|
+
private pendingRequests: Map<string, { resolve: Function; reject: Function }> = new Map();
|
|
14
|
+
private readonly replyChannel: string;
|
|
15
|
+
private readonly timeout: number;
|
|
16
|
+
|
|
17
|
+
constructor(
|
|
18
|
+
url: string,
|
|
19
|
+
token: string,
|
|
20
|
+
userId: string,
|
|
21
|
+
timeout: number = 30000
|
|
22
|
+
) {
|
|
23
|
+
this.replyChannel = `user#${userId}`;
|
|
24
|
+
this.timeout = timeout;
|
|
25
|
+
|
|
26
|
+
this.centrifuge = new Centrifuge(url, {
|
|
27
|
+
token,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
this.centrifuge.on('connected', (ctx) => {
|
|
31
|
+
console.log('✅ Connected to Centrifugo');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
this.centrifuge.on('disconnected', (ctx) => {
|
|
35
|
+
console.warn('Disconnected:', ctx);
|
|
36
|
+
// Reject all pending requests
|
|
37
|
+
this.pendingRequests.forEach(({ reject }) => {
|
|
38
|
+
reject(new Error('Disconnected from Centrifugo'));
|
|
39
|
+
});
|
|
40
|
+
this.pendingRequests.clear();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async connect(): Promise<void> {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
this.centrifuge.connect();
|
|
47
|
+
|
|
48
|
+
// Subscribe to reply channel
|
|
49
|
+
this.subscription = this.centrifuge.newSubscription(this.replyChannel);
|
|
50
|
+
|
|
51
|
+
this.subscription.on('publication', (ctx: any) => {
|
|
52
|
+
this.handleResponse(ctx.data);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
this.subscription.on('subscribed', () => {
|
|
56
|
+
resolve();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
this.subscription.on('error', (ctx: any) => {
|
|
60
|
+
reject(new Error(ctx.error?.message || 'Subscription error'));
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
this.subscription.subscribe();
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async disconnect(): Promise<void> {
|
|
68
|
+
if (this.subscription) {
|
|
69
|
+
this.subscription.unsubscribe();
|
|
70
|
+
}
|
|
71
|
+
this.centrifuge.disconnect();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async call<T = any>(method: string, params: any): Promise<T> {
|
|
75
|
+
const correlationId = this.generateCorrelationId();
|
|
76
|
+
|
|
77
|
+
const message = {
|
|
78
|
+
method,
|
|
79
|
+
params,
|
|
80
|
+
correlation_id: correlationId,
|
|
81
|
+
reply_to: this.replyChannel,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Create promise for response
|
|
85
|
+
const promise = new Promise<T>((resolve, reject) => {
|
|
86
|
+
const timeoutId = setTimeout(() => {
|
|
87
|
+
this.pendingRequests.delete(correlationId);
|
|
88
|
+
reject(new Error(`RPC timeout: ${method}`));
|
|
89
|
+
}, this.timeout);
|
|
90
|
+
|
|
91
|
+
this.pendingRequests.set(correlationId, {
|
|
92
|
+
resolve: (result: T) => {
|
|
93
|
+
clearTimeout(timeoutId);
|
|
94
|
+
resolve(result);
|
|
95
|
+
},
|
|
96
|
+
reject: (error: Error) => {
|
|
97
|
+
clearTimeout(timeoutId);
|
|
98
|
+
reject(error);
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Publish request
|
|
104
|
+
await this.centrifuge.publish('rpc.requests', message);
|
|
105
|
+
|
|
106
|
+
console.log(`📤 RPC call: ${method} (${correlationId})`);
|
|
107
|
+
|
|
108
|
+
return promise;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private handleResponse(data: any): void {
|
|
112
|
+
const correlationId = data.correlation_id;
|
|
113
|
+
if (!correlationId) {
|
|
114
|
+
console.warn('Received response without correlation_id');
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const pending = this.pendingRequests.get(correlationId);
|
|
119
|
+
if (!pending) {
|
|
120
|
+
console.warn(`Received response for unknown correlation_id: ${correlationId}`);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.pendingRequests.delete(correlationId);
|
|
125
|
+
|
|
126
|
+
if (data.error) {
|
|
127
|
+
pending.reject(new Error(data.error.message || 'RPC error'));
|
|
128
|
+
} else {
|
|
129
|
+
console.log(`📥 RPC response: ${correlationId}`);
|
|
130
|
+
pending.resolve(data.result);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private generateCorrelationId(): string {
|
|
135
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"declaration": true,
|
|
11
|
+
"declarationMap": true,
|
|
12
|
+
"sourceMap": true
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utilities for code generation.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .naming import (
|
|
6
|
+
sanitize_method_name,
|
|
7
|
+
to_camel_case,
|
|
8
|
+
to_pascal_case,
|
|
9
|
+
to_python_method_name,
|
|
10
|
+
to_typescript_method_name,
|
|
11
|
+
to_go_method_name,
|
|
12
|
+
)
|
|
13
|
+
from .type_converter import (
|
|
14
|
+
pydantic_to_typescript,
|
|
15
|
+
pydantic_to_python,
|
|
16
|
+
pydantic_to_go,
|
|
17
|
+
generate_typescript_types,
|
|
18
|
+
generate_python_types,
|
|
19
|
+
generate_go_types,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
# Naming
|
|
24
|
+
"sanitize_method_name",
|
|
25
|
+
"to_camel_case",
|
|
26
|
+
"to_pascal_case",
|
|
27
|
+
"to_python_method_name",
|
|
28
|
+
"to_typescript_method_name",
|
|
29
|
+
"to_go_method_name",
|
|
30
|
+
# Type conversion
|
|
31
|
+
"pydantic_to_typescript",
|
|
32
|
+
"pydantic_to_python",
|
|
33
|
+
"pydantic_to_go",
|
|
34
|
+
"generate_typescript_types",
|
|
35
|
+
"generate_python_types",
|
|
36
|
+
"generate_go_types",
|
|
37
|
+
]
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Naming utilities for code generation.
|
|
3
|
+
|
|
4
|
+
Provides functions to convert RPC method names to valid identifiers
|
|
5
|
+
in different programming languages.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def sanitize_method_name(name: str) -> str:
|
|
10
|
+
"""
|
|
11
|
+
Sanitize method name by replacing dots with underscores.
|
|
12
|
+
|
|
13
|
+
This handles namespaced method names (e.g., "workspace.file_changed")
|
|
14
|
+
and converts them to valid identifiers by replacing dots with underscores.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
name: Original method name (may contain dots)
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Sanitized name with underscores instead of dots
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
>>> sanitize_method_name("workspace.file_changed")
|
|
24
|
+
'workspace_file_changed'
|
|
25
|
+
>>> sanitize_method_name("send_email")
|
|
26
|
+
'send_email'
|
|
27
|
+
"""
|
|
28
|
+
return name.replace('.', '_')
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def to_camel_case(snake_str: str) -> str:
|
|
32
|
+
"""
|
|
33
|
+
Convert snake_case to camelCase.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
snake_str: String in snake_case format
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
String in camelCase format
|
|
40
|
+
|
|
41
|
+
Examples:
|
|
42
|
+
>>> to_camel_case("workspace_file_changed")
|
|
43
|
+
'workspaceFileChanged'
|
|
44
|
+
>>> to_camel_case("send_email")
|
|
45
|
+
'sendEmail'
|
|
46
|
+
>>> to_camel_case("user_update_profile")
|
|
47
|
+
'userUpdateProfile'
|
|
48
|
+
"""
|
|
49
|
+
components = snake_str.split('_')
|
|
50
|
+
return components[0] + ''.join(x.title() for x in components[1:])
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def to_typescript_method_name(rpc_name: str) -> str:
|
|
54
|
+
"""
|
|
55
|
+
Convert RPC method name to valid TypeScript method name.
|
|
56
|
+
|
|
57
|
+
Handles namespaced methods by replacing dots with underscores,
|
|
58
|
+
then converts to camelCase.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
rpc_name: Original RPC method name (may contain dots)
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Valid TypeScript method name in camelCase
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
>>> to_typescript_method_name("workspace.file_changed")
|
|
68
|
+
'workspaceFileChanged'
|
|
69
|
+
>>> to_typescript_method_name("session.message")
|
|
70
|
+
'sessionMessage'
|
|
71
|
+
>>> to_typescript_method_name("send_email")
|
|
72
|
+
'sendEmail'
|
|
73
|
+
"""
|
|
74
|
+
sanitized = sanitize_method_name(rpc_name)
|
|
75
|
+
return to_camel_case(sanitized)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def to_python_method_name(rpc_name: str) -> str:
|
|
79
|
+
"""
|
|
80
|
+
Convert RPC method name to valid Python method name.
|
|
81
|
+
|
|
82
|
+
Handles namespaced methods by replacing dots with underscores.
|
|
83
|
+
Python uses snake_case, so we just sanitize the name.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
rpc_name: Original RPC method name (may contain dots)
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Valid Python method name in snake_case
|
|
90
|
+
|
|
91
|
+
Examples:
|
|
92
|
+
>>> to_python_method_name("workspace.file_changed")
|
|
93
|
+
'workspace_file_changed'
|
|
94
|
+
>>> to_python_method_name("session.message")
|
|
95
|
+
'session_message'
|
|
96
|
+
>>> to_python_method_name("send_email")
|
|
97
|
+
'send_email'
|
|
98
|
+
"""
|
|
99
|
+
return sanitize_method_name(rpc_name)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def to_pascal_case(snake_str: str) -> str:
|
|
103
|
+
"""
|
|
104
|
+
Convert snake_case to PascalCase.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
snake_str: String in snake_case format
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
String in PascalCase format
|
|
111
|
+
|
|
112
|
+
Examples:
|
|
113
|
+
>>> to_pascal_case("workspace_file_changed")
|
|
114
|
+
'WorkspaceFileChanged'
|
|
115
|
+
>>> to_pascal_case("send_email")
|
|
116
|
+
'SendEmail'
|
|
117
|
+
>>> to_pascal_case("user_update_profile")
|
|
118
|
+
'UserUpdateProfile'
|
|
119
|
+
"""
|
|
120
|
+
return ''.join(word.capitalize() for word in snake_str.split('_'))
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def to_go_method_name(rpc_name: str) -> str:
|
|
124
|
+
"""
|
|
125
|
+
Convert RPC method name to valid Go method name.
|
|
126
|
+
|
|
127
|
+
Handles namespaced methods by replacing dots with underscores,
|
|
128
|
+
then converts to PascalCase (Go exported methods must start with capital).
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
rpc_name: Original RPC method name (may contain dots)
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Valid Go method name in PascalCase
|
|
135
|
+
|
|
136
|
+
Examples:
|
|
137
|
+
>>> to_go_method_name("workspace.file_changed")
|
|
138
|
+
'WorkspaceFileChanged'
|
|
139
|
+
>>> to_go_method_name("session.message")
|
|
140
|
+
'SessionMessage'
|
|
141
|
+
>>> to_go_method_name("send_email")
|
|
142
|
+
'SendEmail'
|
|
143
|
+
"""
|
|
144
|
+
sanitized = sanitize_method_name(rpc_name)
|
|
145
|
+
return to_pascal_case(sanitized)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
__all__ = [
|
|
149
|
+
'sanitize_method_name',
|
|
150
|
+
'to_camel_case',
|
|
151
|
+
'to_pascal_case',
|
|
152
|
+
'to_typescript_method_name',
|
|
153
|
+
'to_python_method_name',
|
|
154
|
+
'to_go_method_name',
|
|
155
|
+
]
|