@crossdelta/platform-sdk 0.7.16 → 0.7.17

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.
Files changed (2) hide show
  1. package/README.md +55 -77
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -9,9 +9,9 @@
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <strong>Your AI-powered platform engineer.</strong><br />
13
- Scaffold complete <a href="https://turbo.build/repo">Turborepo</a> workspaces, generate microservice boilerplate<br />
14
- with natural language, and deploy to the cloudall from one CLI.
12
+ <strong>Opinionated CLI for event-driven microservice platforms.</strong><br />
13
+ Scaffold <a href="https://turbo.build/repo">Turborepo</a> workspaces, generate services from natural language,<br />
14
+ and deploy via <a href="https://www.pulumi.com">Pulumi</a>DigitalOcean-first, provider-agnostic by design.
15
15
  </p>
16
16
 
17
17
  <p align="center">
@@ -27,7 +27,7 @@
27
27
  </p>
28
28
 
29
29
  <p align="center">
30
- <em><code>pf</code> is not a framework it's a set of conventions that wire code and infrastructure together.</em>
30
+ <em><code>pf</code> enforces conventions that keep application code and cloud infrastructure in lockstep from local development to production.</em>
31
31
  </p>
32
32
 
33
33
  <br />
@@ -151,38 +151,52 @@ When you create a workspace with `pf`, you get a **Turborepo monorepo** with thi
151
151
 
152
152
  ```
153
153
  my-platform/
154
- ├── services/ # Microservices (generate with pf new hono-micro)
155
- └── nats/ # NATS message broker (auto-scaffolded)
156
- ├── apps/ # Frontend apps (optional)
157
- ├── packages/ # Shared libraries
158
- │ └── contracts/ # Event contracts (Schema Registry)
154
+ ├── services/ # Microservices (generate with pf new hono-micro)
155
+ ├── nats/ # NATS message broker (auto-scaffolded)
156
+ │ └── <service>/ # Your services go here
159
157
  │ └── src/
160
- └── index.ts
161
- ├── infra/ # Pulumi Infrastructure-as-Code
162
- ├── index.ts # Main Pulumi program
163
- └── services/ # Per-service K8s configs (auto-generated)
158
+ ├── events/ # Event handlers (*.event.ts)
159
+ ├── use-cases/ # Business logic (*.use-case.ts)
160
+ ├── types/ # Zod schemas & types
161
+ └── index.ts # Service entrypoint
162
+ ├── apps/ # Frontend apps (optional)
163
+ ├── packages/
164
+ │ └── contracts/ # Event contracts (Schema Registry)
165
+ │ └── src/
166
+ │ └── events/ # Event schemas (single source of truth)
167
+ ├── infra/ # Pulumi Infrastructure-as-Code
168
+ │ ├── index.ts # Main Pulumi program
169
+ │ └── services/ # Per-service K8s configs (auto-generated)
164
170
  ├── .github/
165
- │ └── workflows/ # CI/CD pipelines
166
- ├── turbo.json # Turborepo task orchestration
167
- └── .env.local # Auto-generated from infra configs
171
+ │ └── workflows/ # CI/CD pipelines
172
+ ├── turbo.json # Turborepo task orchestration
173
+ └── .env.local # Auto-generated from infra configs
168
174
  ```
169
175
 
170
- ### Key Architectural Decisions
176
+ ### Key Conventions
177
+
178
+ | Location | Purpose |
179
+ |----------|---------|
180
+ | `services/*/src/events/*.event.ts` | Event handlers (auto-discovered) |
181
+ | `services/*/src/use-cases/*.use-case.ts` | Business logic (pure functions) |
182
+ | `services/*/src/types/*.ts` | Service-local Zod schemas |
183
+ | `packages/contracts/src/events/*.ts` | Event contracts (Schema Registry) |
184
+ | `infra/services/*.ts` | Pulumi configs per service |
185
+
186
+ ### Key Rules
171
187
 
172
- 1. **NATS + JetStream baseline** — Event-driven communication is built-in, not bolted on
173
- 2. **Schema Registry Pattern** — All event schemas live in `packages/contracts` as single source of truth
174
- 3. **Infrastructure-as-Code by default** — Every service has a matching `infra/services/<name>.ts` config
175
- 4. **Auto-wiring everywhere** — Ports, env vars, NATS subjects, and event contracts are derived automatically
176
- 5. **AI-assisted generation** — Services generate with correct event schemas from natural language descriptions
177
- 6. **Opinionated conventions** — Event handlers in `src/events/*.event.ts`, business logic in `src/use-cases/*.use-case.ts`, schemas in `src/types/*.ts`
178
- 7. **Bun-first DX** — Ultra-fast installs, tests, and dev server with fallback to npm/yarn
188
+ - **Never duplicate schemas** — Contracts in `packages/contracts` are the single source of truth
189
+ - **Event handlers stay thin** — Delegate to use-cases, no business logic in handlers
190
+ - **Infrastructure is explicit** — Ports, env vars derived from `infra/services/*.ts`
179
191
 
180
192
  ### Event-Driven Mental Model
181
193
 
182
194
  Services communicate via **CloudEvents** over **NATS JetStream** using the **Schema Registry** as single source of truth:
