@kyro-cms/core 0.12.27 → 0.12.30

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.
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';require('../chunk-AHSFSERC.cjs');var commander=require('commander'),fs=require('fs'),path=require('path'),url=require('url'),glob=require('glob');var _documentCurrentScript=typeof document!=='undefined'?document.currentScript:null;function y(e){switch(e.type){case "text":case "email":case "password":case "textarea":case "color":case "code":case "markdown":case "date":case "richtext":case "json":return e.hasMany?"string[]":"string";case "number":return e.hasMany?"number[]":"number";case "checkbox":return "boolean";case "select":case "radio":if(e.options){let t=e.options.map(r=>`'${r.value}'`).join(" | ");return e.hasMany?`(${t})[]`:t}return e.hasMany?"string[]":"string";case "relationship":if(Array.isArray(e.relationTo)){if(e.relationTo.includes("*"))return e.hasMany?"any[]":"any";let t=e.relationTo.map(r=>`${m(r)} | string`).join(" | ");return e.hasMany?`(${t})[]`:`(${t})`}let n=e.relationTo||"unknown";return n==="*"?e.hasMany?"any[]":"any":e.hasMany?`(${m(n)} | string)[]`:`${m(n)} | string`;case "upload":return e.hasMany?"(Media | string)[]":"Media | string";case "array":return e.fields&&e.fields.length>0?`Array<{
3
- ${e.fields.filter(r=>r.name).map(r=>{let o=y(r);return ` ${r.name}${r.required?"":"?"}: ${o};`}).join(`
2
+ 'use strict';require('../chunk-AHSFSERC.cjs');var commander=require('commander'),x=require('fs'),_=require('path'),url=require('url'),glob=require('glob'),child_process=require('child_process'),q=require('readline/promises'),process$1=require('process'),F=require('crypto'),o=require('chalk');var _documentCurrentScript=typeof document!=='undefined'?document.currentScript:null;function _interopDefault(e){return e&&e.__esModule?e:{default:e}}function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var x__default=/*#__PURE__*/_interopDefault(x);var ___default=/*#__PURE__*/_interopDefault(_);var q__namespace=/*#__PURE__*/_interopNamespace(q);var F__default=/*#__PURE__*/_interopDefault(F);var o__default=/*#__PURE__*/_interopDefault(o);function R(e){switch(e.type){case "text":case "email":case "password":case "textarea":case "color":case "code":case "markdown":case "date":case "richtext":case "json":return e.hasMany?"string[]":"string";case "number":return e.hasMany?"number[]":"number";case "checkbox":return "boolean";case "select":case "radio":if(e.options){let t=e.options.map(n=>`'${n.value}'`).join(" | ");return e.hasMany?`(${t})[]`:t}return e.hasMany?"string[]":"string";case "relationship":if(Array.isArray(e.relationTo)){if(e.relationTo.includes("*"))return e.hasMany?"any[]":"any";let t=e.relationTo.map(n=>`${C(n)} | string`).join(" | ");return e.hasMany?`(${t})[]`:`(${t})`}let r=e.relationTo||"unknown";return r==="*"?e.hasMany?"any[]":"any":e.hasMany?`(${C(r)} | string)[]`:`${C(r)} | string`;case "upload":return e.hasMany?"(Media | string)[]":"Media | string";case "array":return e.fields&&e.fields.length>0?`Array<{
3
+ ${e.fields.filter(n=>n.name).map(n=>{let s=R(n);return ` ${n.name}${n.required?"":"?"}: ${s};`}).join(`
4
4
  `)}
5
5
  }>`:"Record<string, any>[]";case "group":return e.fields&&e.fields.length>0?`{
6
- ${e.fields.filter(r=>r.name).map(r=>{let o=y(r);return ` ${r.name}${r.required?"":"?"}: ${o};`}).join(`
6
+ ${e.fields.filter(n=>n.name).map(n=>{let s=R(n);return ` ${n.name}${n.required?"":"?"}: ${s};`}).join(`
7
7
  `)}
8
- }`:"Record<string, any>";case "blocks":return "Block[]";default:return "any"}}function m(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(n,t)=>t.toUpperCase())}function C(e){return e.replace(/-([a-z])/g,(n,t)=>t.toUpperCase())}function _(e){let n=m(e.slug),t=e.fields.filter(r=>r.name).map(r=>{let o=y(r);return ` ${r.name}${r.required?"":"?"}: ${o};`});return t.unshift(" id: string;"),t.push(" createdAt: string;"),t.push(" updatedAt: string;"),`export interface ${n} {
8
+ }`:"Record<string, any>";case "blocks":return "Block[]";default:return "any"}}function C(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(r,t)=>t.toUpperCase())}function N(e){return e.replace(/-([a-z])/g,(r,t)=>t.toUpperCase())}function Y(e){let r=C(e.slug),t=e.fields.filter(n=>n.name).map(n=>{let s=R(n);return ` ${n.name}${n.required?"":"?"}: ${s};`});return t.unshift(" id: string;"),t.push(" createdAt: string;"),t.push(" updatedAt: string;"),`export interface ${r} {
9
9
  ${t.join(`
10
10
  `)}
11
- }`}function T(e){let n=e.map(s=>_(s)),t=`// ============================================================================
11
+ }`}function K(e){let r=e.map(a=>Y(a)),t=`// ============================================================================
12
12
  // Auto-generated by kyro generate
13
13
  // ============================================================================
14
14
 
@@ -31,9 +31,9 @@ export interface Block {
31
31
  [key: string]: any;
32
32
  }
33
33
 
34
- `,r=n.join(`
34
+ `,n=r.join(`
35
35
 
36
- `),o=`
36
+ `),s=`
37
37
 
38
38
  // ============================================================================
39
39
  // Query Types
@@ -96,7 +96,7 @@ export interface KyroDeleteResult<T> {
96
96
  // ============================================================================
97
97
 
98
98
  export interface KyroCollections {
99
- ${e.map(s=>` ${C(s.slug)}: ${m(s.slug)};`).join(`
99
+ ${e.map(a=>` ${N(a.slug)}: ${C(a.slug)};`).join(`
100
100
  `)}
101
101
  }
102
102
 
@@ -114,7 +114,7 @@ export interface KyroTypedClient<C extends keyof KyroCollections> {
114
114
  }
115
115
 
