@crossdelta/platform-sdk 0.8.3 → 0.8.4
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.
- package/README.md +265 -230
- package/bin/cli.js +151 -151
- package/bin/docs/generators/README.md +47 -0
- package/bin/docs/generators/service.md +258 -0
- package/bin/templates/workspace/.github/copilot-instructions.md.hbs +1 -2
- package/install.sh +14 -14
- package/package.json +2 -2
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Generator Documentation
|
|
2
|
+
|
|
3
|
+
This directory contains AI instructions for code generators.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
generators/
|
|
9
|
+
├── README.md # This file
|
|
10
|
+
└── service.md # Service generator instructions
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## How Instructions Are Loaded
|
|
14
|
+
|
|
15
|
+
The AI service generator loads instructions in priority order (most specific first):
|
|
16
|
+
|
|
17
|
+
1. **Generator-specific** (`packages/platform-sdk/docs/generators/service.md`)
|
|
18
|
+
- Detailed rules for the service generator output format
|
|
19
|
+
- Event consumer/publisher workflows
|
|
20
|
+
- File structure requirements
|
|
21
|
+
|
|
22
|
+
2. **Copilot instructions** (`.github/copilot-instructions.md`)
|
|
23
|
+
- Project-wide coding standards
|
|
24
|
+
- Code style rules
|
|
25
|
+
- Package-specific guidelines
|
|
26
|
+
|
|
27
|
+
3. **Project AI guidelines** (`docs/ai-guidelines.md`)
|
|
28
|
+
- General architectural principles
|
|
29
|
+
- Validation patterns
|
|
30
|
+
- Testing guidelines
|
|
31
|
+
|
|
32
|
+
## Adding New Generators
|
|
33
|
+
|
|
34
|
+
To add instructions for a new generator:
|
|
35
|
+
|
|
36
|
+
1. Create `<generator-name>.md` in this directory
|
|
37
|
+
2. Update `INSTRUCTION_FILES` in `ai-service-generator.ts` if needed
|
|
38
|
+
3. Follow the existing format from `service.md`
|
|
39
|
+
|
|
40
|
+
## Template Variables
|
|
41
|
+
|
|
42
|
+
The following variables are replaced at runtime:
|
|
43
|
+
|
|
44
|
+
| Variable | Description |
|
|
45
|
+
|----------|-------------|
|
|
46
|
+
| `{{scope}}` | Package scope (e.g., `@orderboss`) |
|
|
47
|
+
| `{{AVAILABLE_CONTRACTS}}` | Auto-generated list of existing contracts |
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# Service Generator Instructions
|
|
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
|
+
## 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
|
+
## 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
|
+
## 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
|
+
## 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
|
+
## Service Types
|
|
163
|
+
|
|
164
|
+
### 📤 Event Publisher (REST API)
|
|
165
|
+
|
|
166
|
+
**Keywords:** "publishes", "creates", "manages", "REST API"
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import '@crossdelta/telemetry'
|
|
170
|
+
|
|
171
|
+
import { publish } from '@crossdelta/cloudevents'
|
|
172
|
+
import { Hono } from 'hono'
|
|
173
|
+
|
|
174
|
+
const app = new Hono()
|
|
175
|
+
|
|
176
|
+
app.post('/orders', async (c) => {
|
|
177
|
+
const data = await c.req.json()
|
|
178
|
+
await publish('orders.created', data, { source: 'my-service' })
|
|
179
|
+
return c.json({ success: true })
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
Bun.serve({ port: 4001, fetch: app.fetch })
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 📥 Event Consumer (NATS)
|
|
186
|
+
|
|
187
|
+
**Keywords:** "consumes", "listens to", "reacts to", "handles events"
|
|
188
|
+
|
|
189
|
+
See 3-Step Workflow above.
|
|
190
|
+
|
|
191
|
+
### 🔄 Hybrid (Both)
|
|
192
|
+
|
|
193
|
+
Combines REST endpoints + NATS consumer.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Use-Case Rules
|
|
198
|
+
|
|
199
|
+
- Live in `src/use-cases/*.use-case.ts`
|
|
200
|
+
- Pure functions, no framework imports
|
|
201
|
+
- Import types from `@scope/contracts`
|
|
202
|
+
- Inject dependencies as parameters (Map, services, etc.)
|
|
203
|
+
- NO manual validation (adapters handle that)
|
|
204
|
+
- **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
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
import type { OrdersCreatedData } from '{{scope}}/contracts'
|
|
208
|
+
|
|
209
|
+
export const processOrder = async (
|
|
210
|
+
data: OrdersCreatedData,
|
|
211
|
+
orderStore: Map<string, any>
|
|
212
|
+
) => {
|
|
213
|
+
console.log('📦 Processing order:', data.orderId)
|
|
214
|
+
|
|
215
|
+
orderStore.set(data.orderId, { ...data, processedAt: new Date() })
|
|
216
|
+
return { success: true }
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Testing Rules
|
|
223
|
+
|
|
224
|
+
- Test ONLY use-cases
|
|
225
|
+
- Use `import { describe, expect, it } from 'bun:test'`
|
|
226
|
+
- NO mocking (Bun doesn't support it)
|
|
227
|
+
- Focus on error handling and validation
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
import { describe, expect, it } from 'bun:test'
|
|
231
|
+
import { processOrder } from './process-order.use-case'
|
|
232
|
+
|
|
233
|
+
describe('Process Order', () => {
|
|
234
|
+
it('should store order', async () => {
|
|
235
|
+
const store = new Map()
|
|
236
|
+
const result = await processOrder({ orderId: '123', customerId: 'c1', total: 100 }, store)
|
|
237
|
+
expect(store.has('123')).toBe(true)
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Absolute Rules
|
|
245
|
+
|
|
246
|
+
**DO NOT:**
|
|
247
|
+
- Generate full rewrites
|
|
248
|
+
- Use raw NATS clients
|
|
249
|
+
- Put logic in handlers or index.ts
|
|
250
|
+
- Use `src/handlers/` (use `src/events/`)
|
|
251
|
+
- Insert semicolons
|
|
252
|
+
- Edit `packages/contracts/src/index.ts` directly (CLI handles exports)
|
|
253
|
+
|
|
254
|
+
**DO:**
|
|
255
|
+
- Follow naming convention (plural event types)
|
|
256
|
+
- Create contracts in `packages/contracts/src/events/`
|
|
257
|
+
- Export schema separately from contract
|
|
258
|
+
- Keep code minimal and clean
|
|
@@ -10,6 +10,7 @@ Always generate **minimal diffs**, never full rewrites.
|
|
|
10
10
|
- Analyze only the opened file unless explicitly asked.
|
|
11
11
|
- Follow existing architecture and naming conventions.
|
|
12
12
|
- Prefer strict typing; avoid `any`.
|
|
13
|
+
- **Reuse existing code**: Before implementing new functionality, search the codebase for existing functions, utilities, or services that can be reused. Avoid duplicating logic.
|
|
13
14
|
|
|
14
15
|
## Code Style
|
|
15
16
|
- Single quotes, no semicolons, 2-space indent, trailing commas.
|
|
@@ -60,8 +61,6 @@ Always generate **minimal diffs**, never full rewrites.
|
|
|
60
61
|
When working with specific service types or packages, refer to these detailed guidelines:
|
|
61
62
|
|
|
62
63
|
### Service Generation & Architecture
|
|
63
|
-
- [Service Architecture Guidelines](../docs/generators/services/architecture-guidelines.md) - General patterns for all services
|
|
64
|
-
- [Hono Microservice Guidelines](../docs/generators/services/hono-micro-guidelines.md) - Event-driven Hono patterns
|
|
65
64
|
- [CLI Service Generator](../packages/platform-sdk/docs/generators/service.md) - AI code generation rules
|
|
66
65
|
|
|
67
66
|
### Key Packages
|
package/install.sh
CHANGED
|
@@ -11,15 +11,15 @@ NC='\033[0m'
|
|
|
11
11
|
|
|
12
12
|
printf "${CYAN}"
|
|
13
13
|
cat << "EOF"
|
|
14
|
-
______
|
|
14
|
+
______
|
|
15
15
|
/ ____/
|
|
16
|
-
____ / /_
|
|
17
|
-
/ __ \ / __/
|
|
18
|
-
/ /_/ // /
|
|
19
|
-
/ .___//_/
|
|
20
|
-
/_/
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
____ / /_
|
|
17
|
+
/ __ \ / __/
|
|
18
|
+
/ /_/ // /
|
|
19
|
+
/ .___//_/
|
|
20
|
+
/_/
|
|
21
|
+
|
|
22
|
+
@crossdelta/platform-sdk installer
|
|
23
23
|
EOF
|
|
24
24
|
printf "${NC}\n"
|
|
25
25
|
|
|
@@ -44,28 +44,28 @@ detect_or_install_package_manager() {
|
|
|
44
44
|
echo "npm"
|
|
45
45
|
return 0
|
|
46
46
|
fi
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
# No package manager found - ask user for permission
|
|
49
49
|
printf "${YELLOW}No package manager found (bun, pnpm, yarn, npm).${NC}\n"
|
|
50
50
|
printf "${YELLOW}To use @crossdelta/platform-sdk, we recommend installing Bun (fast JavaScript runtime).${NC}\n"
|
|
51
51
|
printf "\n"
|
|
52
52
|
read -p "Do you want to install Bun now? (y/n) " -n 1 -r
|
|
53
53
|
printf "\n"
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
56
56
|
printf "${RED}Installation cancelled. Please install Bun or another package manager manually.${NC}\n"
|
|
57
57
|
printf "${BLUE}Visit: https://bun.sh${NC}\n"
|
|
58
58
|
exit 1
|
|
59
59
|
fi
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
# Install Bun
|
|
62
62
|
printf "${BLUE}Installing Bun...${NC}\n"
|
|
63
63
|
curl -fsSL https://bun.sh/install | bash
|
|
64
|
-
|
|
64
|
+
|
|
65
65
|
# Load Bun into current shell
|
|
66
66
|
export BUN_INSTALL="$HOME/.bun"
|
|
67
67
|
export PATH="$BUN_INSTALL/bin:$PATH"
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
printf "${GREEN}✓${NC} Bun installed successfully\n"
|
|
70
70
|
echo "bun"
|
|
71
71
|
}
|
|
@@ -117,7 +117,7 @@ if [ $# -eq 0 ]; then
|
|
|
117
117
|
else
|
|
118
118
|
# Arguments provided: Run pf command directly
|
|
119
119
|
PF_ARGS=()
|
|
120
|
-
|
|
120
|
+
|
|
121
121
|
while [[ $# -gt 0 ]]; do
|
|
122
122
|
case $1 in
|
|
123
123
|
-h|--help)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crossdelta/platform-sdk",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4",
|
|
4
4
|
"description": "Platform toolkit for event-driven microservices — keeping code and infrastructure in lockstep.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"files": [
|
|
30
30
|
"bin/**/*.js",
|
|
31
31
|
"bin/**/templates/**",
|
|
32
|
-
"bin
|
|
32
|
+
"bin/docs/generators/**",
|
|
33
33
|
"bin/**/*.json",
|
|
34
34
|
"!bin/**/*.map",
|
|
35
35
|
"dist/",
|