@vaiftech/cli 1.6.6 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{chunk-OB2QEQ2L.js → chunk-N7OY2COL.js} +65 -63
- package/dist/cli.cjs +100 -98
- package/dist/cli.js +30 -30
- package/dist/index.cjs +58 -56
- 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.
|
|
6
|
+
Command-line tools for [VAIF Studio](https://vaif.studio) (v1.7.1) — 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
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import h from'fs';import w from'path';import M from'dotenv';import K from'pg';import z from'ora';import
|
|
1
|
+
import h from'fs';import w from'path';import M from'dotenv';import K from'pg';import z from'ora';import n from'chalk';import q from'prettier';import D from'readline';M.config();async function N(a){let t=w.resolve(a);if(!h.existsSync(t))return null;try{let i=h.readFileSync(t,"utf-8"),e=JSON.parse(i);return e.database?.url&&(e.database.url=L(e.database.url)),e.api?.apiKey&&(e.api.apiKey=L(e.api.apiKey)),e}catch{throw new Error(`Failed to parse config file: ${a}`)}}function L(a){return a.replace(/\$\{([^}]+)\}/g,(t,i)=>process.env[i]||t)}async function B(a,t){let i=await a.query(`
|
|
2
2
|
SELECT table_name, table_type
|
|
3
3
|
FROM information_schema.tables
|
|
4
4
|
WHERE table_schema = $1
|
|
@@ -44,9 +44,9 @@ import h from'fs';import w from'path';import M from'dotenv';import K from'pg';im
|
|
|
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
|
-
`,[t]),c=new Map;for(let l of
|
|
48
|
-
`);return `export type ${
|
|
49
|
-
${e};`}function G(a,t,
|
|
47
|
+
`,[t]),c=new Map;for(let l of i.rows)c.set(l.table_name,[]);for(let l of e.rows){let r=c.get(l.table_name);r&&r.push(l);}let d=new Map;for(let l of o.rows){let r=d.get(l.enum_name)||[];r.push(l.enum_value),d.set(l.enum_name,r);}return {tables:c,enums:d,foreignKeys:s.rows}}var T={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 Y(a,t){let{data_type:i,udt_name:e,is_nullable:s}=a;if(t.has(e)){let d=t.get(e).map(l=>`"${l}"`).join(" | ");return s==="YES"?`(${d}) | null`:d}if(i==="ARRAY"){let c=e.replace(/^_/,"");if(t.has(c)){let r=t.get(c).map(u=>`"${u}"`).join(" | ");return s==="YES"?`(${r})[] | null`:`(${r})[]`}let d=T[c]||"unknown";return s==="YES"?`${d}[] | null`:`${d}[]`}let o=T[i]||T[e]||"unknown";return s==="YES"&&(o=`${o} | null`),o}function x(a){return a.split(/[_\-\s]+/).map(t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}function $(a,t){let i=x(a),e=t.map(s=>` | "${s}"`).join(`
|
|
48
|
+
`);return `export type ${i} =
|
|
49
|
+
${e};`}function G(a,t,i){let e=x(a),s=[],o=[],c=[];for(let u of t){let f=Y(u,i),p=u.column_name,v=u.column_default!==null||u.is_identity==="YES",y=u.is_nullable==="YES";s.push(` ${p}: ${f};`),v||u.column_name==="id"?o.push(` ${p}?: ${f.replace(" | null","")} | null;`):y?o.push(` ${p}?: ${f};`):o.push(` ${p}: ${f.replace(" | null","")};`),c.push(` ${p}?: ${f.replace(" | null","")} | null;`);}let d=`export interface ${e} {
|
|
50
50
|
${s.join(`
|
|
51
51
|
`)}
|
|
52
52
|
}`,l=`export interface ${e}Insert {
|
|
@@ -55,11 +55,11 @@ ${o.join(`
|
|
|
55
55
|
}`,r=`export interface ${e}Update {
|
|
56
56
|
${c.join(`
|
|
57
57
|
`)}
|
|
58
|
-
}`;return {base:
|
|
59
|
-
`)}async function
|
|
60
|
-
Provide a connection string via:`)),console.log(
|
|
61
|
-
Error: ${
|
|
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"}],
|
|
58
|
+
}`;return {base:d,insert:l,update:r}}function H(a,t,i){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[o,c]of t)e.push($(o,c)),e.push("");}e.push("// ============ TABLES ============"),e.push("");let s=[];for(let[o,c]of a){let{base:d,insert:l,update:r}=G(o,c,t);s.push(o),e.push(d),e.push(""),e.push(l),e.push(""),e.push(r),e.push("");}e.push("// ============ DATABASE SCHEMA ============"),e.push(""),e.push("export interface Database {");for(let o of s){let c=x(o);e.push(` ${o}: {`),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 ue(a){let t=z("Loading configuration...").start();try{let i=await N(a.config),e=a.connection||i?.database?.url||process.env.DATABASE_URL;(!e||e.includes("${"))&&(t.fail("No database connection string provided"),console.log(n.yellow(`
|
|
60
|
+
Provide a connection string via:`)),console.log(n.gray(" --connection postgresql://user:pass@host:5432/db")),console.log(n.gray(" DATABASE_URL environment variable in .env")),console.log(n.gray(" database.url in vaif.config.json")),e?.includes("${")&&(console.log(n.yellow("\nYour vaif.config.json references ${DATABASE_URL} but the env var is not set.")),console.log(n.gray(" Add DATABASE_URL to your .env file or pass --connection directly."))),process.exit(1)),t.text="Connecting to database...";let s=new K.Client({connectionString:e});await s.connect(),t.text="Introspecting schema...";let{tables:o,enums:c,foreignKeys:d}=await B(s,a.schema);if(await s.end(),o.size===0){t.warn(`No tables found in schema "${a.schema}"`);return}t.text=`Generating types for ${o.size} tables...`;let l=H(o,c,d),r=await q.format(l,{parser:"typescript",semi:!0,singleQuote:!1,trailingComma:"es5",printWidth:100});if(a.dryRun){t.succeed("Generated types (dry run):"),console.log(""),console.log(n.gray("\u2500".repeat(60))),console.log(r),console.log(n.gray("\u2500".repeat(60)));return}let u=w.resolve(a.output),f=w.dirname(u);h.existsSync(f)||h.mkdirSync(f,{recursive:!0}),h.writeFileSync(u,r,"utf-8"),t.succeed(`Generated types for ${o.size} tables \u2192 ${n.cyan(a.output)}`),console.log(""),console.log(n.green("Generated:")),console.log(n.gray(` Tables: ${o.size}`)),console.log(n.gray(` Enums: ${c.size}`)),console.log(""),console.log(n.gray("Import in your code:")),console.log(n.cyan(` import type { Database, Row, Insert, Update } from "${a.output.replace(/\.ts$/,"")}";`));}catch(i){t.fail("Failed to generate types"),i instanceof Error&&(console.error(n.red(`
|
|
61
|
+
Error: ${i.message}`)),i.message.includes("ECONNREFUSED")&&console.log(n.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"}],k={"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
63
|
"name": "my-vaif-app",
|
|
64
64
|
"private": true,
|
|
65
65
|
"version": "0.1.0",
|
|
@@ -155,24 +155,27 @@ body {
|
|
|
155
155
|
|
|
156
156
|
// Browser client \u2013 safe to use in Client Components
|
|
157
157
|
export const vaif = createVaifClient({
|
|
158
|
-
|
|
158
|
+
baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
|
|
159
159
|
apiKey: process.env.NEXT_PUBLIC_VAIF_API_KEY!,
|
|
160
160
|
});
|
|
161
161
|
|
|
162
162
|
// Server client \u2013 use in Server Components, Route Handlers, Server Actions
|
|
163
163
|
export function createVaifServer() {
|
|
164
164
|
return createVaifClient({
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
|
|
166
|
+
apiKey: process.env.VAIF_SECRET_KEY!,
|
|
167
167
|
});
|
|
168
168
|
}
|
|
169
169
|
`},{path:".env.local.example",content:`# VAIF Configuration
|
|
170
170
|
# Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
|
|
171
171
|
|
|
172
|
-
|
|
173
|
-
NEXT_PUBLIC_VAIF_API_KEY=your-
|
|
172
|
+
NEXT_PUBLIC_VAIF_API_URL=https://api.vaif.studio
|
|
173
|
+
NEXT_PUBLIC_VAIF_API_KEY=your-api-key
|
|
174
174
|
VAIF_SECRET_KEY=your-secret-key
|
|
175
175
|
|
|
176
|
+
# Database connection (for vaif generate, vaif db push)
|
|
177
|
+
# DATABASE_URL=postgresql://user:password@host:5432/dbname
|
|
178
|
+
|
|
176
179
|
# CLI uses these (non-prefixed) for vaif db push, vaif secrets, etc.
|
|
177
180
|
VAIF_PROJECT_ID=your-project-id
|
|
178
181
|
`},{path:".gitignore",content:`node_modules
|
|
@@ -288,8 +291,8 @@ export async function middleware(request: NextRequest) {
|
|
|
288
291
|
if (!isProtected) return NextResponse.next();
|
|
289
292
|
|
|
290
293
|
const vaif = createVaifClient({
|
|
291
|
-
|
|
292
|
-
|
|
294
|
+
baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
|
|
295
|
+
apiKey: process.env.VAIF_SECRET_KEY!,
|
|
293
296
|
});
|
|
294
297
|
|
|
295
298
|
return authMiddleware(vaif, request, {
|
|
@@ -650,13 +653,13 @@ function Home() {
|
|
|
650
653
|
`},{path:"src/lib/vaif.ts",content:`import { createVaifClient } from "@vaiftech/client";
|
|
651
654
|
|
|
652
655
|
export const vaif = createVaifClient({
|
|
653
|
-
|
|
656
|
+
baseUrl: import.meta.env.VITE_VAIF_API_URL || 'https://api.vaif.studio',
|
|
654
657
|
apiKey: import.meta.env.VITE_VAIF_API_KEY,
|
|
655
658
|
});
|
|
656
659
|
`},{path:"src/vite-env.d.ts",content:`/// <reference types="vite/client" />
|
|
657
660
|
|
|
658
661
|
interface ImportMetaEnv {
|
|
659
|
-
readonly
|
|
662
|
+
readonly VITE_VAIF_API_URL: string;
|
|
660
663
|
readonly VITE_VAIF_API_KEY: string;
|
|
661
664
|
}
|
|
662
665
|
|
|
@@ -664,13 +667,13 @@ interface ImportMeta {
|
|
|
664
667
|
readonly env: ImportMetaEnv;
|
|
665
668
|
}
|
|
666
669
|
`},{path:".env.example",content:`# VAIF Configuration
|
|
667
|
-
# Get these values from https://vaif.studio/app/security/api-keys
|
|
670
|
+
# Get these values from https://vaif.studio/app/security/api-keys
|
|
668
671
|
|
|
669
|
-
|
|
670
|
-
VITE_VAIF_API_KEY=your-
|
|
672
|
+
VITE_VAIF_API_URL=https://api.vaif.studio
|
|
673
|
+
VITE_VAIF_API_KEY=your-api-key
|
|
671
674
|
|
|
672
|
-
#
|
|
673
|
-
|
|
675
|
+
# Database connection (for vaif generate, vaif db push)
|
|
676
|
+
# DATABASE_URL=postgresql://user:password@host:5432/dbname
|
|
674
677
|
`},{path:".gitignore",content:`node_modules
|
|
675
678
|
dist
|
|
676
679
|
.env
|
|
@@ -2609,7 +2612,7 @@ func HelloHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
2609
2612
|
`}]},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
2613
|
|
|
2611
2614
|
export const vaif = createVaifClient({
|
|
2612
|
-
|
|
2615
|
+
baseUrl: import.meta.env.VITE_VAIF_API_URL || 'https://api.vaif.studio',
|
|
2613
2616
|
apiKey: import.meta.env.VITE_VAIF_API_KEY,
|
|
2614
2617
|
});
|
|
2615
2618
|
|
|
@@ -2661,13 +2664,13 @@ export async function deleteTodo(id: string): Promise<void> {
|
|
|
2661
2664
|
if (error) throw error;
|
|
2662
2665
|
}
|
|
2663
2666
|
`},{path:".env.example",content:`# VAIF Configuration
|
|
2664
|
-
# Get these values from https://vaif.studio/app/security/api-keys
|
|
2667
|
+
# Get these values from https://vaif.studio/app/security/api-keys
|
|
2665
2668
|
|
|
2666
|
-
|
|
2667
|
-
VITE_VAIF_API_KEY=your-
|
|
2669
|
+
VITE_VAIF_API_URL=https://api.vaif.studio
|
|
2670
|
+
VITE_VAIF_API_KEY=your-api-key
|
|
2668
2671
|
|
|
2669
|
-
#
|
|
2670
|
-
|
|
2672
|
+
# Database connection (for vaif generate, vaif db push)
|
|
2673
|
+
# DATABASE_URL=postgresql://user:password@host:5432/dbname
|
|
2671
2674
|
`},{path:"README.md",content:`# Todo App \u2014 VAIF Starter
|
|
2672
2675
|
|
|
2673
2676
|
A simple React todo application for learning [VAIF Studio](https://vaif.studio) basics, including typed database queries and CRUD operations.
|
|
@@ -2803,15 +2806,8 @@ export const posts = pgTable("posts", {
|
|
|
2803
2806
|
`}]},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
2807
|
|
|
2805
2808
|
export const vaif = createVaifClient({
|
|
2806
|
-
|
|
2809
|
+
baseUrl: import.meta.env.VITE_VAIF_API_URL || 'https://api.vaif.studio',
|
|
2807
2810
|
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
2811
|
});
|
|
2816
2812
|
|
|
2817
2813
|
export interface Message {
|
|
@@ -2949,13 +2945,13 @@ export function useRealtimeMessages({
|
|
|
2949
2945
|
return { messages, isLoading, error, refresh };
|
|
2950
2946
|
}
|
|
2951
2947
|
`},{path:".env.example",content:`# VAIF Configuration
|
|
2952
|
-
# Get these values from https://vaif.studio/app/security/api-keys
|
|
2948
|
+
# Get these values from https://vaif.studio/app/security/api-keys
|
|
2953
2949
|
|
|
2954
|
-
|
|
2955
|
-
VITE_VAIF_API_KEY=your-
|
|
2950
|
+
VITE_VAIF_API_URL=https://api.vaif.studio
|
|
2951
|
+
VITE_VAIF_API_KEY=your-api-key
|
|
2956
2952
|
|
|
2957
|
-
#
|
|
2958
|
-
|
|
2953
|
+
# Database connection (for vaif generate, vaif db push)
|
|
2954
|
+
# DATABASE_URL=postgresql://user:password@host:5432/dbname
|
|
2959
2955
|
`},{path:"README.md",content:`# Realtime Chat \u2014 VAIF Starter
|
|
2960
2956
|
|
|
2961
2957
|
A React chat application with live messaging powered by [VAIF Studio](https://vaif.studio) realtime subscriptions.
|
|
@@ -3106,15 +3102,15 @@ export const posts = pgTable("posts", {
|
|
|
3106
3102
|
|
|
3107
3103
|
// Browser client \u2013 use in Client Components
|
|
3108
3104
|
export const vaif = createVaifClient({
|
|
3109
|
-
|
|
3105
|
+
baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
|
|
3110
3106
|
apiKey: process.env.NEXT_PUBLIC_VAIF_API_KEY!,
|
|
3111
3107
|
});
|
|
3112
3108
|
|
|
3113
3109
|
// Server client \u2013 use in Server Components, Route Handlers, Server Actions
|
|
3114
3110
|
export function createVaifServer() {
|
|
3115
3111
|
return createVaifClient({
|
|
3116
|
-
|
|
3117
|
-
|
|
3112
|
+
baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
|
|
3113
|
+
apiKey: process.env.VAIF_SECRET_KEY!,
|
|
3118
3114
|
});
|
|
3119
3115
|
}
|
|
3120
3116
|
`},{path:"lib/auth.ts",content:`import { createVaifServer } from "./vaif";
|
|
@@ -3267,10 +3263,13 @@ export async function requireTeamRole(
|
|
|
3267
3263
|
`},{path:".env.example",content:`# VAIF Configuration
|
|
3268
3264
|
# Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
|
|
3269
3265
|
|
|
3270
|
-
|
|
3271
|
-
NEXT_PUBLIC_VAIF_API_KEY=your-
|
|
3266
|
+
NEXT_PUBLIC_VAIF_API_URL=https://api.vaif.studio
|
|
3267
|
+
NEXT_PUBLIC_VAIF_API_KEY=your-api-key
|
|
3272
3268
|
VAIF_SECRET_KEY=your-secret-key
|
|
3273
3269
|
|
|
3270
|
+
# Database connection (for vaif generate, vaif db push)
|
|
3271
|
+
# DATABASE_URL=postgresql://user:password@host:5432/dbname
|
|
3272
|
+
|
|
3274
3273
|
# CLI uses these (non-prefixed) for vaif db push, vaif secrets, etc.
|
|
3275
3274
|
VAIF_PROJECT_ID=your-project-id
|
|
3276
3275
|
`},{path:"README.md",content:`# SaaS Starter \u2014 VAIF Studio
|
|
@@ -3419,15 +3418,15 @@ export const posts = pgTable("posts", {
|
|
|
3419
3418
|
|
|
3420
3419
|
// Browser client
|
|
3421
3420
|
export const vaif = createVaifClient({
|
|
3422
|
-
|
|
3421
|
+
baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
|
|
3423
3422
|
apiKey: process.env.NEXT_PUBLIC_VAIF_API_KEY!,
|
|
3424
3423
|
});
|
|
3425
3424
|
|
|
3426
3425
|
// Server client
|
|
3427
3426
|
export function createVaifServer() {
|
|
3428
3427
|
return createVaifClient({
|
|
3429
|
-
|
|
3430
|
-
|
|
3428
|
+
baseUrl: process.env.NEXT_PUBLIC_VAIF_API_URL || 'https://api.vaif.studio',
|
|
3429
|
+
apiKey: process.env.VAIF_SECRET_KEY!,
|
|
3431
3430
|
});
|
|
3432
3431
|
}
|
|
3433
3432
|
`},{path:"lib/storage.ts",content:`import { createVaifServer } from "./vaif";
|
|
@@ -3542,10 +3541,13 @@ function getContentType(fileName: string): string {
|
|
|
3542
3541
|
`},{path:".env.example",content:`# VAIF Configuration
|
|
3543
3542
|
# Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
|
|
3544
3543
|
|
|
3545
|
-
|
|
3546
|
-
NEXT_PUBLIC_VAIF_API_KEY=your-
|
|
3544
|
+
NEXT_PUBLIC_VAIF_API_URL=https://api.vaif.studio
|
|
3545
|
+
NEXT_PUBLIC_VAIF_API_KEY=your-api-key
|
|
3547
3546
|
VAIF_SECRET_KEY=your-secret-key
|
|
3548
3547
|
|
|
3548
|
+
# Database connection (for vaif generate, vaif db push)
|
|
3549
|
+
# DATABASE_URL=postgresql://user:password@host:5432/dbname
|
|
3550
|
+
|
|
3549
3551
|
# CLI uses these (non-prefixed) for vaif db push, vaif secrets, etc.
|
|
3550
3552
|
VAIF_PROJECT_ID=your-project-id
|
|
3551
3553
|
`},{path:"README.md",content:`# E-commerce API \u2014 VAIF Studio
|
|
@@ -3688,16 +3690,16 @@ export const posts = pgTable("posts", {
|
|
|
3688
3690
|
|
|
3689
3691
|
return Response.json({ message: \`Hello, \${name}!\` });
|
|
3690
3692
|
}
|
|
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"]}};function ve(){console.log(""),console.log(
|
|
3692
|
-
? Which VAIF features do you want to include?`)),b.forEach((
|
|
3693
|
-
Unknown template: ${a}`)),console.log(
|
|
3694
|
-
`)),process.exit(1));let e;t.features&&t.features.length>0?e=t.features.filter(r=>b.some(
|
|
3695
|
-
No features specified.`)),console.log(
|
|
3696
|
-
`,"utf-8"),console.log(
|
|
3697
|
-
`,"utf-8");}catch{}(
|
|
3698
|
-
--add-features requires --template to know which template to use.`)),console.log(
|
|
3699
|
-
Use --force to overwrite existing configuration.`)),process.exit(1));try{if(h.writeFileSync(
|
|
3693
|
+
`}]},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 ve(){console.log(""),console.log(n.bold("Available project templates")),console.log("");let a=26,t=22;console.log(` ${n.gray("Template".padEnd(a))}${n.gray("Stack".padEnd(t))}${n.gray("Description")}`),console.log(n.gray(" "+"-".repeat(a+t+40)));for(let[i,e]of Object.entries(k))console.log(` ${n.cyan(i.padEnd(a))}${n.yellow(e.tag.padEnd(t))}${n.white(e.description)}`);console.log(""),console.log(n.gray("Usage:")),console.log(n.gray(" npx @vaiftech/cli init --template <name>")),console.log(n.gray(" npx @vaiftech/cli init -t nextjs-fullstack")),console.log(n.gray(" npx @vaiftech/cli init -t react-spa --features auth,database,realtime")),console.log(""),console.log(n.gray("Available features: auth, database, realtime, storage, functions")),console.log("");}async function W(a){if(!process.stdin.isTTY||!process.stdout.isTTY)return a;let t=new Set(a.map(e=>b.findIndex(s=>s.name===e)).filter(e=>e>=0)),i=0;return new Promise(e=>{let s=D.createInterface({input:process.stdin,output:process.stdout});D.emitKeypressEvents(process.stdin,s),process.stdin.setRawMode&&process.stdin.setRawMode(true);function o(){let d=b.length+2;process.stdout.write(`\x1B[${d}A`),c();}function c(){console.log(n.bold(`
|
|
3694
|
+
? Which VAIF features do you want to include?`)),b.forEach((d,l)=>{let r=t.has(l)?n.green("[x]"):"[ ]",u=l===i?n.cyan("> "):" ";console.log(`${u}${r} ${d.label} ${n.gray(`(${d.description})`)}`);}),console.log(n.gray(" (up/down to move, space to toggle, enter to confirm)"));}c(),process.stdin.on("keypress",(d,l)=>{if(l.name==="up"&&i>0)i--,o();else if(l.name==="down"&&i<b.length-1)i++,o();else if(l.name==="space")t.has(i)?t.delete(i):t.add(i),o();else if(l.name==="return"){process.stdin.setRawMode&&process.stdin.setRawMode(false),s.close();let r=[...t].sort().map(u=>b[u].name);e(r.length>0?r:a);}else l.name==="c"&&l.ctrl&&(process.stdin.setRawMode&&process.stdin.setRawMode(false),s.close(),process.exit(0));});})}async function F(a,t={}){let i=k[a];i||(console.log(n.red(`
|
|
3695
|
+
Unknown template: ${a}`)),console.log(n.yellow(`Run 'vaif templates' to see available templates.
|
|
3696
|
+
`)),process.exit(1));let e;t.features&&t.features.length>0?e=t.features.filter(r=>b.some(u=>u.name===r)):t.addOnly?(console.log(n.red(`
|
|
3697
|
+
No features specified.`)),console.log(n.yellow("Usage: vaif init --template <name> --add-features <features>")),console.log(n.gray("Available features: auth, database, realtime, storage, functions")),process.exit(1)):i.featureFiles&&Object.keys(i.featureFiles).length>0?e=await W(i.defaultFeatures??["database","auth"]):e=i.defaultFeatures??[],t.addOnly?(console.log(""),console.log(n.bold(`Adding features to ${n.cyan(i.name)} project...`)),console.log(n.gray(` Features: ${e.join(", ")}`)),console.log("")):(console.log(""),console.log(n.bold(`Scaffolding ${n.cyan(i.name)} template...`)),e.length>0&&console.log(n.gray(` Features: ${e.join(", ")}`)),console.log(""));let s=t.addOnly?[]:[...i.files];if(i.featureFiles)for(let r of e){let u=i.featureFiles[r];u&&s.push(...u);}let o=0,c=0;for(let r of s){let u=w.resolve(r.path),f=w.dirname(u);if(h.existsSync(f)||h.mkdirSync(f,{recursive:true}),r.path==="package.json"&&h.existsSync(u)&&!t.force)try{let p=JSON.parse(h.readFileSync(u,"utf-8")),v=JSON.parse(r.content),y=R=>{if(!R)return {};let C={};for(let[j,A]of Object.entries(R))!A.startsWith("workspace:")&&!A.startsWith("link:")&&!A.startsWith("file:")&&(C[j]=A);return C};p.dependencies={...y(p.dependencies),...v.dependencies||{}},p.devDependencies={...y(p.devDependencies),...v.devDependencies||{}},v.scripts&&(p.scripts={...p.scripts||{},...v.scripts}),h.writeFileSync(u,JSON.stringify(p,null,2)+`
|
|
3698
|
+
`,"utf-8"),console.log(n.green(` merge ${r.path} (added dependencies)`)),o++;continue}catch{}if(h.existsSync(u)&&!t.force){console.log(n.yellow(` skip ${r.path} (already exists)`)),c++;continue}h.writeFileSync(u,r.content,"utf-8"),console.log(n.green(` create ${r.path}`)),o++;}console.log(""),o>0&&console.log(n.green(`Created ${o} file${o!==1?"s":""}.`)),c>0&&console.log(n.yellow(`Skipped ${c} file${c!==1?"s":""} (use --force to overwrite).`));let d={auth:{"@vaiftech/auth":"^1.0.0"},database:{},realtime:{},storage:{},functions:{}},l=w.resolve("package.json");if(h.existsSync(l)&&e.length>0)try{let r=JSON.parse(h.readFileSync(l,"utf-8")),u=!1;for(let f of e){let p=d[f];if(p)for(let[v,y]of Object.entries(p))r.dependencies?.[v]||(r.dependencies=r.dependencies||{},r.dependencies[v]=y,u=!0);}u&&h.writeFileSync(l,JSON.stringify(r,null,2)+`
|
|
3699
|
+
`,"utf-8");}catch{}(i.dependencies?.length||i.devDependencies?.length)&&(console.log(""),console.log(n.bold("Install dependencies:")),i.dependencies?.length&&console.log(n.cyan(` npm install ${i.dependencies.join(" ")}`)),i.devDependencies?.length&&console.log(n.cyan(` npm install -D ${i.devDependencies.join(" ")}`))),console.log(""),console.log(n.bold.green("Project scaffolded successfully!")),console.log(""),console.log(n.bold(" Next steps:")),i.postInstructions.forEach(r=>{console.log(n.gray(` ${r}`));}),console.log(""),console.log(n.gray(" Get your project credentials at https://vaif.studio/app/security/api-keys")),console.log("");}var J={$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 Te(a){if(a.addFeatures){a.template||(console.log(n.red(`
|
|
3700
|
+
--add-features requires --template to know which template to use.`)),console.log(n.gray("Example: vaif init --template react-spa --add-features functions,storage")),process.exit(1));let e=a.addFeatures.split(",").map(s=>s.trim());await F(a.template,{force:a.force,features:e,addOnly:true});return}let t=z("Initializing VAIF configuration...").start(),i=w.resolve("vaif.config.json");h.existsSync(i)&&!a.force&&(t.fail("vaif.config.json already exists"),console.log(n.yellow(`
|
|
3701
|
+
Use --force to overwrite existing configuration.`)),process.exit(1));try{if(h.writeFileSync(i,JSON.stringify(J,null,2),"utf-8"),t.succeed("Created vaif.config.json"),a.template){let e=a.features?a.features.split(",").map(s=>s.trim()):void 0;await F(a.template,{force:a.force,features:e});}else {let e=w.resolve(".env.example");if(h.existsSync(e)||(h.writeFileSync(e,`# VAIF Configuration
|
|
3700
3702
|
DATABASE_URL=postgresql://user:password@localhost:5432/database
|
|
3701
3703
|
VAIF_API_KEY=your-api-key
|
|
3702
|
-
`,"utf-8"),console.log(
|
|
3703
|
-
Error: ${e.message}`)),process.exit(1);}}export{
|
|
3704
|
+
`,"utf-8"),console.log(n.gray("Created .env.example"))),a.typescript){let s=w.resolve("src/types");h.existsSync(s)||(h.mkdirSync(s,{recursive:!0}),console.log(n.gray("Created src/types directory")));}console.log(""),console.log(n.green("VAIF initialized successfully!")),console.log(""),console.log(n.gray("Next steps:")),console.log(n.gray(" 1. Update vaif.config.json with your project ID")),console.log(n.gray(" 2. Set DATABASE_URL in your environment")),console.log(n.gray(" 3. Run: npx vaif generate")),console.log("");}}catch(e){t.fail("Failed to initialize"),e instanceof Error&&console.error(n.red(`
|
|
3705
|
+
Error: ${e.message}`)),process.exit(1);}}export{N as a,ue as b,ve as c,Te as d};
|