@vaiftech/cli 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/dist/{chunk-JRB5YVG7.js → chunk-UQZPP43V.js} +82 -37
- package/dist/cli.cjs +124 -74
- package/dist/cli.js +41 -36
- package/dist/index.cjs +78 -33
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -44,22 +44,22 @@
|
|
|
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
|
|
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(`
|
|
48
48
|
`);return `export type ${t} =
|
|
49
|
-
${e};`}function G(n,a,t){let e=x(n),i=[],r=[],c=[];for(let
|
|
49
|
+
${e};`}function G(n,a,t){let e=x(n),i=[],r=[],c=[];for(let o of a){let d=$(o,t),p=o.column_name,g=o.column_default!==null||o.is_identity==="YES",y=o.is_nullable==="YES";i.push(` ${p}: ${d};`),g||o.column_name==="id"?r.push(` ${p}?: ${d.replace(" | null","")} | null;`):y?r.push(` ${p}?: ${d};`):r.push(` ${p}: ${d.replace(" | null","")};`),c.push(` ${p}?: ${d.replace(" | null","")} | null;`);}let u=`export interface ${e} {
|
|
50
50
|
${i.join(`
|
|
51
51
|
`)}
|
|
52
52
|
}`,l=`export interface ${e}Insert {
|
|
53
53
|
${r.join(`
|
|
54
54
|
`)}
|
|
55
|
-
}`,
|
|
55
|
+
}`,s=`export interface ${e}Update {
|
|
56
56
|
${c.join(`
|
|
57
57
|
`)}
|
|
58
|
-
}`;return {base:u,insert:l,update:
|
|
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
59
|
`)}async function W(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(m__default.default.yellow(`
|
|
60
|
-
Provide a connection string via:`)),console.log(m__default.default.gray(" --connection <url>")),console.log(m__default.default.gray(" DATABASE_URL environment variable")),console.log(m__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),
|
|
60
|
+
Provide a connection string via:`)),console.log(m__default.default.gray(" --connection <url>")),console.log(m__default.default.gray(" DATABASE_URL environment variable")),console.log(m__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(m__default.default.gray("\u2500".repeat(60))),console.log(s),console.log(m__default.default.gray("\u2500".repeat(60)));return}let o=w__default.default.resolve(n.output),d=w__default.default.dirname(o);h__default.default.existsSync(d)||h__default.default.mkdirSync(d,{recursive:!0}),h__default.default.writeFileSync(o,s,"utf-8"),a.succeed(`Generated types for ${r.size} tables \u2192 ${m__default.default.cyan(n.output)}`),console.log(""),console.log(m__default.default.green("Generated:")),console.log(m__default.default.gray(` Tables: ${r.size}`)),console.log(m__default.default.gray(` Enums: ${c.size}`)),console.log(""),console.log(m__default.default.gray("Import in your code:")),console.log(m__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(m__default.default.red(`
|
|
61
61
|
Error: ${t.message}`)),t.message.includes("ECONNREFUSED")&&console.log(m__default.default.yellow(`
|
|
62
|
-
Make sure your database is running and accessible.`))),process.exit(1);}}var
|
|
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"}],J={"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",
|
|
@@ -167,7 +167,7 @@ export function createVaifServer() {
|
|
|
167
167
|
});
|
|
168
168
|
}
|
|
169
169
|
`},{path:".env.local.example",content:`# VAIF Configuration
|
|
170
|
-
# Get these values from https://vaif.studio/
|
|
170
|
+
# Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
|
|
171
171
|
|
|
172
172
|
NEXT_PUBLIC_VAIF_PROJECT_ID=your-project-id
|
|
173
173
|
NEXT_PUBLIC_VAIF_API_KEY=your-anon-key
|
|
@@ -204,7 +204,7 @@ A full-stack Next.js application powered by [VAIF Studio](https://vaif.studio),
|
|
|
204
204
|
cp .env.local.example .env.local
|
|
205
205
|
\\\`\\\`\\\`
|
|
206
206
|
|
|
207
|
-
Get your Project ID, API Key, and Secret Key from <https://vaif.studio/
|
|
207
|
+
Get your Project ID, API Key, and Secret Key from <https://vaif.studio/app/security/api-keys> under **Project Settings > API Keys**.
|
|
208
208
|
|
|
209
209
|
3. **Install and log in to the VAIF CLI**
|
|
210
210
|
|
|
@@ -527,6 +527,11 @@ export const posts = pgTable("posts", {
|
|
|
527
527
|
});
|
|
528
528
|
`}],functions:[{path:"functions/hello.ts",content:`export default async function handler(req: Request): Promise<Response> {
|
|
529
529
|
const { name } = await req.json().catch(() => ({ name: "World" }));
|
|
530
|
+
|
|
531
|
+
// Secrets set via \\\`vaif secrets set\\\` or the Security > Secrets page
|
|
532
|
+
// are available as environment variables at runtime:
|
|
533
|
+
// const apiKey = process.env.MY_API_KEY;
|
|
534
|
+
|
|
530
535
|
return Response.json({ message: \`Hello, \${name}!\` });
|
|
531
536
|
}
|
|
532
537
|
`}]},dependencies:["@vaiftech/client","@vaiftech/auth","@vaiftech/react","next","react","react-dom"],devDependencies:["@types/node","@types/react","@types/react-dom","typescript"],postInstructions:["cd my-vaif-app","npm install","# Copy .env.local.example to .env.local and add your VAIF credentials","npm run dev"]},"react-spa":{name:"React SPA",description:"Single-page React app with Vite, VAIF client, and provider wrapper",tag:"React + Vite",defaultFeatures:["database","auth"],files:[{path:"package.json",content:`{
|
|
@@ -654,7 +659,7 @@ interface ImportMeta {
|
|
|
654
659
|
readonly env: ImportMetaEnv;
|
|
655
660
|
}
|
|
656
661
|
`},{path:".env.example",content:`# VAIF Configuration
|
|
657
|
-
# Get these values from https://vaif.studio/
|
|
662
|
+
# Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
|
|
658
663
|
|
|
659
664
|
VITE_VAIF_PROJECT_ID=your-project-id
|
|
660
665
|
VITE_VAIF_API_KEY=your-anon-key
|
|
@@ -687,7 +692,7 @@ A single-page React application built with [Vite](https://vite.dev/) and powered
|
|
|
687
692
|
cp .env.example .env
|
|
688
693
|
\\\`\\\`\\\`
|
|
689
694
|
|
|
690
|
-
Get your Project ID and API Key from <https://vaif.studio/
|
|
695
|
+
Get your Project ID and API Key from <https://vaif.studio/app/security/api-keys> under **Project Settings > API Keys**.
|
|
691
696
|
|
|
692
697
|
3. **Install and log in to the VAIF CLI**
|
|
693
698
|
|
|
@@ -1036,6 +1041,11 @@ export const posts = pgTable("posts", {
|
|
|
1036
1041
|
});
|
|
1037
1042
|
`}],functions:[{path:"functions/hello.ts",content:`export default async function handler(req: Request): Promise<Response> {
|
|
1038
1043
|
const { name } = await req.json().catch(() => ({ name: "World" }));
|
|
1044
|
+
|
|
1045
|
+
// Secrets set via \\\`vaif secrets set\\\` or the Security > Secrets page
|
|
1046
|
+
// are available as environment variables at runtime:
|
|
1047
|
+
// const apiKey = process.env.MY_API_KEY;
|
|
1048
|
+
|
|
1039
1049
|
return Response.json({ message: \`Hello, \${name}!\` });
|
|
1040
1050
|
}
|
|
1041
1051
|
`}]},dependencies:["@vaiftech/client","@vaiftech/react","react","react-dom","react-router-dom"],devDependencies:["@types/react","@types/react-dom","@vitejs/plugin-react","typescript","vite"],postInstructions:["cd my-vaif-app","npm install","# Copy .env.example to .env and add your VAIF credentials","npm run dev"]},"ios-swift-app":{name:"iOS Swift App",description:"Swift client manager for iOS/macOS apps using Swift Package Manager",tag:"Swift / iOS",defaultFeatures:["database","auth"],files:[{path:"VaifManager.swift",content:`import Foundation
|
|
@@ -1185,7 +1195,7 @@ An iOS/macOS application powered by [VAIF Studio](https://vaif.studio), using th
|
|
|
1185
1195
|
<string>your-anon-key</string>
|
|
1186
1196
|
\\\`\\\`\\\`
|
|
1187
1197
|
|
|
1188
|
-
Get your credentials from <https://vaif.studio/
|
|
1198
|
+
Get your credentials from <https://vaif.studio/app/security/api-keys> under **Project Settings > API Keys**.
|
|
1189
1199
|
|
|
1190
1200
|
3. **Install and log in to the VAIF CLI** (for type generation)
|
|
1191
1201
|
|
|
@@ -1312,7 +1322,7 @@ export const vaif = createExpoClient({
|
|
|
1312
1322
|
realtime: { enabled: true },
|
|
1313
1323
|
});
|
|
1314
1324
|
`},{path:".env.example",content:`# VAIF Configuration
|
|
1315
|
-
# Get these values from https://vaif.studio/
|
|
1325
|
+
# Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
|
|
1316
1326
|
|
|
1317
1327
|
EXPO_PUBLIC_VAIF_PROJECT_ID=your-project-id
|
|
1318
1328
|
EXPO_PUBLIC_VAIF_API_KEY=your-anon-key
|
|
@@ -1346,7 +1356,7 @@ A React Native / Expo mobile application powered by [VAIF Studio](https://vaif.s
|
|
|
1346
1356
|
cp .env.example .env
|
|
1347
1357
|
\\\`\\\`\\\`
|
|
1348
1358
|
|
|
1349
|
-
Get your Project ID and API Key from <https://vaif.studio/
|
|
1359
|
+
Get your Project ID and API Key from <https://vaif.studio/app/security/api-keys> under **Project Settings > API Keys**.
|
|
1350
1360
|
|
|
1351
1361
|
3. **Install and log in to the VAIF CLI**
|
|
1352
1362
|
|
|
@@ -1625,6 +1635,11 @@ export const posts = pgTable("posts", {
|
|
|
1625
1635
|
});
|
|
1626
1636
|
`}],functions:[{path:"functions/hello.ts",content:`export default async function handler(req: Request): Promise<Response> {
|
|
1627
1637
|
const { name } = await req.json().catch(() => ({ name: "World" }));
|
|
1638
|
+
|
|
1639
|
+
// Secrets set via \\\`vaif secrets set\\\` or the Security > Secrets page
|
|
1640
|
+
// are available as environment variables at runtime:
|
|
1641
|
+
// const apiKey = process.env.MY_API_KEY;
|
|
1642
|
+
|
|
1628
1643
|
return Response.json({ message: \`Hello, \${name}!\` });
|
|
1629
1644
|
}
|
|
1630
1645
|
`}]},dependencies:["@vaiftech/sdk-expo","@react-native-async-storage/async-storage","expo","expo-router","react","react-native"],postInstructions:["cd my-vaif-app","npm install","# Copy .env.example to .env and add your VAIF credentials","npx expo start"]},"flutter-app":{name:"Flutter App",description:"Dart/Flutter client setup with environment configuration",tag:"Flutter / Dart",defaultFeatures:["database","auth"],files:[{path:"lib/main.dart",content:`import 'package:flutter/material.dart';
|
|
@@ -1736,7 +1751,7 @@ A Flutter application powered by [VAIF Studio](https://vaif.studio), with Dart c
|
|
|
1736
1751
|
cp .env.example .env
|
|
1737
1752
|
\\\`\\\`\\\`
|
|
1738
1753
|
|
|
1739
|
-
Get your Project ID and API Key from <https://vaif.studio/
|
|
1754
|
+
Get your Project ID and API Key from <https://vaif.studio/app/security/api-keys> under **Project Settings > API Keys**.
|
|
1740
1755
|
|
|
1741
1756
|
3. **Install and log in to the VAIF CLI** (for schema and type generation)
|
|
1742
1757
|
|
|
@@ -1994,7 +2009,7 @@ fastapi>=0.110.0
|
|
|
1994
2009
|
uvicorn[standard]>=0.27.0
|
|
1995
2010
|
python-dotenv>=1.0.0
|
|
1996
2011
|
`},{path:".env.example",content:`# VAIF Configuration
|
|
1997
|
-
# Get these values from https://vaif.studio/
|
|
2012
|
+
# Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
|
|
1998
2013
|
|
|
1999
2014
|
VAIF_PROJECT_ID=your-project-id
|
|
2000
2015
|
VAIF_API_KEY=your-anon-key
|
|
@@ -2036,7 +2051,7 @@ A FastAPI backend application powered by [VAIF Studio](https://vaif.studio), wit
|
|
|
2036
2051
|
cp .env.example .env
|
|
2037
2052
|
\\\`\\\`\\\`
|
|
2038
2053
|
|
|
2039
|
-
Get your Project ID, API Key, and Secret Key from <https://vaif.studio/
|
|
2054
|
+
Get your Project ID, API Key, and Secret Key from <https://vaif.studio/app/security/api-keys> under **Project Settings > API Keys**.
|
|
2040
2055
|
|
|
2041
2056
|
4. **Install and log in to the VAIF CLI**
|
|
2042
2057
|
|
|
@@ -2236,6 +2251,7 @@ async def invoke_function(function_name: str, payload: dict = {}):
|
|
|
2236
2251
|
`},{path:"functions/hello.py",content:`"""Example VAIF serverless function."""
|
|
2237
2252
|
|
|
2238
2253
|
import json
|
|
2254
|
+
import os
|
|
2239
2255
|
|
|
2240
2256
|
|
|
2241
2257
|
def handler(request):
|
|
@@ -2243,6 +2259,10 @@ def handler(request):
|
|
|
2243
2259
|
|
|
2244
2260
|
Deploy with: vaif functions deploy
|
|
2245
2261
|
"""
|
|
2262
|
+
# Secrets set via \\\`vaif secrets set\\\` or the Security > Secrets page
|
|
2263
|
+
# are available as environment variables at runtime:
|
|
2264
|
+
# api_key = os.environ.get("MY_API_KEY")
|
|
2265
|
+
|
|
2246
2266
|
try:
|
|
2247
2267
|
body = json.loads(request.body) if request.body else {}
|
|
2248
2268
|
name = body.get("name", "World")
|
|
@@ -2354,7 +2374,7 @@ A Go backend API powered by [VAIF Studio](https://vaif.studio), with HTTP handle
|
|
|
2354
2374
|
cp .env.example .env
|
|
2355
2375
|
\\\`\\\`\\\`
|
|
2356
2376
|
|
|
2357
|
-
Get your Project ID, API Key, and Secret Key from <https://vaif.studio/
|
|
2377
|
+
Get your Project ID, API Key, and Secret Key from <https://vaif.studio/app/security/api-keys> under **Project Settings > API Keys**.
|
|
2358
2378
|
|
|
2359
2379
|
3. **Install and log in to the VAIF CLI**
|
|
2360
2380
|
|
|
@@ -2557,6 +2577,11 @@ type HelloResponse struct {
|
|
|
2557
2577
|
}
|
|
2558
2578
|
|
|
2559
2579
|
// HelloHandler is an example VAIF serverless function.
|
|
2580
|
+
//
|
|
2581
|
+
// Secrets set via \\\`vaif secrets set\\\` or the Security > Secrets page
|
|
2582
|
+
// are available as environment variables at runtime:
|
|
2583
|
+
//
|
|
2584
|
+
// apiKey := os.Getenv("MY_API_KEY") // import "os"
|
|
2560
2585
|
func HelloHandler(w http.ResponseWriter, r *http.Request) {
|
|
2561
2586
|
var req HelloRequest
|
|
2562
2587
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.Name == "" {
|
|
@@ -2623,7 +2648,7 @@ export async function deleteTodo(id: string): Promise<void> {
|
|
|
2623
2648
|
if (error) throw error;
|
|
2624
2649
|
}
|
|
2625
2650
|
`},{path:".env.example",content:`# VAIF Configuration
|
|
2626
|
-
# Get these values from https://vaif.studio/
|
|
2651
|
+
# Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
|
|
2627
2652
|
|
|
2628
2653
|
VITE_VAIF_PROJECT_ID=your-project-id
|
|
2629
2654
|
VITE_VAIF_API_KEY=your-anon-key
|
|
@@ -2651,7 +2676,7 @@ A simple React todo application for learning [VAIF Studio](https://vaif.studio)
|
|
|
2651
2676
|
cp .env.example .env
|
|
2652
2677
|
\\\`\\\`\\\`
|
|
2653
2678
|
|
|
2654
|
-
Get your Project ID and API Key from <https://vaif.studio/
|
|
2679
|
+
Get your Project ID and API Key from <https://vaif.studio/app/security/api-keys> under **Project Settings > API Keys**.
|
|
2655
2680
|
|
|
2656
2681
|
3. **Install and log in to the VAIF CLI**
|
|
2657
2682
|
|
|
@@ -2752,6 +2777,11 @@ export const posts = pgTable("posts", {
|
|
|
2752
2777
|
});
|
|
2753
2778
|
`}],functions:[{path:"functions/hello.ts",content:`export default async function handler(req: Request): Promise<Response> {
|
|
2754
2779
|
const { name } = await req.json().catch(() => ({ name: "World" }));
|
|
2780
|
+
|
|
2781
|
+
// Secrets set via \\\`vaif secrets set\\\` or the Security > Secrets page
|
|
2782
|
+
// are available as environment variables at runtime:
|
|
2783
|
+
// const apiKey = process.env.MY_API_KEY;
|
|
2784
|
+
|
|
2755
2785
|
return Response.json({ message: \`Hello, \${name}!\` });
|
|
2756
2786
|
}
|
|
2757
2787
|
`}]},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 { createClient } from "@vaiftech/client";
|
|
@@ -2903,7 +2933,7 @@ export function useRealtimeMessages({
|
|
|
2903
2933
|
return { messages, isLoading, error, refresh };
|
|
2904
2934
|
}
|
|
2905
2935
|
`},{path:".env.example",content:`# VAIF Configuration
|
|
2906
|
-
# Get these values from https://vaif.studio/
|
|
2936
|
+
# Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
|
|
2907
2937
|
|
|
2908
2938
|
VITE_VAIF_PROJECT_ID=your-project-id
|
|
2909
2939
|
VITE_VAIF_API_KEY=your-anon-key
|
|
@@ -2931,7 +2961,7 @@ A React chat application with live messaging powered by [VAIF Studio](https://va
|
|
|
2931
2961
|
cp .env.example .env
|
|
2932
2962
|
\\\`\\\`\\\`
|
|
2933
2963
|
|
|
2934
|
-
Get your Project ID and API Key from <https://vaif.studio/
|
|
2964
|
+
Get your Project ID and API Key from <https://vaif.studio/app/security/api-keys> under **Project Settings > API Keys**.
|
|
2935
2965
|
|
|
2936
2966
|
3. **Install and log in to the VAIF CLI**
|
|
2937
2967
|
|
|
@@ -3046,6 +3076,11 @@ export const posts = pgTable("posts", {
|
|
|
3046
3076
|
});
|
|
3047
3077
|
`}],functions:[{path:"functions/hello.ts",content:`export default async function handler(req: Request): Promise<Response> {
|
|
3048
3078
|
const { name } = await req.json().catch(() => ({ name: "World" }));
|
|
3079
|
+
|
|
3080
|
+
// Secrets set via \\\`vaif secrets set\\\` or the Security > Secrets page
|
|
3081
|
+
// are available as environment variables at runtime:
|
|
3082
|
+
// const apiKey = process.env.MY_API_KEY;
|
|
3083
|
+
|
|
3049
3084
|
return Response.json({ message: \`Hello, \${name}!\` });
|
|
3050
3085
|
}
|
|
3051
3086
|
`}]},dependencies:["@vaiftech/client","@vaiftech/react"],postInstructions:["Copy .env.example to .env and fill in your project credentials","Create a 'messages' table with columns: id (uuid), content (text), user_id (text), username (text), channel_id (text), created_at (timestamptz)","Enable Realtime on the messages table in your VAIF dashboard","Use the useRealtimeMessages hook in your components","Run: npx vaif generate to generate TypeScript types"]},"saas-starter":{name:"SaaS Starter",description:"Full SaaS starter with VAIF auth, team/org support, and server-side helpers",tag:"Next.js SaaS",defaultFeatures:["database","auth","functions"],files:[{path:"lib/vaif.ts",content:`import { createClient } from "@vaiftech/client";
|
|
@@ -3212,7 +3247,7 @@ export async function requireTeamRole(
|
|
|
3212
3247
|
return member as TeamMember;
|
|
3213
3248
|
}
|
|
3214
3249
|
`},{path:".env.example",content:`# VAIF Configuration
|
|
3215
|
-
# Get these values from https://vaif.studio/
|
|
3250
|
+
# Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
|
|
3216
3251
|
|
|
3217
3252
|
NEXT_PUBLIC_VAIF_PROJECT_ID=your-project-id
|
|
3218
3253
|
NEXT_PUBLIC_VAIF_API_KEY=your-anon-key
|
|
@@ -3241,7 +3276,7 @@ A full SaaS starter kit powered by [VAIF Studio](https://vaif.studio) with authe
|
|
|
3241
3276
|
cp .env.example .env.local
|
|
3242
3277
|
\\\`\\\`\\\`
|
|
3243
3278
|
|
|
3244
|
-
Get your Project ID, API Key, and Secret Key from <https://vaif.studio/
|
|
3279
|
+
Get your Project ID, API Key, and Secret Key from <https://vaif.studio/app/security/api-keys> under **Project Settings > API Keys**.
|
|
3245
3280
|
|
|
3246
3281
|
3. **Install and log in to the VAIF CLI**
|
|
3247
3282
|
|
|
@@ -3352,6 +3387,11 @@ export const posts = pgTable("posts", {
|
|
|
3352
3387
|
});
|
|
3353
3388
|
`}],functions:[{path:"functions/hello.ts",content:`export default async function handler(req: Request): Promise<Response> {
|
|
3354
3389
|
const { name } = await req.json().catch(() => ({ name: "World" }));
|
|
3390
|
+
|
|
3391
|
+
// Secrets set via \\\`vaif secrets set\\\` or the Security > Secrets page
|
|
3392
|
+
// are available as environment variables at runtime:
|
|
3393
|
+
// const apiKey = process.env.MY_API_KEY;
|
|
3394
|
+
|
|
3355
3395
|
return Response.json({ message: \`Hello, \${name}!\` });
|
|
3356
3396
|
}
|
|
3357
3397
|
`}]},dependencies:["@vaiftech/client","@vaiftech/auth","@vaiftech/react"],postInstructions:["Copy .env.example to .env.local and fill in your project credentials","Create 'teams' and 'team_members' tables in your VAIF dashboard","Import auth helpers from '@/lib/auth' in your Server Components/Actions","Use requireUser() for authenticated routes and requireTeamRole() for role checks","Run: npx vaif generate to generate TypeScript types"]},"ecommerce-api":{name:"E-commerce API",description:"API-first e-commerce setup with VAIF storage for product images",tag:"Next.js E-commerce",defaultFeatures:["database","auth","storage"],files:[{path:"lib/vaif.ts",content:`import { createClient } from "@vaiftech/client";
|
|
@@ -3480,7 +3520,7 @@ function getContentType(fileName: string): string {
|
|
|
3480
3520
|
return mimeTypes[ext ?? ""] ?? "application/octet-stream";
|
|
3481
3521
|
}
|
|
3482
3522
|
`},{path:".env.example",content:`# VAIF Configuration
|
|
3483
|
-
# Get these values from https://vaif.studio/
|
|
3523
|
+
# Get these values from https://vaif.studio/app/security/api-keys \u2192 Project Settings \u2192 API Keys
|
|
3484
3524
|
|
|
3485
3525
|
NEXT_PUBLIC_VAIF_PROJECT_ID=your-project-id
|
|
3486
3526
|
NEXT_PUBLIC_VAIF_API_KEY=your-anon-key
|
|
@@ -3509,7 +3549,7 @@ An API-first e-commerce setup powered by [VAIF Studio](https://vaif.studio) with
|
|
|
3509
3549
|
cp .env.example .env.local
|
|
3510
3550
|
\\\`\\\`\\\`
|
|
3511
3551
|
|
|
3512
|
-
Get your Project ID, API Key, and Secret Key from <https://vaif.studio/
|
|
3552
|
+
Get your Project ID, API Key, and Secret Key from <https://vaif.studio/app/security/api-keys> under **Project Settings > API Keys**.
|
|
3513
3553
|
|
|
3514
3554
|
3. **Install and log in to the VAIF CLI**
|
|
3515
3555
|
|
|
@@ -3618,14 +3658,19 @@ export const posts = pgTable("posts", {
|
|
|
3618
3658
|
});
|
|
3619
3659
|
`}],functions:[{path:"functions/hello.ts",content:`export default async function handler(req: Request): Promise<Response> {
|
|
3620
3660
|
const { name } = await req.json().catch(() => ({ name: "World" }));
|
|
3661
|
+
|
|
3662
|
+
// Secrets set via \\\`vaif secrets set\\\` or the Security > Secrets page
|
|
3663
|
+
// are available as environment variables at runtime:
|
|
3664
|
+
// const apiKey = process.env.MY_API_KEY;
|
|
3665
|
+
|
|
3621
3666
|
return Response.json({ message: \`Hello, \${name}!\` });
|
|
3622
3667
|
}
|
|
3623
|
-
`}]},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=>
|
|
3624
|
-
? Which VAIF features do you want to include?`)),
|
|
3668
|
+
`}]},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=D__default.default.createInterface({input:process.stdin,output:process.stdout});D__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(m__default.default.bold(`
|
|
3669
|
+
? Which VAIF features do you want to include?`)),b.forEach((u,l)=>{let s=a.has(l)?m__default.default.green("[x]"):"[ ]",o=l===t?m__default.default.cyan("> "):" ";console.log(`${o}${s} ${u.label} ${m__default.default.gray(`(${u.description})`)}`);}),console.log(m__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 j(n,a={}){let t=J[n];t||(console.log(m__default.default.red(`
|
|
3625
3670
|
Unknown template: ${n}`)),console.log(m__default.default.yellow(`Run 'vaif templates' to see available templates.
|
|
3626
|
-
`)),process.exit(1));let e;a.features&&a.features.length>0?e=a.features.filter(
|
|
3627
|
-
`,"utf-8"),console.log(m__default.default.green(` merge ${
|
|
3628
|
-
`,"utf-8");}catch{}(t.dependencies?.length||t.devDependencies?.length)&&(console.log(""),console.log(m__default.default.bold("Install dependencies:")),t.dependencies?.length&&console.log(m__default.default.cyan(` npm install ${t.dependencies.join(" ")}`)),t.devDependencies?.length&&console.log(m__default.default.cyan(` npm install -D ${t.devDependencies.join(" ")}`))),console.log(""),console.log(m__default.default.bold.green("Project scaffolded successfully!")),console.log(""),console.log(m__default.default.bold(" Next steps:")),t.postInstructions.forEach(
|
|
3671
|
+
`)),process.exit(1));let e;a.features&&a.features.length>0?e=a.features.filter(s=>b.some(o=>o.name===s)):t.featureFiles&&Object.keys(t.featureFiles).length>0?e=await X(t.defaultFeatures??["database","auth"]):e=t.defaultFeatures??[],console.log(""),console.log(m__default.default.bold(`Scaffolding ${m__default.default.cyan(t.name)} template...`)),e.length>0&&console.log(m__default.default.gray(` Features: ${e.join(", ")}`)),console.log("");let i=[...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),d=w__default.default.dirname(o);if(h__default.default.existsSync(d)||h__default.default.mkdirSync(d,{recursive:true}),s.path==="package.json"&&h__default.default.existsSync(o)&&!a.force)try{let p=JSON.parse(h__default.default.readFileSync(o,"utf-8")),g=JSON.parse(s.content),y=C=>{if(!C)return {};let N={};for(let[k,_]of Object.entries(C))!_.startsWith("workspace:")&&!_.startsWith("link:")&&!_.startsWith("file:")&&(N[k]=_);return N};p.dependencies={...y(p.dependencies),...g.dependencies||{}},p.devDependencies={...y(p.devDependencies),...g.devDependencies||{}},g.scripts&&(p.scripts={...p.scripts||{},...g.scripts}),h__default.default.writeFileSync(o,JSON.stringify(p,null,2)+`
|
|
3672
|
+
`,"utf-8"),console.log(m__default.default.green(` merge ${s.path} (added dependencies)`)),r++;continue}catch{}if(h__default.default.existsSync(o)&&!a.force){console.log(m__default.default.yellow(` skip ${s.path} (already exists)`)),c++;continue}h__default.default.writeFileSync(o,s.content,"utf-8"),console.log(m__default.default.green(` create ${s.path}`)),r++;}console.log(""),r>0&&console.log(m__default.default.green(`Created ${r} file${r!==1?"s":""}.`)),c>0&&console.log(m__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(h__default.default.existsSync(l)&&e.length>0)try{let s=JSON.parse(h__default.default.readFileSync(l,"utf-8")),o=!1;for(let d of e){let p=u[d];if(p)for(let[g,y]of Object.entries(p))s.dependencies?.[g]||(s.dependencies=s.dependencies||{},s.dependencies[g]=y,o=!0);}o&&h__default.default.writeFileSync(l,JSON.stringify(s,null,2)+`
|
|
3673
|
+
`,"utf-8");}catch{}(t.dependencies?.length||t.devDependencies?.length)&&(console.log(""),console.log(m__default.default.bold("Install dependencies:")),t.dependencies?.length&&console.log(m__default.default.cyan(` npm install ${t.dependencies.join(" ")}`)),t.devDependencies?.length&&console.log(m__default.default.cyan(` npm install -D ${t.devDependencies.join(" ")}`))),console.log(""),console.log(m__default.default.bold.green("Project scaffolded successfully!")),console.log(""),console.log(m__default.default.bold(" Next steps:")),t.postInstructions.forEach(s=>{console.log(m__default.default.gray(` ${s}`));}),console.log(""),console.log(m__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){let a=z__default.default("Initializing VAIF configuration...").start(),t=w__default.default.resolve("vaif.config.json");h__default.default.existsSync(t)&&!n.force&&(a.fail("vaif.config.json already exists"),console.log(m__default.default.yellow(`
|
|
3629
3674
|
Use --force to overwrite existing configuration.`)),process.exit(1));try{if(h__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 j(n.template,{force:n.force,features:e});}else {let e=w__default.default.resolve(".env.example");if(h__default.default.existsSync(e)||(h__default.default.writeFileSync(e,`# VAIF Configuration
|
|
3630
3675
|
DATABASE_URL=postgresql://user:password@localhost:5432/database
|
|
3631
3676
|
VAIF_API_KEY=your-api-key
|
|
@@ -3660,16 +3705,16 @@ Error: ${e.message}`)),process.exit(1);}}async function Le(n){let{connectionStri
|
|
|
3660
3705
|
JOIN pg_namespace n ON n.oid = t.typnamespace
|
|
3661
3706
|
WHERE n.nspname = $1
|
|
3662
3707
|
ORDER BY t.typname, e.enumsortorder
|
|
3663
|
-
`,[t]),u=new Map;for(let
|
|
3708
|
+
`,[t]),u=new Map;for(let o of i.rows)u.set(o.table_name,[]);for(let o of r.rows){let d=u.get(o.table_name);d&&d.push(o);}let l=new Map;for(let o of c.rows){let d=l.get(o.enum_name)||[];d.push(o.enum_value),l.set(o.enum_name,d);}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 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 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=R[c]||"unknown";return i==="YES"?`${u}[] | null`:`${u}[]`}let r=R[t]||R[e]||"unknown";return i==="YES"&&(r=`${r} | null`),r}function P(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=P(i),u=r.map(l=>` | "${l}"`).join(`
|
|
3664
3709
|
`);t.push(`export type ${c} =
|
|
3665
|
-
${u};`),t.push("");}}t.push("// ============ TABLES ============"),t.push("");let e=[];for(let[i,r]of n){e.push(i);let c=P(i),u=[],l=[],
|
|
3710
|
+
${u};`),t.push("");}}t.push("// ============ TABLES ============"),t.push("");let e=[];for(let[i,r]of n){e.push(i);let c=P(i),u=[],l=[],s=[];for(let o of r){let d=ne(o,a),p=o.column_name,g=o.column_default!==null||o.is_identity==="YES",y=o.is_nullable==="YES";u.push(` ${p}: ${d};`),g||o.column_name==="id"?l.push(` ${p}?: ${d.replace(" | null","")} | null;`):y?l.push(` ${p}?: ${d};`):l.push(` ${p}: ${d.replace(" | null","")};`),s.push(` ${p}?: ${d.replace(" | null","")} | null;`);}t.push(`export interface ${c} {
|
|
3666
3711
|
${u.join(`
|
|
3667
3712
|
`)}
|
|
3668
3713
|
}`),t.push(""),t.push(`export interface ${c}Insert {
|
|
3669
3714
|
${l.join(`
|
|
3670
3715
|
`)}
|
|
3671
3716
|
}`),t.push(""),t.push(`export interface ${c}Update {
|
|
3672
|
-
${
|
|
3717
|
+
${s.join(`
|
|
3673
3718
|
`)}
|
|
3674
3719
|
}`),t.push("");}t.push("// ============ DATABASE SCHEMA ============"),t.push(""),t.push("export interface Database {");for(let i of e){let r=P(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(`
|
|
3675
3720
|
`)}exports.generateTypes=W;exports.generateTypesFromConnection=Le;exports.initConfig=ee;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-
|
|
1
|
+
export{b as generateTypes,d as initConfig,a as loadConfig}from'./chunk-UQZPP43V.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
|