@crossdelta/platform-sdk 0.8.34 → 0.8.35

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 +270 -229
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,118 +1,136 @@
1
1
  <p align="center">
2
- <img src="https://unpkg.com/@crossdelta/platform-sdk/logo.png" alt="pf" width="120" />
2
+ <img src="https://unpkg.com/@crossdelta/platform-sdk/logo.png" alt="pf" width="140" />
3
3
  </p>
4
4
 
5
5
  <h1 align="center">Platform SDK</h1>
6
6
 
7
7
  <p align="center">
8
- <code>@crossdelta/platform-sdk</code>
8
+ <strong>The full-stack platform toolkit.</strong>
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <strong>Platform toolkit for event-driven microserviceskeeping code and infrastructure in lockstep.</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 for speed and simplicity, providers replaceable by design.
12
+ <code>pf</code> scaffolds production-ready platforms: backend services, event-driven messaging, infrastructure all wired together and kept in sync.
15
13
  </p>
16
14
 
17
15
  <p align="center">
18
- <em>Platform SDK (<code>pf</code>) is a platform opinion, not a generator.<br />
19
- It encodes architectural decisions so teams don't have to rediscover them.</em>
16
+ <sub>Frontend SDK coming soon.</sub>
20
17
  </p>
21
18
 
22
- <p align="center">
23
- <em>Includes optional AI-assisted service generation (OpenAI / Anthropic).</em>
24
- </p>
19
+ <br />
25
20
 
26
21
  <p align="center">
27
- <a href="https://www.npmjs.com/package/@crossdelta/platform-sdk"><img src="https://img.shields.io/npm/v/@crossdelta/platform-sdk.svg?style=flat-square" alt="npm version" /></a>
28
- <img src="https://img.shields.io/badge/bun-%E2%9A%A1-f9f1e1?style=flat-square" alt="Bun" />
29
- <img src="https://img.shields.io/badge/pulumi-ready-blueviolet?style=flat-square" alt="Pulumi" />
30
- <img src="https://img.shields.io/badge/DigitalOcean-App_Platform_|_DOKS-0080FF?style=flat-square" alt="DigitalOcean" />
22
+ <a href="https://www.npmjs.com/package/@crossdelta/platform-sdk"><img src="https://img.shields.io/npm/v/@crossdelta/platform-sdk.svg?style=for-the-badge&color=cb3837" alt="npm version" /></a>
23
+ &nbsp;
24
+ <img src="https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white" alt="TypeScript" />
25
+ &nbsp;
26
+ <img src="https://img.shields.io/badge/Bun-000000?style=for-the-badge&logo=bun&logoColor=white" alt="Bun" />
27
+ &nbsp;
28
+ <img src="https://img.shields.io/badge/License-MIT-22c55e?style=for-the-badge" alt="MIT License" />
31
29
  </p>
32
30
 
33
31
  <p align="center">
34
32
  <img src="https://img.shields.io/badge/Hono-E36002?style=flat-square&logo=hono&logoColor=white" alt="Hono" />
35
33
  <img src="https://img.shields.io/badge/NestJS-E0234E?style=flat-square&logo=nestjs&logoColor=white" alt="NestJS" />
36
34
  <img src="https://img.shields.io/badge/NATS-27AAE1?style=flat-square&logo=natsdotio&logoColor=white" alt="NATS" />
35
+ <img src="https://img.shields.io/badge/Pulumi-8A3391?style=flat-square&logo=pulumi&logoColor=white" alt="Pulumi" />
36
+ <img src="https://img.shields.io/badge/Turborepo-EF4444?style=flat-square&logo=turborepo&logoColor=white" alt="Turborepo" />
37
+ <img src="https://img.shields.io/badge/DigitalOcean-0080FF?style=flat-square&logo=digitalocean&logoColor=white" alt="DigitalOcean" />
37
38
  </p>
38
39
 
39
- ---
40
+ <br />
40
41
 
