@crossdelta/platform-sdk 0.19.0 → 0.19.1

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 (43) hide show
  1. package/README.md +27 -5
  2. package/bin/chunk-634PL24Z.mjs +20 -0
  3. package/bin/cli.mjs +604 -0
  4. package/bin/config-CKQHYOF4.mjs +2 -0
  5. package/bin/docs/generators/code-style.md +79 -0
  6. package/bin/docs/generators/natural-language.md +117 -0
  7. package/bin/docs/generators/service.md +129 -60
  8. package/bin/templates/hono-microservice/Dockerfile.hbs +1 -0
  9. package/bin/templates/hono-microservice/src/config/env.ts.hbs +3 -0
  10. package/bin/templates/nest-microservice/Dockerfile.hbs +2 -0
  11. package/bin/templates/nest-microservice/src/config/env.ts.hbs +17 -0
  12. package/bin/templates/nest-microservice/src/main.ts.hbs +2 -1
  13. package/bin/templates/workspace/.github/actions/prepare-build-context/action.yml +12 -6
  14. package/bin/templates/workspace/biome.json.hbs +4 -1
  15. package/bin/templates/workspace/package.json.hbs +1 -0
  16. package/bin/templates/workspace/packages/contracts/README.md.hbs +5 -5
  17. package/bin/templates/workspace/packages/contracts/package.json.hbs +13 -4
  18. package/bin/templates/workspace/packages/contracts/src/index.ts +1 -1
  19. package/bin/templates/workspace/packages/contracts/tsconfig.json.hbs +6 -1
  20. package/bin/templates/workspace/turbo.json +8 -11
  21. package/bin/templates/workspace/turbo.json.hbs +6 -5
  22. package/dist/facade.d.mts +840 -0
  23. package/dist/facade.d.ts +840 -0
  24. package/dist/facade.js +2294 -0
  25. package/dist/facade.js.map +1 -0
  26. package/dist/facade.mjs +2221 -0
  27. package/dist/facade.mjs.map +1 -0
  28. package/dist/plugin-types-DQOv97Zh.d.mts +180 -0
  29. package/dist/plugin-types-DQOv97Zh.d.ts +180 -0
  30. package/dist/plugin-types.d.mts +1 -0
  31. package/dist/plugin-types.d.ts +1 -0
  32. package/dist/plugin-types.js +19 -0
  33. package/dist/plugin-types.js.map +1 -0
  34. package/dist/plugin-types.mjs +1 -0
  35. package/dist/plugin-types.mjs.map +1 -0
  36. package/dist/plugin.d.mts +31 -0
  37. package/dist/plugin.d.ts +31 -0
  38. package/dist/plugin.js +105 -0
  39. package/dist/plugin.js.map +1 -0
  40. package/dist/plugin.mjs +75 -0
  41. package/dist/plugin.mjs.map +1 -0
  42. package/package.json +118 -99
  43. package/bin/cli.js +0 -540
package/README.md CHANGED
@@ -132,13 +132,13 @@ pf new hono-micro services/orders
132
132
  pf new hono-micro services/notifications
133
133
 
134
134
  # 2. Wire an event from orders → notifications
135
- pf event add order.created --service services/notifications
135
+ pf cloudevents add order.created --service services/notifications
136
136
 
137
137
  # 3. Restart to pick up new services
138
138
  pf dev
139
139
 
140
140
  # 4. Publish a test event — watch notifications react
