@crossdelta/platform-sdk 0.8.3 → 0.8.21
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.
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# AI Generation Rules for CLI Code Output
|
|
2
|
+
|
|
3
|
+
These rules define how AI-generated scaffolded services must be structured.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🚨 CRITICAL: Event Consumer Workflow
|
|
8
|
+
|
|
9
|
+
**FOR EVENT CONSUMER SERVICES (services that "consume", "listen to", "react to" events):**
|
|
10
|
+
|
|
11
|
+
### Naming Convention (CRITICAL!)
|
|
12
|
+
|
|
13
|
+
**Event Type → Contract Name → File Name:**
|
|
14
|
+
|
|
15
|
+
| Event Type | Contract Name | File Name |
|
|
16
|
+
|------------|---------------|-----------|
|
|
17
|
+
| `orders.created` | `OrdersCreatedContract` | `orders-created.ts` |
|
|
18
|
+
| `users.registered` | `UsersRegisteredContract` | `users-registered.ts` |
|
|
19
|
+
| `payments.completed` | `PaymentsCompletedContract` | `payments-completed.ts` |
|
|
20
|
+
|
|
21
|
+
**Rule:** Always use **plural namespace** (`orders.`, `users.`, `payments.`) to match JetStream stream subjects (`orders.>`, `users.>`, etc.)
|
|
22
|
+
|
|
23
|
+
### 3-Step Workflow
|
|
24
|
+
|
|
25
|
+
**STEP 1: CREATE Contract** (`packages/contracts/src/events/<event-name>.ts`):
|
|
26
|
+
```ts
|
|
27
|
+
import { createContract } from '@crossdelta/cloudevents'
|
|
28
|
+
import { z } from 'zod'
|
|
29
|
+
|
|
30
|
+
export const OrdersCreatedSchema = z.object({
|
|
31
|
+
orderId: z.string(),
|
|
32
|
+
customerId: z.string(),
|
|
33
|
+
total: z.number(),
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
export const OrdersCreatedContract = createContract({
|
|
37
|
+
type: 'orders.created', // plural namespace!
|
|
38
|
+
schema: OrdersCreatedSchema,
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
export type OrdersCreatedData = z.infer<typeof OrdersCreatedContract.schema>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**STEP 2: Create Event Handler** (`src/events/orders-created.event.ts`):
|
|
45
|
+
```ts
|
|
46
|
+
import { handleEvent } from '@crossdelta/cloudevents'
|
|
47
|
+
import { OrdersCreatedContract, type OrdersCreatedData } from '{{scope}}/contracts'
|
|
48
|
+
import { processOrder } from '../use-cases/process-order.use-case'
|
|
49
|
+
|
|
50
|
+
export default handleEvent(OrdersCreatedContract, async (data: OrdersCreatedData) => {
|
|
51
|
+
await processOrder(data)
|
|
52
|
+
})
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**STEP 3: Setup Consumer** (`src/index.ts`):
|
|
56
|
+
```ts
|
|
57
|
+
import '@crossdelta/telemetry'
|
|
58
|
+
|
|
59
|
+
import { consumeJetStreamEvents, ensureJetStreamStream } from '@crossdelta/cloudevents'
|
|
60
|
+
import { Hono } from 'hono'
|
|
61
|
+
|
|
62
|
+
const port = Number(process.env.PORT || process.env.MY_SERVICE_PORT) || 4003
|
|
63
|
+
const app = new Hono()
|
|
64
|
+
|
|
65
|
+
app.get('/health', (c) => c.json({ status: 'ok' }))
|
|
66
|
+
|
|
67
|
+
Bun.serve({ port, fetch: app.fetch })
|
|
68
|
+
|
|
69
|
+
await ensureJetStreamStream({
|
|
70
|
+
stream: 'ORDERS',
|
|
71
|
+
subjects: ['orders.>'],
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
consumeJetStreamEvents({
|
|
75
|
+
stream: 'ORDERS',
|
|
76
|
+
consumer: 'my-service',
|
|
77
|
+
discover: './src/events/**/*.event.ts',
|
|
78
|
+
})
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## ⚠️ Code Quality Guidelines
|
|
84
|
+
|
|
85
|
+
- ✅ **Verify package names** on npmjs.com before using
|
|
86
|
+
- ✅ Use exact package names: `@crossdelta/cloudevents`, `@crossdelta/telemetry`
|
|
87
|
+
- ❌ **DO NOT hallucinate** APIs or package names
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
# 1. Commands Block (REQUIRED - MUST BE FIRST)
|
|
92
|
+
|
|
93
|
+
```commands
|
|
94
|
+
pf new hono-micro services/my-service -y
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- Services MUST be in `services/` directory
|
|
98
|
+
- User says "orders" → Generate: `services/orders`
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
# 2. Post-Generation Commands
|
|
103
|
+
|
|
104
|
+
For Event Consumer services:
|
|
105
|
+
|
|
106
|
+
```post-commands
|
|
107
|
+
pf event add <event.type> --service services/my-service
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Note:** `pf event add` creates contract, mock, handler, and adds the export to `packages/contracts/src/index.ts`.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
# 3. Dependencies Block
|
|
115
|
+
|
|
116
|
+
Only include packages not in the scaffold:
|
|
117
|
+
|
|
118
|
+
```dependencies
|
|
119
|
+
zod
|
|
120
|
+
@pusher/push-notifications-server
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Note:** `{{scope}}/contracts` is already in the template's package.json.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
# 4. Required Files
|
|
128
|
+
|
|
129
|
+
**Event Consumer:**
|
|
130
|
+
```
|
|
131
|
+
services/my-service/
|
|
132
|
+
├── src/
|
|
133
|
+
│ ├── index.ts # NATS consumer setup
|
|
134
|
+
│ ├── events/
|
|
135
|
+
│ │ └── orders-created.event.ts # Event handler
|
|
136
|
+
│ └── use-cases/
|
|
137
|
+
│ ├── process-order.use-case.ts
|
|
138
|
+
│ └── process-order.test.ts
|
|
139
|
+
└── README.md
|
|
140
|
+
|
|
141
|
+
packages/contracts/src/events/
|
|
142
|
+
└── orders-created.ts # Contract (export added by CLI)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Event Publisher:**
|
|
146
|
+
```
|
|
147
|
+
services/my-service/
|
|
148
|
+
├── src/
|
|
149
|
+
│ ├── index.ts # REST API + publish()
|
|
150
|
+
│ └── use-cases/
|
|
151
|
+
│ ├── create-order.use-case.ts
|
|
152
|
+
│ └── create-order.test.ts
|
|
153
|
+
└── README.md
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**IMPORTANT:** Do NOT create `src/types/` directories. All types come from contracts:
|
|
157
|
+
- `OrdersCreatedData` → import from `@scope/contracts`
|
|
158
|
+
- Custom request/response types → define inline or in use-case files
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
# 5. Code Style
|
|
163
|
+
|
|
164
|
+
- Biome-compatible, strict TS, arrow functions only
|
|
165
|
+
- No semicolons, minimal comments, alphabetized imports
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
# 6. Service Types
|
|
170
|
+
|
|
171
|
+
## 📤 Event Publisher (REST API)
|
|
172
|
+
|
|
173
|
+
**Keywords:** "publishes", "creates", "manages", "REST API"
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import '@crossdelta/telemetry'
|
|
177
|
+
|
|
178
|
+
import { publish } from '@crossdelta/cloudevents'
|
|
179
|
+
import { Hono } from 'hono'
|
|
180
|
+
|
|
181
|
+
const app = new Hono()
|
|
182
|
+
|
|
183
|
+
app.post('/orders', async (c) => {
|
|
184
|
+
const data = await c.req.json()
|
|
185
|
+
await publish('orders.created', data, { source: 'my-service' })
|
|
186
|
+
return c.json({ success: true })
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
Bun.serve({ port: 4001, fetch: app.fetch })
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## 📥 Event Consumer (NATS)
|
|
193
|
+
|
|
194
|
+
**Keywords:** "consumes", "listens to", "reacts to", "handles events"
|
|
195
|
+
|
|
196
|
+
See 4-Step Workflow above.
|
|
197
|
+
|
|
198
|
+
## 🔄 Hybrid (Both)
|
|
199
|
+
|
|
200
|
+
Combines REST endpoints + NATS consumer.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
# 7. Use-Case Rules
|
|
205
|
+
|
|
206
|
+
- Live in `src/use-cases/*.use-case.ts`
|
|
207
|
+
- Pure functions, no framework imports
|
|
208
|
+
- Import types from `@scope/contracts`
|
|
209
|
+
- Inject dependencies as parameters (Map, services, etc.)
|
|
210
|
+
- NO manual validation (adapters handle that)
|
|
211
|
+
- **Event handlers:** Always log the event type and a key identifier (e.g., `console.log('📦 Processing order:', data.orderId)`) at the start of the use-case for debugging visibility
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
import type { OrdersCreatedData } from '{{scope}}/contracts'
|
|
215
|
+
|
|
216
|
+
export const processOrder = async (
|
|
217
|
+
data: OrdersCreatedData,
|
|
218
|
+
orderStore: Map<string, any>
|
|
219
|
+
) => {
|
|
220
|
+
console.log('📦 Processing order:', data.orderId)
|
|
221
|
+
|
|
222
|
+
orderStore.set(data.orderId, { ...data, processedAt: new Date() })
|
|
223
|
+
return { success: true }
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
# 8. Testing Rules
|
|
230
|
+
|
|
231
|
+
- Test ONLY use-cases
|
|
232
|
+
- Use `import { describe, expect, it } from 'bun:test'`
|
|
233
|
+
- NO mocking (Bun doesn't support it)
|
|
234
|
+
- Focus on error handling and validation
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
import { describe, expect, it } from 'bun:test'
|
|
238
|
+
import { processOrder } from './process-order.use-case'
|
|
239
|
+
|
|
240
|
+
describe('Process Order', () => {
|
|
241
|
+
it('should store order', async () => {
|
|
242
|
+
const store = new Map()
|
|
243
|
+
const result = await processOrder({ orderId: '123', customerId: 'c1', total: 100 }, store)
|
|
244
|
+
expect(store.has('123')).toBe(true)
|
|
245
|
+
})
|
|
246
|
+
})
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
# 9. Absolute Rules
|
|
252
|
+
|
|
253
|
+
**DO NOT:**
|
|
254
|
+
- Generate full rewrites
|
|
255
|
+
- Use raw NATS clients
|
|
256
|
+
- Put logic in handlers or index.ts
|
|
257
|
+
- Use `src/handlers/` (use `src/events/`)
|
|
258
|
+
- Insert semicolons
|
|
259
|
+
- Edit `packages/contracts/src/index.ts` directly (CLI handles exports)
|
|
260
|
+
|
|
261
|
+
**DO:**
|
|
262
|
+
- Follow naming convention (plural event types)
|
|
263
|
+
- Create contracts in `packages/contracts/src/events/`
|
|
264
|
+
- Export schema separately from contract
|
|
265
|
+
- Keep code minimal and clean
|
|
@@ -62,7 +62,6 @@ When working with specific service types or packages, refer to these detailed gu
|
|
|
62
62
|
### Service Generation & Architecture
|
|
63
63
|
- [Service Architecture Guidelines](../docs/generators/services/architecture-guidelines.md) - General patterns for all services
|
|
64
64
|
- [Hono Microservice Guidelines](../docs/generators/services/hono-micro-guidelines.md) - Event-driven Hono patterns
|
|
65
|
-
- [CLI Service Generator](../packages/platform-sdk/docs/generators/service.md) - AI code generation rules
|
|
66
65
|
|
|
67
66
|
### Key Packages
|
|
68
67
|
- [@crossdelta/cloudevents](../packages/cloudevents/README.md) - Event handling with NATS and CloudEvents
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crossdelta/platform-sdk",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.21",
|
|
4
4
|
"description": "Platform toolkit for event-driven microservices — keeping code and infrastructure in lockstep.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"scripts": {
|
|
52
52
|
"start:dev": "node esbuild.config.mjs --watch",
|
|
53
53
|
"build:cli": "node esbuild.config.mjs",
|
|
54
|
-
"build:cli:copy": "cp cli/integration.collection.json bin/integration.collection.json && rm -rf bin/templates && mkdir -p bin/templates && cp -r cli/src/commands/create/workspace/templates bin/templates/workspace && cp -r cli/src/commands/create/hono-microservice/templates bin/templates/hono-microservice && cp -r cli/src/commands/create/nest-microservice/templates bin/templates/nest-microservice && mkdir -p bin/
|
|
54
|
+
"build:cli:copy": "cp cli/integration.collection.json bin/integration.collection.json && rm -rf bin/templates && mkdir -p bin/templates && cp -r cli/src/commands/create/workspace/templates bin/templates/workspace && cp -r cli/src/commands/create/hono-microservice/templates bin/templates/hono-microservice && cp -r cli/src/commands/create/nest-microservice/templates bin/templates/nest-microservice && mkdir -p bin/services/ai/instructions && cp cli/src/services/ai/instructions/ai-instructions.md bin/services/ai/instructions/",
|
|
55
55
|
"build:schematics:transpile": "tsc --project tsconfig.schematics.json",
|
|
56
56
|
"build:schematics:copy": "cp -R schematics/* dist/schematics && find dist/schematics -name '*.ts' -delete",
|
|
57
57
|
"build:schematics": "npm run build:schematics:transpile && npm run build:schematics:copy",
|