41
- ## Who is this for?
42
+ <p align="center">
43
+ <a href="#-quick-start">Quick Start</a> •
44
+ <a href="#-5-minute-tutorial">Tutorial</a> •
45
+ <a href="#-commands">Commands</a> •
46
+ <a href="#-ai-assisted-generation">AI Generation</a> •
47
+ <a href="#-deployment">Deployment</a>
48
+ </p>
42
49
 
43
- - **Teams building event-driven backends** — NATS, CloudEvents, type-safe contracts
44
- - **Startups & internal platforms** that want long-term consistency over short-term speed
45
- - **Engineers tired of infra & app drift** — ports, env vars, deployments always in sync
50
+ ---
46
51
 
47
- You can start without understanding all the pieces. The depth reveals itself as you grow.
52
+ <br />
53
+
54
+ ## 👋 Who is this for?
55
+
56
+ <table>
57
+ <tr>
58
+ <td width="60">🏗️</td>
59
+ <td><strong>Teams building full-stack platforms</strong> — services, events, apps that actually work together</td>
60
+ </tr>
61
+ <tr>
62
+ <td>📡</td>
63
+ <td><strong>Event-driven architectures</strong> — or teams ready to start using events</td>
64
+ </tr>
65
+ <tr>
66
+ <td>😤</td>
67
+ <td><strong>Engineers tired of drift</strong> — ports, env vars, and infra configs that never match</td>
68
+ </tr>
69
+ <tr>
70
+ <td>🚀</td>
71
+ <td><strong>Startups & platform teams</strong> — who want consistency without building everything from scratch</td>
72
+ </tr>
73
+ </table>
74
+
75
+ > **You can start without understanding all the pieces.**
76
+ > The depth reveals itself as you grow.
48
77
 
49
78
  ---
50
79
 
51
- ## Installation
80
+ ## 🚀 Quick Start
52
81
 
53
82
  ```bash
83
+ # With Bun
54
84
  bun add -g @crossdelta/platform-sdk
55
- # or: npm install -g @crossdelta/platform-sdk
56
- ```
57
85
 
58
- <details>
59
- <summary>Alternative: Auto-installer or run without installing</summary>
86
+ # With npm
87
+ npm install -g @crossdelta/platform-sdk
60
88
 
61
- **Unix/macOS:**
62
- ```bash
63
- # Auto-installer (installs CLI globally, prompts to install Bun if missing)
89
+ # Or auto-install (macOS/Linux/WSL)
64
90
  curl -fsSL https://unpkg.com/@crossdelta/platform-sdk@latest/install.sh | bash
65
91
  ```
66
92
 
67
- **Windows:**
68
- ```powershell
69
- # Recommended: Use npm directly
70
- npm install -g @crossdelta/platform-sdk
71
-
72
- # Or use WSL (Windows Subsystem for Linux)
73
- wsl bash -c "curl -fsSL https://unpkg.com/@crossdelta/platform-sdk@latest/install.sh | bash"
74
- ```
75
-
76
- **Run without installing:**
77
- ```bash
78
- bunx @crossdelta/platform-sdk new workspace my-platform
79
- # or: npx @crossdelta/platform-sdk new workspace my-platform
80
- ```
81
-
82
- </details>
83
-
84
- ---
85
-
86
- ## Quick Start
93
+ > **Windows users:** Use [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) for the best experience.
87
94
 
95
+ **Then create your first platform:**
88
96
  ```bash
89
97
  pf new workspace my-platform -y && cd my-platform
90
98
  pf dev
91
99
  ```
92
100
 
93
- **What you get:**
94
- - Turborepo monorepo with Biome linting
95
- - NATS + JetStream for event-driven messaging
96
- - Pulumi infrastructure (`infra/services/*.ts`)
97
- - Auto-generated `.env.local` with service ports
98
-
99
- > **Lockstep by design:**
100
- > In `pf`, application code and infrastructure are generated from the same source of truth.
101
- > Service metadata defines ports, env vars, event wiring, and Pulumi configs —
102
- > eliminating drift between local development, CI, and production.
101
+ <br />
102
+
103
+ <table>
104
+ <tr>
105
+ <td>✅</td>
106
+ <td>Turborepo monorepo with Biome linting</td>
107
+ </tr>
108
+ <tr>
109
+ <td>✅</td>
110
+ <td>NATS + JetStream for event-driven messaging</td>
111
+ </tr>
112
+ <tr>
113
+ <td>✅</td>
114
+ <td>Pulumi infrastructure ready for deployment</td>
115
+ </tr>
116
+ <tr>
117
+ <td>✅</td>
118
+ <td>Auto-generated <code>.env.local</code> with service ports</td>
119
+ </tr>
120
+ </table>
103
121
 