116
116
  export interface KyroClient {
117
- ${e.map(s=>` ${C(s.slug)}: KyroTypedClient<'${s.slug}'>;`).join(`
117
+ ${e.map(a=>` ${N(a.slug)}: KyroTypedClient<'${a.slug}'>;`).join(`
118
118
  `)}
119
119
  }
120
120
 
@@ -122,7 +122,7 @@ export function createClient(config: { url: string; token?: string }): KyroClien
122
122
  // Client implementation would be here
123
123
  throw new Error('Not implemented');
124
124
  }
125
- `;return t+r+o}async function q(e,n){let t=`${e.replace(/\/+$/,"")}/api/__schema`,r=await fetch(t,{headers:{Authorization:`ApiKey ${n}`}});if(!r.ok){let o=await r.text();throw new Error(`Schema fetch failed (${r.status}): ${o}`)}return r.json()}function D(e){let n=`// ============================================================================
125
+ `;return t+n+s}async function G(e,r){let t=`${e.replace(/\/+$/,"")}/api/__schema`,n=await fetch(t,{headers:{Authorization:`ApiKey ${r}`}});if(!n.ok){let s=await n.text();throw new Error(`Schema fetch failed (${n.status}): ${s}`)}return n.json()}function Q(e){let r=`// ============================================================================
126
126
  // Auto-generated by kyro generate --api
127
127
  // ============================================================================
128
128
 
@@ -145,12 +145,12 @@ export interface Block {
145
145
  [key: string]: any;
146
146
  }
147
147
 
148
- `;for(let t of e){let r=m(t.slug),o=t.fields.filter(s=>s.name).map(s=>{let a=y(s);return ` ${s.name}${s.required?"":"?"}: ${a};`});o.unshift(" id: string;"),o.push(" createdAt: string;"),o.push(" updatedAt: string;"),n+=`export interface ${r} {
149
- ${o.join(`
148
+ `;for(let t of e){let n=C(t.slug),s=t.fields.filter(a=>a.name).map(a=>{let c=R(a);return ` ${a.name}${a.required?"":"?"}: ${c};`});s.unshift(" id: string;"),s.push(" createdAt: string;"),s.push(" updatedAt: string;"),r+=`export interface ${n} {
149
+ ${s.join(`
150
150
  `)}
151
151
  }
152
152
 
153
- `;}return n+=`// ============================================================================
153
+ `;}return r+=`// ============================================================================
154
154
  // Typed REST Client
155
155
  // ============================================================================
156
156
 
@@ -189,23 +189,107 @@ export function createKyroClient(opts: KyroClientOptions) {
189
189
  }
190
190
 
191
191
  return {
192
- ${e.map(t=>{let r=m(t.slug);return ` ${C(t.slug)}: {
192
+ ${e.map(t=>{let n=C(t.slug);return ` ${N(t.slug)}: {
193
193
  find: (args?: { where?: Record<string, any>; sort?: string; limit?: number; page?: number; draft?: boolean }) =>
194
- request<{ docs: ${r}[]; totalDocs: number; page: number; totalPages: number; hasNextPage: boolean; hasPrevPage: boolean }>(\`/${t.slug}\${args ? "?" + qs(args) : ""}\`),
194
+ request<{ docs: ${n}[]; totalDocs: number; page: number; totalPages: number; hasNextPage: boolean; hasPrevPage: boolean }>(\`/${t.slug}\${args ? "?" + qs(args) : ""}\`),
195
195
  findByID: (id: string, args?: { draft?: boolean }) =>
196
- request<${r}>(\`/${t.slug}/\${id}\${args ? "?" + qs(args) : ""}\`),
196
+ request<${n}>(\`/${t.slug}/\${id}\${args ? "?" + qs(args) : ""}\`),
197
197
  findBySlug: (slug: string, args?: { draft?: boolean }) =>
198
- request<{ docs: ${r}[] }>(\`/${t.slug}?where=\${encodeURIComponent(JSON.stringify({ slug: { equals: slug } }))}\`),
199
- create: (data: Partial<${r}>) =>
200
- request<{ doc: ${r}; message?: string }>(\`/${t.slug}\`, { method: "POST", body: JSON.stringify(data) }),
201
- update: (id: string, data: Partial<${r}>, args?: { baseUpdatedAt?: string }) =>
202
- request<{ doc: ${r}; message?: string }>(\`/${t.slug}/\${id}\`, { method: "PATCH", body: JSON.stringify({ ...data, ...args }) }),
198
+ request<{ docs: ${n}[] }>(\`/${t.slug}?where=\${encodeURIComponent(JSON.stringify({ slug: { equals: slug } }))}\`),
199
+ create: (data: Partial<${n}>) =>
200
+ request<{ doc: ${n}; message?: string }>(\`/${t.slug}\`, { method: "POST", body: JSON.stringify(data) }),
201
+ update: (id: string, data: Partial<${n}>, args?: { baseUpdatedAt?: string }) =>
202
+ request<{ doc: ${n}; message?: string }>(\`/${t.slug}/\${id}\`, { method: "PATCH", body: JSON.stringify({ ...data, ...args }) }),
203
203
  delete: (id: string) =>
204
- request<{ doc: ${r}; message: string }>(\`/${t.slug}/\${id}\`, { method: "DELETE" }),
204
+ request<{ doc: ${n}; message: string }>(\`/${t.slug}/\${id}\`, { method: "DELETE" }),
205
205
  count: (args?: { where?: Record<string, any> }) =>
206
206
  request<{ totalDocs: number }>(\`/${t.slug}/count\${args ? "?" + qs(args) : ""}\`),
207
207
  },`}).join(`
208
208
  `)}
209
209
  };
210
210
  }
211
- `,n}function K(){return new commander.Command("generate").description("Generate TypeScript types from collection configs").option("-c, --config <path>","Path to config file or directory","./src/kyro").option("-o, --output <path>","Output file path","./src/types/kyro.d.ts").option("-w, --watch","Watch for changes and regenerate").option("--url <url>","URL of a running Kyro CMS instance (enables remote mode)").option("--api-key <key>","API key for authentication (required with --url)").action(async n=>{if(n.url){n.url||(console.error("\u274C --url is required when using --api"),process.exit(1)),n.apiKey||(console.error("\u274C --api-key is required when using --api"),process.exit(1));let o=path.resolve(n.output);try{let s=await q(n.url,n.apiKey),a=D(s),d=path.join(o,"..");fs.existsSync(d)||fs.mkdirSync(d,{recursive:!0}),fs.writeFileSync(o,a);}catch(s){console.error("\u274C Error:",s.message),process.exit(1);}return}let t=path.resolve(n.config),r=path.resolve(n.output);try{let o=await glob.glob(`${t}/**/*.{ts,js}`);o.length===0&&(console.error("\u274C No config files found at:",t),process.exit(1));let s=[];for(let i of o)try{let l=await import(i),u=Object.values(l).filter(c=>c&&c.slug&&c.fields);s.push(...u);}catch{console.warn(`\u26A0\uFE0F Could not parse: ${i}`);}s.length===0&&(console.error("\u274C No valid collection configs found"),process.exit(1));let a=T(s),d=path.join(r,"..");if(fs.existsSync(d)||fs.mkdirSync(d,{recursive:!0}),fs.writeFileSync(r,a),n.watch){let{watch:i}=await import('fs');i(t,{recursive:!0},async(l,u)=>{let c=[];for(let S of o)try{let k=await import(S+`?t=${Date.now()}`),v=Object.values(k).filter(h=>h&&h.slug&&h.fields);c.push(...v);}catch{}let f=T(c);fs.writeFileSync(r,f);});}}catch(o){console.error("\u274C Error:",o.message),process.exit(1);}})}var L=url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))),N=path.dirname(L),P="0.1.0";try{P=JSON.parse(fs.readFileSync(path.join(N,"../../package.json"),"utf-8")).version;}catch{}var p=new commander.Command;p.name("kyro").description("Kyro CMS - Astro-native headless CMS").version(P);p.command("dev").description("Start Kyro CMS development server").option("-p, --port <port>","Port to run on","4321").option("-h, --host <host>","Host to bind to","localhost").action(async e=>{let{exec:n}=await import('child_process'),t=n(`astro dev --port ${e.port} --host ${e.host}`,{env:{...process.env,NODE_NO_WARNINGS:"1"}});t.stdout?.on("data",r=>process.stdout.write(r)),t.stderr?.on("data",r=>process.stderr.write(r)),process.on("SIGINT",()=>{t.kill("SIGINT"),process.exit(0);}),process.on("SIGTERM",()=>{t.kill("SIGTERM"),process.exit(0);});});p.addCommand(K());var g=p.command("db").description("Database management commands");g.command("generate").description("Generate migrations from schema").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit generate",(n,t,r)=>{n&&(console.error("\u274C Generation failed:",n.message),process.exit(1));});});g.command("migrate").description("Run database migrations").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit migrate",(n,t,r)=>{n&&(console.error("\u274C Migration failed:",n.message),process.exit(1));});});g.command("push").description("Push schema to database (development)").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit push",(n,t,r)=>{n&&(console.error("\u274C Push failed:",n.message),process.exit(1));});});g.command("seed").description("Seed database with initial data").action(async()=>{let{exec:e}=await import('child_process');e("npx tsx src/database/drizzle/seed.ts",(n,t,r)=>{n&&(console.error("\u274C Seeding failed:",n.message),process.exit(1));});});g.command("studio").description("Open Drizzle Studio").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit studio",(n,t,r)=>{n&&(console.error("\u274C Studio failed:",n.message),process.exit(1));});});var F=p.command("auth").description("Authentication management commands");F.command("bootstrap").description("Create initial admin user").option("-e, --email <email>","Admin email",process.env.KYRO_ADMIN_EMAIL).option("-p, --password <password>","Admin password",process.env.KYRO_ADMIN_PASSWORD).option("-r, --role <role>","Admin role",process.env.KYRO_ADMIN_ROLE||"admin").action(async e=>{(!e.email||!e.password)&&(console.error("\u274C Email and password are required. Set KYRO_ADMIN_EMAIL and KYRO_ADMIN_PASSWORD env vars or use -e and -p options."),process.exit(1));try{let{bootstrapAdmin:n}=await import('../bootstrap-ETJ6QNGR.cjs'),t=process.env.DATABASE_URL||"",r=t.toLowerCase().startsWith("postgres://")||t.toLowerCase().startsWith("postgresql://"),o=t.toLowerCase().startsWith("mongodb://")||t.toLowerCase().startsWith("mongodb+srv://"),s=!t||t.includes(".db")||t.includes("sqlite")||t.includes("file:"),a;if(r){let{PostgresAuthAdapter:i}=await import('../postgres-auth-adapter-JKDYYULH.cjs'),{drizzle:l}=await import('drizzle-orm/postgres-js'),{default:u}=await import('postgres'),c=u(t,{max:1,onnotice:()=>{}}),f=l(c);a=new i({db:f});}else if(o){let{MongoDBAuthAdapter:i}=await import('../mongo-auth-adapter-JVE5M3S4.cjs'),l=await import('mongodb'),u=new l.MongoClient(t);await u.connect();let c=u.db();a=new i({db:c});}else {let{SQLiteAuthAdapter:i}=await import('../sqlite-adapter-PLD57WOH.cjs'),l=process.env.KYRO_AUTH_DB_PATH||"./data/auth.db";a=new i({path:l});}a.connect&&await a.connect();let d=await n({authAdapter:a,adminEmail:e.email,adminPassword:e.password,adminRole:e.role});a.disconnect&&await a.disconnect(),d.success||(console.error("\u274C Failed to create admin:",d.error),process.exit(1));}catch(n){console.error("\u274C Bootstrap failed:",n),process.exit(1);}});p.command("health").description("Check system health").action(async()=>{let e=process.env.DATABASE_URL||"",n=e.toLowerCase().startsWith("postgres://")||e.toLowerCase().startsWith("postgresql://"),t=e.toLowerCase().startsWith("mongodb://")||e.toLowerCase().startsWith("mongodb+srv://"),r=!e||e.includes(".db")||e.includes("sqlite")||e.includes("file:");if(n)try{let{default:o}=await import('postgres'),s=o(e,{max:1,onnotice:()=>{}});await s.unsafe("SELECT 1"),await s.end();}catch{}else if(t)try{let o=await import('mongodb'),s=new o.MongoClient(e);await s.connect(),await s.db().admin().ping(),await s.close();}catch{}else if(r)try{let o=process.env.KYRO_AUTH_DB_PATH||"./data/auth.db",{existsSync:s}=await import('fs');s(o);}catch{}});p.parse();process.argv.slice(2).length||p.outputHelp();
211
+ `,r}function U(){return new commander.Command("generate").description("Generate TypeScript types from collection configs").option("-c, --config <path>","Path to config file or directory","./src/kyro").option("-o, --output <path>","Output file path","./src/types/kyro.d.ts").option("-w, --watch","Watch for changes and regenerate").option("--url <url>","URL of a running Kyro CMS instance (enables remote mode)").option("--api-key <key>","API key for authentication (required with --url)").action(async r=>{if(r.url){r.url||(console.error("\u274C --url is required when using --api"),process.exit(1)),r.apiKey||(console.error("\u274C --api-key is required when using --api"),process.exit(1));let s=_.resolve(r.output);try{let a=await G(r.url,r.apiKey),c=Q(a),d=_.join(s,"..");x.existsSync(d)||x.mkdirSync(d,{recursive:!0}),x.writeFileSync(s,c);}catch(a){console.error("\u274C Error:",a.message),process.exit(1);}return}let t=_.resolve(r.config),n=_.resolve(r.output);try{let s=await glob.glob(`${t}/**/*.{ts,js}`);s.length===0&&(console.error("\u274C No config files found at:",t),process.exit(1));let a=[];for(let l of s)try{let p=await import(l),f=Object.values(p).filter(m=>m&&m.slug&&m.fields);a.push(...f);}catch{console.warn(`\u26A0\uFE0F Could not parse: ${l}`);}a.length===0&&(console.error("\u274C No valid collection configs found"),process.exit(1));let c=K(a),d=_.join(n,"..");if(x.existsSync(d)||x.mkdirSync(d,{recursive:!0}),x.writeFileSync(n,c),r.watch){let{watch:l}=await import('fs');l(t,{recursive:!0},async(p,f)=>{let m=[];for(let S of s)try{let y=await import(S+`?t=${Date.now()}`),w=Object.values(y).filter(h=>h&&h.slug&&h.fields);m.push(...w);}catch{}let A=K(m);x.writeFileSync(n,A);});}}catch(s){console.error("\u274C Error:",s.message),process.exit(1);}})}function ee(e=3){return F__default.default.randomBytes(e).toString("hex")}function te(){return F__default.default.randomBytes(12).toString("base64").replace(/[^a-zA-Z0-9]/g,"").slice(0,16)}function j(){let e=new commander.Command("deploy").description("Deploy Kyro CMS");return e.command("cloudflare").description("Deploy to Cloudflare Workers with Assets").option("-d, --database <type>","Database type (d1|postgres)").option("-u, --database-url <url>","PostgreSQL connection string").option("-n, --name <name>","Cloudflare project name").option("-b, --r2-bucket <name>","R2 storage bucket name").option("-e, --email <email>","Initial Super Admin email").option("-p, --password <password>","Initial Super Admin password").option("-y, --non-interactive","Skip all prompts and use defaults").action(async r=>{console.log(o__default.default.cyan("==============================================================================")),console.log(o__default.default.bold("\u{1F680} Kyro CMS Cloudflare Deployment (Workers)")),console.log(o__default.default.cyan(`==============================================================================
212
+ `));let t=ee(),n=te(),{database:s,databaseUrl:a,name:c,r2Bucket:d,email:l,password:p,nonInteractive:f}=r,m=`kyro-postgres-hd-${t}`;if(a&&!s&&(s="postgres"),!f&&process.stdout.isTTY){let i=q__namespace.createInterface({input:process$1.stdin,output:process$1.stdout});console.log(o__default.default.yellow.bold("\u{1F4CB} Setup Configuration")),console.log(o__default.default.dim(`Answer the prompts below to configure your deployment.
213
+ `)),s||(console.log(o__default.default.cyan("\u250C\u2500 ")+o__default.default.bold("Select Database Infrastructure")),console.log(o__default.default.cyan("\u2502")+o__default.default.green.bold(" 1 ")+"Native Cloudflare D1 "+o__default.default.dim("\u2014 serverless SQLite, auto-provisioned ")+o__default.default.dim("\u2190 default")),console.log(o__default.default.cyan("\u2502")+o__default.default.dim(" 2 ")+"PostgreSQL "+o__default.default.dim("\u2014 via Cloudflare Hyperdrive")),console.log(o__default.default.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),s=(await i.question(o__default.default.magenta(" \u203A ")+"Enter number (default: 1): ")).trim()==="2"?"postgres":"d1"),s==="postgres"&&!a&&(console.log(o__default.default.cyan(`
214
+ \u250C\u2500 `)+o__default.default.bold("PostgreSQL Connection URL")),console.log(o__default.default.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),a=await i.question(o__default.default.magenta(" \u203A ")+"postgresql://user:pass@host/db: ")),c||(console.log(o__default.default.cyan(`
215
+ \u250C\u2500 `)+o__default.default.bold("Cloudflare Project Name")),console.log(o__default.default.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),c=(await i.question(o__default.default.magenta(" \u203A ")+o__default.default.dim(`(default: kyro-app-${t}): `))).trim()||`kyro-app-${t}`),d||(console.log(o__default.default.cyan(`
216
+ \u250C\u2500 `)+o__default.default.bold("Cloudflare R2 Bucket Name")),console.log(o__default.default.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),d=(await i.question(o__default.default.magenta(" \u203A ")+o__default.default.dim(`(default: kyro-media-${t}): `))).trim()||`kyro-media-${t}`),l||(console.log(o__default.default.cyan(`
217
+ \u250C\u2500 `)+o__default.default.bold("Initial Super Admin Email")),console.log(o__default.default.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),l=(await i.question(o__default.default.magenta(" \u203A ")+o__default.default.dim("(default: admin@kyro-cms.com): "))).trim()||"admin@kyro-cms.com"),p||(console.log(o__default.default.cyan(`
218
+ \u250C\u2500 `)+o__default.default.bold("Initial Super Admin Password")),console.log(o__default.default.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),p=(await i.question(o__default.default.magenta(" \u203A ")+o__default.default.dim("(default: auto-generate secure password): "))).trim()||n),i.close();}c=c||`kyro-app-${t}`,d=d||`kyro-media-${t}`,l=l||"admin@kyro-cms.com",p=p||n,s=s||"d1",console.log(o__default.default.cyan(`
219
+ \u2699\uFE0F Configuration Summary:`)),console.log(` \u2022 Target Hosting: ${o__default.default.bold("Cloudflare Workers with Assets")}`),console.log(` \u2022 Database Mode : ${o__default.default.bold(s)}`),console.log(` \u2022 Project Name : ${o__default.default.bold(c)}`),console.log(` \u2022 R2 Bucket Name: ${o__default.default.bold(d)}`),console.log(` \u2022 Admin Email : ${o__default.default.bold(l)}`);let S=x__default.default.existsSync(___default.default.join(process.cwd(),"pnpm-lock.yaml"))?"pnpm":"npm",y=`${S} dlx wrangler`;console.log(`
220
+ \u{1F50D} Checking Cloudflare Wrangler authentication...`);try{child_process.execSync(`${y} whoami`,{stdio:"ignore"}),console.log(o__default.default.green("\u2705 Cloudflare Wrangler Authenticated."));}catch{console.log(o__default.default.red("\u274C Cloudflare Wrangler authentication required.")),console.log(` Run ${o__default.default.bold(`${y} login`)} or set the ${o__default.default.bold("CLOUDFLARE_API_TOKEN")} env var.`),process.exit(1);}let w="",h="";if(s==="postgres"){a||(console.log(o__default.default.red("\u274C postgres mode requires a database URL.")),process.exit(1)),console.log(`
221
+ \u26A1 Provisioning Cloudflare Hyperdrive (${m})...`);try{let i=child_process.execSync(`${y} hyperdrive list --json`,{stdio:"pipe"}).toString(),b=JSON.parse(i.slice(i.indexOf("["))).find(D=>D.name===m);b&&(h=b.id||b.uuid);}catch{}if(!h)try{let i=child_process.execSync(`${y} hyperdrive create "${m}" --connection-string="${a}" --json`,{stdio:"pipe"}).toString(),u=JSON.parse(i.slice(i.indexOf("{")));h=u.id||u.uuid;}catch{}console.log(o__default.default.green(`\u2705 Hyperdrive Provisioned (ID: ${h||"auto"})`));}else {let i=`${c}-d1`;console.log(`
222
+ \u{1F5C2}\uFE0F Selecting or creating D1 database (${i})...`);try{let b=child_process.execSync(`${y} d1 create "${i}"`,{stdio:"pipe"}).toString().match(/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/i);b&&(w=b[1]);}catch{try{let b=child_process.execSync(`${y} d1 list --json`,{stdio:"pipe"}).toString(),k=JSON.parse(b).find(z=>z.name===i);k&&(w=k.id||k.uuid);}catch{}}console.log(o__default.default.green(`\u2705 Using D1 database: ${i} (ID: ${w})`));}console.log(`
223
+ \u{1F5C4}\uFE0F Provisioning R2 Bucket '${d}'...`);try{child_process.execSync(`${y} r2 bucket create "${d}"`,{stdio:"ignore"});}catch{console.log(`\u2139\uFE0F Bucket '${d}' already exists.`);}try{child_process.execSync(`echo "y" | ${y} r2 bucket dev-url enable "${d}"`,{stdio:"ignore"});}catch{}console.log(`
224
+ \u2699\uFE0F Generating wrangler.toml...`);let E=`name = "${c}"
225
+ compatibility_date = "2026-01-01"
226
+ compatibility_flags = ["nodejs_compat"]
227
+ `;s==="postgres"?E+=`
228
+ [[hyperdrive]]
229
+ binding = "HYPERDRIVE"
230
+ id = "${h}"
231
+ `:E+=`
232
+ [[d1_databases]]
233
+ binding = "DB"
234
+ database_name = "${c}-d1"
235
+ database_id = "${w}"
236
+ `,E+=`
237
+ [[r2_buckets]]
238
+ binding = "STORAGE_BUCKET"
239
+ bucket_name = "${d}"
240
+ `,x__default.default.writeFileSync(___default.default.join(process.cwd(),"wrangler.toml"),E,"utf8"),console.log(`
241
+ \u{1F5C3}\uFE0F Running schema migrations & seeding super admin...`);let W=`import bcrypt from 'bcryptjs'; console.log(bcrypt.hashSync('${p}', 10));`,I="";try{I=child_process.execSync(`node -e "${W}"`,{stdio:"pipe"}).toString().trim();}catch{}if(s==="postgres"){try{child_process.execSync(`DATABASE_URL="${a}" npx drizzle-kit push --force`,{stdio:"ignore"});}catch{}let i=`
242
+ import postgres from 'postgres';
243
+ import bcrypt from 'bcryptjs';
244
+ const sql = postgres(process.env.DATABASE_URL || '${a}');
245
+ async function bootstrap() {
246
+ try {
247
+ await sql\`CREATE TABLE IF NOT EXISTS users (id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email VARCHAR(255) NOT NULL, password_hash VARCHAR(255), role VARCHAR(50) DEFAULT 'customer', email_verified BOOLEAN DEFAULT true, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW())\`;
248
+ await sql\`CREATE UNIQUE INDEX IF NOT EXISTS users_email_idx ON users (email)\`;
249
+ const existing = await sql\`SELECT id FROM users WHERE email = '${l}'\`;
250
+ if (existing.length === 0) {
251
+ const hash = bcrypt.hashSync('${p}', 10);
252
+ await sql\`INSERT INTO users (email, password_hash, role, email_verified) VALUES ('${l}', \\\${hash}, 'super_admin', true)\`;
253
+ console.log(' \u2705 PostgreSQL Super Admin Configured');
254
+ }
255
+ } catch (e) {
256
+ console.warn(' \u26A0\uFE0F Bootstrap note:', e.message);
257
+ } finally { await sql.end(); }
258
+ }
259
+ bootstrap();
260
+ `;try{child_process.execSync(`node -e "${i.replace(/\n/g," ")}"`,{stdio:"inherit"});}catch{}}else {let i=`
261
+ CREATE TABLE IF NOT EXISTS users (
262
+ id TEXT PRIMARY KEY,
263
+ email TEXT UNIQUE NOT NULL,
264
+ password_hash TEXT,
265
+ role TEXT DEFAULT 'customer',
266
+ email_verified INTEGER DEFAULT 1,
267
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP,
268
+ updated_at TEXT DEFAULT CURRENT_TIMESTAMP
269
+ );
270
+ CREATE TABLE IF NOT EXISTS sessions (
271
+ id TEXT PRIMARY KEY,
272
+ user_id TEXT NOT NULL,
273
+ token TEXT UNIQUE NOT NULL,
274
+ expires_at TEXT NOT NULL,
275
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP
276
+ );
277
+ CREATE TABLE IF NOT EXISTS audit_logs (
278
+ id TEXT PRIMARY KEY,
279
+ user_id TEXT,
280
+ action TEXT NOT NULL,
281
+ resource TEXT,
282
+ details TEXT,
283
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP
284
+ );
285
+ INSERT OR IGNORE INTO users (id, email, password_hash, role, email_verified)
286
+ VALUES ('admin-super-1', '${l}', '${I}', 'super_admin', 1);
287
+ `;try{child_process.execSync(`${y} d1 execute "${c}-d1" --remote --command="${i.replace(/\n/g," ")}"`,{stdio:"ignore"}),console.log(o__default.default.green(" \u2705 D1 Schema Migrated & Super Admin Configured."));}catch{}}console.log(`
288
+ \u{1F6E0}\uFE0F Building for Cloudflare...`);try{child_process.execSync(`${S} run build`,{stdio:"inherit"});}catch{console.log(o__default.default.red(`
289
+ \u274C Build Failed. Check the output above.`)),process.exit(1);}console.log(`
290
+ \u2601\uFE0F Deploying to Cloudflare Workers...`),x__default.default.existsSync(___default.default.join(process.cwd(),".wrangler"))&&x__default.default.rmSync(___default.default.join(process.cwd(),".wrangler"),{recursive:true,force:true});try{child_process.execSync(`${y} deploy`,{stdio:"inherit"}),console.log(o__default.default.cyan(`
291
+ ==============================================================================`)),console.log(o__default.default.green.bold("\u{1F389} Kyro CMS Deployment Successful!")),console.log(o__default.default.cyan("==============================================================================")),console.log(`
292
+ Super Admin Credentials:`),console.log(` \u2022 Email : ${o__default.default.bold(l)}`),console.log(` \u2022 Password: ${o__default.default.bold(p)}`),console.log(`
293
+ Save these credentials! This is the only time the password is displayed.
294
+ `);}catch{console.log(o__default.default.cyan(`
295
+ ==============================================================================`)),console.log(o__default.default.red.bold("\u274C Kyro CMS Cloudflare Deployment Failed!")),console.log(o__default.default.cyan("==============================================================================")),console.log("Inspect the Wrangler output above for error details."),process.exit(1);}}),e}var ie=url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))),ce=_.dirname(ie),B="0.1.0";try{B=JSON.parse(x.readFileSync(_.join(ce,"../../package.json"),"utf-8")).version;}catch{}var T=new commander.Command;T.name("kyro").description("Kyro CMS - Astro-native headless CMS").version(B);T.command("dev").description("Start Kyro CMS development server").option("-p, --port <port>","Port to run on","4321").option("-h, --host <host>","Host to bind to","localhost").action(async e=>{let{exec:r}=await import('child_process'),t=r(`astro dev --port ${e.port} --host ${e.host}`,{env:{...process.env,NODE_NO_WARNINGS:"1"}});t.stdout?.on("data",n=>process.stdout.write(n)),t.stderr?.on("data",n=>process.stderr.write(n)),process.on("SIGINT",()=>{t.kill("SIGINT"),process.exit(0);}),process.on("SIGTERM",()=>{t.kill("SIGTERM"),process.exit(0);});});T.addCommand(U());T.addCommand(j());var $=T.command("db").description("Database management commands");$.command("generate").description("Generate migrations from schema").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit generate",(r,t,n)=>{r&&(console.error("\u274C Generation failed:",r.message),process.exit(1));});});$.command("migrate").description("Run database migrations").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit migrate",(r,t,n)=>{r&&(console.error("\u274C Migration failed:",r.message),process.exit(1));});});$.command("push").description("Push schema to database (development)").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit push",(r,t,n)=>{r&&(console.error("\u274C Push failed:",r.message),process.exit(1));});});$.command("seed").description("Seed database with initial data").action(async()=>{let{exec:e}=await import('child_process');e("npx tsx src/database/drizzle/seed.ts",(r,t,n)=>{r&&(console.error("\u274C Seeding failed:",r.message),process.exit(1));});});$.command("studio").description("Open Drizzle Studio").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit studio",(r,t,n)=>{r&&(console.error("\u274C Studio failed:",r.message),process.exit(1));});});var le=T.command("auth").description("Authentication management commands");le.command("bootstrap").description("Create initial admin user").option("-e, --email <email>","Admin email",process.env.KYRO_ADMIN_EMAIL).option("-p, --password <password>","Admin password",process.env.KYRO_ADMIN_PASSWORD).option("-r, --role <role>","Admin role",process.env.KYRO_ADMIN_ROLE||"admin").action(async e=>{(!e.email||!e.password)&&(console.error("\u274C Email and password are required. Set KYRO_ADMIN_EMAIL and KYRO_ADMIN_PASSWORD env vars or use -e and -p options."),process.exit(1));try{let{bootstrapAdmin:r}=await import('../bootstrap-ETJ6QNGR.cjs'),t=process.env.DATABASE_URL||"",n=t.toLowerCase().startsWith("postgres://")||t.toLowerCase().startsWith("postgresql://"),s=t.toLowerCase().startsWith("mongodb://")||t.toLowerCase().startsWith("mongodb+srv://"),a=!t||t.includes(".db")||t.includes("sqlite")||t.includes("file:"),c;if(n){let{PostgresAuthAdapter:l}=await import('../postgres-auth-adapter-JKDYYULH.cjs'),{drizzle:p}=await import('drizzle-orm/postgres-js'),{default:f}=await import('postgres'),m=f(t,{max:1,onnotice:()=>{}}),A=p(m);c=new l({db:A});}else if(s){let{MongoDBAuthAdapter:l}=await import('../mongo-auth-adapter-JVE5M3S4.cjs'),p=await import('mongodb'),f=new p.MongoClient(t);await f.connect();let m=f.db();c=new l({db:m});}else {let{SQLiteAuthAdapter:l}=await import('../sqlite-adapter-PLD57WOH.cjs'),p=process.env.KYRO_AUTH_DB_PATH||"./data/auth.db";c=new l({path:p});}c.connect&&await c.connect();let d=await r({authAdapter:c,adminEmail:e.email,adminPassword:e.password,adminRole:e.role});c.disconnect&&await c.disconnect(),d.success||(console.error("\u274C Failed to create admin:",d.error),process.exit(1));}catch(r){console.error("\u274C Bootstrap failed:",r),process.exit(1);}});T.command("health").description("Check system health").action(async()=>{let e=process.env.DATABASE_URL||"",r=e.toLowerCase().startsWith("postgres://")||e.toLowerCase().startsWith("postgresql://"),t=e.toLowerCase().startsWith("mongodb://")||e.toLowerCase().startsWith("mongodb+srv://"),n=!e||e.includes(".db")||e.includes("sqlite")||e.includes("file:");if(r)try{let{default:s}=await import('postgres'),a=s(e,{max:1,onnotice:()=>{}});await a.unsafe("SELECT 1"),await a.end();}catch{}else if(t)try{let s=await import('mongodb'),a=new s.MongoClient(e);await a.connect(),await a.db().admin().ping(),await a.close();}catch{}else if(n)try{let s=process.env.KYRO_AUTH_DB_PATH||"./data/auth.db",{existsSync:a}=await import('fs');a(s);}catch{}});T.parse();process.argv.slice(2).length||T.outputHelp();
package/dist/cli/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import'../chunk-5J6HXUF6.js';import {Command}from'commander';import {readFileSync,existsSync,mkdirSync,writeFileSync}from'fs';import {dirname,join,resolve}from'path';import {fileURLToPath}from'url';import {glob}from'glob';function y(e){switch(e.type){case "text":case "email":case "password":case "textarea":case "color":case "code":case "markdown":case "date":case "richtext":case "json":return e.hasMany?"string[]":"string";case "number":return e.hasMany?"number[]":"number";case "checkbox":return "boolean";case "select":case "radio":if(e.options){let t=e.options.map(r=>`'${r.value}'`).join(" | ");return e.hasMany?`(${t})[]`:t}return e.hasMany?"string[]":"string";case "relationship":if(Array.isArray(e.relationTo)){if(e.relationTo.includes("*"))return e.hasMany?"any[]":"any";let t=e.relationTo.map(r=>`${m(r)} | string`).join(" | ");return e.hasMany?`(${t})[]`:`(${t})`}let n=e.relationTo||"unknown";return n==="*"?e.hasMany?"any[]":"any":e.hasMany?`(${m(n)} | string)[]`:`${m(n)} | string`;case "upload":return e.hasMany?"(Media | string)[]":"Media | string";case "array":return e.fields&&e.fields.length>0?`Array<{
3
- ${e.fields.filter(r=>r.name).map(r=>{let o=y(r);return ` ${r.name}${r.required?"":"?"}: ${o};`}).join(`
2
+ import'../chunk-5J6HXUF6.js';import {Command}from'commander';import x,{readFileSync,existsSync,mkdirSync,writeFileSync}from'fs';import _,{dirname,join,resolve}from'path';import {fileURLToPath}from'url';import {glob}from'glob';import {execSync}from'child_process';import*as q from'readline/promises';import {stdout,stdin}from'process';import F from'crypto';import o from'chalk';function R(e){switch(e.type){case "text":case "email":case "password":case "textarea":case "color":case "code":case "markdown":case "date":case "richtext":case "json":return e.hasMany?"string[]":"string";case "number":return e.hasMany?"number[]":"number";case "checkbox":return "boolean";case "select":case "radio":if(e.options){let t=e.options.map(n=>`'${n.value}'`).join(" | ");return e.hasMany?`(${t})[]`:t}return e.hasMany?"string[]":"string";case "relationship":if(Array.isArray(e.relationTo)){if(e.relationTo.includes("*"))return e.hasMany?"any[]":"any";let t=e.relationTo.map(n=>`${C(n)} | string`).join(" | ");return e.hasMany?`(${t})[]`:`(${t})`}let r=e.relationTo||"unknown";return r==="*"?e.hasMany?"any[]":"any":e.hasMany?`(${C(r)} | string)[]`:`${C(r)} | string`;case "upload":return e.hasMany?"(Media | string)[]":"Media | string";case "array":return e.fields&&e.fields.length>0?`Array<{
3
+ ${e.fields.filter(n=>n.name).map(n=>{let s=R(n);return ` ${n.name}${n.required?"":"?"}: ${s};`}).join(`
4
4
  `)}
5
5
  }>`:"Record<string, any>[]";case "group":return e.fields&&e.fields.length>0?`{
6
- ${e.fields.filter(r=>r.name).map(r=>{let o=y(r);return ` ${r.name}${r.required?"":"?"}: ${o};`}).join(`
6
+ ${e.fields.filter(n=>n.name).map(n=>{let s=R(n);return ` ${n.name}${n.required?"":"?"}: ${s};`}).join(`
7
7
  `)}
8
- }`:"Record<string, any>";case "blocks":return "Block[]";default:return "any"}}function m(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(n,t)=>t.toUpperCase())}function C(e){return e.replace(/-([a-z])/g,(n,t)=>t.toUpperCase())}function _(e){let n=m(e.slug),t=e.fields.filter(r=>r.name).map(r=>{let o=y(r);return ` ${r.name}${r.required?"":"?"}: ${o};`});return t.unshift(" id: string;"),t.push(" createdAt: string;"),t.push(" updatedAt: string;"),`export interface ${n} {
8
+ }`:"Record<string, any>";case "blocks":return "Block[]";default:return "any"}}function C(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(r,t)=>t.toUpperCase())}function N(e){return e.replace(/-([a-z])/g,(r,t)=>t.toUpperCase())}function Y(e){let r=C(e.slug),t=e.fields.filter(n=>n.name).map(n=>{let s=R(n);return ` ${n.name}${n.required?"":"?"}: ${s};`});return t.unshift(" id: string;"),t.push(" createdAt: string;"),t.push(" updatedAt: string;"),`export interface ${r} {
9
9
  ${t.join(`
10
10
  `)}
11
- }`}function T(e){let n=e.map(s=>_(s)),t=`// ============================================================================
11
+ }`}function K(e){let r=e.map(a=>Y(a)),t=`// ============================================================================
12
12
  // Auto-generated by kyro generate
13
13
  // ============================================================================
14
14
 
@@ -31,9 +31,9 @@ export interface Block {
31
31
  [key: string]: any;
32
32
  }
33
33
 
34
- `,r=n.join(`
34
+ `,n=r.join(`
35
35
 
36
- `),o=`
36
+ `),s=`
37
37
 
38
38
  // ============================================================================
39
39
  // Query Types
@@ -96,7 +96,7 @@ export interface KyroDeleteResult<T> {
96
96
  // ============================================================================
97
97
 
98
98
  export interface KyroCollections {
99
- ${e.map(s=>` ${C(s.slug)}: ${m(s.slug)};`).join(`
99
+ ${e.map(a=>` ${N(a.slug)}: ${C(a.slug)};`).join(`
100
100
  `)}
101
101
  }
102
102
 
@@ -114,7 +114,7 @@ export interface KyroTypedClient<C extends keyof KyroCollections> {
114
114
  }
115
115
 
116
116
  export interface KyroClient {
117
- ${e.map(s=>` ${C(s.slug)}: KyroTypedClient<'${s.slug}'>;`).join(`
117
+ ${e.map(a=>` ${N(a.slug)}: KyroTypedClient<'${a.slug}'>;`).join(`
118
118
  `)}
119
119
  }
120
120
 
@@ -122,7 +122,7 @@ export function createClient(config: { url: string; token?: string }): KyroClien
122
122
  // Client implementation would be here
123
123
  throw new Error('Not implemented');
124
124
  }
125
- `;return t+r+o}async function q(e,n){let t=`${e.replace(/\/+$/,"")}/api/__schema`,r=await fetch(t,{headers:{Authorization:`ApiKey ${n}`}});if(!r.ok){let o=await r.text();throw new Error(`Schema fetch failed (${r.status}): ${o}`)}return r.json()}function D(e){let n=`// ============================================================================
125
+ `;return t+n+s}async function G(e,r){let t=`${e.replace(/\/+$/,"")}/api/__schema`,n=await fetch(t,{headers:{Authorization:`ApiKey ${r}`}});if(!n.ok){let s=await n.text();throw new Error(`Schema fetch failed (${n.status}): ${s}`)}return n.json()}function Q(e){let r=`// ============================================================================
126
126
  // Auto-generated by kyro generate --api
127
127
  // ============================================================================
128
128
 
@@ -145,12 +145,12 @@ export interface Block {
145
145
  [key: string]: any;
146
146
  }
147
147
 
148
- `;for(let t of e){let r=m(t.slug),o=t.fields.filter(s=>s.name).map(s=>{let a=y(s);return ` ${s.name}${s.required?"":"?"}: ${a};`});o.unshift(" id: string;"),o.push(" createdAt: string;"),o.push(" updatedAt: string;"),n+=`export interface ${r} {
149
- ${o.join(`
148
+ `;for(let t of e){let n=C(t.slug),s=t.fields.filter(a=>a.name).map(a=>{let c=R(a);return ` ${a.name}${a.required?"":"?"}: ${c};`});s.unshift(" id: string;"),s.push(" createdAt: string;"),s.push(" updatedAt: string;"),r+=`export interface ${n} {
149
+ ${s.join(`
150
150
  `)}
151
151
  }
152
152
 
153
- `;}return n+=`// ============================================================================
153
+ `;}return r+=`// ============================================================================
154
154
  // Typed REST Client
155
155
  // ============================================================================
156
156
 
@@ -189,23 +189,107 @@ export function createKyroClient(opts: KyroClientOptions) {
189
189
  }
190
190
 
191
191
  return {
192
- ${e.map(t=>{let r=m(t.slug);return ` ${C(t.slug)}: {
192
+ ${e.map(t=>{let n=C(t.slug);return ` ${N(t.slug)}: {
193
193
  find: (args?: { where?: Record<string, any>; sort?: string; limit?: number; page?: number; draft?: boolean }) =>
194
- request<{ docs: ${r}[]; totalDocs: number; page: number; totalPages: number; hasNextPage: boolean; hasPrevPage: boolean }>(\`/${t.slug}\${args ? "?" + qs(args) : ""}\`),
194
+ request<{ docs: ${n}[]; totalDocs: number; page: number; totalPages: number; hasNextPage: boolean; hasPrevPage: boolean }>(\`/${t.slug}\${args ? "?" + qs(args) : ""}\`),
195
195
  findByID: (id: string, args?: { draft?: boolean }) =>
196
- request<${r}>(\`/${t.slug}/\${id}\${args ? "?" + qs(args) : ""}\`),
196
+ request<${n}>(\`/${t.slug}/\${id}\${args ? "?" + qs(args) : ""}\`),
197
197
  findBySlug: (slug: string, args?: { draft?: boolean }) =>
198
- request<{ docs: ${r}[] }>(\`/${t.slug}?where=\${encodeURIComponent(JSON.stringify({ slug: { equals: slug } }))}\`),
199
- create: (data: Partial<${r}>) =>
200
- request<{ doc: ${r}; message?: string }>(\`/${t.slug}\`, { method: "POST", body: JSON.stringify(data) }),
201
- update: (id: string, data: Partial<${r}>, args?: { baseUpdatedAt?: string }) =>
202
- request<{ doc: ${r}; message?: string }>(\`/${t.slug}/\${id}\`, { method: "PATCH", body: JSON.stringify({ ...data, ...args }) }),
198
+ request<{ docs: ${n}[] }>(\`/${t.slug}?where=\${encodeURIComponent(JSON.stringify({ slug: { equals: slug } }))}\`),
199
+ create: (data: Partial<${n}>) =>
200
+ request<{ doc: ${n}; message?: string }>(\`/${t.slug}\`, { method: "POST", body: JSON.stringify(data) }),
201
+ update: (id: string, data: Partial<${n}>, args?: { baseUpdatedAt?: string }) =>
202
+ request<{ doc: ${n}; message?: string }>(\`/${t.slug}/\${id}\`, { method: "PATCH", body: JSON.stringify({ ...data, ...args }) }),
203
203
  delete: (id: string) =>
204
- request<{ doc: ${r}; message: string }>(\`/${t.slug}/\${id}\`, { method: "DELETE" }),
204
+ request<{ doc: ${n}; message: string }>(\`/${t.slug}/\${id}\`, { method: "DELETE" }),
205
205
  count: (args?: { where?: Record<string, any> }) =>
206
206
  request<{ totalDocs: number }>(\`/${t.slug}/count\${args ? "?" + qs(args) : ""}\`),
207
207
  },`}).join(`
208
208
  `)}
209
209
  };
210
210
  }
211
- `,n}function K(){return new Command("generate").description("Generate TypeScript types from collection configs").option("-c, --config <path>","Path to config file or directory","./src/kyro").option("-o, --output <path>","Output file path","./src/types/kyro.d.ts").option("-w, --watch","Watch for changes and regenerate").option("--url <url>","URL of a running Kyro CMS instance (enables remote mode)").option("--api-key <key>","API key for authentication (required with --url)").action(async n=>{if(n.url){n.url||(console.error("\u274C --url is required when using --api"),process.exit(1)),n.apiKey||(console.error("\u274C --api-key is required when using --api"),process.exit(1));let o=resolve(n.output);try{let s=await q(n.url,n.apiKey),a=D(s),d=join(o,"..");existsSync(d)||mkdirSync(d,{recursive:!0}),writeFileSync(o,a);}catch(s){console.error("\u274C Error:",s.message),process.exit(1);}return}let t=resolve(n.config),r=resolve(n.output);try{let o=await glob(`${t}/**/*.{ts,js}`);o.length===0&&(console.error("\u274C No config files found at:",t),process.exit(1));let s=[];for(let i of o)try{let l=await import(i),u=Object.values(l).filter(c=>c&&c.slug&&c.fields);s.push(...u);}catch{console.warn(`\u26A0\uFE0F Could not parse: ${i}`);}s.length===0&&(console.error("\u274C No valid collection configs found"),process.exit(1));let a=T(s),d=join(r,"..");if(existsSync(d)||mkdirSync(d,{recursive:!0}),writeFileSync(r,a),n.watch){let{watch:i}=await import('fs');i(t,{recursive:!0},async(l,u)=>{let c=[];for(let S of o)try{let k=await import(S+`?t=${Date.now()}`),v=Object.values(k).filter(h=>h&&h.slug&&h.fields);c.push(...v);}catch{}let f=T(c);writeFileSync(r,f);});}}catch(o){console.error("\u274C Error:",o.message),process.exit(1);}})}var L=fileURLToPath(import.meta.url),N=dirname(L),P="0.1.0";try{P=JSON.parse(readFileSync(join(N,"../../package.json"),"utf-8")).version;}catch{}var p=new Command;p.name("kyro").description("Kyro CMS - Astro-native headless CMS").version(P);p.command("dev").description("Start Kyro CMS development server").option("-p, --port <port>","Port to run on","4321").option("-h, --host <host>","Host to bind to","localhost").action(async e=>{let{exec:n}=await import('child_process'),t=n(`astro dev --port ${e.port} --host ${e.host}`,{env:{...process.env,NODE_NO_WARNINGS:"1"}});t.stdout?.on("data",r=>process.stdout.write(r)),t.stderr?.on("data",r=>process.stderr.write(r)),process.on("SIGINT",()=>{t.kill("SIGINT"),process.exit(0);}),process.on("SIGTERM",()=>{t.kill("SIGTERM"),process.exit(0);});});p.addCommand(K());var g=p.command("db").description("Database management commands");g.command("generate").description("Generate migrations from schema").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit generate",(n,t,r)=>{n&&(console.error("\u274C Generation failed:",n.message),process.exit(1));});});g.command("migrate").description("Run database migrations").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit migrate",(n,t,r)=>{n&&(console.error("\u274C Migration failed:",n.message),process.exit(1));});});g.command("push").description("Push schema to database (development)").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit push",(n,t,r)=>{n&&(console.error("\u274C Push failed:",n.message),process.exit(1));});});g.command("seed").description("Seed database with initial data").action(async()=>{let{exec:e}=await import('child_process');e("npx tsx src/database/drizzle/seed.ts",(n,t,r)=>{n&&(console.error("\u274C Seeding failed:",n.message),process.exit(1));});});g.command("studio").description("Open Drizzle Studio").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit studio",(n,t,r)=>{n&&(console.error("\u274C Studio failed:",n.message),process.exit(1));});});var F=p.command("auth").description("Authentication management commands");F.command("bootstrap").description("Create initial admin user").option("-e, --email <email>","Admin email",process.env.KYRO_ADMIN_EMAIL).option("-p, --password <password>","Admin password",process.env.KYRO_ADMIN_PASSWORD).option("-r, --role <role>","Admin role",process.env.KYRO_ADMIN_ROLE||"admin").action(async e=>{(!e.email||!e.password)&&(console.error("\u274C Email and password are required. Set KYRO_ADMIN_EMAIL and KYRO_ADMIN_PASSWORD env vars or use -e and -p options."),process.exit(1));try{let{bootstrapAdmin:n}=await import('../bootstrap-6G6HI26Z.js'),t=process.env.DATABASE_URL||"",r=t.toLowerCase().startsWith("postgres://")||t.toLowerCase().startsWith("postgresql://"),o=t.toLowerCase().startsWith("mongodb://")||t.toLowerCase().startsWith("mongodb+srv://"),s=!t||t.includes(".db")||t.includes("sqlite")||t.includes("file:"),a;if(r){let{PostgresAuthAdapter:i}=await import('../postgres-auth-adapter-33QOIRXT.js'),{drizzle:l}=await import('drizzle-orm/postgres-js'),{default:u}=await import('postgres'),c=u(t,{max:1,onnotice:()=>{}}),f=l(c);a=new i({db:f});}else if(o){let{MongoDBAuthAdapter:i}=await import('../mongo-auth-adapter-5TJO5J5U.js'),l=await import('mongodb'),u=new l.MongoClient(t);await u.connect();let c=u.db();a=new i({db:c});}else {let{SQLiteAuthAdapter:i}=await import('../sqlite-adapter-EXYRYZEV.js'),l=process.env.KYRO_AUTH_DB_PATH||"./data/auth.db";a=new i({path:l});}a.connect&&await a.connect();let d=await n({authAdapter:a,adminEmail:e.email,adminPassword:e.password,adminRole:e.role});a.disconnect&&await a.disconnect(),d.success||(console.error("\u274C Failed to create admin:",d.error),process.exit(1));}catch(n){console.error("\u274C Bootstrap failed:",n),process.exit(1);}});p.command("health").description("Check system health").action(async()=>{let e=process.env.DATABASE_URL||"",n=e.toLowerCase().startsWith("postgres://")||e.toLowerCase().startsWith("postgresql://"),t=e.toLowerCase().startsWith("mongodb://")||e.toLowerCase().startsWith("mongodb+srv://"),r=!e||e.includes(".db")||e.includes("sqlite")||e.includes("file:");if(n)try{let{default:o}=await import('postgres'),s=o(e,{max:1,onnotice:()=>{}});await s.unsafe("SELECT 1"),await s.end();}catch{}else if(t)try{let o=await import('mongodb'),s=new o.MongoClient(e);await s.connect(),await s.db().admin().ping(),await s.close();}catch{}else if(r)try{let o=process.env.KYRO_AUTH_DB_PATH||"./data/auth.db",{existsSync:s}=await import('fs');s(o);}catch{}});p.parse();process.argv.slice(2).length||p.outputHelp();
211
+ `,r}function U(){return new Command("generate").description("Generate TypeScript types from collection configs").option("-c, --config <path>","Path to config file or directory","./src/kyro").option("-o, --output <path>","Output file path","./src/types/kyro.d.ts").option("-w, --watch","Watch for changes and regenerate").option("--url <url>","URL of a running Kyro CMS instance (enables remote mode)").option("--api-key <key>","API key for authentication (required with --url)").action(async r=>{if(r.url){r.url||(console.error("\u274C --url is required when using --api"),process.exit(1)),r.apiKey||(console.error("\u274C --api-key is required when using --api"),process.exit(1));let s=resolve(r.output);try{let a=await G(r.url,r.apiKey),c=Q(a),d=join(s,"..");existsSync(d)||mkdirSync(d,{recursive:!0}),writeFileSync(s,c);}catch(a){console.error("\u274C Error:",a.message),process.exit(1);}return}let t=resolve(r.config),n=resolve(r.output);try{let s=await glob(`${t}/**/*.{ts,js}`);s.length===0&&(console.error("\u274C No config files found at:",t),process.exit(1));let a=[];for(let l of s)try{let p=await import(l),f=Object.values(p).filter(m=>m&&m.slug&&m.fields);a.push(...f);}catch{console.warn(`\u26A0\uFE0F Could not parse: ${l}`);}a.length===0&&(console.error("\u274C No valid collection configs found"),process.exit(1));let c=K(a),d=join(n,"..");if(existsSync(d)||mkdirSync(d,{recursive:!0}),writeFileSync(n,c),r.watch){let{watch:l}=await import('fs');l(t,{recursive:!0},async(p,f)=>{let m=[];for(let S of s)try{let y=await import(S+`?t=${Date.now()}`),w=Object.values(y).filter(h=>h&&h.slug&&h.fields);m.push(...w);}catch{}let A=K(m);writeFileSync(n,A);});}}catch(s){console.error("\u274C Error:",s.message),process.exit(1);}})}function ee(e=3){return F.randomBytes(e).toString("hex")}function te(){return F.randomBytes(12).toString("base64").replace(/[^a-zA-Z0-9]/g,"").slice(0,16)}function j(){let e=new Command("deploy").description("Deploy Kyro CMS");return e.command("cloudflare").description("Deploy to Cloudflare Workers with Assets").option("-d, --database <type>","Database type (d1|postgres)").option("-u, --database-url <url>","PostgreSQL connection string").option("-n, --name <name>","Cloudflare project name").option("-b, --r2-bucket <name>","R2 storage bucket name").option("-e, --email <email>","Initial Super Admin email").option("-p, --password <password>","Initial Super Admin password").option("-y, --non-interactive","Skip all prompts and use defaults").action(async r=>{console.log(o.cyan("==============================================================================")),console.log(o.bold("\u{1F680} Kyro CMS Cloudflare Deployment (Workers)")),console.log(o.cyan(`==============================================================================
212
+ `));let t=ee(),n=te(),{database:s,databaseUrl:a,name:c,r2Bucket:d,email:l,password:p,nonInteractive:f}=r,m=`kyro-postgres-hd-${t}`;if(a&&!s&&(s="postgres"),!f&&process.stdout.isTTY){let i=q.createInterface({input:stdin,output:stdout});console.log(o.yellow.bold("\u{1F4CB} Setup Configuration")),console.log(o.dim(`Answer the prompts below to configure your deployment.
213
+ `)),s||(console.log(o.cyan("\u250C\u2500 ")+o.bold("Select Database Infrastructure")),console.log(o.cyan("\u2502")+o.green.bold(" 1 ")+"Native Cloudflare D1 "+o.dim("\u2014 serverless SQLite, auto-provisioned ")+o.dim("\u2190 default")),console.log(o.cyan("\u2502")+o.dim(" 2 ")+"PostgreSQL "+o.dim("\u2014 via Cloudflare Hyperdrive")),console.log(o.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),s=(await i.question(o.magenta(" \u203A ")+"Enter number (default: 1): ")).trim()==="2"?"postgres":"d1"),s==="postgres"&&!a&&(console.log(o.cyan(`
214
+ \u250C\u2500 `)+o.bold("PostgreSQL Connection URL")),console.log(o.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),a=await i.question(o.magenta(" \u203A ")+"postgresql://user:pass@host/db: ")),c||(console.log(o.cyan(`
215
+ \u250C\u2500 `)+o.bold("Cloudflare Project Name")),console.log(o.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),c=(await i.question(o.magenta(" \u203A ")+o.dim(`(default: kyro-app-${t}): `))).trim()||`kyro-app-${t}`),d||(console.log(o.cyan(`
216
+ \u250C\u2500 `)+o.bold("Cloudflare R2 Bucket Name")),console.log(o.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),d=(await i.question(o.magenta(" \u203A ")+o.dim(`(default: kyro-media-${t}): `))).trim()||`kyro-media-${t}`),l||(console.log(o.cyan(`
217
+ \u250C\u2500 `)+o.bold("Initial Super Admin Email")),console.log(o.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),l=(await i.question(o.magenta(" \u203A ")+o.dim("(default: admin@kyro-cms.com): "))).trim()||"admin@kyro-cms.com"),p||(console.log(o.cyan(`
218
+ \u250C\u2500 `)+o.bold("Initial Super Admin Password")),console.log(o.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),p=(await i.question(o.magenta(" \u203A ")+o.dim("(default: auto-generate secure password): "))).trim()||n),i.close();}c=c||`kyro-app-${t}`,d=d||`kyro-media-${t}`,l=l||"admin@kyro-cms.com",p=p||n,s=s||"d1",console.log(o.cyan(`
219
+ \u2699\uFE0F Configuration Summary:`)),console.log(` \u2022 Target Hosting: ${o.bold("Cloudflare Workers with Assets")}`),console.log(` \u2022 Database Mode : ${o.bold(s)}`),console.log(` \u2022 Project Name : ${o.bold(c)}`),console.log(` \u2022 R2 Bucket Name: ${o.bold(d)}`),console.log(` \u2022 Admin Email : ${o.bold(l)}`);let S=x.existsSync(_.join(process.cwd(),"pnpm-lock.yaml"))?"pnpm":"npm",y=`${S} dlx wrangler`;console.log(`
220
+ \u{1F50D} Checking Cloudflare Wrangler authentication...`);try{execSync(`${y} whoami`,{stdio:"ignore"}),console.log(o.green("\u2705 Cloudflare Wrangler Authenticated."));}catch{console.log(o.red("\u274C Cloudflare Wrangler authentication required.")),console.log(` Run ${o.bold(`${y} login`)} or set the ${o.bold("CLOUDFLARE_API_TOKEN")} env var.`),process.exit(1);}let w="",h="";if(s==="postgres"){a||(console.log(o.red("\u274C postgres mode requires a database URL.")),process.exit(1)),console.log(`
221
+ \u26A1 Provisioning Cloudflare Hyperdrive (${m})...`);try{let i=execSync(`${y} hyperdrive list --json`,{stdio:"pipe"}).toString(),b=JSON.parse(i.slice(i.indexOf("["))).find(D=>D.name===m);b&&(h=b.id||b.uuid);}catch{}if(!h)try{let i=execSync(`${y} hyperdrive create "${m}" --connection-string="${a}" --json`,{stdio:"pipe"}).toString(),u=JSON.parse(i.slice(i.indexOf("{")));h=u.id||u.uuid;}catch{}console.log(o.green(`\u2705 Hyperdrive Provisioned (ID: ${h||"auto"})`));}else {let i=`${c}-d1`;console.log(`
222
+ \u{1F5C2}\uFE0F Selecting or creating D1 database (${i})...`);try{let b=execSync(`${y} d1 create "${i}"`,{stdio:"pipe"}).toString().match(/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/i);b&&(w=b[1]);}catch{try{let b=execSync(`${y} d1 list --json`,{stdio:"pipe"}).toString(),k=JSON.parse(b).find(z=>z.name===i);k&&(w=k.id||k.uuid);}catch{}}console.log(o.green(`\u2705 Using D1 database: ${i} (ID: ${w})`));}console.log(`
223
+ \u{1F5C4}\uFE0F Provisioning R2 Bucket '${d}'...`);try{execSync(`${y} r2 bucket create "${d}"`,{stdio:"ignore"});}catch{console.log(`\u2139\uFE0F Bucket '${d}' already exists.`);}try{execSync(`echo "y" | ${y} r2 bucket dev-url enable "${d}"`,{stdio:"ignore"});}catch{}console.log(`
224
+ \u2699\uFE0F Generating wrangler.toml...`);let E=`name = "${c}"
225
+ compatibility_date = "2026-01-01"
226
+ compatibility_flags = ["nodejs_compat"]
227
+ `;s==="postgres"?E+=`
228
+ [[hyperdrive]]
229
+ binding = "HYPERDRIVE"
230
+ id = "${h}"
231
+ `:E+=`
232
+ [[d1_databases]]
233
+ binding = "DB"
234
+ database_name = "${c}-d1"
235
+ database_id = "${w}"
236
+ `,E+=`
237
+ [[r2_buckets]]
238
+ binding = "STORAGE_BUCKET"
239
+ bucket_name = "${d}"
240
+ `,x.writeFileSync(_.join(process.cwd(),"wrangler.toml"),E,"utf8"),console.log(`
241
+ \u{1F5C3}\uFE0F Running schema migrations & seeding super admin...`);let W=`import bcrypt from 'bcryptjs'; console.log(bcrypt.hashSync('${p}', 10));`,I="";try{I=execSync(`node -e "${W}"`,{stdio:"pipe"}).toString().trim();}catch{}if(s==="postgres"){try{execSync(`DATABASE_URL="${a}" npx drizzle-kit push --force`,{stdio:"ignore"});}catch{}let i=`
242
+ import postgres from 'postgres';
243
+ import bcrypt from 'bcryptjs';
244
+ const sql = postgres(process.env.DATABASE_URL || '${a}');
245
+ async function bootstrap() {
246
+ try {
247
+ await sql\`CREATE TABLE IF NOT EXISTS users (id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email VARCHAR(255) NOT NULL, password_hash VARCHAR(255), role VARCHAR(50) DEFAULT 'customer', email_verified BOOLEAN DEFAULT true, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW())\`;
248
+ await sql\`CREATE UNIQUE INDEX IF NOT EXISTS users_email_idx ON users (email)\`;
249
+ const existing = await sql\`SELECT id FROM users WHERE email = '${l}'\`;
250
+ if (existing.length === 0) {
251
+ const hash = bcrypt.hashSync('${p}', 10);
252
+ await sql\`INSERT INTO users (email, password_hash, role, email_verified) VALUES ('${l}', \\\${hash}, 'super_admin', true)\`;
253
+ console.log(' \u2705 PostgreSQL Super Admin Configured');
254
+ }
255
+ } catch (e) {
256
+ console.warn(' \u26A0\uFE0F Bootstrap note:', e.message);
257
+ } finally { await sql.end(); }
258
+ }
259
+ bootstrap();
260
+ `;try{execSync(`node -e "${i.replace(/\n/g," ")}"`,{stdio:"inherit"});}catch{}}else {let i=`
261
+ CREATE TABLE IF NOT EXISTS users (
262
+ id TEXT PRIMARY KEY,
263
+ email TEXT UNIQUE NOT NULL,
264
+ password_hash TEXT,
265
+ role TEXT DEFAULT 'customer',
266
+ email_verified INTEGER DEFAULT 1,
267
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP,
268
+ updated_at TEXT DEFAULT CURRENT_TIMESTAMP
269
+ );
270
+ CREATE TABLE IF NOT EXISTS sessions (
271
+ id TEXT PRIMARY KEY,
272
+ user_id TEXT NOT NULL,
273
+ token TEXT UNIQUE NOT NULL,
274
+ expires_at TEXT NOT NULL,
275
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP
276
+ );
277
+ CREATE TABLE IF NOT EXISTS audit_logs (
278
+ id TEXT PRIMARY KEY,
279
+ user_id TEXT,
280
+ action TEXT NOT NULL,
281
+ resource TEXT,
282
+ details TEXT,
283
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP
284
+ );
285
+ INSERT OR IGNORE INTO users (id, email, password_hash, role, email_verified)
286
+ VALUES ('admin-super-1', '${l}', '${I}', 'super_admin', 1);
287
+ `;try{execSync(`${y} d1 execute "${c}-d1" --remote --command="${i.replace(/\n/g," ")}"`,{stdio:"ignore"}),console.log(o.green(" \u2705 D1 Schema Migrated & Super Admin Configured."));}catch{}}console.log(`
288
+ \u{1F6E0}\uFE0F Building for Cloudflare...`);try{execSync(`${S} run build`,{stdio:"inherit"});}catch{console.log(o.red(`
289
+ \u274C Build Failed. Check the output above.`)),process.exit(1);}console.log(`
290
+ \u2601\uFE0F Deploying to Cloudflare Workers...`),x.existsSync(_.join(process.cwd(),".wrangler"))&&x.rmSync(_.join(process.cwd(),".wrangler"),{recursive:true,force:true});try{execSync(`${y} deploy`,{stdio:"inherit"}),console.log(o.cyan(`
291
+ ==============================================================================`)),console.log(o.green.bold("\u{1F389} Kyro CMS Deployment Successful!")),console.log(o.cyan("==============================================================================")),console.log(`
292
+ Super Admin Credentials:`),console.log(` \u2022 Email : ${o.bold(l)}`),console.log(` \u2022 Password: ${o.bold(p)}`),console.log(`
293
+ Save these credentials! This is the only time the password is displayed.
294
+ `);}catch{console.log(o.cyan(`
295
+ ==============================================================================`)),console.log(o.red.bold("\u274C Kyro CMS Cloudflare Deployment Failed!")),console.log(o.cyan("==============================================================================")),console.log("Inspect the Wrangler output above for error details."),process.exit(1);}}),e}var ie=fileURLToPath(import.meta.url),ce=dirname(ie),B="0.1.0";try{B=JSON.parse(readFileSync(join(ce,"../../package.json"),"utf-8")).version;}catch{}var T=new Command;T.name("kyro").description("Kyro CMS - Astro-native headless CMS").version(B);T.command("dev").description("Start Kyro CMS development server").option("-p, --port <port>","Port to run on","4321").option("-h, --host <host>","Host to bind to","localhost").action(async e=>{let{exec:r}=await import('child_process'),t=r(`astro dev --port ${e.port} --host ${e.host}`,{env:{...process.env,NODE_NO_WARNINGS:"1"}});t.stdout?.on("data",n=>process.stdout.write(n)),t.stderr?.on("data",n=>process.stderr.write(n)),process.on("SIGINT",()=>{t.kill("SIGINT"),process.exit(0);}),process.on("SIGTERM",()=>{t.kill("SIGTERM"),process.exit(0);});});T.addCommand(U());T.addCommand(j());var $=T.command("db").description("Database management commands");$.command("generate").description("Generate migrations from schema").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit generate",(r,t,n)=>{r&&(console.error("\u274C Generation failed:",r.message),process.exit(1));});});$.command("migrate").description("Run database migrations").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit migrate",(r,t,n)=>{r&&(console.error("\u274C Migration failed:",r.message),process.exit(1));});});$.command("push").description("Push schema to database (development)").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit push",(r,t,n)=>{r&&(console.error("\u274C Push failed:",r.message),process.exit(1));});});$.command("seed").description("Seed database with initial data").action(async()=>{let{exec:e}=await import('child_process');e("npx tsx src/database/drizzle/seed.ts",(r,t,n)=>{r&&(console.error("\u274C Seeding failed:",r.message),process.exit(1));});});$.command("studio").description("Open Drizzle Studio").action(async()=>{let{exec:e}=await import('child_process');e("npx drizzle-kit studio",(r,t,n)=>{r&&(console.error("\u274C Studio failed:",r.message),process.exit(1));});});var le=T.command("auth").description("Authentication management commands");le.command("bootstrap").description("Create initial admin user").option("-e, --email <email>","Admin email",process.env.KYRO_ADMIN_EMAIL).option("-p, --password <password>","Admin password",process.env.KYRO_ADMIN_PASSWORD).option("-r, --role <role>","Admin role",process.env.KYRO_ADMIN_ROLE||"admin").action(async e=>{(!e.email||!e.password)&&(console.error("\u274C Email and password are required. Set KYRO_ADMIN_EMAIL and KYRO_ADMIN_PASSWORD env vars or use -e and -p options."),process.exit(1));try{let{bootstrapAdmin:r}=await import('../bootstrap-6G6HI26Z.js'),t=process.env.DATABASE_URL||"",n=t.toLowerCase().startsWith("postgres://")||t.toLowerCase().startsWith("postgresql://"),s=t.toLowerCase().startsWith("mongodb://")||t.toLowerCase().startsWith("mongodb+srv://"),a=!t||t.includes(".db")||t.includes("sqlite")||t.includes("file:"),c;if(n){let{PostgresAuthAdapter:l}=await import('../postgres-auth-adapter-33QOIRXT.js'),{drizzle:p}=await import('drizzle-orm/postgres-js'),{default:f}=await import('postgres'),m=f(t,{max:1,onnotice:()=>{}}),A=p(m);c=new l({db:A});}else if(s){let{MongoDBAuthAdapter:l}=await import('../mongo-auth-adapter-5TJO5J5U.js'),p=await import('mongodb'),f=new p.MongoClient(t);await f.connect();let m=f.db();c=new l({db:m});}else {let{SQLiteAuthAdapter:l}=await import('../sqlite-adapter-EXYRYZEV.js'),p=process.env.KYRO_AUTH_DB_PATH||"./data/auth.db";c=new l({path:p});}c.connect&&await c.connect();let d=await r({authAdapter:c,adminEmail:e.email,adminPassword:e.password,adminRole:e.role});c.disconnect&&await c.disconnect(),d.success||(console.error("\u274C Failed to create admin:",d.error),process.exit(1));}catch(r){console.error("\u274C Bootstrap failed:",r),process.exit(1);}});T.command("health").description("Check system health").action(async()=>{let e=process.env.DATABASE_URL||"",r=e.toLowerCase().startsWith("postgres://")||e.toLowerCase().startsWith("postgresql://"),t=e.toLowerCase().startsWith("mongodb://")||e.toLowerCase().startsWith("mongodb+srv://"),n=!e||e.includes(".db")||e.includes("sqlite")||e.includes("file:");if(r)try{let{default:s}=await import('postgres'),a=s(e,{max:1,onnotice:()=>{}});await a.unsafe("SELECT 1"),await a.end();}catch{}else if(t)try{let s=await import('mongodb'),a=new s.MongoClient(e);await a.connect(),await a.db().admin().ping(),await a.close();}catch{}else if(n)try{let s=process.env.KYRO_AUTH_DB_PATH||"./data/auth.db",{existsSync:a}=await import('fs');a(s);}catch{}});T.parse();process.argv.slice(2).length||T.outputHelp();