@vaiftech/cli 1.7.5 → 1.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/{chunk-WYTLXCHQ.js → chunk-T7GOLIY4.js} +52 -35
- package/dist/cli.cjs +70 -53
- package/dist/cli.js +2 -2
- package/dist/index.cjs +55 -38
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@vaiftech/cli)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
Command-line tools for [VAIF Studio](https://vaif.studio) (v1.7.
|
|
6
|
+
Command-line tools for [VAIF Studio](https://vaif.studio) (v1.7.6) — scaffold full projects from templates with feature selection, browser-based authentication, manage schemas, deploy functions, generate TypeScript types, and more.
|
|
7
7
|
|
|
8
8
|
## Installation
|
|
9
9
|
|
|
@@ -286,6 +286,8 @@ The CLI automatically loads `.env` files from the current directory. You can set
|
|
|
286
286
|
| `VAIF_API_URL` | API base URL (default: `https://api.vaif.studio`) |
|
|
287
287
|
| `VAIF_TOKEN` | API token (alternative to `vaif login`) |
|
|
288
288
|
| `VAIF_PROJECT_ID` | Default project ID (also read from `vaif.config.json`) |
|
|
289
|
+
| `VITE_VAIF_PROJECT_ID` | Project ID for Vite-based templates (React SPA) |
|
|
290
|
+
| `NEXT_PUBLIC_VAIF_PROJECT_ID` | Project ID for Next.js templates |
|
|
289
291
|
|
|
290
292
|
Project ID resolution order: `--project-id` flag > `vaif.config.json` > `VAIF_PROJECT_ID` env var > login session.
|
|
291
293
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
Could not connect to VAIF API. Please try again later.`)),process.exit(1));let
|
|
3
|
-
Could not connect to VAIF API.`)),console.log(
|
|
4
|
-
The authentication session expired. Please try again.`)),process.exit(1));continue}let
|
|
5
|
-
Timed out waiting for browser authentication.`)),console.log(
|
|
6
|
-
No email provided. Login cancelled.`)),process.exit(1));let n=await
|
|
7
|
-
No password provided. Login cancelled.`)),process.exit(1));let e=
|
|
8
|
-
${
|
|
9
|
-
Could not connect to VAIF API. Please try again later.`)),process.exit(1);}}async function
|
|
10
|
-
Your session has expired. Please login again.`)),process.exit(1)),t.succeed("Authenticated"),console.log(""),console.log(
|
|
1
|
+
import b from'fs';import k from'path';import Z from'dotenv';import ee from'os';import {exec}from'child_process';import L from'ora';import l from'chalk';import $ from'readline';import ue from'pg';import pe from'prettier';Z.config();async function q(a){let t=k.resolve(a);if(!b.existsSync(t))return null;try{let n=b.readFileSync(t,"utf-8"),e=JSON.parse(n);return e.database?.url&&(e.database.url=B(e.database.url)),e.api?.apiKey&&(e.api.apiKey=B(e.api.apiKey)),e}catch{throw new Error(`Failed to parse config file: ${a}`)}}function B(a){return a.replace(/\$\{([^}]+)\}/g,(t,n)=>process.env[n]||t)}var C=k.join(ee.homedir(),".vaif"),_=k.join(C,"auth.json"),R=process.env.VAIF_API_URL||"https://api.vaif.studio";function ae(){b.existsSync(C)||b.mkdirSync(C,{recursive:true});}function G(a){ae(),b.writeFileSync(_,JSON.stringify(a,null,2),"utf-8"),b.chmodSync(_,384);}function V(){if(!b.existsSync(_))return null;try{let a=b.readFileSync(_,"utf-8");return JSON.parse(a)}catch{return null}}function ne(a){let t=$.createInterface({input:process.stdin,output:process.stdout});return new Promise(n=>{t.question(a,e=>{t.close(),n(e);});})}function ie(a){return new Promise(t=>{let n=$.createInterface({input:process.stdin,output:process.stdout});process.stdin;let r=process.stdout.write.bind(process.stdout),i=false;process.stdout.write=((...c)=>i?true:r(...c)),n.question(a,c=>{i=false,process.stdout.write=r,console.log(""),n.close(),t(c);}),i=true;})}function oe(a){let t=process.platform,n;t==="darwin"?n=`open "${a}"`:t==="win32"?n=`start "" "${a}"`:n=`xdg-open "${a}"`,exec(n,e=>{});}function re(a){return new Promise(t=>setTimeout(t,a))}async function se(a){try{let t=await fetch(`${R}/auth/me`,{headers:{Authorization:`Bearer ${a}`}});if(t.ok){let n=await t.json();return {valid:!0,email:n.user?.email||n.email}}return {valid:!1}}catch{return {valid:false}}}async function le(a){let t=L();t.start("Setting up authentication...");let n,e;try{let u=await fetch(`${R}/auth/cli/authorize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({})});u.ok||(t.fail("Failed to initiate authentication"),console.log(l.red(`
|
|
2
|
+
Could not connect to VAIF API. Please try again later.`)),process.exit(1));let o=await u.json();n=o.code,e=o.url;}catch{t.fail("Failed to connect to VAIF API"),console.log(l.red(`
|
|
3
|
+
Could not connect to VAIF API.`)),console.log(l.gray("Check your internet connection or try: vaif login --email")),process.exit(1);}t.stop(),console.log(l.cyan(" Opening browser for authentication...")),console.log(""),console.log(l.gray(" If the browser doesn't open, visit this URL:")),console.log(l.white(` ${e}`)),console.log(""),oe(e),t.start("Waiting for browser authentication...");let r=12e4,i=2e3,c=Date.now();for(;Date.now()-c<r;){await re(i);try{let u=await fetch(`${R}/auth/cli/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:n})});if(!u.ok){let s=await u.json();(s.error==="ExpiredCode"||s.error==="InvalidCode")&&(t.fail("Authentication expired"),console.log(l.red(`
|
|
4
|
+
The authentication session expired. Please try again.`)),process.exit(1));continue}let o=await u.json();if(o.ok&&o.accessToken){let s={token:o.accessToken,email:o.user?.email,projectId:a,expiresAt:new Date(Date.now()+o.expiresIn*1e3).toISOString()};G(s),t.succeed("Logged in successfully"),console.log(""),o.user?.email&&console.log(l.green(` Authenticated as: ${o.user.email}`)),console.log(l.gray(` Config saved to: ${_}`)),console.log("");return}}catch{}}t.fail("Authentication timed out"),console.log(l.red(`
|
|
5
|
+
Timed out waiting for browser authentication.`)),console.log(l.gray("Try again or use: vaif login --email")),process.exit(1);}async function ce(a){console.log(""),console.log(l.bold("VAIF CLI Login")),console.log(l.gray("Enter your VAIF account credentials")),console.log("");let t=await ne(l.cyan(" Email: "));(!t||t.trim()==="")&&(console.log(l.red(`
|
|
6
|
+
No email provided. Login cancelled.`)),process.exit(1));let n=await ie(l.cyan(" Password: "));(!n||n.trim()==="")&&(console.log(l.red(`
|
|
7
|
+
No password provided. Login cancelled.`)),process.exit(1));let e=L("Authenticating...").start();try{let r=await fetch(`${R}/auth/cli/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:t.trim(),password:n})}),i=await r.json();(!r.ok||!i.ok)&&(e.fail("Login failed"),console.log(l.red(`
|
|
8
|
+
${i.message||"Invalid email or password."}`)),process.exit(1));let c={token:i.accessToken,email:i.user?.email,projectId:a,expiresAt:new Date(Date.now()+i.expiresIn*1e3).toISOString()};G(c),e.succeed("Logged in successfully"),console.log(""),i.user?.email&&console.log(l.green(` Authenticated as: ${i.user.email}`)),console.log(l.gray(` Config saved to: ${_}`)),console.log("");}catch{e.fail("Failed to connect to VAIF API"),console.log(l.red(`
|
|
9
|
+
Could not connect to VAIF API. Please try again later.`)),process.exit(1);}}async function Ue(a){console.log(""),console.log(l.bold("Welcome to VAIF CLI")),console.log(l.gray("Authenticate to access your VAIF projects")),console.log(""),a.email?await ce(a.projectId):await le(a.projectId),console.log(l.gray("You can now use VAIF CLI commands like:")),console.log(l.gray(" vaif pull - Pull remote schema")),console.log(l.gray(" vaif push - Push schema changes")),console.log(l.gray(" vaif generate - Generate TypeScript types")),console.log("");}async function De(){b.existsSync(_)?(b.unlinkSync(_),console.log(l.green("Logged out successfully"))):console.log(l.yellow("Not currently logged in"));}async function ke(){let a=V();(!a||!a.token)&&(console.log(l.yellow("Not logged in")),console.log(l.gray("Run `vaif login` to authenticate")),process.exit(1));let t=L("Checking authentication...").start(),{valid:n,email:e}=await se(a.token);n||(t.fail("Session expired"),console.log(l.yellow(`
|
|
10
|
+
Your session has expired. Please login again.`)),process.exit(1)),t.succeed("Authenticated"),console.log(""),console.log(l.green(` Email: ${e||a.email||"Unknown"}`)),a.projectId&&console.log(l.green(` Project: ${a.projectId}`)),console.log("");}var me=process.env.VAIF_API_URL||"https://api.vaif.studio";async function fe(a,t){let n=await fetch(`${me}/schema-engine/introspect/${t}`,{headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"}});if(!n.ok){let u=await n.text();throw new Error(`API introspection failed: ${u}`)}let e=await n.json();if(!e.ok||!e.schemaExists)throw new Error("Project schema does not exist yet. Push a migration first with `vaif db push`.");let r=new Map,i=[];for(let u of e.tables){let o=u.columns.map(s=>({column_name:s.name,data_type:s.type,is_nullable:s.nullable?"YES":"NO",column_default:s.default,udt_name:s.type,is_identity:s.primaryKey&&s.default?.includes("gen_random_uuid")?"YES":"NO",character_maximum_length:null,numeric_precision:null,numeric_scale:null}));r.set(u.name,o);for(let s of u.foreignKeys)i.push({constraint_name:s.constraintName,table_name:u.name,column_name:s.columnName,foreign_table_name:s.refTable,foreign_column_name:s.refColumn});}return {tables:r,enums:new Map,foreignKeys:i}}async function ge(a,t){let n=await a.query(`
|
|
11
11
|
SELECT table_name, table_type
|
|
12
12
|
FROM information_schema.tables
|
|
13
13
|
WHERE table_schema = $1
|
|
@@ -44,7 +44,7 @@ Your session has expired. Please login again.`)),process.exit(1)),t.succeed("Aut
|
|
|
44
44
|
AND ccu.table_schema = tc.table_schema
|
|
45
45
|
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
46
46
|
AND tc.table_schema = $1
|
|
47
|
-
`,[t]),
|
|
47
|
+
`,[t]),i=await a.query(`
|
|
48
48
|
SELECT
|
|
49
49
|
t.typname as enum_name,
|
|
50
50
|
e.enumlabel as enum_value
|
|
@@ -53,24 +53,24 @@ Your session has expired. Please login again.`)),process.exit(1)),t.succeed("Aut
|
|
|
53
53
|
JOIN pg_namespace n ON n.oid = t.typnamespace
|
|
54
54
|
WHERE n.nspname = $1
|
|
55
55
|
ORDER BY t.typname, e.enumsortorder
|
|
56
|
-
`,[t]),
|
|
56
|
+
`,[t]),c=new Map;for(let o of n.rows)c.set(o.table_name,[]);for(let o of e.rows){let s=c.get(o.table_name);s&&s.push(o);}let u=new Map;for(let o of i.rows){let s=u.get(o.enum_name)||[];s.push(o.enum_value),u.set(o.enum_name,s);}return {tables:c,enums:u,foreignKeys:r.rows}}var U={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 he(a,t){let{data_type:n,udt_name:e,is_nullable:r}=a;if(t.has(e)){let u=t.get(e).map(o=>`"${o}"`).join(" | ");return r==="YES"?`(${u}) | null`:u}if(n==="ARRAY"){let c=e.replace(/^_/,"");if(t.has(c)){let s=t.get(c).map(f=>`"${f}"`).join(" | ");return r==="YES"?`(${s})[] | null`:`(${s})[]`}let u=U[c]||"unknown";return r==="YES"?`${u}[] | null`:`${u}[]`}let i=U[n]||U[e]||"unknown";return r==="YES"&&(i=`${i} | null`),i}function D(a){return a.split(/[_\-\s]+/).map(t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}function ve(a,t){let n=D(a),e=t.map(r=>` | "${r}"`).join(`
|
|
57
57
|
`);return `export type ${n} =
|
|
58
|
-
${e};`}function
|
|
58
|
+
${e};`}function ye(a,t,n){let e=D(a),r=[],i=[],c=[];for(let f of t){let h=he(f,n),d=f.column_name,m=f.column_default!==null||f.is_identity==="YES",I=f.is_nullable==="YES";r.push(` ${d}: ${h};`),m||f.column_name==="id"?i.push(` ${d}?: ${h.replace(" | null","")} | null;`):I?i.push(` ${d}?: ${h};`):i.push(` ${d}: ${h.replace(" | null","")};`),c.push(` ${d}?: ${h.replace(" | null","")} | null;`);}let u=`export interface ${e} {
|
|
59
59
|
${r.join(`
|
|
60
60
|
`)}
|
|
61
|
-
}`,
|
|
62
|
-
${
|
|
61
|
+
}`,o=`export interface ${e}Insert {
|
|
62
|
+
${i.join(`
|
|
63
63
|
`)}
|
|
64
|
-
}`,
|
|
65
|
-
${
|
|
64
|
+
}`,s=`export interface ${e}Update {
|
|
65
|
+
${c.join(`
|
|
66
66
|
`)}
|
|
67
|
-
}`;return {base:u,insert:
|
|
68
|
-
`)}async function
|
|
69
|
-
Either:`)),console.log(
|
|
70
|
-
Set projectId in vaif.config.json or use VAIF_PROJECT_ID env var.`)),process.exit(1)),t.text="Introspecting schema via API...",{tables:
|
|
71
|
-
Push a migration first: vaif db push`));return}t.text=`Generating types for ${
|
|
72
|
-
Error: ${n.message}`)),n.message.includes("ECONNREFUSED")&&console.log(
|
|
73
|
-
Make sure your database is running and accessible.`))),process.exit(1);}}var
|
|
67
|
+
}`;return {base:u,insert:o,update:s}}function be(a,t,n){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(t.size>0){e.push("// ============ ENUMS ============"),e.push("");for(let[i,c]of t)e.push(ve(i,c)),e.push("");}e.push("// ============ TABLES ============"),e.push("");let r=[];for(let[i,c]of a){let{base:u,insert:o,update:s}=ye(i,c,t);r.push(i),e.push(u),e.push(""),e.push(o),e.push(""),e.push(s),e.push("");}e.push("// ============ DATABASE SCHEMA ============"),e.push(""),e.push("export interface Database {");for(let i of r){let c=D(i);e.push(` ${i}: {`),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(`
|
|
68
|
+
`)}async function He(a){let t=L("Loading configuration...").start();try{let n=await q(a.config),e=a.connection||n?.database?.url||process.env.DATABASE_URL,r=e&&!e.includes("${"),i,c,u;if(r){t.text="Connecting to database...";let d=new ue.Client({connectionString:e});await d.connect(),t.text="Introspecting schema...",{tables:i,enums:c,foreignKeys:u}=await ge(d,a.schema),await d.end();}else {let d=V();(!d||!d.token)&&(t.fail("No database connection and not logged in"),console.log(l.yellow(`
|
|
69
|
+
Either:`)),console.log(l.gray(" 1. Run `vaif login` to authenticate (no DATABASE_URL needed)")),console.log(l.gray(" 2. Set DATABASE_URL in your .env file")),console.log(l.gray(" 3. Pass --connection postgresql://user:pass@host:5432/db")),process.exit(1));let m=n?.projectId||process.env.VAIF_PROJECT_ID||d.projectId;m||(t.fail("No project ID specified"),console.log(l.yellow(`
|
|
70
|
+
Set projectId in vaif.config.json or use VAIF_PROJECT_ID env var.`)),process.exit(1)),t.text="Introspecting schema via API...",{tables:i,enums:c,foreignKeys:u}=await fe(d.token,m);}if(i.size===0){t.warn("No tables found"),console.log(l.yellow(`
|
|
71
|
+
Push a migration first: vaif db push`));return}t.text=`Generating types for ${i.size} tables...`;let o=be(i,c,u),s=await pe.format(o,{parser:"typescript",semi:!0,singleQuote:!1,trailingComma:"es5",printWidth:100});if(a.dryRun){t.succeed("Generated types (dry run):"),console.log(""),console.log(l.gray("\u2500".repeat(60))),console.log(s),console.log(l.gray("\u2500".repeat(60)));return}let f=k.resolve(a.output),h=k.dirname(f);b.existsSync(h)||b.mkdirSync(h,{recursive:!0}),b.writeFileSync(f,s,"utf-8"),t.succeed(`Generated types for ${i.size} tables \u2192 ${l.cyan(a.output)}`),console.log(""),console.log(l.green("Generated:")),console.log(l.gray(` Tables: ${i.size}`)),console.log(l.gray(` Enums: ${c.size}`)),console.log(""),console.log(l.gray("Import in your code:")),console.log(l.cyan(` import type { Database, Row, Insert, Update } from "${a.output.replace(/\.ts$/,"")}";`));}catch(n){t.fail("Failed to generate types"),n instanceof Error&&(console.error(l.red(`
|
|
72
|
+
Error: ${n.message}`)),n.message.includes("ECONNREFUSED")&&console.log(l.yellow(`
|
|
73
|
+
Make sure your database is running and accessible.`))),process.exit(1);}}var T=[{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:`{
|
|
74
74
|
"name": "my-vaif-app",
|
|
75
75
|
"private": true,
|
|
76
76
|
"version": "0.1.0",
|
|
@@ -167,6 +167,7 @@ body {
|
|
|
167
167
|
// Browser client \u2013 safe to use in Client Components
|
|
168
168
|
export const vaif = createVaifClient({
|
|
169
169
|
baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
|
|
170
|
+
projectId: process.env.NEXT_PUBLIC_VAIF_PROJECT_ID,
|
|
170
171
|
apiKey: process.env.NEXT_PUBLIC_VAIF_API_KEY!,
|
|
171
172
|
});
|
|
172
173
|
|
|
@@ -174,6 +175,7 @@ export const vaif = createVaifClient({
|
|
|
174
175
|
export function createVaifServer() {
|
|
175
176
|
return createVaifClient({
|
|
176
177
|
baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
|
|
178
|
+
projectId: process.env.VAIF_PROJECT_ID,
|
|
177
179
|
apiKey: process.env.VAIF_SECRET_KEY!,
|
|
178
180
|
});
|
|
179
181
|
}
|
|
@@ -181,6 +183,7 @@ export function createVaifServer() {
|
|
|
181
183
|
# Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
|
|
182
184
|
|
|
183
185
|
NEXT_PUBLIC_VAIF_API_URL=https://api.vaif.studio
|
|
186
|
+
NEXT_PUBLIC_VAIF_PROJECT_ID=your-project-id
|
|
184
187
|
NEXT_PUBLIC_VAIF_API_KEY=your-api-key
|
|
185
188
|
VAIF_SECRET_KEY=your-secret-key
|
|
186
189
|
|
|
@@ -314,6 +317,7 @@ export async function middleware(request: NextRequest) {
|
|
|
314
317
|
|
|
315
318
|
const vaif = createVaifClient({
|
|
316
319
|
baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
|
|
320
|
+
projectId: process.env.VAIF_PROJECT_ID,
|
|
317
321
|
apiKey: process.env.VAIF_SECRET_KEY!,
|
|
318
322
|
});
|
|
319
323
|
|
|
@@ -676,12 +680,14 @@ function Home() {
|
|
|
676
680
|
|
|
677
681
|
export const vaif = createVaifClient({
|
|
678
682
|
baseUrl: import.meta.env.VITE_VAIF_API_URL || 'https://api.vaif.studio',
|
|
683
|
+
projectId: import.meta.env.VITE_VAIF_PROJECT_ID,
|
|
679
684
|
apiKey: import.meta.env.VITE_VAIF_API_KEY,
|
|
680
685
|
});
|
|
681
686
|
`},{path:"src/vite-env.d.ts",content:`/// <reference types="vite/client" />
|
|
682
687
|
|
|
683
688
|
interface ImportMetaEnv {
|
|
684
689
|
readonly VITE_VAIF_API_URL: string;
|
|
690
|
+
readonly VITE_VAIF_PROJECT_ID: string;
|
|
685
691
|
readonly VITE_VAIF_API_KEY: string;
|
|
686
692
|
}
|
|
687
693
|
|
|
@@ -692,6 +698,7 @@ interface ImportMeta {
|
|
|
692
698
|
# Get these values from https://vaif.studio/app/security/api-keys
|
|
693
699
|
|
|
694
700
|
VITE_VAIF_API_URL=https://api.vaif.studio
|
|
701
|
+
VITE_VAIF_PROJECT_ID=your-project-id
|
|
695
702
|
VITE_VAIF_API_KEY=your-api-key
|
|
696
703
|
`},{path:".gitignore",content:`node_modules
|
|
697
704
|
dist
|
|
@@ -2692,6 +2699,7 @@ func HelloHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
2692
2699
|
|
|
2693
2700
|
export const vaif = createVaifClient({
|
|
2694
2701
|
baseUrl: import.meta.env.VITE_VAIF_API_URL || 'https://api.vaif.studio',
|
|
2702
|
+
projectId: import.meta.env.VITE_VAIF_PROJECT_ID,
|
|
2695
2703
|
apiKey: import.meta.env.VITE_VAIF_API_KEY,
|
|
2696
2704
|
});
|
|
2697
2705
|
|
|
@@ -2746,6 +2754,7 @@ export async function deleteTodo(id: string): Promise<void> {
|
|
|
2746
2754
|
# Get these values from https://vaif.studio/app/security/api-keys
|
|
2747
2755
|
|
|
2748
2756
|
VITE_VAIF_API_URL=https://api.vaif.studio
|
|
2757
|
+
VITE_VAIF_PROJECT_ID=your-project-id
|
|
2749
2758
|
VITE_VAIF_API_KEY=your-api-key
|
|
2750
2759
|
`},{path:"README.md",content:`# Todo App \u2014 VAIF Starter
|
|
2751
2760
|
|
|
@@ -2883,6 +2892,7 @@ export const posts = pgTable("posts", {
|
|
|
2883
2892
|
|
|
2884
2893
|
export const vaif = createVaifClient({
|
|
2885
2894
|
baseUrl: import.meta.env.VITE_VAIF_API_URL || 'https://api.vaif.studio',
|
|
2895
|
+
projectId: import.meta.env.VITE_VAIF_PROJECT_ID,
|
|
2886
2896
|
apiKey: import.meta.env.VITE_VAIF_API_KEY,
|
|
2887
2897
|
});
|
|
2888
2898
|
|
|
@@ -3024,6 +3034,7 @@ export function useRealtimeMessages({
|
|
|
3024
3034
|
# Get these values from https://vaif.studio/app/security/api-keys
|
|
3025
3035
|
|
|
3026
3036
|
VITE_VAIF_API_URL=https://api.vaif.studio
|
|
3037
|
+
VITE_VAIF_PROJECT_ID=your-project-id
|
|
3027
3038
|
VITE_VAIF_API_KEY=your-api-key
|
|
3028
3039
|
`},{path:"README.md",content:`# Realtime Chat \u2014 VAIF Starter
|
|
3029
3040
|
|
|
@@ -3176,6 +3187,7 @@ export const posts = pgTable("posts", {
|
|
|
3176
3187
|
// Browser client \u2013 use in Client Components
|
|
3177
3188
|
export const vaif = createVaifClient({
|
|
3178
3189
|
baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
|
|
3190
|
+
projectId: process.env.NEXT_PUBLIC_VAIF_PROJECT_ID,
|
|
3179
3191
|
apiKey: process.env.NEXT_PUBLIC_VAIF_API_KEY!,
|
|
3180
3192
|
});
|
|
3181
3193
|
|
|
@@ -3183,6 +3195,7 @@ export const vaif = createVaifClient({
|
|
|
3183
3195
|
export function createVaifServer() {
|
|
3184
3196
|
return createVaifClient({
|
|
3185
3197
|
baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
|
|
3198
|
+
projectId: process.env.VAIF_PROJECT_ID,
|
|
3186
3199
|
apiKey: process.env.VAIF_SECRET_KEY!,
|
|
3187
3200
|
});
|
|
3188
3201
|
}
|
|
@@ -3337,6 +3350,7 @@ export async function requireTeamRole(
|
|
|
3337
3350
|
# Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
|
|
3338
3351
|
|
|
3339
3352
|
NEXT_PUBLIC_VAIF_API_URL=https://api.vaif.studio
|
|
3353
|
+
NEXT_PUBLIC_VAIF_PROJECT_ID=your-project-id
|
|
3340
3354
|
NEXT_PUBLIC_VAIF_API_KEY=your-api-key
|
|
3341
3355
|
VAIF_SECRET_KEY=your-secret-key
|
|
3342
3356
|
|
|
@@ -3489,6 +3503,7 @@ export const posts = pgTable("posts", {
|
|
|
3489
3503
|
// Browser client
|
|
3490
3504
|
export const vaif = createVaifClient({
|
|
3491
3505
|
baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
|
|
3506
|
+
projectId: process.env.NEXT_PUBLIC_VAIF_PROJECT_ID,
|
|
3492
3507
|
apiKey: process.env.NEXT_PUBLIC_VAIF_API_KEY!,
|
|
3493
3508
|
});
|
|
3494
3509
|
|
|
@@ -3496,6 +3511,7 @@ export const vaif = createVaifClient({
|
|
|
3496
3511
|
export function createVaifServer() {
|
|
3497
3512
|
return createVaifClient({
|
|
3498
3513
|
baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
|
|
3514
|
+
projectId: process.env.VAIF_PROJECT_ID,
|
|
3499
3515
|
apiKey: process.env.VAIF_SECRET_KEY!,
|
|
3500
3516
|
});
|
|
3501
3517
|
}
|
|
@@ -3612,6 +3628,7 @@ function getContentType(fileName: string): string {
|
|
|
3612
3628
|
# Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
|
|
3613
3629
|
|
|
3614
3630
|
NEXT_PUBLIC_VAIF_API_URL=https://api.vaif.studio
|
|
3631
|
+
NEXT_PUBLIC_VAIF_PROJECT_ID=your-project-id
|
|
3615
3632
|
NEXT_PUBLIC_VAIF_API_KEY=your-api-key
|
|
3616
3633
|
VAIF_SECRET_KEY=your-secret-key
|
|
3617
3634
|
|
|
@@ -3757,16 +3774,16 @@ export const posts = pgTable("posts", {
|
|
|
3757
3774
|
|
|
3758
3775
|
return Response.json({ message: \`Hello, \${name}!\` });
|
|
3759
3776
|
}
|
|
3760
|
-
`}]},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"]}};function
|
|
3761
|
-
? Which VAIF features do you want to include?`)),
|
|
3762
|
-
Unknown template: ${a}`)),console.log(
|
|
3763
|
-
`)),process.exit(1));let e;t.features&&t.features.length>0?e=t.features.filter(
|
|
3764
|
-
No features specified.`)),console.log(
|
|
3765
|
-
`,"utf-8"),console.log(
|
|
3766
|
-
`,"utf-8");}catch{}(n.dependencies?.length||n.devDependencies?.length)&&(console.log(""),console.log(
|
|
3767
|
-
--add-features requires --template to know which template to use.`)),console.log(
|
|
3768
|
-
Use --force to overwrite existing configuration.`)),process.exit(1));try{if(
|
|
3777
|
+
`}]},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"]}};function tt(){console.log(""),console.log(l.bold("Available project templates")),console.log("");let a=26,t=22;console.log(` ${l.gray("Template".padEnd(a))}${l.gray("Stack".padEnd(t))}${l.gray("Description")}`),console.log(l.gray(" "+"-".repeat(a+t+40)));for(let[n,e]of Object.entries(W))console.log(` ${l.cyan(n.padEnd(a))}${l.yellow(e.tag.padEnd(t))}${l.white(e.description)}`);console.log(""),console.log(l.gray("Usage:")),console.log(l.gray(" npx @vaiftech/cli init --template <name>")),console.log(l.gray(" npx @vaiftech/cli init -t nextjs-fullstack")),console.log(l.gray(" npx @vaiftech/cli init -t react-spa --features auth,database,realtime")),console.log(""),console.log(l.gray("Available features: auth, database, realtime, storage, functions")),console.log("");}async function Ie(a){if(!process.stdin.isTTY||!process.stdout.isTTY)return a;let t=new Set(a.map(e=>T.findIndex(r=>r.name===e)).filter(e=>e>=0)),n=0;return new Promise(e=>{let r=$.createInterface({input:process.stdin,output:process.stdout});$.emitKeypressEvents(process.stdin,r),process.stdin.setRawMode&&process.stdin.setRawMode(true);function i(){let u=T.length+2;process.stdout.write(`\x1B[${u}A`),c();}function c(){console.log(l.bold(`
|
|
3778
|
+
? Which VAIF features do you want to include?`)),T.forEach((u,o)=>{let s=t.has(o)?l.green("[x]"):"[ ]",f=o===n?l.cyan("> "):" ";console.log(`${f}${s} ${u.label} ${l.gray(`(${u.description})`)}`);}),console.log(l.gray(" (up/down to move, space to toggle, enter to confirm)"));}c(),process.stdin.on("keypress",(u,o)=>{if(o.name==="up"&&n>0)n--,i();else if(o.name==="down"&&n<T.length-1)n++,i();else if(o.name==="space")t.has(n)?t.delete(n):t.add(n),i();else if(o.name==="return"){process.stdin.setRawMode&&process.stdin.setRawMode(false),r.close();let s=[...t].sort().map(f=>T[f].name);e(s.length>0?s:a);}else o.name==="c"&&o.ctrl&&(process.stdin.setRawMode&&process.stdin.setRawMode(false),r.close(),process.exit(0));});})}async function j(a,t={}){let n=W[a];n||(console.log(l.red(`
|
|
3779
|
+
Unknown template: ${a}`)),console.log(l.yellow(`Run 'vaif templates' to see available templates.
|
|
3780
|
+
`)),process.exit(1));let e;t.features&&t.features.length>0?e=t.features.filter(d=>T.some(m=>m.name===d)):t.addOnly?(console.log(l.red(`
|
|
3781
|
+
No features specified.`)),console.log(l.yellow("Usage: vaif init --template <name> --add-features <features>")),console.log(l.gray("Available features: auth, database, realtime, storage, functions")),process.exit(1)):n.featureFiles&&Object.keys(n.featureFiles).length>0?e=await Ie(n.defaultFeatures??["database","auth"]):e=n.defaultFeatures??[],t.addOnly?(console.log(""),console.log(l.bold(`Adding features to ${l.cyan(n.name)} project...`)),console.log(l.gray(` Features: ${e.join(", ")}`)),console.log("")):(console.log(""),console.log(l.bold(`Scaffolding ${l.cyan(n.name)} template...`)),e.length>0&&console.log(l.gray(` Features: ${e.join(", ")}`)),console.log(""));let r=t.addOnly?[]:[...n.files],i=new Set,c=[];if(n.featureFiles)for(let d of e){let m=n.featureFiles[d];if(m)for(let I of m)i.add(I.path),c.push(I);}let u=r.filter(d=>!i.has(d.path)).concat(c),o=0,s=0;for(let d of u){let m=k.resolve(d.path),I=k.dirname(m);if(b.existsSync(I)||b.mkdirSync(I,{recursive:true}),d.path==="package.json"&&b.existsSync(m)&&!t.force)try{let y=JSON.parse(b.readFileSync(m,"utf-8")),E=JSON.parse(d.content),S=M=>{if(!M)return {};let K={};for(let[X,w]of Object.entries(M))!w.startsWith("workspace:")&&!w.startsWith("link:")&&!w.startsWith("file:")&&(K[X]=w);return K};y.dependencies={...S(y.dependencies),...E.dependencies||{}},y.devDependencies={...S(y.devDependencies),...E.devDependencies||{}},E.scripts&&(y.scripts={...y.scripts||{},...E.scripts}),b.writeFileSync(m,JSON.stringify(y,null,2)+`
|
|
3782
|
+
`,"utf-8"),console.log(l.green(` merge ${d.path} (added dependencies)`)),o++;continue}catch{}if(b.existsSync(m)&&!t.force){console.log(l.yellow(` skip ${d.path} (already exists)`)),s++;continue}b.writeFileSync(m,d.content,"utf-8"),console.log(l.green(` create ${d.path}`)),o++;}console.log(""),o>0&&console.log(l.green(`Created ${o} file${o!==1?"s":""}.`)),s>0&&console.log(l.yellow(`Skipped ${s} file${s!==1?"s":""} (use --force to overwrite).`));let f={auth:{"@vaiftech/auth":"^1.0.0"},database:{},realtime:{},storage:{},functions:{}},h=k.resolve("package.json");if(b.existsSync(h)&&e.length>0)try{let d=JSON.parse(b.readFileSync(h,"utf-8")),m=!1;for(let I of e){let y=f[I];if(y)for(let[E,S]of Object.entries(y))d.dependencies?.[E]||(d.dependencies=d.dependencies||{},d.dependencies[E]=S,m=!0);}m&&b.writeFileSync(h,JSON.stringify(d,null,2)+`
|
|
3783
|
+
`,"utf-8");}catch{}(n.dependencies?.length||n.devDependencies?.length)&&(console.log(""),console.log(l.bold("Install dependencies:")),n.dependencies?.length&&console.log(l.cyan(` npm install ${n.dependencies.join(" ")}`)),n.devDependencies?.length&&console.log(l.cyan(` npm install -D ${n.devDependencies.join(" ")}`))),console.log(""),console.log(l.bold.green("Project scaffolded successfully!")),console.log(""),console.log(l.bold(" Next steps:")),n.postInstructions.forEach(d=>{console.log(l.gray(` ${d}`));}),console.log(""),console.log(l.gray(" Get your project credentials at https://vaif.studio/app/security/api-keys")),console.log("");}var _e={$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 ct(a){if(a.addFeatures){a.template||(console.log(l.red(`
|
|
3784
|
+
--add-features requires --template to know which template to use.`)),console.log(l.gray("Example: vaif init --template react-spa --add-features functions,storage")),process.exit(1));let e=a.addFeatures.split(",").map(r=>r.trim());await j(a.template,{force:a.force,features:e,addOnly:true});return}let t=L("Initializing VAIF configuration...").start(),n=k.resolve("vaif.config.json");b.existsSync(n)&&!a.force&&(t.fail("vaif.config.json already exists"),console.log(l.yellow(`
|
|
3785
|
+
Use --force to overwrite existing configuration.`)),process.exit(1));try{if(b.writeFileSync(n,JSON.stringify(_e,null,2),"utf-8"),t.succeed("Created vaif.config.json"),a.template){let e=a.features?a.features.split(",").map(r=>r.trim()):void 0;await j(a.template,{force:a.force,features:e});}else {let e=k.resolve(".env.example");if(b.existsSync(e)||(b.writeFileSync(e,`# VAIF Configuration
|
|
3769
3786
|
DATABASE_URL=postgresql://user:password@localhost:5432/database
|
|
3770
3787
|
VAIF_API_KEY=your-api-key
|
|
3771
|
-
`,"utf-8"),console.log(
|
|
3772
|
-
Error: ${e.message}`)),process.exit(1);}}export{
|
|
3788
|
+
`,"utf-8"),console.log(l.gray("Created .env.example"))),a.typescript){let r=k.resolve("src/types");b.existsSync(r)||(b.mkdirSync(r,{recursive:!0}),console.log(l.gray("Created src/types directory")));}console.log(""),console.log(l.green("VAIF initialized successfully!")),console.log(""),console.log(l.gray("Next steps:")),console.log(l.gray(" 1. Update vaif.config.json with your project ID")),console.log(l.gray(" 2. Set DATABASE_URL in your environment")),console.log(l.gray(" 3. Run: npx vaif generate")),console.log("");}}catch(e){t.fail("Failed to initialize"),e instanceof Error&&console.error(l.red(`
|
|
3789
|
+
Error: ${e.message}`)),process.exit(1);}}export{q as a,V as b,Ue as c,De as d,ke as e,He as f,tt as g,ct as h};
|