104
122
  ---
105
123
 
106
- ## 5-Minute Tutorial
124
+ ## 🎯 5-Minute Tutorial
107
125
 
108
- After running Quick Start, add services and wire events:
126
+ Add two services and wire an event between them:
109
127
 
110
128
  ```bash
111
- # 1. Add two services
129
+ # 1. Create two services
112
130
  pf new hono-micro services/orders
113
131
  pf new hono-micro services/notifications
114
132
 
115
- # 2. Wire an event between them
133
+ # 2. Wire an event from orders → notifications
116
134
  pf event add orders.created --service services/notifications
117
135
 
118
136
  # 3. Restart to pick up new services
@@ -122,92 +140,194 @@ pf dev
122
140
  pf event publish orders.created
123
141
  ```
124
142
 
125
- That's it. Two services, one event contract, auto-discovered handlers, no manual wiring.
143
+ <br />
144
+
145
+ <table>
146
+ <tr>
147
+ <th align="left">What just happened</th>
148
+ </tr>
149
+ <tr>
150
+ <td>
151
+ 📦 Two services with health checks and Pulumi configs<br />
152
+ 📝 One event contract in <code>packages/contracts/</code><br />
153
+ 🔗 One handler that auto-discovers the event<br />
154
+ ✨ <strong>No manual wiring. No config drift.</strong>
155
+ </td>
156
+ </tr>
157
+ </table>
126
158
 
127
159
  ---
128
160
 
129
- ## 🧭 Commands & Options
161
+ ## 💡 What problem does pf solve?
162
+
163
+ <table>
164
+ <tr>
165
+ <th width="300">❌ The Problem</th>
166
+ <th width="300">✅ With pf</th>
167
+ </tr>
168
+ <tr>
169
+ <td>Application code lives here, infra config lives somewhere else</td>
170
+ <td>Both generated from the same source of truth</td>
171
+ </tr>
172
+ <tr>
173
+ <td>Ports, env vars, and event wiring drift over time</td>
174
+ <td>Change a service → infra stays in sync</td>
175
+ </tr>
176
+ <tr>
177
+ <td>New devs spend days setting up local environments</td>
178
+ <td>Run <code>pf dev</code> → everything starts together</td>
179
+ </tr>
180
+ <tr>
181
+ <td>Manual event subscriptions and handler registration</td>
182
+ <td>Add an event → consumers are wired automatically</td>
183
+ </tr>
184
+ </table>
130
185
 
131
- ### Service generators
186
+ ---
132
187
 
133
- **Hono** (lightweight, Bun-optimized):
134
- ```bash
135
- pf new hono-micro services/orders
136
- ```
188
+ ## 📋 Commands
137
189
 
138
- **NestJS** (full-featured, decorator-based):
139
- ```bash
140
- pf new nest-micro services/orders
141
- ```
190
+ | Command | What it does |
191
+ |:--------|:-------------|
192
+ | `pf dev` | 🚀 Start NATS + all services in watch mode |
193
+ | `pf new hono-micro <path>` | ⚡ Create a Hono service (lightweight, Bun-optimized) |
194
+ | `pf new nest-micro <path>` | 🏢 Create a NestJS service (full-featured, decorators) |
195
+ | `pf event add <type> --service <path>` | 🔗 Add contract + handler + wire stream |
196
+ | `pf event list` | 📋 List available events and consumers |
197
+ | `pf event publish <type>` | 📤 Publish mock event to NATS |
198
+ | `pf test` | 🧪 Run tests across the monorepo |
199
+ | `pf build` | 📦 Build all packages and services |
200
+ | `pf lint` | ✨ Lint and format with Biome |
201
+
202
+ > `pf` proxies to Turborepo from any subdirectory.
142
203
 