183
195
 
196
+ **1. Define contract (Schema Registry):**
197
+
184
198
  ```typescript
185
- // packages/contracts/src/events/orders-created.ts (Schema Registry)
199
+ // packages/contracts/src/events/orders-created.ts
186
200
  import { createContract } from '@crossdelta/cloudevents'
187
201
  import { z } from 'zod'
188
202
 
@@ -196,8 +210,12 @@ export const OrdersCreatedContract = createContract({
196
210
  })
197
211
 
198
212
  export type OrdersCreatedData = z.infer<typeof OrdersCreatedContract.schema>
213
+ ```
199
214
 
200
- // Service A publishes an event (Event Publisher)
215
+ **2. Service A publishes an event:**
216
+
217
+ ```typescript
218
+ // services/orders/src/index.ts
201
219
  import { publish } from '@crossdelta/cloudevents'
202
220
  import { OrdersCreatedContract } from '@my-platform/contracts'
203
221
 
@@ -206,14 +224,18 @@ await publish(OrdersCreatedContract, {
206
224
  customerId: 'cust-456',
207
225
  total: 99.99
208
226
  })
227
+ ```
228
+
229
+ **3. Service B auto-discovers and handles it:**
209
230
 
210
- // Service B auto-discovers and handles it (Event Consumer)
211
- // File: services/notifications/src/events/orders-created.event.ts
231
+ ```typescript
232
+ // services/notifications/src/events/orders-created.event.ts
212
233
  import { handleEvent } from '@crossdelta/cloudevents'
213
234
  import { OrdersCreatedContract, type OrdersCreatedData } from '@my-platform/contracts'
235
+ import { sendOrderNotification } from '../use-cases/send-order-notification.use-case'
214
236
 
215
237
  export default handleEvent(OrdersCreatedContract, async (data: OrdersCreatedData) => {
216
- await sendNotification(data)
238
+ await sendOrderNotification(data) // Delegate to use-case
217
239
  })
218
240
  ```
219
241
 
@@ -409,22 +431,11 @@ pf dev
409
431
 
410
432
  ---
411
433
 
412
- ## ⚡ Event-Driven Architecture
413
-
414
- Every workspace includes **NATS + JetStream** for event-driven microservices communication using **[`@crossdelta/cloudevents`](https://www.npmjs.com/package/@crossdelta/cloudevents)**:
415
-
416
- - 🎯 **Type-safe event handlers** with Zod schemas
417
- - 🔄 **Auto-discovery** of event handlers (`*.event.ts` files)
418
- - 📦 **Publisher/Consumer patterns** out of the box
419
- - 🚀 **NATS auto-scaffolded** in `services/nats/` with Docker setup
420
- - 🗄️ **JetStream persistence** for durable event streaming
421
-
422
- ### NATS Message Broker
434
+ ## ⚡ NATS Message Broker
423
435
 
424
- Every workspace includes a pre-configured NATS service:
436
+ Every workspace includes a pre-configured NATS service with JetStream:
425
437
 
426
- ```bash
427
- # Auto-started with `bun dev`
438
+ ```
428
439
  services/nats/
429
440
  ├── nats.conf # Local dev config (JetStream enabled)
430
441
  ├── nats.prod.conf # Production config (auth + persistence)
@@ -433,44 +444,11 @@ services/nats/
433
444
  ```
434
445
 
435
446
  **Local Development:**
447
+ - Auto-started with `pf dev`
436
448
  - Runs in Docker on ports `4222` (client) and `8222` (HTTP monitoring)
437
449
  - Data persisted in `.nats-data/` directory
438
450
  - Health check: `curl http://localhost:8222/healthz`
439
451
 
440
- ### Publish Events
441
-
442
- ```typescript
443
- import { publish } from '@crossdelta/cloudevents'
444
-
445
- await publish('orders.created', { orderId: 'ord_123', total: 99.99 })
446
- ```
447
-
448
- ### Consume Events (Auto-Discovered)
449
-
450
- ```typescript
451
- // services/notifications/src/events/orders-created.event.ts
452
- import { handleEvent } from '@crossdelta/cloudevents'
453
- import { z } from 'zod'
454
-
455
- const OrdersCreatedSchema = z.object({
456
- orderId: z.string(),
457
- total: z.number(),
458
- })
459
-
460
- // Export type for use in use-cases
461
- export type OrdersCreatedEvent = z.infer<typeof OrdersCreatedSchema>
462
-
463
- export default handleEvent(
464
- {
465
- schema: OrdersCreatedSchema,
466
- type: 'orders.created',
467
- },
468
- async (data) => {
469
- await sendNotification(data)
470
- },
471
- )
472
- ```
473
-
474
452
  **📚 Learn more:** See `services/nats/README.md` in your workspace for monitoring, configuration, and JetStream details.
475
453
 
476
454
  <br />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crossdelta/platform-sdk",
3
- "version": "0.7.16",
3
+ "version": "0.7.17",
4
4
  "description": "Your AI-powered platform engineer. Scaffold complete Turborepo workspaces, generate microservice boilerplate with natural language, and deploy to the cloud — all from one CLI",
5
5
  "keywords": [
6
6
  "cli",