Skip to content

Commit 84d0b48

Browse files
committed
chore: update cursor files
1 parent f49dd48 commit 84d0b48

File tree

3 files changed

+659
-0
lines changed

3 files changed

+659
-0
lines changed

.cursor/rules.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@
6464
"path": "core.mdc",
6565
"globs": ["schemas/**/*.json"],
6666
"description": "JSON schema management patterns"
67+
},
68+
{
69+
"path": "protocols.mdc",
70+
"globs": ["src/codegen/generators/typescript/channels/protocols/**/*.ts"],
71+
"description": "Protocol implementation patterns for channels"
72+
},
73+
{
74+
"path": "troubleshooting.mdc",
75+
"globs": ["**/*"],
76+
"description": "Troubleshooting guide for common issues"
6777
}
6878
]
6979
}

.cursor/rules/protocols.mdc

Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
---
2+
description: Protocol implementation guide for channels generator
3+
globs: ["src/codegen/generators/typescript/channels/protocols/**/*.ts"]
4+
alwaysApply: false
5+
---
6+
7+
# Protocol Implementation Guide
8+
9+
Guidelines for adding new protocol support to the channels generator.
10+
11+
## Supported Protocols
12+
13+
Current implementations:
14+
- **NATS**: Message streaming and request/reply
15+
- **Kafka**: Event streaming with consumer groups
16+
- **MQTT**: IoT messaging with QoS and user properties
17+
- **AMQP**: Enterprise messaging with exchanges/queues
18+
- **EventSource**: Server-sent events
19+
- **HTTP Client**: RESTful API communication
20+
- **WebSocket**: Bidirectional communication
21+
22+
## Protocol File Structure
23+
24+
```
25+
src/codegen/generators/typescript/channels/protocols/[protocol]/
26+
├── index.ts # Main protocol handler
27+
├── publish.ts # Publish operation
28+
├── subscribe.ts # Subscribe operation
29+
├── request.ts # Request operation (if applicable)
30+
├── reply.ts # Reply operation (if applicable)
31+
└── utils.ts # Protocol-specific utilities
32+
```
33+
34+
## Critical Requirements
35+
36+
### 1. Object Parameters (MANDATORY)
37+
38+
```typescript
39+
// ✅ REQUIRED: Object parameters for all functions
40+
export async function publish({message, parameters, headers, client}: {
41+
message: MessageType,
42+
parameters?: ParametersType,
43+
headers?: HeadersType,
44+
client: ClientType
45+
}): Promise<void> { }
46+
47+
// ✅ REQUIRED: Object parameter callbacks
48+
onDataCallback: (params: {
49+
err?: Error,
50+
msg?: MessageType,
51+
parameters?: ParametersType,
52+
headers?: HeadersType,
53+
protocolMsg?: ProtocolMessageType
54+
}) => void
55+
```
56+
57+
### 2. Function Type Registration
58+
59+
```typescript
60+
// src/codegen/generators/typescript/channels/types.ts
61+
export enum ChannelFunctionTypes {
62+
[PROTOCOL]_PUBLISH = '[protocol]_publish',
63+
[PROTOCOL]_SUBSCRIBE = '[protocol]_subscribe',
64+
[PROTOCOL]_REQUEST = '[protocol]_request', // if applicable
65+
[PROTOCOL]_REPLY = '[protocol]_reply', // if applicable
66+
}
67+
68+
// Add to receiving types if applicable
69+
const receivingFunctionTypes = [
70+
ChannelFunctionTypes.[PROTOCOL]_SUBSCRIBE,
71+
// ...
72+
];
73+
```
74+
75+
## Protocol-Specific Patterns
76+
77+
### MQTT Requirements
78+
79+
**CRITICAL**: MQTT v5 is REQUIRED for user properties (headers):
80+
81+
```typescript
82+
// Connect with MQTT v5
83+
const client = await MqttClient.connectAsync("mqtt://0.0.0.0:1883", {
84+
protocolVersion: 5 // Required for headers support
85+
});
86+
87+
// Publish with headers
88+
await client.publishAsync(topic, payload, {
89+
properties: {
90+
userProperties: headerData
91+
}
92+
});
93+
94+
// Subscribe with topic filtering (CRITICAL)
95+
const topicPattern = findRegexFromChannel(channel);
96+
client.on('message', (topic, message, packet) => {
97+
if (!topicPattern.test(topic)) {
98+
return; // Filter non-matching topics
99+
}
100+
101+
// Extract headers from user properties
102+
let headers;
103+
if (packet.properties && packet.properties.userProperties) {
104+
headers = HeaderType.unmarshal(packet.properties.userProperties);
105+
}
106+
107+
// Call callback with object parameters
108+
onDataCallback({
109+
err: undefined,
110+
msg: parsedMessage,
111+
parameters: extractedParameters,
112+
headers: headers,
113+
mqttMsg: packet
114+
});
115+
});
116+
```
117+
118+
**Why Topic Filtering?**
119+
- Single `client.on('message')` receives ALL messages
120+
- Multiple subscriptions share the same handler
121+
- Must filter to prevent cross-channel processing
122+
123+
### NATS Patterns
124+
125+
```typescript
126+
// Headers from NATS headers
127+
let headerData = {};
128+
if (msg.headers) {
129+
for (const key of msg.headers.keys()) {
130+
headerData[key] = msg.headers.get(key);
131+
}
132+
}
133+
134+
// Object parameter callback
135+
onDataCallback({
136+
err: undefined,
137+
msg: parsedMessage,
138+
parameters: extractedParameters,
139+
headers: extractedHeaders
140+
});
141+
```
142+
143+
### Kafka Patterns
144+
145+
```typescript
146+
// Headers from Kafka headers
147+
let headerData = {};
148+
if (message.headers) {
149+
for (const [key, value] of Object.entries(message.headers)) {
150+
headerData[key] = value?.toString();
151+
}
152+
}
153+
154+
// Object parameter callback
155+
onDataCallback({
156+
err: undefined,
157+
msg: parsedMessage,
158+
headers: extractedHeaders,
159+
kafkaMessage: message
160+
});
161+
```
162+
163+
### AMQP Patterns
164+
165+
```typescript
166+
// Headers from AMQP properties
167+
let headers;
168+
if (msg.properties && msg.properties.headers) {
169+
headers = HeaderType.unmarshal(msg.properties.headers);
170+
}
171+
172+
// Object parameter callback
173+
onDataCallback({
174+
err: undefined,
175+
msg: parsedMessage,
176+
headers: headers,
177+
amqpMsg: msg
178+
});
179+
```
180+
181+
## Adding a New Protocol
182+
183+
### Step 1: Create Protocol Directory
184+
185+
```bash
186+
mkdir -p src/codegen/generators/typescript/channels/protocols/[protocol]
187+
```
188+
189+
### Step 2: Implement Operations
190+
191+
Create files for each operation (publish.ts, subscribe.ts, etc.) following existing patterns.
192+
193+
### Step 3: Register Function Types
194+
195+
Add to `ChannelFunctionTypes` enum in `types.ts`
196+
197+
### Step 4: Create Docker Compose
198+
199+
```yaml
200+
# test/runtime/docker-compose-[protocol].yml
201+
version: '3.8'
202+
services:
203+
[protocol]:
204+
image: [protocol-image]
205+
ports:
206+
- "[port]:[port]"
207+
environment:
208+
# Protocol-specific config
209+
```
210+
211+
### Step 5: Write Runtime Tests
212+
213+
```typescript
214+
// test/runtime/typescript/test/channels/regular/[protocol].spec.ts
215+
describe('[protocol]', () => {
216+
test('should publish and subscribe with object parameters', () => {
217+
return new Promise<void>(async (resolve, reject) => {
218+
const client = await connectTo[Protocol]();
219+
220+
await subscribeTo[Protocol]({
221+
onDataCallback: (params) => {
222+
const {err, msg, parameters, headers, protocolMsg} = params;
223+
try {
224+
expect(err).toBeUndefined();
225+
expect(msg?.marshal()).toEqual(testMessage.marshal());
226+
resolve();
227+
} catch (error) {
228+
reject(error);
229+
}
230+
},
231+
parameters: testParameters,
232+
headers: testHeaders,
233+
[protocolClient]: client
234+
});
235+
236+
setTimeout(async () => {
237+
await publishTo[Protocol]({
238+
message: testMessage,
239+
parameters: testParameters,
240+
headers: testHeaders,
241+
[protocolClient]: client
242+
});
243+
}, 100);
244+
});
245+
});
246+
});
247+
```
248+
249+
### Step 6: Add npm Scripts
250+
251+
```json
252+
{
253+
"scripts": {
254+
"runtime:[protocol]:start": "cd test/runtime && docker compose -f ./docker-compose-[protocol].yml up -d",
255+
"runtime:[protocol]:stop": "cd test/runtime && docker compose -f ./docker-compose-[protocol].yml down"
256+
}
257+
}
258+
```
259+
260+
## Testing Checklist
261+
262+
- [ ] Docker compose file created
263+
- [ ] Runtime tests with object parameter callbacks
264+
- [ ] Publish operation implemented
265+
- [ ] Subscribe operation implemented
266+
- [ ] Request operation implemented (if applicable)
267+
- [ ] Reply operation implemented (if applicable)
268+
- [ ] Function types registered
269+
- [ ] Headers properly extracted per protocol
270+
- [ ] Topic/channel filtering implemented (if needed)
271+
- [ ] Protocol-specific error handling
272+
- [ ] All tests pass with `npm run prepare:pr`
273+
274+
## Common Mistakes
275+
276+
- ❌ Not using object parameter callbacks
277+
- ❌ Forgetting MQTT v5 configuration
278+
- ❌ Not filtering MQTT topics in subscribe
279+
- ❌ Not handling protocol-specific headers correctly
280+
- ❌ Using positional parameters
281+
- ❌ Not testing with Docker containers
282+
283+
## References
284+
285+
- Existing protocols in `src/codegen/generators/typescript/channels/protocols/`
286+
- Runtime tests in `test/runtime/typescript/test/channels/`
287+
- See `generators.mdc` for general generator patterns
288+
- See `testing.mdc` for runtime testing requirements

0 commit comments

Comments
 (0)