@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.
@@ -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
- @crossdelta/platform-sdk installer
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",
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/**/instructions/**",
32
+ "bin/docs/generators/**",
33
33
  "bin/**/*.json",
34
34
  "!bin/**/*.map",
35
35
  "dist/",