141
- pf event publish order.created
141
+ pf cloudevents publish order.created
142
142
  ```
143
143
 
144
144
  <br />
@@ -193,9 +193,9 @@ pf event publish order.created
193
193
  | `pf dev` | 🚀 Start development infrastructure (NATS) + all services in watch mode |
194
194
  | `pf new hono-micro <path>` | ⚡ Create a Hono service (lightweight, Bun-optimized) |
195
195
  | `pf new nest-micro <path>` | 🏢 Create a NestJS service (full-featured, decorators) |
196
- | `pf event add <type> --service <path>` | 🔗 Add contract + handler + wire stream |
197
- | `pf event list` | 📋 List available events and consumers |
198
- | `pf event publish <type>` | 📤 Publish mock event to NATS |
196
+ | `pf cloudevents add <type> --service <path>` | 🔗 Add contract + handler + wire stream |
197
+ | `pf cloudevents list` | 📋 List available events and consumers |
198
+ | `pf cloudevents publish <type>` | 📤 Publish mock event to NATS |
199
199
  | `pf setup completion` | 🔧 Install shell autocompletion (zsh/bash) |
200
200
  | `pf setup ai` | 🤖 Configure AI provider for code generation |
201
201
  | `pf test` | 🧪 Run tests across the monorepo |
@@ -224,6 +224,28 @@ Add descriptions to your workspace commands for better autocompletion:
224
224
 
225
225
  Then `pf <TAB>` shows: `deploy -- Deploy infrastructure to production`
226
226
 
227
+ #### Plugins
228
+
229
+ Extend `pf` with additional commands via plugins. Plugins are loaded from workspace `package.json`:
230
+
231
+ ```json
232
+ {
233
+ "pf": {
234
+ "plugins": ["@crossdelta/cloudevents"]
235
+ }
236
+ }
237
+ ```
238
+
239
+ **Built-in plugins:**
240
+ - `@crossdelta/cloudevents` - Event contracts, handlers, and NATS publishing (auto-enabled in new workspaces)
241
+
242
+ **Plugin commands are namespaced:**
243
+ ```bash
244
+ pf cloudevents add order.created --service services/orders
245
+ pf cloudevents list
246
+ pf cloudevents publish order.created
247
+ ```
248
+
227
249
  ---
228
250
 
229
251
  ## 🤖 AI-Assisted Generation
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ var tt=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(r,e)=>(typeof require<"u"?require:r)[e]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});import{existsSync as C,readdirSync as Tt,readFileSync as q,writeFileSync as St}from"fs";import{join as p,resolve as At}from"path";var Mt=process.env.npm_package_version||"0.0.0",_=["bun.lock","bun.lockb","package-lock.json","yarn.lock","pnpm-lock.yaml"],Ht="start:dev";import w from"chalk";function qt(t,r){if(t.length===0)return"No entries to display.";let e=r?.title||"Benchmark Results",n=r?.footer||"",o=r?.maxBarWidth||50,s=r?.unit||"",i=Math.max(...t.map(c=>c.value)),a=[];a.push(""),a.push(e),a.push("");for(let c of t){let g=rt(c.barColor??r?.barColor),u=et(c,i,o,g,s,r?.labelColor);a.push(u)}return n&&(a.push(""),a.push(n)),a.join(`
3
+ `)}function rt(t){return t?w[t]("\u2587"):"\u2587"}function et(t,r,e,n,o,s){let i=Math.round(t.value/r*e),a=t.barColor?w[t.barColor](n.repeat(i)):n.repeat(i),c=t.color??s;return`${w.bold(c?w[c](t.label.padEnd(12)):t.label.padEnd(12))} ${a} ${t.value.toLocaleString()}${o?` ${o}`:""}`}import G from"chalk";import{Command as dt}from"commander";import{Listr as U}from"listr2";var d={SUCCESS:0,GENERAL_ERROR:1,USAGE_ERROR:2,WORKSPACE_ERROR:64,VALIDATION_ERROR:65,CONFIG_ERROR:66,IO_ERROR:74,PERMISSION_ERROR:77,CANCELLED:130};var m=class extends Error{exitCode;category;hint;cause;constructor(r,e=d.GENERAL_ERROR,n={}){super(r),this.name="CliError",this.exitCode=e,this.category=n.category??"process",this.hint=n.hint,this.cause=n.cause}toUserMessage(){let r=[this.message];return this.hint&&r.push(`
4
+ Hint: ${this.hint}`),r.join("")}};var f=class extends m{path;constructor(r,e,n={}){super(r,d.IO_ERROR,{...n,category:"io"}),this.name="IoError",this.path=e}},y=class extends m{constructor(r="Operation cancelled",e={}){super(r,d.CANCELLED,{...e,category:"user"}),this.name="CancelledError"}};import h from"chalk";var nt=t=>t instanceof Error,nr=t=>nt(t)?t.message:typeof t=="string"?t:String(t),W=["ExitPromptError"],I=["Cancelled prompt","User force closed"],ot=["ERR_USE_AFTER_CLOSE"],st=t=>W.some(r=>t.name?.includes(r))||I.some(r=>t.message?.includes(r)),$=t=>{if(t instanceof y)return!0;if(!(t instanceof Error))return!1;if(W.some(e=>t.name?.includes(e))||I.some(e=>t.message?.includes(e)))return!0;let r=t.code;return r&&ot.includes(r)?st(t):!1},it=t=>{if(t instanceof m){let e=t.toUserMessage();return h.red(`\u2716 ${e||"Unexpected error (re-run with DEBUG=true for details)"}`)}if(t instanceof Error){let e=t.message?.trim();return e?h.red(`\u2716 ${e}`):h.red("\u2716 Unexpected error (re-run with DEBUG=true for details)")}let r=String(t);return!r||r==="undefined"||r==="null"?h.red("\u2716 Unexpected error (re-run with DEBUG=true for details)"):h.red(`\u2716 ${r}`)},at=t=>t instanceof m?t.exitCode:$(t)?d.CANCELLED:d.GENERAL_ERROR,J=(t,r={})=>{let{debug:e=process.env.DEBUG==="true",exit:n=!0,logger:o=console.error}=r;if($(t)){n&&process.exit(d.CANCELLED);return}o(it(t)),e&&t instanceof Error&&t.stack&&o(h.dim(t.stack)),t instanceof m&&t.hint&&o(h.dim(`
5
+ Hint: ${t.hint}`)),n&&process.exit(at(t))};import{existsSync as S,unlinkSync as ct,writeFileSync as pt}from"fs";import{join as T}from"path";import L from"chokidar";var lt=".pf-generating",P=t=>T(t,lt),gt=t=>S(P(t)),D=t=>{pt(P(t),"","utf-8")},A=t=>{let r=P(t);S(r)&&ct(r)},ut=t=>{let e=R(t)?.pf?.paths;return e?Object.values(e).filter(n=>typeof n=="object"&&n!==null&&n.watch===!0&&typeof n.path=="string"):[{path:"services"},{path:"apps"}]},mr=(t,r)=>{A(t);let e=ut(t),n=P(t),s=j(async()=>{gt(t)||await r()},300),i=[];i.push(L.watch(n,{ignoreInitial:!0}).on("unlink",()=>r()));for(let a of e){let c=T(t,a.path);if(!S(c))continue;let g=a.ignorePatterns?.map(u=>T(c,u));i.push(L.watch(c,{ignoreInitial:!0,depth:0,ignored:g,usePolling:!0,interval:1e3}).on("addDir",u=>u!==c&&s()).on("unlinkDir",u=>u!==c&&s())),i.push(L.watch(`${c}/*/package.json`,{ignoreInitial:!0,ignored:g}).on("add",s).on("change",s))}return async()=>{await Promise.all(i.map(a=>a.close()))}};var yr=t=>{let r=new dt(t.name).description(t.description).showHelpAfterError();t.arguments?.forEach(([o,s])=>{r.argument(o,s)}),t.options?.forEach(([o,s])=>{r.option(o,s)}),t.exampleUsage&&r.addHelpText("after",()=>`${G.cyan.bold(`
6
+ Example:`)}
7
+ ${G.bold(t.exampleUsage)}
8
+ `),t.additionalInfo&&r.addHelpText("after",()=>(typeof t.additionalInfo=="function"?t.additionalInfo():t.additionalInfo)??"");let e=async o=>{t.prompts?.length&&await new U(B(t.prompts,o),{rendererOptions:{lazy:!0,showErrorMessage:!1}}).run(o),await new U(B(t.actions,o),{rendererOptions:{lazy:!1,showErrorMessage:!1}}).run(o),await t.onComplete?.(o)},n=()=>{try{let o=k();return D(o),o}catch{return null}};return r.action(async(...o)=>{let s=null;try{let i=o.at(-1),a=i.args,c=i.opts(),g=mt(t.arguments??[],a);if(t.shouldSkipWorkflow?.(g,c)){await t.onSkipWorkflow?.(g,c);return}let u=await t.buildContext(g,c);s=n(),await e(u)}catch(i){J(i,{exit:!1})}finally{s&&A(s)}}),r},mt=(t,r)=>{let e=t.map(([n],o)=>[n.replace(/[<>[\]]/g,""),r[o]]);return Object.fromEntries(e)},B=(t,r)=>t.map(e=>typeof e=="function"?e(r):e);var j=(t,r)=>{let e=null;return(...n)=>(e&&clearTimeout(e),new Promise(o=>{e=setTimeout(async()=>{e=null,await t(...n),o()},r)}))};import{execaSync as ft}from"execa";function kt(t){try{return ft(t,["--version"]),!0}catch{return!1}}import{readdirSync as ht}from"fs";import{dirname as V,isAbsolute as xt,join as Et,normalize as Ct,resolve as M,sep as wt}from"path";import{fileURLToPath as yt}from"url";import{packageUpSync as Pt}from"package-up";import{rimraf as Rt}from"rimraf";var vt=()=>typeof import.meta?.url=="string"?yt(import.meta.url):process.cwd(),$r=t=>{let r=K()?k():process.cwd();return Et(r,t)},Jr=(t,r)=>{if(!t||!t.trim())throw new f("Path cannot be empty",t,{hint:"Provide a valid relative path"});if(xt(t))throw new f(`Absolute paths are not allowed: ${t}`,t,{hint:"Use a relative path within the target directory"});if(/^[a-zA-Z]:/.test(t))throw new f(`Windows drive paths are not allowed: ${t}`,t,{hint:"Use a relative path within the target directory"});if(t.replace(/\\/g,"/").split("/").some(a=>a===".."))throw new f(`Path traversal not allowed: ${t}`,t,{hint:"The path must stay within the target directory"});let o=Ct(t),s=M(r),i=M(r,o);if(!i.startsWith(s+wt)&&i!==s)throw new f(`Path escapes target directory: ${t}`,t,{hint:"The path must stay within the target directory"});return i},Dr=t=>{try{return ht(t).length===0}catch{return!0}};function H(){let t=Pt({cwd:V(vt())});if(!t)throw new Error("Could not find package.json");return V(t)}var jr=t=>Rt(t);import x from"chalk";var z={debug:0,info:1,warn:2,error:3,silent:4},bt=t=>t==="debug"||t==="info"||t==="warn"||t==="error"||t==="silent",Ot=()=>{let t=process.env.LOG_LEVEL;return bt(t)?t:process.env.DEBUG==="true"||process.env.VERBOSE==="true"?"debug":"info"},v=t=>{let r=Ot();return z[t]>=z[r]};var l={logs:[],breakLine:()=>(console.log(),l),success:(t,...r)=>(console.log(x.green(`\u2714 ${t}`),...r),l),info:(t,...r)=>(v("info")&&console.log(x.cyan(`\u{1F6C8} ${t}`),...r),l),warn:(t,...r)=>(v("warn")&&console.warn(x.yellow(`\u26A0\uFE0E ${t}`),...r),l),error:(t,...r)=>(v("error")&&console.error(x.red(`\u2716 ${t}`),...r),l),debug:(t,...r)=>(v("debug")&&console.log(x.dim(`[debug] ${t}`),...r),l),log:(t,...r)=>(console.log(t,...r),l.logs.push({message:t,context:r.join()}),l),getStoredLogs:t=>t?l.logs.filter(r=>r.context?.includes(t)):l.logs,storeLog:(t,r)=>l.logs.push({message:t,context:r})};import Lt from"chalk";async function Hr(t,r){let e=Date.now(),n=t.title,o=()=>Math.floor((Date.now()-e)/1e3),s=setInterval(()=>{o()>1&&(t.title=`${n} (${o()}s)`)},1e3);try{return await r(o)}finally{clearInterval(s)}}async function Kr(t,r,e){for(let n=0;n<r.length;n++){let o=r[n];t.output=Lt.dim(`[${n+1}/${r.length}] ${o.title}`),await o.fn(e??{},t)}}var F=t=>JSON.parse(q(t,"utf-8")),Nt=F,Ft=(t,r,e)=>St(t,`${JSON.stringify(r,null,2)}
9
+ `,"utf-8"),_t=["@crossdelta/cloudevents"],E={services:"services",apps:"apps",packages:"packages",contracts:"packages/contracts"},Wt={docs:{base:["service.md"],frameworks:{}},serviceTypes:{hono:{commandType:"hono-micro",entryPoint:"src/index.ts",skipFiles:[]},nest:{commandType:"nest-micro",entryPoint:"src/main.ts",skipFiles:[]}}},O=t=>{if(!C(t))return null;try{return JSON.parse(q(t,"utf-8"))}catch{return null}},b=(t,r)=>typeof t=="string"?t:typeof t=="object"&&t!==null&&"path"in t?t.path:r,It=t=>t.split("/").pop()||"workspace",$t=t=>{let r=t.slice(0,t.lastIndexOf("/"));return r===t?null:r},Y=t=>t.split("."),Jt=(t,r)=>{if(!t.workspaces)return!1;if(t.pf||C(p(r,"turbo.json")))return!0;let e=_.some(o=>C(p(r,o))),n=C(p(r,"infra"));return e&&n},Dt=t=>{let r=O(p(t,"package.json"));return r?Jt(r,t):!1},Z=t=>{let r=t;for(;r;){if(Dt(r))return r;r=$t(r)}return null},K=()=>Z(process.cwd())!==null,k=()=>{let t=Z(process.cwd());if(!t)throw new Error(`
10
+ \x1B[31m\u2716\x1B[0m Not in a workspace directory
11
+
12
+ Current directory: ${process.cwd()}
13
+
14
+ This command must be run from within a workspace created with \x1B[36mpf new workspace\x1B[0m
15
+
16
+ To create a new workspace, run:
17
+
18
+ \x1B[36mpf new workspace my-platform\x1B[0m
19
+ `);return t},R=t=>{let r=t??k();return O(p(r,"package.json"))},Q=t=>{let r=R(t);if(!r?.pf?.paths)return E;let{paths:e}=r.pf;return{services:b(e.services,E.services),apps:b(e.apps,E.apps),packages:b(e.packages,E.packages),contracts:b(e.contracts,E.contracts)}},le=t=>{let r=R(t);return{plugins:r?.pf?.plugins??_t,dev:{filter:r?.pf?.dev?.filter??[]}}},ge=t=>{let r=t??k(),e=Q(r),n=p(r,e.contracts),s=O(p(n,"package.json"))?.name??`${jt()}/contracts`;return{packagePath:n,eventsPath:p(n,"src","events"),indexPath:p(n,"src","index.ts"),relativePath:e.contracts,packageName:s}},jt=()=>{let t=k(),r=O(p(t,"package.json")),e=`@${It(t)}`;return r?.name?r.name.startsWith("@")?r.name.split("/")[0]:`@${r.name}`:e},Gt=(t,r)=>{let e=Y(r),n=t;for(let o of e){if(n===null||typeof n!="object"||!(o in n))return;n=n[o]}return n},Ut=(t,r,e)=>{let n=Y(r),o=n[n.length-1],s=t;for(let i of n.slice(0,-1))(!(i in s)||typeof s[i]!="object"||s[i]===null)&&(s[i]={}),s=s[i];s[o]=e},ue=(t,r=process.cwd())=>{let e=F(p(r,"package.json"));return Gt(e,t)},de=(t,r,e=process.cwd())=>{let n=p(e,"package.json"),o=F(n);Ut(o,t,r),Ft(n,o,{spaces:2,EOL:`
20
+ `,encoding:"utf-8"})},Bt=t=>{let r=H();return Nt(At(r,t))},N=null,X=()=>(N||(N=Bt("package.json")),N),me=new Proxy({},{get:(t,r)=>X()[r]}),fe=()=>X().generatorConfig??Wt,ke=t=>{let r=t??k(),e=Q(r),n=p(r,e.services);if(!C(n))return[];try{return Tt(n,{withFileTypes:!0}).filter(s=>s.isDirectory()&&!s.name.startsWith(".")).map(s=>`${e.services}/${s.name}`).sort()}catch{return[]}};export{tt as a,d as b,nt as c,nr as d,$ as e,J as f,Ht as g,qt as h,lt as i,mr as j,yr as k,j as l,kt as m,$r as n,Jr as o,Dr as p,jr as q,l as r,Hr as s,Kr as t,K as u,k as v,R as w,Q as x,le as y,ge as z,jt as A,ue as B,de as C,Bt as D,X as E,me as F,fe as G,ke as H};