@vaiftech/cli 1.7.0 → 1.7.2

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/dist/index.cjs CHANGED
@@ -1,10 +1,10 @@
1
- 'use strict';var v=require('fs'),w=require('path'),M=require('dotenv'),K=require('pg'),z=require('ora'),d=require('chalk'),q=require('prettier'),j=require('readline');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var v__default=/*#__PURE__*/_interopDefault(v);var w__default=/*#__PURE__*/_interopDefault(w);var M__default=/*#__PURE__*/_interopDefault(M);var K__default=/*#__PURE__*/_interopDefault(K);var z__default=/*#__PURE__*/_interopDefault(z);var d__default=/*#__PURE__*/_interopDefault(d);var q__default=/*#__PURE__*/_interopDefault(q);var j__default=/*#__PURE__*/_interopDefault(j);M__default.default.config();async function E(n){let a=w__default.default.resolve(n);if(!v__default.default.existsSync(a))return null;try{let t=v__default.default.readFileSync(a,"utf-8"),e=JSON.parse(t);return e.database?.url&&(e.database.url=U(e.database.url)),e.api?.apiKey&&(e.api.apiKey=U(e.api.apiKey)),e}catch{throw new Error(`Failed to parse config file: ${n}`)}}function U(n){return n.replace(/\$\{([^}]+)\}/g,(a,t)=>process.env[t]||a)}async function B(n,a){let t=await n.query(`
1
+ 'use strict';var v=require('fs'),w=require('path'),q=require('dotenv'),G=require('pg'),H=require('ora'),p=require('chalk'),W=require('prettier'),B=require('os'),K=require('readline');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var v__default=/*#__PURE__*/_interopDefault(v);var w__default=/*#__PURE__*/_interopDefault(w);var q__default=/*#__PURE__*/_interopDefault(q);var G__default=/*#__PURE__*/_interopDefault(G);var H__default=/*#__PURE__*/_interopDefault(H);var p__default=/*#__PURE__*/_interopDefault(p);var W__default=/*#__PURE__*/_interopDefault(W);var B__default=/*#__PURE__*/_interopDefault(B);var K__default=/*#__PURE__*/_interopDefault(K);q__default.default.config();async function E(i){let a=w__default.default.resolve(i);if(!v__default.default.existsSync(a))return null;try{let t=v__default.default.readFileSync(a,"utf-8"),e=JSON.parse(t);return e.database?.url&&(e.database.url=V(e.database.url)),e.api?.apiKey&&(e.api.apiKey=V(e.api.apiKey)),e}catch{throw new Error(`Failed to parse config file: ${i}`)}}function V(i){return i.replace(/\$\{([^}]+)\}/g,(a,t)=>process.env[t]||a)}var Y=w__default.default.join(B__default.default.homedir(),".vaif"),k=w__default.default.join(Y,"auth.json");process.env.VAIF_API_URL||"https://api.vaif.studio";function O(){if(!v__default.default.existsSync(k))return null;try{let i=v__default.default.readFileSync(k,"utf-8");return JSON.parse(i)}catch{return null}}var J=process.env.VAIF_API_URL||"https://api.vaif.studio";async function X(i,a){let t=await fetch(`${J}/schema-engine/introspect/${a}`,{headers:{Authorization:`Bearer ${i}`,"Content-Type":"application/json"}});if(!t.ok){let l=await t.text();throw new Error(`API introspection failed: ${l}`)}let e=await t.json();if(!e.ok||!e.schemaExists)throw new Error("Project schema does not exist yet. Push a migration first with `vaif db push`.");let s=new Map,o=[];for(let l of e.tables){let c=l.columns.map(n=>({column_name:n.name,data_type:n.type,is_nullable:n.nullable?"YES":"NO",column_default:n.default,udt_name:n.type,is_identity:n.primaryKey&&n.default?.includes("gen_random_uuid")?"YES":"NO",character_maximum_length:null,numeric_precision:null,numeric_scale:null}));s.set(l.name,c);for(let n of l.foreignKeys)o.push({constraint_name:n.constraintName,table_name:l.name,column_name:n.columnName,foreign_table_name:n.refTable,foreign_column_name:n.refColumn});}return {tables:s,enums:new Map,foreignKeys:o}}async function Q(i,a){let t=await i.query(`
2
2
  SELECT table_name, table_type
3
3
  FROM information_schema.tables
4
4
  WHERE table_schema = $1
5
5
  AND table_type = 'BASE TABLE'
6
6
  ORDER BY table_name
7
- `,[a]),e=await n.query(`
7
+ `,[a]),e=await i.query(`
8
8
  SELECT
9
9
  table_name,
10
10
  column_name,
@@ -19,7 +19,7 @@
19
19
  FROM information_schema.columns
20
20
  WHERE table_schema = $1
21
21
  ORDER BY table_name, ordinal_position
22
- `,[a]),i=await n.query(`
22
+ `,[a]),s=await i.query(`
23
23
  SELECT
24
24
  tc.constraint_name,
25
25
  tc.table_name,
@@ -35,7 +35,7 @@
35
35
  AND ccu.table_schema = tc.table_schema
36
36
  WHERE tc.constraint_type = 'FOREIGN KEY'
37
37
  AND tc.table_schema = $1
38
- `,[a]),r=await n.query(`
38
+ `,[a]),o=await i.query(`
39
39
  SELECT
40
40
  t.typname as enum_name,
41
41
  e.enumlabel as enum_value
@@ -44,22 +44,24 @@
44
44
  JOIN pg_namespace n ON n.oid = t.typnamespace
45
45
  WHERE n.nspname = $1
46
46
  ORDER BY t.typname, e.enumsortorder
47
- `,[a]),c=new Map;for(let l of t.rows)c.set(l.table_name,[]);for(let l of e.rows){let s=c.get(l.table_name);s&&s.push(l);}let u=new Map;for(let l of r.rows){let s=u.get(l.enum_name)||[];s.push(l.enum_value),u.set(l.enum_name,s);}return {tables:c,enums:u,foreignKeys:i.rows}}var S={smallint:"number",integer:"number",bigint:"string",int2:"number",int4:"number",int8:"string",decimal:"string",numeric:"string",real:"number",float4:"number",float8:"number","double precision":"number",money:"string",boolean:"boolean",bool:"boolean",text:"string",varchar:"string",char:"string",character:"string","character varying":"string",name:"string",citext:"string",date:"string",time:"string",timetz:"string","time without time zone":"string","time with time zone":"string",timestamp:"string",timestamptz:"string","timestamp without time zone":"string","timestamp with time zone":"string",interval:"string",bytea:"Buffer",uuid:"string",json:"unknown",jsonb:"unknown",inet:"string",cidr:"string",macaddr:"string",macaddr8:"string",point:"{ x: number; y: number }",line:"string",lseg:"string",box:"string",path:"string",polygon:"string",circle:"string",ARRAY:"unknown[]"};function $(n,a){let{data_type:t,udt_name:e,is_nullable:i}=n;if(a.has(e)){let u=a.get(e).map(l=>`"${l}"`).join(" | ");return i==="YES"?`(${u}) | null`:u}if(t==="ARRAY"){let c=e.replace(/^_/,"");if(a.has(c)){let s=a.get(c).map(o=>`"${o}"`).join(" | ");return i==="YES"?`(${s})[] | null`:`(${s})[]`}let u=S[c]||"unknown";return i==="YES"?`${u}[] | null`:`${u}[]`}let r=S[t]||S[e]||"unknown";return i==="YES"&&(r=`${r} | null`),r}function x(n){return n.split(/[_\-\s]+/).map(a=>a.charAt(0).toUpperCase()+a.slice(1).toLowerCase()).join("")}function Y(n,a){let t=x(n),e=a.map(i=>` | "${i}"`).join(`
47
+ `,[a]),u=new Map;for(let c of t.rows)u.set(c.table_name,[]);for(let c of e.rows){let n=u.get(c.table_name);n&&n.push(c);}let l=new Map;for(let c of o.rows){let n=l.get(c.enum_name)||[];n.push(c.enum_value),l.set(c.enum_name,n);}return {tables:u,enums:l,foreignKeys:s.rows}}var S={smallint:"number",integer:"number",bigint:"string",int2:"number",int4:"number",int8:"string",decimal:"string",numeric:"string",real:"number",float4:"number",float8:"number","double precision":"number",money:"string",boolean:"boolean",bool:"boolean",text:"string",varchar:"string",char:"string",character:"string","character varying":"string",name:"string",citext:"string",date:"string",time:"string",timetz:"string","time without time zone":"string","time with time zone":"string",timestamp:"string",timestamptz:"string","timestamp without time zone":"string","timestamp with time zone":"string",interval:"string",bytea:"Buffer",uuid:"string",json:"unknown",jsonb:"unknown",inet:"string",cidr:"string",macaddr:"string",macaddr8:"string",point:"{ x: number; y: number }",line:"string",lseg:"string",box:"string",path:"string",polygon:"string",circle:"string",ARRAY:"unknown[]"};function Z(i,a){let{data_type:t,udt_name:e,is_nullable:s}=i;if(a.has(e)){let l=a.get(e).map(c=>`"${c}"`).join(" | ");return s==="YES"?`(${l}) | null`:l}if(t==="ARRAY"){let u=e.replace(/^_/,"");if(a.has(u)){let n=a.get(u).map(r=>`"${r}"`).join(" | ");return s==="YES"?`(${n})[] | null`:`(${n})[]`}let l=S[u]||"unknown";return s==="YES"?`${l}[] | null`:`${l}[]`}let o=S[t]||S[e]||"unknown";return s==="YES"&&(o=`${o} | null`),o}function x(i){return i.split(/[_\-\s]+/).map(a=>a.charAt(0).toUpperCase()+a.slice(1).toLowerCase()).join("")}function ee(i,a){let t=x(i),e=a.map(s=>` | "${s}"`).join(`
48
48
  `);return `export type ${t} =
49
- ${e};`}function G(n,a,t){let e=x(n),i=[],r=[],c=[];for(let o of a){let p=$(o,t),m=o.column_name,g=o.column_default!==null||o.is_identity==="YES",y=o.is_nullable==="YES";i.push(` ${m}: ${p};`),g||o.column_name==="id"?r.push(` ${m}?: ${p.replace(" | null","")} | null;`):y?r.push(` ${m}?: ${p};`):r.push(` ${m}: ${p.replace(" | null","")};`),c.push(` ${m}?: ${p.replace(" | null","")} | null;`);}let u=`export interface ${e} {
50
- ${i.join(`
49
+ ${e};`}function te(i,a,t){let e=x(i),s=[],o=[],u=[];for(let r of a){let m=Z(r,t),d=r.column_name,g=r.column_default!==null||r.is_identity==="YES",y=r.is_nullable==="YES";s.push(` ${d}: ${m};`),g||r.column_name==="id"?o.push(` ${d}?: ${m.replace(" | null","")} | null;`):y?o.push(` ${d}?: ${m};`):o.push(` ${d}: ${m.replace(" | null","")};`),u.push(` ${d}?: ${m.replace(" | null","")} | null;`);}let l=`export interface ${e} {
50
+ ${s.join(`
51
51
  `)}
52
- }`,l=`export interface ${e}Insert {
53
- ${r.join(`
52
+ }`,c=`export interface ${e}Insert {
53
+ ${o.join(`
54
54
  `)}
55
- }`,s=`export interface ${e}Update {
56
- ${c.join(`
55
+ }`,n=`export interface ${e}Update {
56
+ ${u.join(`
57
57
  `)}
58
- }`;return {base:u,insert:l,update:s}}function H(n,a,t){let e=["/**"," * Auto-generated TypeScript types from database schema"," * Generated by @vaiftech/cli",` * Generated at: ${new Date().toISOString()}`," * "," * DO NOT EDIT MANUALLY - changes will be overwritten"," */",""];if(a.size>0){e.push("// ============ ENUMS ============"),e.push("");for(let[r,c]of a)e.push(Y(r,c)),e.push("");}e.push("// ============ TABLES ============"),e.push("");let i=[];for(let[r,c]of n){let{base:u,insert:l,update:s}=G(r,c,a);i.push(r),e.push(u),e.push(""),e.push(l),e.push(""),e.push(s),e.push("");}e.push("// ============ DATABASE SCHEMA ============"),e.push(""),e.push("export interface Database {");for(let r of i){let c=x(r);e.push(` ${r}: {`),e.push(` Row: ${c};`),e.push(` Insert: ${c}Insert;`),e.push(` Update: ${c}Update;`),e.push(" };");}return e.push("}"),e.push(""),e.push("export type TableName = keyof Database;"),e.push(""),e.push("// ============ HELPER TYPES ============"),e.push(""),e.push('export type Row<T extends TableName> = Database[T]["Row"];'),e.push('export type Insert<T extends TableName> = Database[T]["Insert"];'),e.push('export type Update<T extends TableName> = Database[T]["Update"];'),e.push(""),e.join(`
59
- `)}async function J(n){let a=z__default.default("Loading configuration...").start();try{let t=await E(n.config),e=n.connection||t?.database?.url||process.env.DATABASE_URL;e||(a.fail("No database connection string provided"),console.log(d__default.default.yellow(`
60
- Provide a connection string via:`)),console.log(d__default.default.gray(" --connection <url>")),console.log(d__default.default.gray(" DATABASE_URL environment variable")),console.log(d__default.default.gray(" vaif.config.json database.url")),process.exit(1)),a.text="Connecting to database...";let i=new K__default.default.Client({connectionString:e});await i.connect(),a.text="Introspecting schema...";let{tables:r,enums:c,foreignKeys:u}=await B(i,n.schema);if(await i.end(),r.size===0){a.warn(`No tables found in schema "${n.schema}"`);return}a.text=`Generating types for ${r.size} tables...`;let l=H(r,c,u),s=await q__default.default.format(l,{parser:"typescript",semi:!0,singleQuote:!1,trailingComma:"es5",printWidth:100});if(n.dryRun){a.succeed("Generated types (dry run):"),console.log(""),console.log(d__default.default.gray("\u2500".repeat(60))),console.log(s),console.log(d__default.default.gray("\u2500".repeat(60)));return}let o=w__default.default.resolve(n.output),p=w__default.default.dirname(o);v__default.default.existsSync(p)||v__default.default.mkdirSync(p,{recursive:!0}),v__default.default.writeFileSync(o,s,"utf-8"),a.succeed(`Generated types for ${r.size} tables \u2192 ${d__default.default.cyan(n.output)}`),console.log(""),console.log(d__default.default.green("Generated:")),console.log(d__default.default.gray(` Tables: ${r.size}`)),console.log(d__default.default.gray(` Enums: ${c.size}`)),console.log(""),console.log(d__default.default.gray("Import in your code:")),console.log(d__default.default.cyan(` import type { Database, Row, Insert, Update } from "${n.output.replace(/\.ts$/,"")}";`));}catch(t){a.fail("Failed to generate types"),t instanceof Error&&(console.error(d__default.default.red(`
61
- Error: ${t.message}`)),t.message.includes("ECONNREFUSED")&&console.log(d__default.default.yellow(`
62
- Make sure your database is running and accessible.`))),process.exit(1);}}var b=[{name:"database",label:"Database",description:"CRUD queries, type-safe operations"},{name:"auth",label:"Authentication",description:"login, signup, OAuth, sessions"},{name:"realtime",label:"Realtime",description:"live subscriptions, presence"},{name:"storage",label:"Storage",description:"file uploads, signed URLs"},{name:"functions",label:"Functions",description:"serverless function calls"}],W={"nextjs-fullstack":{name:"Next.js Full-Stack",description:"Next.js app with server/client VAIF client, auth middleware, and React hooks",tag:"Next.js",defaultFeatures:["database","auth"],files:[{path:"package.json",content:`{
58
+ }`;return {base:l,insert:c,update:n}}function ae(i,a,t){let e=["/**"," * Auto-generated TypeScript types from database schema"," * Generated by @vaiftech/cli",` * Generated at: ${new Date().toISOString()}`," * "," * DO NOT EDIT MANUALLY - changes will be overwritten"," */",""];if(a.size>0){e.push("// ============ ENUMS ============"),e.push("");for(let[o,u]of a)e.push(ee(o,u)),e.push("");}e.push("// ============ TABLES ============"),e.push("");let s=[];for(let[o,u]of i){let{base:l,insert:c,update:n}=te(o,u,a);s.push(o),e.push(l),e.push(""),e.push(c),e.push(""),e.push(n),e.push("");}e.push("// ============ DATABASE SCHEMA ============"),e.push(""),e.push("export interface Database {");for(let o of s){let u=x(o);e.push(` ${o}: {`),e.push(` Row: ${u};`),e.push(` Insert: ${u}Insert;`),e.push(` Update: ${u}Update;`),e.push(" };");}return e.push("}"),e.push(""),e.push("export type TableName = keyof Database;"),e.push(""),e.push("// ============ HELPER TYPES ============"),e.push(""),e.push('export type Row<T extends TableName> = Database[T]["Row"];'),e.push('export type Insert<T extends TableName> = Database[T]["Insert"];'),e.push('export type Update<T extends TableName> = Database[T]["Update"];'),e.push(""),e.join(`
59
+ `)}async function ne(i){let a=H__default.default("Loading configuration...").start();try{let t=await E(i.config),e=i.connection||t?.database?.url||process.env.DATABASE_URL,s=e&&!e.includes("${"),o,u,l;if(s){a.text="Connecting to database...";let d=new G__default.default.Client({connectionString:e});await d.connect(),a.text="Introspecting schema...",{tables:o,enums:u,foreignKeys:l}=await Q(d,i.schema),await d.end();}else {let d=O();(!d||!d.token)&&(a.fail("No database connection and not logged in"),console.log(p__default.default.yellow(`
60
+ Either:`)),console.log(p__default.default.gray(" 1. Run `vaif login` to authenticate (no DATABASE_URL needed)")),console.log(p__default.default.gray(" 2. Set DATABASE_URL in your .env file")),console.log(p__default.default.gray(" 3. Pass --connection postgresql://user:pass@host:5432/db")),process.exit(1));let g=t?.projectId||process.env.VAIF_PROJECT_ID||d.projectId;g||(a.fail("No project ID specified"),console.log(p__default.default.yellow(`
61
+ Set projectId in vaif.config.json or use VAIF_PROJECT_ID env var.`)),process.exit(1)),a.text="Introspecting schema via API...",{tables:o,enums:u,foreignKeys:l}=await X(d.token,g);}if(o.size===0){a.warn("No tables found"),console.log(p__default.default.yellow(`
62
+ Push a migration first: vaif db push`));return}a.text=`Generating types for ${o.size} tables...`;let c=ae(o,u,l),n=await W__default.default.format(c,{parser:"typescript",semi:!0,singleQuote:!1,trailingComma:"es5",printWidth:100});if(i.dryRun){a.succeed("Generated types (dry run):"),console.log(""),console.log(p__default.default.gray("\u2500".repeat(60))),console.log(n),console.log(p__default.default.gray("\u2500".repeat(60)));return}let r=w__default.default.resolve(i.output),m=w__default.default.dirname(r);v__default.default.existsSync(m)||v__default.default.mkdirSync(m,{recursive:!0}),v__default.default.writeFileSync(r,n,"utf-8"),a.succeed(`Generated types for ${o.size} tables \u2192 ${p__default.default.cyan(i.output)}`),console.log(""),console.log(p__default.default.green("Generated:")),console.log(p__default.default.gray(` Tables: ${o.size}`)),console.log(p__default.default.gray(` Enums: ${u.size}`)),console.log(""),console.log(p__default.default.gray("Import in your code:")),console.log(p__default.default.cyan(` import type { Database, Row, Insert, Update } from "${i.output.replace(/\.ts$/,"")}";`));}catch(t){a.fail("Failed to generate types"),t instanceof Error&&(console.error(p__default.default.red(`
63
+ Error: ${t.message}`)),t.message.includes("ECONNREFUSED")&&console.log(p__default.default.yellow(`
64
+ Make sure your database is running and accessible.`))),process.exit(1);}}var b=[{name:"database",label:"Database",description:"CRUD queries, type-safe operations"},{name:"auth",label:"Authentication",description:"login, signup, OAuth, sessions"},{name:"realtime",label:"Realtime",description:"live subscriptions, presence"},{name:"storage",label:"Storage",description:"file uploads, signed URLs"},{name:"functions",label:"Functions",description:"serverless function calls"}],ie={"nextjs-fullstack":{name:"Next.js Full-Stack",description:"Next.js app with server/client VAIF client, auth middleware, and React hooks",tag:"Next.js",defaultFeatures:["database","auth"],files:[{path:"package.json",content:`{
63
65
  "name": "my-vaif-app",
64
66
  "private": true,
65
67
  "version": "0.1.0",
@@ -155,24 +157,27 @@ body {
155
157
 
156
158
  // Browser client \u2013 safe to use in Client Components
157
159
  export const vaif = createVaifClient({
158
- projectId: process.env.NEXT_PUBLIC_VAIF_PROJECT_ID!,
160
+ baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
159
161
  apiKey: process.env.NEXT_PUBLIC_VAIF_API_KEY!,
160
162
  });
161
163
 
162
164
  // Server client \u2013 use in Server Components, Route Handlers, Server Actions
163
165
  export function createVaifServer() {
164
166
  return createVaifClient({
165
- projectId: process.env.NEXT_PUBLIC_VAIF_PROJECT_ID!,
166
- secretKey: process.env.VAIF_SECRET_KEY!,
167
+ baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
168
+ apiKey: process.env.VAIF_SECRET_KEY!,
167
169
  });
168
170
  }
169
171
  `},{path:".env.local.example",content:`# VAIF Configuration
170
172
  # Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
171
173
 
172
- NEXT_PUBLIC_VAIF_PROJECT_ID=your-project-id
173
- NEXT_PUBLIC_VAIF_API_KEY=your-anon-key
174
+ NEXT_PUBLIC_VAIF_API_URL=https://api.vaif.studio
175
+ NEXT_PUBLIC_VAIF_API_KEY=your-api-key
174
176
  VAIF_SECRET_KEY=your-secret-key
175
177
 
178
+ # Database connection (for vaif generate, vaif db push)
179
+ # DATABASE_URL=postgresql://user:password@host:5432/dbname
180
+
176
181
  # CLI uses these (non-prefixed) for vaif db push, vaif secrets, etc.
177
182
  VAIF_PROJECT_ID=your-project-id
178
183
  `},{path:".gitignore",content:`node_modules
@@ -288,8 +293,8 @@ export async function middleware(request: NextRequest) {
288
293
  if (!isProtected) return NextResponse.next();
289
294
 
290
295
  const vaif = createVaifClient({
291
- projectId: process.env.NEXT_PUBLIC_VAIF_PROJECT_ID!,
292
- secretKey: process.env.VAIF_SECRET_KEY!,
296
+ baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
297
+ apiKey: process.env.VAIF_SECRET_KEY!,
293
298
  });
294
299
 
295
300
  return authMiddleware(vaif, request, {
@@ -650,13 +655,13 @@ function Home() {
650
655
  `},{path:"src/lib/vaif.ts",content:`import { createVaifClient } from "@vaiftech/client";
651
656
 
652
657
  export const vaif = createVaifClient({
653
- projectId: import.meta.env.VITE_VAIF_PROJECT_ID,
658
+ baseUrl: import.meta.env.VITE_VAIF_API_URL || 'https://api.vaif.studio',
654
659
  apiKey: import.meta.env.VITE_VAIF_API_KEY,
655
660
  });
656
661
  `},{path:"src/vite-env.d.ts",content:`/// <reference types="vite/client" />
657
662
 
658
663
  interface ImportMetaEnv {
659
- readonly VITE_VAIF_PROJECT_ID: string;
664
+ readonly VITE_VAIF_API_URL: string;
660
665
  readonly VITE_VAIF_API_KEY: string;
661
666
  }
662
667
 
@@ -664,13 +669,13 @@ interface ImportMeta {
664
669
  readonly env: ImportMetaEnv;
665
670
  }
666
671
  `},{path:".env.example",content:`# VAIF Configuration
667
- # Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
672
+ # Get these values from https://vaif.studio/app/security/api-keys
668
673
 
669
- VITE_VAIF_PROJECT_ID=your-project-id
670
- VITE_VAIF_API_KEY=your-anon-key
674
+ VITE_VAIF_API_URL=https://api.vaif.studio
675
+ VITE_VAIF_API_KEY=your-api-key
671
676
 
672
- # CLI uses these (non-prefixed) for vaif db push, vaif secrets, etc.
673
- VAIF_PROJECT_ID=your-project-id
677
+ # Database connection (for vaif generate, vaif db push)
678
+ # DATABASE_URL=postgresql://user:password@host:5432/dbname
674
679
  `},{path:".gitignore",content:`node_modules
675
680
  dist
676
681
  .env
@@ -2609,7 +2614,7 @@ func HelloHandler(w http.ResponseWriter, r *http.Request) {
2609
2614
  `}]},postInstructions:["go mod tidy","# Copy .env.example to .env and add your VAIF credentials","go run main.go"]},"todo-app":{name:"Todo App",description:"Simple React todo app \u2013 great for learning VAIF basics",tag:"React Starter",defaultFeatures:["database"],files:[{path:"src/lib/vaif.ts",content:`import { createVaifClient } from "@vaiftech/client";
2610
2615
 
2611
2616
  export const vaif = createVaifClient({
2612
- projectId: import.meta.env.VITE_VAIF_PROJECT_ID,
2617
+ baseUrl: import.meta.env.VITE_VAIF_API_URL || 'https://api.vaif.studio',
2613
2618
  apiKey: import.meta.env.VITE_VAIF_API_KEY,
2614
2619
  });
2615
2620
 
@@ -2661,13 +2666,13 @@ export async function deleteTodo(id: string): Promise<void> {
2661
2666
  if (error) throw error;
2662
2667
  }
2663
2668
  `},{path:".env.example",content:`# VAIF Configuration
2664
- # Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
2669
+ # Get these values from https://vaif.studio/app/security/api-keys
2665
2670
 
2666
- VITE_VAIF_PROJECT_ID=your-project-id
2667
- VITE_VAIF_API_KEY=your-anon-key
2671
+ VITE_VAIF_API_URL=https://api.vaif.studio
2672
+ VITE_VAIF_API_KEY=your-api-key
2668
2673
 
2669
- # CLI uses these (non-prefixed) for vaif db push, vaif secrets, etc.
2670
- VAIF_PROJECT_ID=your-project-id
2674
+ # Database connection (for vaif generate, vaif db push)
2675
+ # DATABASE_URL=postgresql://user:password@host:5432/dbname
2671
2676
  `},{path:"README.md",content:`# Todo App \u2014 VAIF Starter
2672
2677
 
2673
2678
  A simple React todo application for learning [VAIF Studio](https://vaif.studio) basics, including typed database queries and CRUD operations.
@@ -2803,15 +2808,8 @@ export const posts = pgTable("posts", {
2803
2808
  `}]},dependencies:["@vaiftech/client","@vaiftech/react"],postInstructions:["Copy .env.example to .env and fill in your project credentials","Create a 'todos' table in your VAIF dashboard with columns: id (uuid), title (text), done (boolean), created_at (timestamptz)","Import helpers from './lib/vaif' in your components","Run: npx vaif generate to generate TypeScript types"]},"realtime-chat":{name:"Realtime Chat",description:"React chat app with VAIF realtime subscriptions for live messaging",tag:"React + Realtime",defaultFeatures:["database","realtime","auth"],files:[{path:"src/lib/vaif.ts",content:`import { createVaifClient } from "@vaiftech/client";
2804
2809
 
2805
2810
  export const vaif = createVaifClient({
2806
- projectId: import.meta.env.VITE_VAIF_PROJECT_ID,
2811
+ baseUrl: import.meta.env.VITE_VAIF_API_URL || 'https://api.vaif.studio',
2807
2812
  apiKey: import.meta.env.VITE_VAIF_API_KEY,
2808
- realtime: {
2809
- enabled: true,
2810
- // Automatically reconnect on connection loss
2811
- reconnect: true,
2812
- reconnectInterval: 1000,
2813
- maxReconnectAttempts: 10,
2814
- },
2815
2813
  });
2816
2814
 
2817
2815
  export interface Message {
@@ -2949,13 +2947,13 @@ export function useRealtimeMessages({
2949
2947
  return { messages, isLoading, error, refresh };
2950
2948
  }
2951
2949
  `},{path:".env.example",content:`# VAIF Configuration
2952
- # Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
2950
+ # Get these values from https://vaif.studio/app/security/api-keys
2953
2951
 
2954
- VITE_VAIF_PROJECT_ID=your-project-id
2955
- VITE_VAIF_API_KEY=your-anon-key
2952
+ VITE_VAIF_API_URL=https://api.vaif.studio
2953
+ VITE_VAIF_API_KEY=your-api-key
2956
2954
 
2957
- # CLI uses these (non-prefixed) for vaif db push, vaif secrets, etc.
2958
- VAIF_PROJECT_ID=your-project-id
2955
+ # Database connection (for vaif generate, vaif db push)
2956
+ # DATABASE_URL=postgresql://user:password@host:5432/dbname
2959
2957
  `},{path:"README.md",content:`# Realtime Chat \u2014 VAIF Starter
2960
2958
 
2961
2959
  A React chat application with live messaging powered by [VAIF Studio](https://vaif.studio) realtime subscriptions.
@@ -3106,15 +3104,15 @@ export const posts = pgTable("posts", {
3106
3104
 
3107
3105
  // Browser client \u2013 use in Client Components
3108
3106
  export const vaif = createVaifClient({
3109
- projectId: process.env.NEXT_PUBLIC_VAIF_PROJECT_ID!,
3107
+ baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
3110
3108
  apiKey: process.env.NEXT_PUBLIC_VAIF_API_KEY!,
3111
3109
  });
3112
3110
 
3113
3111
  // Server client \u2013 use in Server Components, Route Handlers, Server Actions
3114
3112
  export function createVaifServer() {
3115
3113
  return createVaifClient({
3116
- projectId: process.env.NEXT_PUBLIC_VAIF_PROJECT_ID!,
3117
- secretKey: process.env.VAIF_SECRET_KEY!,
3114
+ baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
3115
+ apiKey: process.env.VAIF_SECRET_KEY!,
3118
3116
  });
3119
3117
  }
3120
3118
  `},{path:"lib/auth.ts",content:`import { createVaifServer } from "./vaif";
@@ -3267,10 +3265,13 @@ export async function requireTeamRole(
3267
3265
  `},{path:".env.example",content:`# VAIF Configuration
3268
3266
  # Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
3269
3267
 
3270
- NEXT_PUBLIC_VAIF_PROJECT_ID=your-project-id
3271
- NEXT_PUBLIC_VAIF_API_KEY=your-anon-key
3268
+ NEXT_PUBLIC_VAIF_API_URL=https://api.vaif.studio
3269
+ NEXT_PUBLIC_VAIF_API_KEY=your-api-key
3272
3270
  VAIF_SECRET_KEY=your-secret-key
3273
3271
 
3272
+ # Database connection (for vaif generate, vaif db push)
3273
+ # DATABASE_URL=postgresql://user:password@host:5432/dbname
3274
+
3274
3275
  # CLI uses these (non-prefixed) for vaif db push, vaif secrets, etc.
3275
3276
  VAIF_PROJECT_ID=your-project-id
3276
3277
  `},{path:"README.md",content:`# SaaS Starter \u2014 VAIF Studio
@@ -3419,15 +3420,15 @@ export const posts = pgTable("posts", {
3419
3420
 
3420
3421
  // Browser client
3421
3422
  export const vaif = createVaifClient({
3422
- projectId: process.env.NEXT_PUBLIC_VAIF_PROJECT_ID!,
3423
+ baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
3423
3424
  apiKey: process.env.NEXT_PUBLIC_VAIF_API_KEY!,
3424
3425
  });
3425
3426
 
3426
3427
  // Server client
3427
3428
  export function createVaifServer() {
3428
3429
  return createVaifClient({
3429
- projectId: process.env.NEXT_PUBLIC_VAIF_PROJECT_ID!,
3430
- secretKey: process.env.VAIF_SECRET_KEY!,
3430
+ baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
3431
+ apiKey: process.env.VAIF_SECRET_KEY!,
3431
3432
  });
3432
3433
  }
3433
3434
  `},{path:"lib/storage.ts",content:`import { createVaifServer } from "./vaif";
@@ -3542,10 +3543,13 @@ function getContentType(fileName: string): string {
3542
3543
  `},{path:".env.example",content:`# VAIF Configuration
3543
3544
  # Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
3544
3545
 
3545
- NEXT_PUBLIC_VAIF_PROJECT_ID=your-project-id
3546
- NEXT_PUBLIC_VAIF_API_KEY=your-anon-key
3546
+ NEXT_PUBLIC_VAIF_API_URL=https://api.vaif.studio
3547
+ NEXT_PUBLIC_VAIF_API_KEY=your-api-key
3547
3548
  VAIF_SECRET_KEY=your-secret-key
3548
3549
 
3550
+ # Database connection (for vaif generate, vaif db push)
3551
+ # DATABASE_URL=postgresql://user:password@host:5432/dbname
3552
+
3549
3553
  # CLI uses these (non-prefixed) for vaif db push, vaif secrets, etc.
3550
3554
  VAIF_PROJECT_ID=your-project-id
3551
3555
  `},{path:"README.md",content:`# E-commerce API \u2014 VAIF Studio
@@ -3688,25 +3692,25 @@ export const posts = pgTable("posts", {
3688
3692
 
3689
3693
  return Response.json({ message: \`Hello, \${name}!\` });
3690
3694
  }
3691
- `}]},dependencies:["@vaiftech/client","@vaiftech/auth"],postInstructions:["Copy .env.example to .env.local and fill in your project credentials","Create a 'product-images' storage bucket in your VAIF dashboard","Import storage helpers from '@/lib/storage' in your API routes","Use uploadProductImage() in your product creation flow","Run: npx vaif generate to generate TypeScript types"]}};async function X(n){if(!process.stdin.isTTY||!process.stdout.isTTY)return n;let a=new Set(n.map(e=>b.findIndex(i=>i.name===e)).filter(e=>e>=0)),t=0;return new Promise(e=>{let i=j__default.default.createInterface({input:process.stdin,output:process.stdout});j__default.default.emitKeypressEvents(process.stdin,i),process.stdin.setRawMode&&process.stdin.setRawMode(true);function r(){let u=b.length+2;process.stdout.write(`\x1B[${u}A`),c();}function c(){console.log(d__default.default.bold(`
3692
- ? Which VAIF features do you want to include?`)),b.forEach((u,l)=>{let s=a.has(l)?d__default.default.green("[x]"):"[ ]",o=l===t?d__default.default.cyan("> "):" ";console.log(`${o}${s} ${u.label} ${d__default.default.gray(`(${u.description})`)}`);}),console.log(d__default.default.gray(" (up/down to move, space to toggle, enter to confirm)"));}c(),process.stdin.on("keypress",(u,l)=>{if(l.name==="up"&&t>0)t--,r();else if(l.name==="down"&&t<b.length-1)t++,r();else if(l.name==="space")a.has(t)?a.delete(t):a.add(t),r();else if(l.name==="return"){process.stdin.setRawMode&&process.stdin.setRawMode(false),i.close();let s=[...a].sort().map(o=>b[o].name);e(s.length>0?s:n);}else l.name==="c"&&l.ctrl&&(process.stdin.setRawMode&&process.stdin.setRawMode(false),i.close(),process.exit(0));});})}async function F(n,a={}){let t=W[n];t||(console.log(d__default.default.red(`
3693
- Unknown template: ${n}`)),console.log(d__default.default.yellow(`Run 'vaif templates' to see available templates.
3694
- `)),process.exit(1));let e;a.features&&a.features.length>0?e=a.features.filter(s=>b.some(o=>o.name===s)):a.addOnly?(console.log(d__default.default.red(`
3695
- No features specified.`)),console.log(d__default.default.yellow("Usage: vaif init --template <name> --add-features <features>")),console.log(d__default.default.gray("Available features: auth, database, realtime, storage, functions")),process.exit(1)):t.featureFiles&&Object.keys(t.featureFiles).length>0?e=await X(t.defaultFeatures??["database","auth"]):e=t.defaultFeatures??[],a.addOnly?(console.log(""),console.log(d__default.default.bold(`Adding features to ${d__default.default.cyan(t.name)} project...`)),console.log(d__default.default.gray(` Features: ${e.join(", ")}`)),console.log("")):(console.log(""),console.log(d__default.default.bold(`Scaffolding ${d__default.default.cyan(t.name)} template...`)),e.length>0&&console.log(d__default.default.gray(` Features: ${e.join(", ")}`)),console.log(""));let i=a.addOnly?[]:[...t.files];if(t.featureFiles)for(let s of e){let o=t.featureFiles[s];o&&i.push(...o);}let r=0,c=0;for(let s of i){let o=w__default.default.resolve(s.path),p=w__default.default.dirname(o);if(v__default.default.existsSync(p)||v__default.default.mkdirSync(p,{recursive:true}),s.path==="package.json"&&v__default.default.existsSync(o)&&!a.force)try{let m=JSON.parse(v__default.default.readFileSync(o,"utf-8")),g=JSON.parse(s.content),y=N=>{if(!N)return {};let L={};for(let[k,_]of Object.entries(N))!_.startsWith("workspace:")&&!_.startsWith("link:")&&!_.startsWith("file:")&&(L[k]=_);return L};m.dependencies={...y(m.dependencies),...g.dependencies||{}},m.devDependencies={...y(m.devDependencies),...g.devDependencies||{}},g.scripts&&(m.scripts={...m.scripts||{},...g.scripts}),v__default.default.writeFileSync(o,JSON.stringify(m,null,2)+`
3696
- `,"utf-8"),console.log(d__default.default.green(` merge ${s.path} (added dependencies)`)),r++;continue}catch{}if(v__default.default.existsSync(o)&&!a.force){console.log(d__default.default.yellow(` skip ${s.path} (already exists)`)),c++;continue}v__default.default.writeFileSync(o,s.content,"utf-8"),console.log(d__default.default.green(` create ${s.path}`)),r++;}console.log(""),r>0&&console.log(d__default.default.green(`Created ${r} file${r!==1?"s":""}.`)),c>0&&console.log(d__default.default.yellow(`Skipped ${c} file${c!==1?"s":""} (use --force to overwrite).`));let u={auth:{"@vaiftech/auth":"^1.0.0"},database:{},realtime:{},storage:{},functions:{}},l=w__default.default.resolve("package.json");if(v__default.default.existsSync(l)&&e.length>0)try{let s=JSON.parse(v__default.default.readFileSync(l,"utf-8")),o=!1;for(let p of e){let m=u[p];if(m)for(let[g,y]of Object.entries(m))s.dependencies?.[g]||(s.dependencies=s.dependencies||{},s.dependencies[g]=y,o=!0);}o&&v__default.default.writeFileSync(l,JSON.stringify(s,null,2)+`
3697
- `,"utf-8");}catch{}(t.dependencies?.length||t.devDependencies?.length)&&(console.log(""),console.log(d__default.default.bold("Install dependencies:")),t.dependencies?.length&&console.log(d__default.default.cyan(` npm install ${t.dependencies.join(" ")}`)),t.devDependencies?.length&&console.log(d__default.default.cyan(` npm install -D ${t.devDependencies.join(" ")}`))),console.log(""),console.log(d__default.default.bold.green("Project scaffolded successfully!")),console.log(""),console.log(d__default.default.bold(" Next steps:")),t.postInstructions.forEach(s=>{console.log(d__default.default.gray(` ${s}`));}),console.log(""),console.log(d__default.default.gray(" Get your project credentials at https://vaif.studio/app/security/api-keys")),console.log("");}var Z={$schema:"https://vaif.studio/schemas/config.json",projectId:"",database:{url:"${DATABASE_URL}",schema:"public"},types:{output:"./src/types/database.ts"},api:{baseUrl:"https://api.vaif.studio"}};async function ee(n){if(n.addFeatures){n.template||(console.log(d__default.default.red(`
3698
- --add-features requires --template to know which template to use.`)),console.log(d__default.default.gray("Example: vaif init --template react-spa --add-features functions,storage")),process.exit(1));let e=n.addFeatures.split(",").map(i=>i.trim());await F(n.template,{force:n.force,features:e,addOnly:true});return}let a=z__default.default("Initializing VAIF configuration...").start(),t=w__default.default.resolve("vaif.config.json");v__default.default.existsSync(t)&&!n.force&&(a.fail("vaif.config.json already exists"),console.log(d__default.default.yellow(`
3699
- Use --force to overwrite existing configuration.`)),process.exit(1));try{if(v__default.default.writeFileSync(t,JSON.stringify(Z,null,2),"utf-8"),a.succeed("Created vaif.config.json"),n.template){let e=n.features?n.features.split(",").map(i=>i.trim()):void 0;await F(n.template,{force:n.force,features:e});}else {let e=w__default.default.resolve(".env.example");if(v__default.default.existsSync(e)||(v__default.default.writeFileSync(e,`# VAIF Configuration
3695
+ `}]},dependencies:["@vaiftech/client","@vaiftech/auth"],postInstructions:["Copy .env.example to .env.local and fill in your project credentials","Create a 'product-images' storage bucket in your VAIF dashboard","Import storage helpers from '@/lib/storage' in your API routes","Use uploadProductImage() in your product creation flow","Run: npx vaif generate to generate TypeScript types"]}};async function oe(i){if(!process.stdin.isTTY||!process.stdout.isTTY)return i;let a=new Set(i.map(e=>b.findIndex(s=>s.name===e)).filter(e=>e>=0)),t=0;return new Promise(e=>{let s=K__default.default.createInterface({input:process.stdin,output:process.stdout});K__default.default.emitKeypressEvents(process.stdin,s),process.stdin.setRawMode&&process.stdin.setRawMode(true);function o(){let l=b.length+2;process.stdout.write(`\x1B[${l}A`),u();}function u(){console.log(p__default.default.bold(`
3696
+ ? Which VAIF features do you want to include?`)),b.forEach((l,c)=>{let n=a.has(c)?p__default.default.green("[x]"):"[ ]",r=c===t?p__default.default.cyan("> "):" ";console.log(`${r}${n} ${l.label} ${p__default.default.gray(`(${l.description})`)}`);}),console.log(p__default.default.gray(" (up/down to move, space to toggle, enter to confirm)"));}u(),process.stdin.on("keypress",(l,c)=>{if(c.name==="up"&&t>0)t--,o();else if(c.name==="down"&&t<b.length-1)t++,o();else if(c.name==="space")a.has(t)?a.delete(t):a.add(t),o();else if(c.name==="return"){process.stdin.setRawMode&&process.stdin.setRawMode(false),s.close();let n=[...a].sort().map(r=>b[r].name);e(n.length>0?n:i);}else c.name==="c"&&c.ctrl&&(process.stdin.setRawMode&&process.stdin.setRawMode(false),s.close(),process.exit(0));});})}async function F(i,a={}){let t=ie[i];t||(console.log(p__default.default.red(`
3697
+ Unknown template: ${i}`)),console.log(p__default.default.yellow(`Run 'vaif templates' to see available templates.
3698
+ `)),process.exit(1));let e;a.features&&a.features.length>0?e=a.features.filter(n=>b.some(r=>r.name===n)):a.addOnly?(console.log(p__default.default.red(`
3699
+ No features specified.`)),console.log(p__default.default.yellow("Usage: vaif init --template <name> --add-features <features>")),console.log(p__default.default.gray("Available features: auth, database, realtime, storage, functions")),process.exit(1)):t.featureFiles&&Object.keys(t.featureFiles).length>0?e=await oe(t.defaultFeatures??["database","auth"]):e=t.defaultFeatures??[],a.addOnly?(console.log(""),console.log(p__default.default.bold(`Adding features to ${p__default.default.cyan(t.name)} project...`)),console.log(p__default.default.gray(` Features: ${e.join(", ")}`)),console.log("")):(console.log(""),console.log(p__default.default.bold(`Scaffolding ${p__default.default.cyan(t.name)} template...`)),e.length>0&&console.log(p__default.default.gray(` Features: ${e.join(", ")}`)),console.log(""));let s=a.addOnly?[]:[...t.files];if(t.featureFiles)for(let n of e){let r=t.featureFiles[n];r&&s.push(...r);}let o=0,u=0;for(let n of s){let r=w__default.default.resolve(n.path),m=w__default.default.dirname(r);if(v__default.default.existsSync(m)||v__default.default.mkdirSync(m,{recursive:true}),n.path==="package.json"&&v__default.default.existsSync(r)&&!a.force)try{let d=JSON.parse(v__default.default.readFileSync(r,"utf-8")),g=JSON.parse(n.content),y=N=>{if(!N)return {};let L={};for(let[z,_]of Object.entries(N))!_.startsWith("workspace:")&&!_.startsWith("link:")&&!_.startsWith("file:")&&(L[z]=_);return L};d.dependencies={...y(d.dependencies),...g.dependencies||{}},d.devDependencies={...y(d.devDependencies),...g.devDependencies||{}},g.scripts&&(d.scripts={...d.scripts||{},...g.scripts}),v__default.default.writeFileSync(r,JSON.stringify(d,null,2)+`
3700
+ `,"utf-8"),console.log(p__default.default.green(` merge ${n.path} (added dependencies)`)),o++;continue}catch{}if(v__default.default.existsSync(r)&&!a.force){console.log(p__default.default.yellow(` skip ${n.path} (already exists)`)),u++;continue}v__default.default.writeFileSync(r,n.content,"utf-8"),console.log(p__default.default.green(` create ${n.path}`)),o++;}console.log(""),o>0&&console.log(p__default.default.green(`Created ${o} file${o!==1?"s":""}.`)),u>0&&console.log(p__default.default.yellow(`Skipped ${u} file${u!==1?"s":""} (use --force to overwrite).`));let l={auth:{"@vaiftech/auth":"^1.0.0"},database:{},realtime:{},storage:{},functions:{}},c=w__default.default.resolve("package.json");if(v__default.default.existsSync(c)&&e.length>0)try{let n=JSON.parse(v__default.default.readFileSync(c,"utf-8")),r=!1;for(let m of e){let d=l[m];if(d)for(let[g,y]of Object.entries(d))n.dependencies?.[g]||(n.dependencies=n.dependencies||{},n.dependencies[g]=y,r=!0);}r&&v__default.default.writeFileSync(c,JSON.stringify(n,null,2)+`
3701
+ `,"utf-8");}catch{}(t.dependencies?.length||t.devDependencies?.length)&&(console.log(""),console.log(p__default.default.bold("Install dependencies:")),t.dependencies?.length&&console.log(p__default.default.cyan(` npm install ${t.dependencies.join(" ")}`)),t.devDependencies?.length&&console.log(p__default.default.cyan(` npm install -D ${t.devDependencies.join(" ")}`))),console.log(""),console.log(p__default.default.bold.green("Project scaffolded successfully!")),console.log(""),console.log(p__default.default.bold(" Next steps:")),t.postInstructions.forEach(n=>{console.log(p__default.default.gray(` ${n}`));}),console.log(""),console.log(p__default.default.gray(" Get your project credentials at https://vaif.studio/app/security/api-keys")),console.log("");}var re={$schema:"https://vaif.studio/schemas/config.json",projectId:"",database:{url:"${DATABASE_URL}",schema:"public"},types:{output:"./src/types/database.ts"},api:{baseUrl:"https://api.vaif.studio"}};async function le(i){if(i.addFeatures){i.template||(console.log(p__default.default.red(`
3702
+ --add-features requires --template to know which template to use.`)),console.log(p__default.default.gray("Example: vaif init --template react-spa --add-features functions,storage")),process.exit(1));let e=i.addFeatures.split(",").map(s=>s.trim());await F(i.template,{force:i.force,features:e,addOnly:true});return}let a=H__default.default("Initializing VAIF configuration...").start(),t=w__default.default.resolve("vaif.config.json");v__default.default.existsSync(t)&&!i.force&&(a.fail("vaif.config.json already exists"),console.log(p__default.default.yellow(`
3703
+ Use --force to overwrite existing configuration.`)),process.exit(1));try{if(v__default.default.writeFileSync(t,JSON.stringify(re,null,2),"utf-8"),a.succeed("Created vaif.config.json"),i.template){let e=i.features?i.features.split(",").map(s=>s.trim()):void 0;await F(i.template,{force:i.force,features:e});}else {let e=w__default.default.resolve(".env.example");if(v__default.default.existsSync(e)||(v__default.default.writeFileSync(e,`# VAIF Configuration
3700
3704
  DATABASE_URL=postgresql://user:password@localhost:5432/database
3701
3705
  VAIF_API_KEY=your-api-key
3702
- `,"utf-8"),console.log(d__default.default.gray("Created .env.example"))),n.typescript){let i=w__default.default.resolve("src/types");v__default.default.existsSync(i)||(v__default.default.mkdirSync(i,{recursive:!0}),console.log(d__default.default.gray("Created src/types directory")));}console.log(""),console.log(d__default.default.green("VAIF initialized successfully!")),console.log(""),console.log(d__default.default.gray("Next steps:")),console.log(d__default.default.gray(" 1. Update vaif.config.json with your project ID")),console.log(d__default.default.gray(" 2. Set DATABASE_URL in your environment")),console.log(d__default.default.gray(" 3. Run: npx vaif generate")),console.log("");}}catch(e){a.fail("Failed to initialize"),e instanceof Error&&console.error(d__default.default.red(`
3703
- Error: ${e.message}`)),process.exit(1);}}async function Ve(n){let{connectionString:a,schema:t="public"}=n,e=new K__default.default.Client({connectionString:a});await e.connect();try{let i=await e.query(`
3706
+ `,"utf-8"),console.log(p__default.default.gray("Created .env.example"))),i.typescript){let s=w__default.default.resolve("src/types");v__default.default.existsSync(s)||(v__default.default.mkdirSync(s,{recursive:!0}),console.log(p__default.default.gray("Created src/types directory")));}console.log(""),console.log(p__default.default.green("VAIF initialized successfully!")),console.log(""),console.log(p__default.default.gray("Next steps:")),console.log(p__default.default.gray(" 1. Update vaif.config.json with your project ID")),console.log(p__default.default.gray(" 2. Set DATABASE_URL in your environment")),console.log(p__default.default.gray(" 3. Run: npx vaif generate")),console.log("");}}catch(e){a.fail("Failed to initialize"),e instanceof Error&&console.error(p__default.default.red(`
3707
+ Error: ${e.message}`)),process.exit(1);}}async function Ze(i){let{connectionString:a,schema:t="public"}=i,e=new G__default.default.Client({connectionString:a});await e.connect();try{let s=await e.query(`
3704
3708
  SELECT table_name, table_type
3705
3709
  FROM information_schema.tables
3706
3710
  WHERE table_schema = $1
3707
3711
  AND table_type = 'BASE TABLE'
3708
3712
  ORDER BY table_name
3709
- `,[t]),r=await e.query(`
3713
+ `,[t]),o=await e.query(`
3710
3714
  SELECT
3711
3715
  table_name,
3712
3716
  column_name,
@@ -3721,7 +3725,7 @@ Error: ${e.message}`)),process.exit(1);}}async function Ve(n){let{connectionStri
3721
3725
  FROM information_schema.columns
3722
3726
  WHERE table_schema = $1
3723
3727
  ORDER BY table_name, ordinal_position
3724
- `,[t]),c=await e.query(`
3728
+ `,[t]),u=await e.query(`
3725
3729
  SELECT
3726
3730
  t.typname as enum_name,
3727
3731
  e.enumlabel as enum_value
@@ -3730,16 +3734,16 @@ Error: ${e.message}`)),process.exit(1);}}async function Ve(n){let{connectionStri
3730
3734
  JOIN pg_namespace n ON n.oid = t.typnamespace
3731
3735
  WHERE n.nspname = $1
3732
3736
  ORDER BY t.typname, e.enumsortorder
3733
- `,[t]),u=new Map;for(let o of i.rows)u.set(o.table_name,[]);for(let o of r.rows){let p=u.get(o.table_name);p&&p.push(o);}let l=new Map;for(let o of c.rows){let p=l.get(o.enum_name)||[];p.push(o.enum_value),l.set(o.enum_name,p);}let s=ie(u,l);return q__default.default.format(s,{parser:"typescript",semi:!0,singleQuote:!1,trailingComma:"es5",printWidth:100})}finally{await e.end();}}var P={smallint:"number",integer:"number",bigint:"string",int2:"number",int4:"number",int8:"string",decimal:"string",numeric:"string",real:"number",float4:"number",float8:"number","double precision":"number",money:"string",boolean:"boolean",bool:"boolean",text:"string",varchar:"string",char:"string",character:"string","character varying":"string",name:"string",citext:"string",date:"string",time:"string",timetz:"string",timestamp:"string",timestamptz:"string","timestamp without time zone":"string","timestamp with time zone":"string",interval:"string",bytea:"Buffer",uuid:"string",json:"unknown",jsonb:"unknown",inet:"string",cidr:"string",macaddr:"string",point:"{ x: number; y: number }",ARRAY:"unknown[]"};function ne(n,a){let{data_type:t,udt_name:e,is_nullable:i}=n;if(a.has(e)){let u=a.get(e).map(l=>`"${l}"`).join(" | ");return i==="YES"?`(${u}) | null`:u}if(t==="ARRAY"){let c=e.replace(/^_/,"");if(a.has(c)){let s=a.get(c).map(o=>`"${o}"`).join(" | ");return i==="YES"?`(${s})[] | null`:`(${s})[]`}let u=P[c]||"unknown";return i==="YES"?`${u}[] | null`:`${u}[]`}let r=P[t]||P[e]||"unknown";return i==="YES"&&(r=`${r} | null`),r}function C(n){return n.split(/[_\-\s]+/).map(a=>a.charAt(0).toUpperCase()+a.slice(1).toLowerCase()).join("")}function ie(n,a){let t=["/**"," * Auto-generated TypeScript types from database schema"," * Generated by @vaiftech/cli",` * Generated at: ${new Date().toISOString()}`," * "," * DO NOT EDIT MANUALLY - changes will be overwritten"," */",""];if(a.size>0){t.push("// ============ ENUMS ============"),t.push("");for(let[i,r]of a){let c=C(i),u=r.map(l=>` | "${l}"`).join(`
3734
- `);t.push(`export type ${c} =
3735
- ${u};`),t.push("");}}t.push("// ============ TABLES ============"),t.push("");let e=[];for(let[i,r]of n){e.push(i);let c=C(i),u=[],l=[],s=[];for(let o of r){let p=ne(o,a),m=o.column_name,g=o.column_default!==null||o.is_identity==="YES",y=o.is_nullable==="YES";u.push(` ${m}: ${p};`),g||o.column_name==="id"?l.push(` ${m}?: ${p.replace(" | null","")} | null;`):y?l.push(` ${m}?: ${p};`):l.push(` ${m}: ${p.replace(" | null","")};`),s.push(` ${m}?: ${p.replace(" | null","")} | null;`);}t.push(`export interface ${c} {
3736
- ${u.join(`
3737
- `)}
3738
- }`),t.push(""),t.push(`export interface ${c}Insert {
3737
+ `,[t]),l=new Map;for(let r of s.rows)l.set(r.table_name,[]);for(let r of o.rows){let m=l.get(r.table_name);m&&m.push(r);}let c=new Map;for(let r of u.rows){let m=c.get(r.enum_name)||[];m.push(r.enum_value),c.set(r.enum_name,m);}let n=pe(l,c);return W__default.default.format(n,{parser:"typescript",semi:!0,singleQuote:!1,trailingComma:"es5",printWidth:100})}finally{await e.end();}}var R={smallint:"number",integer:"number",bigint:"string",int2:"number",int4:"number",int8:"string",decimal:"string",numeric:"string",real:"number",float4:"number",float8:"number","double precision":"number",money:"string",boolean:"boolean",bool:"boolean",text:"string",varchar:"string",char:"string",character:"string","character varying":"string",name:"string",citext:"string",date:"string",time:"string",timetz:"string",timestamp:"string",timestamptz:"string","timestamp without time zone":"string","timestamp with time zone":"string",interval:"string",bytea:"Buffer",uuid:"string",json:"unknown",jsonb:"unknown",inet:"string",cidr:"string",macaddr:"string",point:"{ x: number; y: number }",ARRAY:"unknown[]"};function de(i,a){let{data_type:t,udt_name:e,is_nullable:s}=i;if(a.has(e)){let l=a.get(e).map(c=>`"${c}"`).join(" | ");return s==="YES"?`(${l}) | null`:l}if(t==="ARRAY"){let u=e.replace(/^_/,"");if(a.has(u)){let n=a.get(u).map(r=>`"${r}"`).join(" | ");return s==="YES"?`(${n})[] | null`:`(${n})[]`}let l=R[u]||"unknown";return s==="YES"?`${l}[] | null`:`${l}[]`}let o=R[t]||R[e]||"unknown";return s==="YES"&&(o=`${o} | null`),o}function C(i){return i.split(/[_\-\s]+/).map(a=>a.charAt(0).toUpperCase()+a.slice(1).toLowerCase()).join("")}function pe(i,a){let t=["/**"," * Auto-generated TypeScript types from database schema"," * Generated by @vaiftech/cli",` * Generated at: ${new Date().toISOString()}`," * "," * DO NOT EDIT MANUALLY - changes will be overwritten"," */",""];if(a.size>0){t.push("// ============ ENUMS ============"),t.push("");for(let[s,o]of a){let u=C(s),l=o.map(c=>` | "${c}"`).join(`
3738
+ `);t.push(`export type ${u} =
3739
+ ${l};`),t.push("");}}t.push("// ============ TABLES ============"),t.push("");let e=[];for(let[s,o]of i){e.push(s);let u=C(s),l=[],c=[],n=[];for(let r of o){let m=de(r,a),d=r.column_name,g=r.column_default!==null||r.is_identity==="YES",y=r.is_nullable==="YES";l.push(` ${d}: ${m};`),g||r.column_name==="id"?c.push(` ${d}?: ${m.replace(" | null","")} | null;`):y?c.push(` ${d}?: ${m};`):c.push(` ${d}: ${m.replace(" | null","")};`),n.push(` ${d}?: ${m.replace(" | null","")} | null;`);}t.push(`export interface ${u} {
3739
3740
  ${l.join(`
3740
3741
  `)}
3741
- }`),t.push(""),t.push(`export interface ${c}Update {
3742
- ${s.join(`
3742
+ }`),t.push(""),t.push(`export interface ${u}Insert {
3743
+ ${c.join(`
3744
+ `)}
3745
+ }`),t.push(""),t.push(`export interface ${u}Update {
3746
+ ${n.join(`
3743
3747
  `)}
3744
- }`),t.push("");}t.push("// ============ DATABASE SCHEMA ============"),t.push(""),t.push("export interface Database {");for(let i of e){let r=C(i);t.push(` ${i}: {`),t.push(` Row: ${r};`),t.push(` Insert: ${r}Insert;`),t.push(` Update: ${r}Update;`),t.push(" };");}return t.push("}"),t.push(""),t.push("export type TableName = keyof Database;"),t.push(""),t.push("// ============ HELPER TYPES ============"),t.push(""),t.push('export type Row<T extends TableName> = Database[T]["Row"];'),t.push('export type Insert<T extends TableName> = Database[T]["Insert"];'),t.push('export type Update<T extends TableName> = Database[T]["Update"];'),t.push(""),t.join(`
3745
- `)}exports.generateTypes=J;exports.generateTypesFromConnection=Ve;exports.initConfig=ee;exports.loadConfig=E;
3748
+ }`),t.push("");}t.push("// ============ DATABASE SCHEMA ============"),t.push(""),t.push("export interface Database {");for(let s of e){let o=C(s);t.push(` ${s}: {`),t.push(` Row: ${o};`),t.push(` Insert: ${o}Insert;`),t.push(` Update: ${o}Update;`),t.push(" };");}return t.push("}"),t.push(""),t.push("export type TableName = keyof Database;"),t.push(""),t.push("// ============ HELPER TYPES ============"),t.push(""),t.push('export type Row<T extends TableName> = Database[T]["Row"];'),t.push('export type Insert<T extends TableName> = Database[T]["Insert"];'),t.push('export type Update<T extends TableName> = Database[T]["Update"];'),t.push(""),t.join(`
3749
+ `)}exports.generateTypes=ne;exports.generateTypesFromConnection=Ze;exports.initConfig=le;exports.loadConfig=E;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export{b as generateTypes,d as initConfig,a as loadConfig}from'./chunk-OB2QEQ2L.js';import T from'pg';import $ from'prettier';async function S(p){let{connectionString:a,schema:e="public"}=p,r=new T.Client({connectionString:a});await r.connect();try{let t=await r.query(`
1
+ export{f as generateTypes,h as initConfig,a as loadConfig}from'./chunk-KXD5F33V.js';import T from'pg';import $ from'prettier';async function S(p){let{connectionString:a,schema:e="public"}=p,r=new T.Client({connectionString:a});await r.connect();try{let t=await r.query(`
2
2
  SELECT table_name, table_type
3
3
  FROM information_schema.tables
4
4
  WHERE table_schema = $1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaiftech/cli",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "VAIF CLI - Type generation and development tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",