143
- Both generate the service structure, Pulumi config in `infra/services/`, and wire everything automatically.
204
+ ---
205
+
206
+ ## 🤖 AI-Assisted Generation
144
207
 
145
- ### AI-assisted generation (optional)
208
+ > **Optional but powerful.** Configure once, then use `--ai` with any generator.
146
209
 
147
- Configure once:
148
210
  ```bash
149
211
  pf setup --ai # OpenAI or Anthropic
212
+
213
+ pf new hono-micro services/notifications --ai \
214
+ -d "Send emails when orders are created"
150
215
  ```
151
216
 
152
- Then use `--ai` with any generator:
217
+ AI generates service code, event handlers, use cases, and tests — **all following the same conventions you'd write by hand.**
218
+
219
+ ---
220
+
221
+ ## 🚢 Deployment
222
+
153
223
  ```bash
154
- pf new hono-micro services/notifications --ai -d "Send emails on order events"
224
+ pf pulumi up --stack dev
155
225
  ```
156
226
 
157
- AI generates: service code, event handlers, use cases, tests, and documentation.
158
- All generated code follows the same conventions and can be written manually.
227
+ **Pre-configured GitHub Actions included:**
159
228
 
160
- ### Daily commands
229
+ | Trigger | Action |
230
+ |:--------|:-------|
231
+ | PR to `main` | 🧪 Lint + test |
232
+ | Push to `main` | 🚀 Build, push to GHCR, deploy |
233
+ | Changes in `packages/` | 📦 Publish to npm |
161
234
 
