@crossdelta/platform-sdk 0.5.13 β†’ 0.7.0

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 CHANGED
@@ -26,44 +26,85 @@
26
26
  <img src="https://img.shields.io/badge/DigitalOcean-App_Platform_|_DOKS-0080FF?style=flat-square" alt="DigitalOcean" />
27
27
  </p>
28
28
 
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>
31
+ </p>
32
+
29
33
  <br />
30
34
 
31
35
  ---
32
36
  ## πŸš€ Quick Start
33
37
 
34
38
  ```bash
35
- # Create workspace (works with npx/yarn/pnpm too)
39
+ # Create workspace (works with bunx/npx/pnpm dlx/yarn dlx)
36
40
  bunx @crossdelta/platform-sdk new workspace my-platform -y
37
41
  cd my-platform
38
42
 
39
- # Generate service with AI
40
- # (first time: you'll be prompted to configure an AI provider)
43
+ # Generate microservice with AI (first time: run `pf setup --ai` to configure provider)
41
44
  bunx @crossdelta/platform-sdk new hono-micro services/orders --ai \
42
- -d "Handle order creation and payment processing"
45
+ -d "Handle order creation and payment"
43
46
 
44
- # Start all services (or: npm run dev)
45
- bun dev
47
+ # Start development
48
+ pf dev
46
49
  ```
47
50
 
48
- **In under a minute you have a running, event-driven microservice platform with infra parity between local and production.**
51
+ **What you get in minutes:**
49
52
 
