@crossdelta/platform-sdk 0.18.6 → 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.
- package/README.md +27 -5
- package/bin/chunk-634PL24Z.mjs +20 -0
- package/bin/cli.mjs +604 -0
- package/bin/config-CKQHYOF4.mjs +2 -0
- package/bin/docs/generators/code-style.md +79 -0
- package/bin/docs/generators/natural-language.md +117 -0
- package/bin/docs/generators/service.md +129 -60
- package/bin/templates/hono-microservice/Dockerfile.hbs +1 -0
- package/bin/templates/hono-microservice/src/config/env.ts.hbs +3 -0
- package/bin/templates/nest-microservice/Dockerfile.hbs +2 -0
- package/bin/templates/nest-microservice/src/config/env.ts.hbs +17 -0
- package/bin/templates/nest-microservice/src/main.ts.hbs +2 -1
- package/bin/templates/workspace/.github/actions/prepare-build-context/action.yml +12 -6
- package/bin/templates/workspace/biome.json.hbs +4 -1
- package/bin/templates/workspace/infra/package.json.hbs +1 -1
- package/bin/templates/workspace/package.json.hbs +1 -0
- package/bin/templates/workspace/packages/contracts/README.md.hbs +5 -5
- package/bin/templates/workspace/packages/contracts/package.json.hbs +14 -5
- package/bin/templates/workspace/packages/contracts/src/index.ts +1 -1
- package/bin/templates/workspace/packages/contracts/tsconfig.json.hbs +6 -1
- package/bin/templates/workspace/turbo.json +8 -10
- package/bin/templates/workspace/turbo.json.hbs +6 -5
- package/dist/facade.d.mts +840 -0
- package/dist/facade.d.ts +840 -0
- package/dist/facade.js +2294 -0
- package/dist/facade.js.map +1 -0
- package/dist/facade.mjs +2221 -0
- package/dist/facade.mjs.map +1 -0
- package/dist/plugin-types-DQOv97Zh.d.mts +180 -0
- package/dist/plugin-types-DQOv97Zh.d.ts +180 -0
- package/dist/plugin-types.d.mts +1 -0
- package/dist/plugin-types.d.ts +1 -0
- package/dist/plugin-types.js +19 -0
- package/dist/plugin-types.js.map +1 -0
- package/dist/plugin-types.mjs +1 -0
- package/dist/plugin-types.mjs.map +1 -0
- package/dist/plugin.d.mts +31 -0
- package/dist/plugin.d.ts +31 -0
- package/dist/plugin.js +105 -0
- package/dist/plugin.js.map +1 -0
- package/dist/plugin.mjs +75 -0
- package/dist/plugin.mjs.map +1 -0
- package/package.json +118 -99
- package/bin/cli.js +0 -544
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
|
|
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
|
|
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
|
|
197
|
-
| `pf
|
|
198
|
-
| `pf
|
|
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};
|