162
- | Command | What it does |
163
- |---------|--------------|
164
- | `pf dev` | Start NATS + all services in watch mode |
165
- | `pf test` | Run tests across the monorepo |
166
- | `pf lint` | Lint and format with Biome |
167
- | `pf build` | Build all packages and services |
168
- | `pf event add <type> --service <path>` | Add contract, mock, handler + wire stream |
169
- | `pf event list` | List available events and their consumers |
170
- | `pf event publish <type>` | Publish mock event to NATS |
171
- | `pf pulumi up` | Deploy infrastructure (runs in `infra/`) |
235
+ <details>
236
+ <summary>🔐 Required secrets</summary>
237
+
238
+ <br />
239
+
240
+ | Secret | Description |
241
+ |:-------|:------------|
242
+ | `PULUMI_ACCESS_TOKEN` | [Pulumi Cloud token](https://app.pulumi.com/account/tokens) |
243
+ | `DIGITALOCEAN_TOKEN` | [DO API token](https://cloud.digitalocean.com/account/api/tokens) |
244
+ | `GHCR_TOKEN` | GitHub Container Registry PAT |
245
+
246
+ </details>
247
+
248
+ ---
249
+
250
+ ## 📋 Requirements
172
251
 
173
- `pf` proxies to Turborepo from any subdirectory.
252
+ | Requirement | Notes |
253
+ |:------------|:------|
254
+ | **Bun** or Node.js ≥ 21 | Bun recommended for speed |
255
+ | **[Pulumi CLI](https://www.pulumi.com/docs/install/)** | For infrastructure deployment |
256
+ | **[Docker](https://www.docker.com/)** | For local NATS |
174
257
 
175
- ### Configuration (advanced)
258
+ ---
259
+
260
+ ## 🔍 Under the Hood
261
+
262
+ <details>
263
+ <summary>📁 <b>Project structure</b></summary>
264
+
265
+ <br />
266
+
267
+ ```
268
+ my-platform/
269
+ ├── services/ # Your microservices
270
+ │ ├── orders/
271
+ │ └── notifications/
272
+ ├── packages/
273
+ │ └── contracts/ # Event contracts (single source of truth)
274
+ ├── infra/
275
+ │ └── services/ # Auto-generated Pulumi configs
276
+ └── .env.local # Auto-generated from infra
277
+ ```
278
+
279
+ **The key insight:** Services define their ports, env vars, and event subscriptions once. Everything else is derived.
280
+
281
+ </details>
176
282
 
177
283
  <details>
178
- <summary>Workspace configuration via <code>package.json</code></summary>
284
+ <summary>🛠️ <b>Tech stack</b></summary>
285
+
286
+ <br />
287
+
288
+ | Layer | Technology |
289
+ |:------|:-----------|
290
+ | Monorepo | [Turborepo](https://turbo.build/repo) |
291
+ | Services | [Hono](https://hono.dev) or [NestJS](https://nestjs.com) |
292
+ | Messaging | [NATS](https://nats.io) + JetStream |
293
+ | Events | [CloudEvents](https://cloudevents.io) + Zod validation |
294
+ | Infrastructure | [Pulumi](https://pulumi.com) → DigitalOcean (extensible) |
295
+ | Runtime | [Bun](https://bun.sh) |
296
+
297
+ </details>
298
+
299
+ <details>
300
+ <summary>⚙️ <b>Workspace configuration</b></summary>
301
+
302
+ <br />
179
303
 
180
304
  ```json
181
305
  {
182
306
  "pf": {
183
- "registry": "my-platform/platform",
307
+ "registry": "my-org/my-platform",
184
308
  "commands": {
185
- "pulumi": { "cwd": "infra" },
186
309
  "deploy": { "cwd": "infra", "command": "pulumi up --yes" }
187
310
  },
188
311
  "paths": {
189
312
  "services": { "path": "services", "watch": true },
190
- "apps": { "path": "apps", "watch": true },
191
- "packages": { "path": "packages", "watch": true },
192
313
  "contracts": { "path": "packages/contracts" }
193
314
  }
194
315
  }
195
316
  }
196
317
  ```
197
318
 
198
- - `commands`: Custom shortcuts with working directory overrides
199
- - `paths.<type>.watch`: Enable file watching in dev mode
200
- - `paths.<type>.ignorePatterns`: Glob patterns to exclude
201
-
202
319
  </details>
203
320
 
204
321
  <details>
205
- <summary>Infrastructure configuration via <code>infra/services/*.ts</code></summary>
322
+ <summary>🏗️ <b>Service infrastructure config</b></summary>
323
+
324
+ <br />
206
325
 
207
- ```ts
326
+ ```typescript
327
+ // infra/services/orders.ts
208
328
  import { ports, type K8sServiceConfig } from '@crossdelta/infrastructure'
209
329
 
210
- export const config: K8sServiceConfig = {
330
+ const config: K8sServiceConfig = {
211
331
  name: 'orders',
212
332
  ports: ports().http(4001).build(),
213
333
  replicas: 1,
@@ -217,102 +337,21 @@ export const config: K8sServiceConfig = {
217
337
  limits: { cpu: '150m', memory: '128Mi' },
218
338
  },
219
339
  }
340
+
341
+ export default config
220
342
  ```
221
343
 
222
344
  See [@crossdelta/infrastructure](https://www.npmjs.com/package/@crossdelta/infrastructure) for full options.
223
345
 
224
346
  </details>
225
347
 
226
- ---
227
-
228
- ## 🎯 Why This Exists
229
-
230
- `pf` solves platform engineering problems:
231
-
232
- - **Infrastructure drift** — Infra configs diverge from code in separate repos
233
- - **Manual wiring** — Ports, env vars, service discovery configured by hand
234
- - **Slow onboarding** — New devs spend days setting up local environments
235
-
236
- **Solution:** Services auto-generate `infra/services/*.ts`, ports/env derived automatically, event handlers type-safe and auto-discovered.
237
-
238
- **In short: docker-compose starts services — `pf` prevents systems from drifting apart over time.**
239
-
240
- ---
241
-
242
- ## 🧩 What pf Is / Is Not
243
-
244
- **✅ pf is:**
245
- - Opinionated platform toolkit for event-driven microservices
246
- - Turborepo scaffolder with Pulumi IaC and NATS messaging built-in
247
- - AI-assisted code generator from natural language descriptions
248
- - Unified dev workflow — one command to run everything
249
- - DigitalOcean-first for speed and simplicity — providers replaceable by design
250
-
251
- **❌ pf is not:**
252
- - Generic microservice generator — makes architectural choices for you
253
- - Multi-cloud out of the box — DigitalOcean first, extensible to other providers
254
- - Runtime manager — scaffolds code, you deploy with Pulumi
255
-
256
- **Note:** `pf` runs nothing implicitly. No hidden daemons, no automatic deployments. You control when code runs and infrastructure deploys.
257
-
258
- ---
259
-
260
- ## 🏗️ Architecture
261
-
262
- ```
263
- my-platform/
264
- ├── services/ # Microservices
265
- │ ├── nats/ # NATS message broker (auto-scaffolded)
266
- │ └── <service>/
267
- │ └── src/
268
- │ ├── events/ # Event handlers (*.event.ts)
269
- │ ├── use-cases/ # Business logic (*.use-case.ts)
270
- │ ├── types/ # Zod schemas
271
- │ └── index.ts
272
- ├── packages/
273
- │ └── contracts/ # Event contracts (Schema Registry)
274
- ├── infra/ # Pulumi Infrastructure-as-Code
275
- │ └── services/ # Per-service K8s configs
276
- └── .env.local # Auto-generated from infra
277
- ```
278
-
279
- ### Conventions
280
-
281
- | Location | Purpose |
282
- |----------|---------|
283
- | `services/*/src/events/*.event.ts` | Event handlers (auto-discovered) |
284
- | `services/*/src/use-cases/*.use-case.ts` | Business logic (pure functions) |
285
- | `packages/contracts/src/events/*.ts` | Event contracts (single source of truth) |
286
- | `infra/services/*.ts` | Pulumi configs per service |
287
-
288
- > **Schema Registry pattern:**
289
- > All event contracts live in `packages/contracts` as the single source of truth.
290
- > Services import contracts instead of redefining schemas, ensuring
291
- > type safety, compatibility, and explicit ownership across service boundaries.
292
-
293
- ### Event-Driven Pattern
294
-
295
- **Add events with one command:**
296
- ```bash
297
- # Creates contract, mock, handler, and wires the stream automatically
298
- pf event add orders.created --service services/notifications
299
- ```
300
-
301
- This generates:
302
- - `packages/contracts/src/events/orders-created.ts` (contract)
303
- - `packages/contracts/src/events/orders-created.mock.json` (test data)
304
- - `services/notifications/src/events/orders-created.event.ts` (handler)
305
- - Adds stream to service `index.ts` if needed
348
+ <details>
349
+ <summary>📡 <b>Event-driven architecture</b></summary>
306
350
 
307
- **Test events locally:**
308
- ```bash
309
- pf event list # Show available events
310
- pf event publish orders.created # Publish mock event to NATS
311
- ```
351
+ <br />
312
352
 
313
- **Manual pattern (if you prefer):**
353
+ **Contracts** live in `packages/contracts/` as the single source of truth:
314
354
 
315
- **1. Define contract:**
316
355
  ```typescript
317
356
  // packages/contracts/src/events/orders-created.ts
318
357
  import { createContract } from '@crossdelta/cloudevents'
@@ -324,25 +363,27 @@ export const OrdersCreatedContract = createContract({
324
363
  })
325
364
  ```
326
365
 
327
- **2. Publish (Service A):**
328
- ```typescript
329
- // services/orders/src/use-cases/create-order.use-case.ts
330
- await publish(OrdersCreatedContract, { orderId: '123', total: 99.99 })
331
- ```
366
+ **Handlers** import contracts and delegate to use cases:
332
367
 
333
- **3. Handle (Service B, auto-discovered):**
334
368
  ```typescript
335
369
  // services/notifications/src/events/orders-created.event.ts
370
+ import { handleEvent } from '@crossdelta/cloudevents'
371
+ import { OrdersCreatedContract } from '@my-org/contracts'
372
+ import { sendOrderNotification } from '../use-cases/send-notification.use-case'
373
+
336
374
  export default handleEvent(OrdersCreatedContract, async (data) => {
337
375
  await sendOrderNotification(data)
338
376
  })
339
377
  ```
340
378
 
341
- No manual subscriptions. Convention over configuration.
379
+ Handlers are auto-discovered. No manual subscriptions.
342
380
 
343
- ---
381
+ </details>
382
+
383
+ <details>
384
+ <summary>⚡ <b>NATS message broker</b></summary>
344
385
 
345
- ## ⚡ NATS Message Broker
386
+ <br />
346
387
 
347
388
  Every workspace includes pre-configured NATS with JetStream:
348
389
 
@@ -350,46 +391,46 @@ Every workspace includes pre-configured NATS with JetStream:
350
391
  - Ports: `4222` (client), `8222` (monitoring)
351
392
  - Health check: `curl http://localhost:8222/healthz`
352
393
 
353
- See `services/nats/README.md` for details.
394
+ </details>
354
395
 
355
396
  ---
356
397
 
357
- ## Deployment
358
-
359
- ```bash
360
- pulumi login && pulumi up --stack dev
361
- ```
398
+ ## 🧭 Philosophy
362
399
 
363
- ### GitHub Actions (pre-configured)
400
+ <table>
401
+ <tr>
402
+ <td width="50%">
364
403
 
365
- | Workflow | Trigger | Purpose |
366
- |----------|---------|---------|
367
- | `lint-and-tests.yml` | PR to `main` | Lint + test |
368
- | `build-and-deploy.yml` | Push to `main` | Build, push to GHCR, deploy |
369
- | `publish-packages.yml` | Changes in `packages/` | Publish to npm |
404
+ ### What pf is
370
405
 
371
- <details>
372
- <summary>Required secrets</summary>
406
+ - Opinionated full-stack platform toolkit
407
+ - Unified dev workflow — one command to run everything
408
+ - Infrastructure that stays in sync with your code
373
409
 
374
- | Secret | Description |
375
- |--------|-------------|
376
- | `PULUMI_ACCESS_TOKEN` | [Pulumi Cloud token](https://app.pulumi.com/account/tokens) |
377
- | `DIGITALOCEAN_TOKEN` | [DO API token](https://cloud.digitalocean.com/account/api/tokens) |
378
- | `GHCR_TOKEN` | GitHub Container Registry PAT |
379
- | `NPM_TOKEN` | [npm access token](https://www.npmjs.com/settings/~/tokens) (only for `publish-packages.yml`) |
410
+ </td>
411
+ <td width="50%">
380
412
 
381
- </details>
413
+ ### ❌ What pf is not
382
414
 
383
- ---
415
+ - Generic scaffolder — it makes choices for you
416
+ - Multi-cloud out of the box — DigitalOcean first, extensible later
417
+ - Magic — no hidden daemons, you control when things run
384
418
 
385
- ## 📚 Requirements
419
+ </td>
420
+ </tr>
421
+ </table>
386
422
 
387
- - **Bun** (recommended) or Node.js 21
388
- - **[Pulumi CLI](https://www.pulumi.com/docs/install/)** for deployment
389
- - **[Docker](https://www.docker.com/)** for local NATS
423
+ > **`pf` makes architectural decisions so your team doesn't have to.**
424
+ > You can still understand everything — but you don't have to on day one.
390
425
 
391
426
  ---
392
427
 
393
- ## 📄 License
428
+ <p align="center">
429
+ <strong>MIT © <a href="https://crossdelta.io">Crossdelta</a></strong>
430
+ </p>
394
431
 
395
- MIT © Crossdelta
432
+ <p align="center">
433
+ <a href="https://www.npmjs.com/package/@crossdelta/platform-sdk">npm</a> •
434
+ <a href="https://github.com/crossdelta/platform-sdk">GitHub</a> •
435
+ <a href="https://crossdelta.io">Website</a>
436
+ </p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crossdelta/platform-sdk",
3
- "version": "0.8.34",
3
+ "version": "0.8.35",
4
4
  "description": "Platform toolkit for event-driven microservices — keeping code and infrastructure in lockstep.",
5
5
  "keywords": [
6
6
  "cli",