50
- You get: [Turborepo](https://turbo.build/repo) monorepo + [NATS](https://nats.io) + event-driven microservices + [Pulumi](https://www.pulumi.com) infra + auto-generated `.env.local` + **AI-generated services** β€” all wired automatically.
53
+ - βœ” Turborepo monorepo with Biome linting
54
+ - βœ” NATS + event-driven microservices
55
+ - βœ” Pulumi infrastructure (`infra/services/*.ts`)
56
+ - βœ” Auto-generated `.env.local` with service ports
57
+ - βœ” AI-generated service code
51
58
 
52
- <details>
53
- <summary><strong>πŸ’‘ Prefer shorter commands? Install globally (Bun/npm/yarn/pnpm)</strong></summary>
59
+ All wired automatically. Local + production infra in lockstep.
60
+
61
+ ### ⚑ One CLI for everything
62
+
63
+ `pf` runs your workspace scripts from anywhere:
54
64
 
55
65
  ```bash
56
- # With Bun (recommended)
57
- bun add -g @crossdelta/platform-sdk
66
+ pf test # β†’ turbo run test
67
+ pf build # β†’ turbo run build
68
+ pf pulumi up # β†’ runs in infra/ directory
69
+ ```
70
+
71
+ **Why:** Keeps commands consistent across the team and works from any subdirectory.
72
+
73
+ **How it works:** `pf` walks up to find your workspace root, then proxies to your scripts. Configured commands via `pf.commands` can override the working directory or command. Registered `pf` commands (like `pf new`) take precedence.
74
+
75
+ > **πŸ“– Note:** You can be productive with `pf` in minutes using the commands above. The sections below are reference documentationβ€”explore them when you need specific details.
76
+
77
+ ### No runtime installed?
78
+
79
+ If you don't have a JavaScript runtime, use our installer that sets everything up.
80
+ **The installer is optional** β€” you can always use `bunx`/`npx` or a global install.
58
81
 
59
- # With npm/yarn/pnpm
60
- npm install -g @crossdelta/platform-sdk
82
+ ```bash
83
+ # Auto-installer (detects bun/pnpm/yarn/npm; if none found it can install Bun)
84
+ curl -fsSL https://unpkg.com/@crossdelta/platform-sdk@latest/install.sh | bash
61
85
 
62
86
  # Then use short commands
63
87
  pf new workspace my-platform
64
88
  pf new hono-micro services/orders --ai -d "..."
65
89
  ```
66
90
 
91
+ > **Security:** The installer asks permission before installing Bun (if needed) and does not run any workspace commands automatically.
92
+
93
+ <details>
94
+ <summary><strong>πŸ” What does the installer do?</strong></summary>
95
+
96
+ The script ([view source](https://unpkg.com/@crossdelta/platform-sdk@latest/install.sh)):
97
+ 1. Checks for bun/pnpm/yarn/npm
98
+ 2. If none found, **asks permission** to install Bun
99
+ 3. Installs `pf` CLI globally
100
+
101
+ **Manual installation:**
102
+ ```bash
103
+ # With Bun/npm/yarn/pnpm
104
+ bun add -g @crossdelta/platform-sdk
105
+ # or: npm install -g @crossdelta/platform-sdk
106
+ ```
107
+
67
108
  </details>
68
109
 
69
110
  <br />
@@ -91,7 +132,7 @@ pf new hono-micro services/orders --ai -d "..."
91
132
  - **Opinionated CLI** for event-driven microservice platforms
92
133
  - **[Turborepo](https://turbo.build/repo) scaffolder** with [Pulumi](https://www.pulumi.com) IaC and [NATS](https://nats.io) messaging built-in
93
134
  - **AI-assisted code generator** that creates service boilerplate from descriptions
94
- - **Unified dev workflow** β€” one command to run all services (`bun dev`)
135
+ - **Unified dev workflow** β€” one command to run all services (`pf dev`)
95
136
  - **[DigitalOcean](https://www.digitalocean.com)-first** deployment target (App Platform + DOKS)
96
137
 
97
138
  ### ❌ `pf` is not:
@@ -101,6 +142,8 @@ pf new hono-micro services/orders --ai -d "..."
101
142
  - **Runtime manager** β€” scaffolds code, you deploy with Pulumi
102
143
  - **Kubernetes replacement** β€” generates K8s configs via Pulumi
103
144
 
145
+ **Note:** `pf` runs nothing implicitlyβ€”no hidden daemons, no automatic deployments or provisioning. You maintain explicit control over when code runs and infrastructure is deployed.
146
+
104
147
  ### πŸ”₯ Why `pf` vs other tools?
105
148
 
106
149
  - **πŸ”— Lockstep infra + code** β€” `infra/services/*.ts` auto-generated from service metadata, ports/env derived automatically
@@ -141,7 +184,7 @@ my-platform/
141
184
  1. **NATS + JetStream baseline** β€” Event-driven communication is built-in, not bolted on
142
185
  2. **Infrastructure-as-Code by default** β€” Every service has a matching `infra/services/<name>.ts` config
143
186
  3. **Auto-wiring everywhere** β€” Ports, env vars, and NATS subjects are derived automatically
144
- 4. **Opinionated conventions** β€” Event handlers live in `src/handlers/*.event.ts`, business logic in `src/use-cases/*.use-case.ts`
187
+ 4. **Opinionated conventions** β€” Event handlers live in `src/events/*.event.ts`, business logic in `src/use-cases/*.use-case.ts`
145
188
  5. **Bun-first DX** β€” Ultra-fast installs, tests, and dev server with fallback to npm/yarn
146
189
 
147
190
  ### Event-Driven Mental Model
@@ -153,7 +196,7 @@ Services communicate via **CloudEvents** over **NATS JetStream**:
153
196
  await publish('orders.created', { orderId: '123', total: 99.99 })
154
197
 
155
198
  // Service B auto-discovers and handles it
156
- // File: services/notifications/src/handlers/order-created.event.ts
199
+ // File: services/notifications/src/events/order-created.event.ts
157
200
  export default handleEvent(
158
201
  { schema: OrderCreatedSchema, type: 'orders.created' },
159
202
  async (data) => { await sendNotification(data) }
@@ -186,6 +229,15 @@ These principles guide every decision in `pf`:
186
229
 
187
230
  `pf` is designed for **small to mid-sized teams building event-driven systems** who want strong conventions, infra parity, and fast onboarding β€” without maintaining their own internal platform.
188
231
 
232
+ <br />
233
+
234
+ ---
235
+
236
+ ## πŸ“š Deep Dive & Reference
237
+
238
+ The sections below cover architectural details, workflows, and advanced usage.
239
+ **You don't need to read them to get started** β€” they're here when you need them.
240
+
189
241
  ---
190
242
 
191
243
  ## πŸ“˜ Workflows
@@ -220,7 +272,7 @@ pf new hono-micro services/payments --ai \
220
272
 
221
273
  ```bash
222
274
  cd my-platform
223
- bun dev
275
+ pf dev
224
276
  ```
225
277
 
226
278
  This will:
@@ -233,15 +285,55 @@ This will:
233
285
 
234
286
  ```bash
235
287
  # Run all tests across the monorepo
236
- bun test
288
+ pf test
237
289
 
238
290
  # Lint and format all code with Biome
239
- bun lint
291
+ pf lint
240
292
 
241
293
  # Build all packages and services
242
- bun run build
294
+ pf build
243
295
  ```
244
296
 
297
+ ### 5. Workspace Configuration
298
+
299
+ Configure workspace behavior via the `pf` field in your root `package.json`:
300
+
301
+ ```json
302
+ {
303
+ "pf": {
304
+ "registry": "my-platform/platform",
305
+ "commands": {
306
+ "pulumi": { "cwd": "infra" },
307
+ "deploy": { "cwd": "infra", "command": "pulumi up --yes" }
308
+ },
309
+ "paths": {
310
+ "services": {
311
+ "path": "services",
312
+ "watch": true
313
+ },
314
+ "apps": {
315
+ "path": "apps",
316
+ "watch": true
317
+ },
318
+ "packages": {
319
+ "path": "packages",
320
+ "watch": true,
321
+ "ignorePatterns": ["packages/some-internal-package"]
322
+ },
323
+ "contracts": {
324
+ "path": "packages/contracts"
325
+ }
326
+ }
327
+ }
328
+ }
329
+ ```
330
+
331
+ **Options:**
332
+ - `commands`: Custom command shortcuts with `cwd` (working directory) and `command` overrides
333
+ - `paths.<type>.path`: Directory path for each workspace type
334
+ - `paths.<type>.watch`: Whether to watch this directory in dev mode (default: `false`)
335
+ - `paths.<type>.ignorePatterns`: Glob patterns to ignore within this path (optional)
336
+
245
337
  <br />
246
338
 
247
339
  ---
@@ -250,7 +342,10 @@ bun run build
250
342
 
251
343
  Here's how developers actually use `pf` in real-world scenarios:
252
344
 
253
- ### Workflow 1: Start a New Platform
345
+ <details>
346
+ <summary><strong>Workflow 1: Start a New Platform</strong></summary>
347
+
348
+ <br />
254
349
 
255
350
  You're building a new product from scratch and want to establish a solid foundation.
256
351
 
@@ -270,7 +365,7 @@ cd my-platform
270
365
  # - Database instance sizes
271
366
 
272
367
  # Step 3: Start local development
273
- bun dev
368
+ pf dev
274
369
  ```
275
370
 
276
371
  **What you get:**
@@ -280,182 +375,23 @@ bun dev
280
375
  - βœ… GitHub Actions workflows for CI/CD
281
376
  - βœ… `.env.local` auto-generated with all service ports
282
377
 
283
- **Time to first service running:** ~60 seconds
378
+ </details>
284
379
 
285
380
  ---
286
381
 
287
382
  ### Workflow 2: Add a New Microservice
288
383
 
289
- Your platform is growing and you need to add a new service for handling payments.
290
-
291
- **Option A: Manual scaffolding (fast, predictable)**
292
-
293
- ```bash
294
- # Generate a lightweight Hono microservice
295
- pf new hono-micro services/payments -y
296
-
297
- # What gets auto-generated:
298
- # βœ… services/payments/src/index.ts (Hono server)
299
- # βœ… services/payments/src/handlers/*.event.ts (example event handler)
300
- # βœ… infra/services/payments.ts (Pulumi K8s config)
301
- # βœ… services/payments/README.md (service documentation)
302
- # βœ… Dockerfile + package.json with scripts
303
- # βœ… Auto-assigned port (e.g., 4003)
304
-
305
- # Start the service
306
- bun dev
307
- ```
308
-
309
- **Option B: AI-powered generation (intelligent scaffolding)**
310
-
311
384
  ```bash
312
- # First time: configure AI provider
313
- pf setup --ai
314
-
315
- # Generate service boilerplate with AI
385
+ # Generate with AI (optional: use --ai flag)
316
386
  pf new hono-micro services/payments --ai \
317
- -d "Stripe payment processing: handle checkout.session.completed webhooks, \
318
- publish payment.succeeded events, update order status in database"
319
-
320
- # AI generates:
321
- # βœ… Service structure with Stripe SDK integration
322
- # βœ… Event handler stubs for incoming webhooks
323
- # βœ… Event publisher functions for payment lifecycle
324
- # βœ… Use case templates with validation logic
325
- # βœ… Test file boilerplate
326
- # βœ… Environment variable documentation
327
- # βœ… Basic README with usage examples
328
- ```
329
-
330
- **When to use which:**
331
- - **Manual scaffolding:** You know exactly what you're building, want full control
332
- - **AI generation:** Quick prototyping, exploring new integrations, generating boilerplate faster
333
-
334
- **Note:** AI-generated code is a starting point, not production-ready. Always review and refine.
335
-
336
- ---
337
-
338
- ### Workflow 3: Build an Event-Driven Feature
339
-
340
- You want to send notifications whenever a new order is created.
387
+ -d "Stripe payment processing: handle webhooks, publish events"
341
388
 
342
- **Step 1: Create the notification service**
343
-
344
- ```bash
345
- pf new hono-micro services/notifications -y
346
- ```
347
-
348
- **Step 2: Implement the event handler**
349
-
350
- ```typescript
351
- // services/notifications/src/handlers/order-created.event.ts
352
- import { handleEvent } from '@crossdelta/cloudevents'
353
- import { z } from 'zod'
354
- import { sendNotification } from '../use-cases/send-notification.use-case'
355
-
356
- const OrderCreatedSchema = z.object({
357
- orderId: z.string(),
358
- customerId: z.string(),
359
- total: z.number(),
360
- items: z.array(
361
- z.object({
362
- productId: z.string(),
363
- quantity: z.number(),
364
- price: z.number(),
365
- }),
366
- ).optional(),
367
- })
368
-
369
- // Export type for use in use-cases
370
- export type OrderCreatedEvent = z.infer<typeof OrderCreatedSchema>
371
-
372
- export default handleEvent(
373
- {
374
- schema: OrderCreatedSchema,
375
- type: 'orders.created', // Event type to subscribe to
376
- },
377
- async (data) => {
378
- await sendNotification(data)
379
- },
380
- )
381
- ```
382
-
383
- **Step 3: Implement the use case**
384
-
385
- ```typescript
386
- // services/notifications/src/use-cases/send-notification.use-case.ts
387
- import type { OrderCreatedEvent } from '../handlers/order-created.event'
388
-
389
- export async function sendNotification(data: OrderCreatedEvent): Promise<void> {
390
- // Full type inference from the event handler schema
391
- console.log(`Sending notification for order: ${data.orderId}`)
392
-
393
- // Your notification logic here:
394
- // - Send email via SendGrid
395
- // - Push notification via Firebase
396
- // - SMS via Twilio
397
- }
398
- ```
399
-
400
- **Step 4: Start consuming events**
401
-
402
- ```typescript
403
- // services/notifications/src/index.ts
404
- import '@crossdelta/telemetry' // Must be first import
405
-
406
- import { consumeJetStreamEvents } from '@crossdelta/cloudevents'
407
- import { Hono } from 'hono'
408
-
409
- const port = Number(process.env.PORT || process.env.NOTIFICATIONS_PORT) || 4002
410
- const app = new Hono()
411
-
412
- app.get('/health', (c) => c.json({ status: 'ok' }))
413
-
414
- // Auto-discover and register all event handlers
415
- consumeJetStreamEvents({
416
- stream: 'ORDERS',
417
- subjects: ['orders.>'], // Subscribe to all orders.* events
418
- consumer: 'notifications',
419
- discover: './src/handlers/**/*.event.ts',
420
- })
421
-
422
- Bun.serve({ port, fetch: app.fetch })
423
- ```
424
-
425
- **Step 5: Publish events from the orders service**
426
-
427
- ```typescript
428
- // services/orders/src/routes/create-order.ts
429
- import { publish } from '@crossdelta/cloudevents'
430
-
431
- export async function createOrder(orderData) {
432
- const order = await db.orders.create(orderData)
433
-
434
- // Publish event to NATS
435
- await publish('orders.created', {
436
- orderId: order.id,
437
- customerId: order.customerId,
438
- total: order.total,
439
- items: order.items,
440
- })
441
-
442
- return order
443
- }
389
+ # Auto-generated: service code + infra config + tests + README
390
+ # Start the service
391
+ pf dev
444
392
  ```
445
393
 
446
- **How it works:**
447
- 1. **Publishing:** `publish()` sends a CloudEvent to NATS JetStream
448
- 2. **Auto-discovery:** `consumeJetStreamEvents()` scans `src/handlers/*.event.ts` and registers handlers
449
- 3. **Type safety:** Zod schema validates incoming events, provides TypeScript types
450
- 4. **Decoupling:** Services don't know about each other, only about events
451
-
452
- **Benefits:**
453
- - βœ… Zero boilerplate for NATS subscriptions
454
- - βœ… Type-safe event handling with Zod
455
- - βœ… Automatic retries and error handling (JetStream guarantees)
456
- - βœ… Easy to add new consumers without touching existing services
457
-
458
- <br />
394
+ **AI generates:** Service structure, event handlers, use cases, tests, and documentation. Always review before deploying.
459
395
 
460
396
  ---
461
397
 
@@ -498,7 +434,7 @@ await publish('orders.created', { orderId: 'ord_123', total: 99.99 })
498
434
  ### Consume Events (Auto-Discovered)
499
435
 
500
436
  ```typescript
501
- // services/notifications/src/handlers/order-created.event.ts
437
+ // services/notifications/src/events/order-created.event.ts
502
438
  import { handleEvent } from '@crossdelta/cloudevents'
503
439
  import { z } from 'zod'
504
440
 
@@ -550,14 +486,14 @@ export default handleEvent(
550
486
  | `pf new nest-micro <path>` | Generate a NestJS microservice (enterprise-grade) |
551
487
  | `pf new hono-micro <path> --ai` | Generate service with AI (requires `pf setup --ai`) |
552
488
 
553
- ### Code Generation
489
+ ### Event Testing
554
490
 
555
491
  | Command | Description |
556
492
  |---------|-------------|
557
- | `pf generate event-handler <name>` | Generate an event handler |
558
- | `pf generate use-case <name>` | Generate a use case |
493
+ | `pf event:generate <path>` | Generate event mocks from event handlers |
559
494
  | `pf event:list` | List all available event mocks |
560
- | `pf event:send <name>` | Send a test event to NATS |
495
+ | `pf event:publish <name>` | Publish to NATS JetStream |
496
+ | `pf event:http <name>` | Send via HTTP Pub/Sub endpoint |
561
497
 
562
498
  ### Utility Commands
563
499
 
@@ -643,8 +579,8 @@ Configure these secrets in your repository settings (`Settings` β†’ `Secrets and
643
579
 
644
580
  ## πŸ“š Requirements
645
581
 
646
- - **[Bun](https://bun.sh)** (latest) β€” recommended for best performance
647
- - **Node.js** β‰₯ 21 β€” supported as fallback (npm/yarn/pnpm)
582
+ - **JavaScript runtime** β€” Bun (recommended) or Node.js β‰₯ 21 (npm/yarn/pnpm)
583
+ _No runtime? Use our [installer](#no-nodejsbun-installed) β€” it sets up Bun automatically_
648
584
  - **[Pulumi CLI](https://www.pulumi.com/docs/install/)** β€” for infrastructure deployment
649
585
  - **[Docker](https://www.docker.com/)** β€” required for local NATS. Without Docker, you can still scaffold/build
650
586