@unreal-orm/cli 1.0.0-alpha.3

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.
Files changed (3) hide show
  1. package/README.md +365 -0
  2. package/dist/index.js +236 -0
  3. package/package.json +52 -0
package/README.md ADDED
@@ -0,0 +1,365 @@
1
+ # UnrealORM CLI
2
+
3
+ Command-line interface for UnrealORM - a TypeScript ORM for SurrealDB.
4
+
5
+ ## Quick Start
6
+
7
+ The fastest way to get started with UnrealORM:
8
+
9
+ ```bash
10
+ # Using bunx (recommended)
11
+ bunx @unreal-orm/cli init
12
+
13
+ # Or with other package managers
14
+ npx @unreal-orm/cli init
15
+ pnpm dlx @unreal-orm/cli init
16
+ yarn dlx @unreal-orm/cli init
17
+ ```
18
+
19
+ This interactive command will:
20
+
21
+ - Configure your database connection
22
+ - Set up the project structure (`unreal/` folder)
23
+ - Install dependencies (`unreal-orm`, `surrealdb`, `@unreal-orm/cli`)
24
+ - Optionally generate sample tables or import from existing database
25
+
26
+ ## Installation
27
+
28
+ After running `init`, the CLI is installed as a dev dependency. You can then use it via:
29
+
30
+ ```bash
31
+ # Using package.json scripts (recommended)
32
+ bun unreal pull
33
+ npm run unreal pull
34
+
35
+ # Or directly
36
+ bunx unreal pull
37
+ npx unreal pull
38
+ ```
39
+
40
+ For global installation (optional):
41
+
42
+ ```bash
43
+ npm install -g @unreal-orm/cli
44
+ ```
45
+
46
+ ## Commands
47
+
48
+ ### `init`
49
+
50
+ Initialize a new UnrealORM project with configuration.
51
+
52
+ ```bash
53
+ unreal init [options]
54
+
55
+ Options:
56
+ --url <url> Database URL (e.g., http://localhost:8000)
57
+ -u, --username <username> Database username
58
+ -p, --password <password> Database password
59
+ -n, --namespace <namespace> Database namespace
60
+ -d, --database <database> Database name
61
+ --auth-level <level> Auth level: root, namespace, or database
62
+ --embedded <mode> Use embedded mode (memory or file path)
63
+ --skip-install Skip dependency installation
64
+ ```
65
+
66
+ **Interactive prompts:**
67
+
68
+ - Connection details (if not provided via flags)
69
+ - Dependency installation confirmation
70
+ - Next action selection (create sample schema, pull from database, or skip)
71
+
72
+ **Generated files:**
73
+
74
+ - `unreal.config.json` - Connection and schema configuration
75
+ - `surreal.ts` - Database connection module
76
+ - Sample schema files (optional)
77
+
78
+ ### `pull`
79
+
80
+ Introspect a SurrealDB database and generate TypeScript schema files.
81
+
82
+ ```bash
83
+ unreal pull [options]
84
+
85
+ Options:
86
+ --url <url> Database URL (e.g., http://localhost:8000)
87
+ -u, --username <username> Database username
88
+ -p, --password <password> Database password
89
+ -n, --namespace <namespace> Database namespace
90
+ -d, --database <database> Database name
91
+ -s, --schema-dir <path> Schema directory path
92
+ --auth-level <level> Auth level: root, namespace, or database
93
+ --embedded <mode> Use embedded mode (memory or file path)
94
+ -y, --yes Skip confirmation prompts
95
+ ```
96
+
97
+ **Features:**
98
+
99
+ - Introspects database schema via `INFO FOR DB` and `INFO FOR TABLE`
100
+ - Generates TypeScript model classes using UnrealORM syntax
101
+ - **Smart merge**: Preserves user customizations (comments, custom methods)
102
+ - Adds new fields/indexes with `// Added from database` comments
103
+ - Comments out removed fields/indexes for review
104
+
105
+ **Example output:**
106
+
107
+ ```typescript
108
+ // User.ts
109
+ import { Table, Field, Index } from "unreal-orm";
110
+ import { surql } from "surrealdb";
111
+
112
+ export class User extends Table.normal({
113
+ name: "user",
114
+ schemafull: true,
115
+ fields: {
116
+ name: Field.string(),
117
+ email: Field.string(),
118
+ age: Field.int({ default: surql`18` }),
119
+ created: Field.datetime({ value: surql`time::now()` }),
120
+ },
121
+ }) {}
122
+
123
+ export const idx_user_email = Index.define(() => User, {
124
+ name: "idx_user_email",
125
+ fields: ["email"],
126
+ unique: true,
127
+ });
128
+
129
+ export const UserDefinitions = [User, idx_user_email];
130
+ ```
131
+
132
+ ### `push`
133
+
134
+ Apply TypeScript schema changes to the database.
135
+
136
+ ```bash
137
+ unreal push [options]
138
+
139
+ Options:
140
+ --url <url> Database URL (e.g., http://localhost:8000)
141
+ -u, --username <username> Database username
142
+ -p, --password <password> Database password
143
+ -n, --namespace <namespace> Database namespace
144
+ -d, --database <database> Database name
145
+ -s, --schema-dir <path> Schema directory path
146
+ --auth-level <level> Auth level: root, namespace, or database
147
+ --embedded <mode> Use embedded mode (memory or file path)
148
+ -y, --yes Skip confirmation prompts
149
+ ```
150
+
151
+ **Features:**
152
+
153
+ - Compares code schema with database schema
154
+ - Shows detailed change preview before applying
155
+ - Generates and executes SurrealQL migrations
156
+ - Uses `OVERWRITE` keyword for safe modifications
157
+ - Supports table creation with all fields and indexes
158
+
159
+ ### `diff`
160
+
161
+ Compare TypeScript schema with database schema.
162
+
163
+ ```bash
164
+ unreal diff [options]
165
+
166
+ Options:
167
+ --url <url> Database URL (e.g., http://localhost:8000)
168
+ -u, --username <username> Database username
169
+ -p, --password <password> Database password
170
+ -n, --namespace <namespace> Database namespace
171
+ -d, --database <database> Database name
172
+ -s, --schema-dir <path> Schema directory path
173
+ --auth-level <level> Auth level: root, namespace, or database
174
+ --embedded <mode> Use embedded mode (memory or file path)
175
+ --detailed Show detailed field-level changes
176
+ ```
177
+
178
+ **Features:**
179
+
180
+ - Semantic AST-based comparison (ignores formatting differences)
181
+ - Detects added, removed, and modified tables/fields/indexes
182
+ - Shows field-level details with `--detailed` flag
183
+
184
+ ### `view`
185
+
186
+ Interactive TUI for browsing and editing database records.
187
+
188
+ ```bash
189
+ unreal view [options]
190
+
191
+ Options:
192
+ --url <url> Database URL (e.g., http://localhost:8000)
193
+ -u, --username <username> Database username
194
+ -p, --password <password> Database password
195
+ -n, --namespace <namespace> Database namespace
196
+ -d, --database <database> Database name
197
+ --auth-level <level> Auth level: root, namespace, or database
198
+ --embedded <mode> Use embedded mode (memory or file path)
199
+ --page-size <size> Records per page (5-100, default: auto)
200
+ --timeout <seconds> Query timeout in seconds (default: 3)
201
+ --concurrency <count> Max concurrent count queries (default: 5)
202
+ ```
203
+
204
+ **Features:**
205
+
206
+ - Browse all tables with record counts
207
+ - Navigate and view records with pagination
208
+ - Edit record fields with multi-line text editor
209
+ - Add/remove fields, delete records
210
+ - Batch editing with change preview before saving
211
+ - Filter tables by name
212
+
213
+ **Keyboard shortcuts:**
214
+
215
+ - `↑/↓` or `j/k` - Navigate
216
+ - `Enter` - Select/Edit
217
+ - `e` - Edit field
218
+ - `+` - Add field
219
+ - `-` - Remove field
220
+ - `s` - Save changes
221
+ - `d` - Delete record
222
+ - `b` or `Esc` - Go back
223
+ - `q` - Quit
224
+
225
+ ### `mermaid`
226
+
227
+ Generate Mermaid ERD diagrams from your schema.
228
+
229
+ ```bash
230
+ unreal mermaid [options]
231
+
232
+ Options:
233
+ --source <source> Schema source: code, database, or .surql file
234
+ -o, --output <path> Output file path
235
+ --stdout Output to stdout instead of file
236
+ --url <url> Database URL (for database source)
237
+ -s, --schema-dir <path> Schema directory (for code source)
238
+ ```
239
+
240
+ **Example output:**
241
+
242
+ ```mermaid
243
+ erDiagram
244
+ User {
245
+ string name
246
+ string email
247
+ datetime created_at
248
+ }
249
+ Post {
250
+ string title
251
+ string content
252
+ record author
253
+ }
254
+ User ||--o{ Post : "author"
255
+ ```
256
+
257
+ ## Configuration
258
+
259
+ The CLI uses `unreal.config.json` for persistent configuration:
260
+
261
+ ```json
262
+ {
263
+ "schemaDir": "./unreal/tables"
264
+ }
265
+ ```
266
+
267
+ Connection details are stored in `surreal.ts`:
268
+
269
+ ```typescript
270
+ import Surreal from "surrealdb";
271
+
272
+ const db = new Surreal();
273
+
274
+ await db.connect("http://localhost:8000");
275
+ await db.signin({ username: "root", password: "root" });
276
+ await db.use({ namespace: "test", database: "test" });
277
+
278
+ export default db;
279
+ ```
280
+
281
+ ## Connection Modes
282
+
283
+ ### Remote Connection
284
+
285
+ ```bash
286
+ unreal push --url http://localhost:8000 -u root -p root -n test -d test
287
+ ```
288
+
289
+ ### Embedded Mode (Memory)
290
+
291
+ ```bash
292
+ unreal push --embedded memory -n test -d test
293
+ ```
294
+
295
+ ### Embedded Mode (File)
296
+
297
+ ```bash
298
+ unreal push --embedded ./data/surreal.db -n test -d test
299
+ ```
300
+
301
+ ### Full Automation
302
+
303
+ ```bash
304
+ unreal push \
305
+ --url ws://localhost:8000 \
306
+ -u root -p secret \
307
+ -n production -d myapp \
308
+ --auth-level root \
309
+ -s ./unreal/tables \
310
+ -y
311
+ ```
312
+
313
+ ## Supported SurrealDB Features
314
+
315
+ ### Tables
316
+
317
+ - ✅ Normal tables
318
+ - ✅ Relation tables
319
+ - ✅ View tables
320
+ - ✅ Schemafull/schemaless
321
+ - ✅ Permissions
322
+
323
+ ### Fields
324
+
325
+ - ✅ All primitive types (string, int, float, bool, datetime, etc.)
326
+ - ✅ Complex types (array, set, object, record)
327
+ - ✅ Optional types (option<T>)
328
+ - ✅ Default values
329
+ - ✅ Value expressions
330
+ - ✅ Assertions
331
+ - ✅ Permissions
332
+
333
+ ### Indexes
334
+
335
+ - ✅ Standard indexes
336
+ - ✅ Unique indexes
337
+ - ✅ Multi-column indexes
338
+ - ⏳ Search indexes (parsed, not fully generated)
339
+
340
+ ### Events
341
+
342
+ - ⏳ Changefeeds (planned)
343
+
344
+ ## Development
345
+
346
+ ```bash
347
+ # Install dependencies
348
+ bun install
349
+
350
+ # Build
351
+ bun run build
352
+
353
+ # Run tests
354
+ bun test
355
+
356
+ # Link for local testing
357
+ bun link
358
+
359
+ # Test the CLI
360
+ unreal --help
361
+ ```
362
+
363
+ ## License
364
+
365
+ ISC
package/dist/index.js ADDED
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env node
2
+ import{createRequire as B2}from"node:module";var $2=Object.create;var{getPrototypeOf:Q2,defineProperty:v0,getOwnPropertyNames:J2}=Object;var X2=Object.prototype.hasOwnProperty;var X0=($,X,Q)=>{Q=$!=null?$2(Q2($)):{};let J=X||!$||!$.__esModule?v0(Q,"default",{value:$,enumerable:!0}):Q;for(let Z of J2($))if(!X2.call(J,Z))v0(J,Z,{get:()=>$[Z],enumerable:!0});return J};var Z2=($,X)=>{for(var Q in X)v0($,Q,{get:X[Q],enumerable:!0,configurable:!0,set:(J)=>X[Q]=()=>J})};var N0=($,X)=>()=>($&&(X=$($=0)),X);var Z0=B2(import.meta.url);class e0{lineCount=0;log($=""){console.log($),this.lineCount+=$.split(`
3
+ `).length}clear(){if(this.lineCount>0)process.stdout.moveCursor(0,-this.lineCount),process.stdout.clearScreenDown(),this.lineCount=0}reset(){this.lineCount=0}}var $1;var Q1=N0(()=>{$1=new e0});import l from"chalk";import Y2 from"ora";var Q0,x,B;var m=N0(()=>{Q1();Q0={success:"✅",error:"❌",warning:"⚠️",info:"ℹ️",step:"\uD83D\uDD39",arrow:"➜",line:"─",corner:"└─"},x={primary:l.hex("#FF00A0"),secondary:l.cyan,success:l.green,error:l.red,warning:l.yellow,info:l.blue,dim:l.gray,code:l.hex("#E0E0E0"),url:l.underline.cyan},B={header($,X){if(console.log(""),console.log(x.primary.bold(` ${$} `)),X)console.log(x.dim(` ${X}`));console.log("")},divider(){console.log(x.dim(Q0.line.repeat(60)))},success($){console.log(x.success(`${Q0.success} ${$}`))},error($,X){if(console.log(x.error(`${Q0.error} ${$}`)),X)if(X instanceof Error)console.log(x.dim(` ${X.stack||X.message}`));else console.log(x.dim(` ${String(X)}`))},warn($){console.log(x.warning(`${Q0.warning} ${$}`))},info($){console.log(x.info(`${Q0.info} ${$}`))},step($,X){console.log(x.secondary(`${Q0.step} ${$}`)+(X?x.dim(` ${X}`):""))},spin($){return Y2({text:$,color:"cyan",spinner:"dots"}).start()},code($){return x.code($)},cmd($){return x.code(`$ ${$}`)},link($,X){return x.url(X||$)},dim($){return x.dim($)},bold($){return l.bold($)},newline(){console.log("")},get printer(){return $1},theme:x,symbols:Q0}});var B1={};Z2(B1,{promptText:()=>O0,promptSelectWithDisabled:()=>k0,promptSelect:()=>S0,promptForConnection:()=>V0,promptFileReview:()=>j0,confirm:()=>K2});import B0 from"prompts";async function V0($){let X=$.embedded,Q=await B0([{type:!X&&!$.url?"text":null,name:"url",message:"Database URL:",initial:"http://localhost:8000"},{type:!X&&!$.username?"text":null,name:"username",message:"Username:",initial:"root"},{type:!X&&!$.password?"password":null,name:"password",message:"Password:"},{type:!X&&!$.authLevel?"select":null,name:"authLevel",message:"Auth level:",choices:[{title:"Root",value:"root"},{title:"Namespace",value:"namespace"},{title:"Database",value:"database"}],initial:0},{type:!$.namespace?"text":null,name:"namespace",message:"Namespace:"},{type:!$.database?"text":null,name:"database",message:"Database:"}],{onCancel:()=>{B.newline(),B.warn("Operation cancelled."),process.exit(0)}});if(X)return{embedded:X==="memory"?"memory":`file://${X}`,namespace:$.namespace||Q.namespace,database:$.database||Q.database};let J=$.url||Q.url,Z=$.username||Q.username,Y=$.password||Q.password,_=$.authLevel||Q.authLevel||"root",G=$.namespace||Q.namespace,j=$.database||Q.database,U;if(_==="database")U={username:Z,password:Y,namespace:G,database:j};else if(_==="namespace")U={username:Z,password:Y,namespace:G};else U={username:Z,password:Y};return{url:J,namespace:G,database:j,authentication:U}}async function K2($,X=!0){return(await B0({type:"confirm",name:"value",message:$,initial:X},{onCancel:()=>{console.log(`
4
+ Operation cancelled.`),process.exit(0)}})).value}async function O0($,X){return(await B0({type:"text",name:"value",message:$,initial:X},{onCancel:()=>{B.newline(),B.warn("Operation cancelled."),process.exit(0)}})).value||""}async function S0($,X){return(await B0({type:"select",name:"value",message:$,choices:X},{onCancel:()=>{console.log(`
5
+ Operation cancelled.`),process.exit(0)}})).value}async function k0($,X){return(await B0({type:"select",name:"value",message:$,choices:X.map((J)=>({title:J.title,value:J.value,disabled:J.disabled}))},{onCancel:()=>{console.log(`
6
+ Operation cancelled.`),process.exit(0)}})).value}async function j0($,X,Q){let Z=(await B0({type:"text",name:"action",message:`[${X}/${Q}] Apply this change? (y)es / (n)o / (a)ccept all / (c)ancel`,validate:(Y)=>{let _=Y.toLowerCase().trim();if(["y","yes","n","no","a","all","c","cancel"].includes(_))return!0;return"Please enter: y/yes, n/no, a/all, or c/cancel"}},{onCancel:()=>{B.newline(),B.warn("Operation cancelled."),process.exit(0)}})).action.toLowerCase().trim();if(Z==="y"||Z==="yes")return"yes";if(Z==="n"||Z==="no")return"no";if(Z==="a"||Z==="all")return"all";if(Z==="c"||Z==="cancel")return"cancel";return"no"}var Y0=N0(()=>{m()});import{Command as g4}from"@commander-js/extra-typings";m();import{Command as G2}from"@commander-js/extra-typings";import g from"prompts";import T from"node:fs/promises";import f from"node:path";import{execSync as J1}from"node:child_process";var __dirname="E:\\GitHub\\unreal-orm\\packages\\unreal-cli\\src\\commands",h=()=>{B.newline(),B.warn("Operation cancelled."),process.exit(0)},Z1=new G2("init").description("Initialize UnrealORM in your project").option("--url <url>","SurrealDB URL").option("-u, --username <username>","Database username").option("-p, --password <password>","Database password").option("-n, --namespace <ns>","Namespace").option("-d, --database <db>","Database").option("-e, --embedded <mode>","Embedded mode (memory or file path)").option("--sample","Generate sample schema tables").option("--from-db","Import schema from existing database").option("--from-surql <file>","Import schema from .surql file").option("--install","Install dependencies automatically").option("--no-install","Skip dependency installation").option("--pm <manager>","Package manager (npm, yarn, pnpm, bun)").action(async($)=>{B.header("\uD83D\uDE80 UnrealORM Setup","Initialize your project with UnrealORM");let X,Q;if($.url)Q="remote";else if($.embedded)Q=$.embedded==="memory"?"memory":"file";else Q=(await g({type:"select",name:"connectionMode",message:"How will you connect to SurrealDB?",choices:[{title:"Remote (URL)",value:"remote",description:"Connect via WebSocket/HTTP"},{title:"Embedded (Memory)",value:"memory",description:"In-memory, great for dev/testing"},{title:"Embedded (File)",value:"file",description:"Persist to local file"}]},{onCancel:h})).connectionMode;if(!Q)B.error("Operation cancelled."),process.exit(1);if(Q==="remote"){let I=$.url||(await g({type:"text",name:"url",message:"SurrealDB URL:",initial:"ws://localhost:8000"},{onCancel:h})).url,E=$.username,w=$.password,P="root";if(!E||!w){let b=await g([{type:$.username?null:"select",name:"authLevel",message:"Authentication level:",choices:[{title:"Root",value:"root"},{title:"Namespace",value:"namespace"},{title:"Database",value:"database"}]},{type:$.username?null:"text",name:"username",message:"Username:",initial:"root"},{type:$.password?null:"password",name:"password",message:"Password:"}],{onCancel:h});E=$.username||b.username,w=$.password||b.password,P=b.authLevel||"root"}let{namespace:F,database:L}=$,N=[];if(!F&&(P!=="root"||!L))N.push({type:"text",name:"namespace",message:"Namespace:",initial:"test"});if(!L)N.push({type:"text",name:"database",message:"Database:",initial:"test"});if(N.length>0){let b=await g(N,{onCancel:h});F=F||b.namespace,L=L||b.database}let v,C=E||"",S=w||"";if(P==="database"&&F&&L)v={username:C,password:S,namespace:F,database:L};else if(P==="namespace"&&F)v={username:C,password:S,namespace:F};else v={username:C,password:S};X={url:I,authentication:v,namespace:F,database:L}}else if(Q==="memory"){let{namespace:I,database:E}=$;if(!I||!E){let w=await g([{type:I?null:"text",name:"namespace",message:"Namespace:",initial:"test"},{type:E?null:"text",name:"database",message:"Database:",initial:"test"}],{onCancel:h});I=I||w.namespace,E=E||w.database}X={embedded:"memory",namespace:I,database:E},B.newline(),B.warn("Note: Embedded mode requires @surrealdb/node package")}else{let I=$.embedded!=="surrealkv"?$.embedded:void 0,E=$.namespace,w=$.database;if(!I)I=(await g({type:"text",name:"path",message:"Database file path:",initial:"./data/local"},{onCancel:h})).path;if(!E||!w){let P=await g([{type:E?null:"text",name:"namespace",message:"Namespace:",initial:"test"},{type:w?null:"text",name:"database",message:"Database:",initial:"test"}],{onCancel:h});E=E||P.namespace,w=w||P.database}X={embedded:I?.startsWith("surrealkv://")?I:`surrealkv://${I}`,namespace:E,database:w},B.newline(),B.warn("Note: Embedded mode requires @surrealdb/node package"),B.newline()}let Z=await T.access(f.join(process.cwd(),"src")).then(()=>!0).catch(()=>!1)?"./src/unreal":"./unreal",_=(await g({type:"text",name:"path",message:"Where should the unreal folder be created?",initial:Z},{onCancel:h})).path||Z,G=f.resolve(process.cwd(),_),j=f.join(G,"tables");await T.mkdir(j,{recursive:!0}),B.success(`Created ${_}/ folder structure`);let U=j2(_);await T.writeFile(f.join(process.cwd(),"unreal.config.json"),JSON.stringify(U,null,"\t")),B.success("Created unreal.config.json");let W=U2(Q);await T.writeFile(f.join(G,"surreal.ts"),W),B.success(`Created ${_}/surreal.ts`);let H=z2(X,Q),q=f.join(process.cwd(),".env"),z=await T.access(q).then(()=>!0).catch(()=>!1);if(B.newline(),z){if((await g({type:"confirm",name:"appendEnv",message:"Append SurrealDB config to existing .env file?",initial:!0},{onCancel:h})).appendEnv)if((await T.readFile(q,"utf-8")).includes("SURREAL_URL"))B.warn(".env already contains SURREAL_* variables, skipping append");else await T.appendFile(q,`
7
+
8
+ ${H}
9
+ `),B.success("Appended SurrealDB config to .env")}else if((await g({type:"confirm",name:"createEnv",message:"Create .env file with SurrealDB config?",initial:!0},{onCancel:h})).createEnv)await T.writeFile(q,`${H}
10
+ `),B.success("Created .env file"),B.info(" Remember to add .env to your .gitignore!");let K=_2(),A=["unreal-orm@alpha","surrealdb@alpha"],D=["@unreal-orm/cli@alpha"];if(Q==="memory"||Q==="file")A.push("@surrealdb/node@alpha");let O=$.install;if(O===void 0){let I=[...A,...D.map((w)=>`${w} (dev)`)],{install:E}=await g({type:"confirm",name:"install",message:`Install dependencies? (${I.join(", ")})`,initial:!0},{onCancel:h});O=E}if(O){let I=$.pm??"";if(!I){let P=[{title:"npm",value:"npm"},{title:"yarn",value:"yarn"},{title:"pnpm",value:"pnpm"},{title:"bun",value:"bun"}],F=P.findIndex((N)=>N.value===K),{pm:L}=await g({type:"select",name:"pm",message:"Package manager:",choices:P,initial:F>=0?F:0},{onCancel:h});I=L??K}let E=X1(I,A,!1);B.newline(),B.info(`Running: ${E}...`);try{J1(E,{stdio:"inherit"})}catch(P){B.error("Failed to install dependencies")}let w=X1(I,D,!0);B.info(`Running: ${w}...`);try{J1(w,{stdio:"inherit"}),B.success("Dependencies installed")}catch(P){B.error("Failed to install dev dependencies")}}let V="none";if($.sample)V="sample";else if($.fromDb)V="from-db";else if($.fromSurql)V="from-surql";else V=(await g({type:"select",name:"action",message:"What would you like to do next?",choices:[{title:"Generate sample tables",value:"sample",description:"User, Post, Follow tables with indexes & relations"},{title:"Import from Database",value:"from-db",description:"Introspect existing DB"},{title:"Import from .surql file",value:"from-surql",description:"Parse SurrealQL file"},{title:"Nothing for now",value:"none"}]},{onCancel:h})).action;if(V==="sample"){let I=f.resolve(__dirname,"../../examples/simple"),E=["User.ts","Post.ts","Follow.ts"];for(let w of E){let P=await T.readFile(f.join(I,w),"utf-8");await T.writeFile(f.join(j,w),P)}B.success("Generated sample tables:"),console.log(B.dim(" • User.ts - Basic user table with indexes")),console.log(B.dim(" • Post.ts - Posts with record links, arrays, and methods")),console.log(B.dim(" • Follow.ts - Relation table (graph edge) example"))}else if(V==="from-db")B.info("Run 'unreal pull' to import schema from database");else if(V==="from-surql")B.info("Run 'unreal pull --file <path>' to import schema");if(B.newline(),(await g({type:"confirm",name:"addImport",message:"Add import to your entry point? (e.g., index.ts, main.ts)",initial:!0},{onCancel:h})).addImport){let I=["src/index.ts","src/main.ts","src/app.ts","index.ts","main.ts","app.ts"],E=null;for(let F of I){let L=f.join(process.cwd(),F);if(await T.access(L).then(()=>!0).catch(()=>!1)){E=F;break}}let P=(await g({type:"text",name:"entryPoint",message:"Entry point file:",initial:E||"src/index.ts"},{onCancel:h})).entryPoint;if(P){let F=f.join(process.cwd(),P),L=await T.access(F).then(()=>!0).catch(()=>!1),N=f.dirname(F),v=f.relative(N,G);if(!v.startsWith("."))v=`./${v}`;v=v.replace(/\\/g,"/");let C=`// Initialize database connection and configure ORM (must be first import)
11
+ import "${v}/surreal";`;if(L){let S=await T.readFile(F,"utf-8");if(S.includes("/surreal"))B.warn("Entry point already imports surreal.ts, skipping");else{let b=`${C}
12
+ ${S}`;await T.writeFile(F,b),B.success(`Added import to ${P}`)}}else{let S=`${C}
13
+
14
+ // Your app code here
15
+ console.log("Hello from UnrealORM!");
16
+ `;await T.mkdir(f.dirname(F),{recursive:!0}),await T.writeFile(F,S),B.success(`Created ${P} with import`)}}}B.header("UnrealORM setup complete!","You are ready to build!"),console.log(B.dim("Project structure:")),console.log(B.dim(" unreal.config.json - Path configuration")),console.log(B.dim(` ${_}/`)),console.log(B.dim(" surreal.ts - Database connection & ORM config")),console.log(B.dim(" tables/ - Table definitions")),B.newline(),console.log(B.dim("Quick start:")),console.log(B.dim(` 1. Import "${_}/surreal" in your entry point`)),console.log(B.dim(" 2. Define tables in tables/ directory")),console.log(B.dim(" 3. Use models: await User.select({ limit: 10 })")),B.newline(),console.log(B.dim("CLI commands:")),console.log(B.dim(" • unreal pull - Import schema from database")),console.log(B.dim(" • unreal push - Apply local schema to database")),console.log(B.dim(" • unreal diff - Compare schemas")),B.newline(),B.warn("⭐ If you find UnrealORM useful, please give us a star on GitHub!"),console.log(B.dim(` https://github.com/Jimpex/unreal-orm
17
+ `))});function _2(){let $=process.env.npm_config_user_agent;if($?.startsWith("bun"))return"bun";if($?.startsWith("pnpm"))return"pnpm";if($?.startsWith("yarn"))return"yarn";return"npm"}function X1($,X,Q){let J=X.join(" "),Z=Q?" -D":"";switch($){case"bun":return`bun add${Z} ${J}`;case"pnpm":return`pnpm add${Z} ${J}`;case"yarn":return`yarn add${Z} ${J}`;default:return`npm install${Q?" --save-dev":""} ${J}`}}function j2($){return{$schema:"./node_modules/unreal-orm/schema.json",path:$}}function z2($,X){let Q=X==="memory"||X==="file",J=["# SurrealDB Connection (generated by UnrealORM)"];if(Q){let Z="embedded"in $?$.embedded:"mem://",Y=Z==="memory"?"mem://":Z;J.push(`SURREAL_URL=${Y}`),J.push(`SURREAL_NS=${$.namespace}`),J.push(`SURREAL_DB=${$.database}`)}else{let Z="url"in $?$.url:"ws://localhost:8000",Y="authentication"in $&&$.authentication&&typeof $.authentication==="object"?$.authentication:null,_=Y&&"username"in Y?Y.username:"",G=Y&&"password"in Y?Y.password:"";J.push(`SURREAL_URL=${Z}`),J.push(`SURREAL_NS=${$.namespace}`),J.push(`SURREAL_DB=${$.database}`),J.push(`SURREAL_USER=${_}`),J.push(`SURREAL_PASS=${G}`)}return J.join(`
18
+ `)}function U2($){let X=$==="memory"||$==="file",Q=X?"Embedded":"Remote",J=X?"mem://, surrealkv://./data":"ws://localhost:8000",Z=["SURREAL_URL","SURREAL_NS","SURREAL_DB"];if(!X)Z.push("SURREAL_USER","SURREAL_PASS");let Y=X?`import { Unreal } from "unreal-orm";
19
+ import { createRemoteEngines, Surreal } from "surrealdb";
20
+ import { createNodeEngines } from "@surrealdb/node";`:`import { Unreal } from "unreal-orm";
21
+ import { Surreal } from "surrealdb";`,_=Z.map((q)=>`const ${q} = process.env.${q};`).join(`
22
+ `),G=Z.join(" || !"),j=Z.join(", "),U=X?`db = new Surreal({
23
+ engines: {
24
+ ...createRemoteEngines(),
25
+ ...createNodeEngines(),
26
+ },
27
+ });`:"db = new Surreal();",W=X?`{
28
+ namespace: SURREAL_NS,
29
+ database: SURREAL_DB,
30
+ }`:`{
31
+ namespace: SURREAL_NS,
32
+ database: SURREAL_DB,
33
+ authentication: {
34
+ username: SURREAL_USER,
35
+ password: SURREAL_PASS,
36
+ },
37
+ }`,H=X?"SURREAL_URL!":"SURREAL_URL";return`/**
38
+ * SurrealDB Client Configuration (${Q} Mode)
39
+ *
40
+ * This file manages your database connection and configures the ORM.
41
+ * Generated by UnrealORM CLI - feel free to customize.
42
+ *
43
+ * ## Setup
44
+ *
45
+ * 1. Import this file once in your app's entry point:
46
+ * \`\`\`ts
47
+ * import "./unreal/surreal";
48
+ * \`\`\`
49
+ *
50
+ * 2. Use ORM models anywhere in your app:
51
+ * \`\`\`ts
52
+ * import { User } from "./unreal/tables/User";
53
+ * const users = await User.select({ limit: 10 });
54
+ * \`\`\`
55
+ *
56
+ * ## Direct Database Access
57
+ *
58
+ * For raw queries or operations not covered by the ORM:
59
+ * \`\`\`ts
60
+ * import { getDatabase } from "./unreal/surreal";
61
+ *
62
+ * const db = await getDatabase();
63
+ * const result = await db.query("SELECT * FROM user WHERE active = true");
64
+ * \`\`\`
65
+ *
66
+ * ## Required Environment Variables
67
+ *
68
+ ${Z.map((q)=>` * - \`${q}\`${q==="SURREAL_URL"?` - Connection URL (e.g., ${J})`:""}`).join(`
69
+ `)}
70
+ *
71
+ * Note: Bun, Vite, and Next.js auto-load .env files.
72
+ * For Node.js, use \`dotenv\` or set variables manually.
73
+ */
74
+
75
+ ${Y}
76
+
77
+ // =============================================================================
78
+ // Environment Configuration
79
+ // =============================================================================
80
+
81
+ ${_}
82
+
83
+ if (!${G}) {
84
+ throw new Error(
85
+ "Missing required SurrealDB environment variables: ${j}\\n" +
86
+ "Make sure your .env file exists and contains these variables."
87
+ );
88
+ }
89
+
90
+ // =============================================================================
91
+ // Database Connection
92
+ // =============================================================================
93
+
94
+ let db: Surreal | null = null;
95
+ let connectionPromise: Promise<Surreal> | null = null;
96
+
97
+ /**
98
+ * Get the database instance, connecting if necessary.
99
+ *
100
+ * This is the recommended way to access the database for direct queries.
101
+ * The connection is lazy-initialized on first call and cached.
102
+ *
103
+ * @example
104
+ * \`\`\`ts
105
+ * const db = await getDatabase();
106
+ * const result = await db.query(surql\`SELECT * FROM user\`);
107
+ * \`\`\`
108
+ */
109
+ export async function getDatabase(): Promise<Surreal> {
110
+ if (db) return db;
111
+ if (connectionPromise) return connectionPromise;
112
+ connectionPromise = connect();
113
+ return connectionPromise;
114
+ }
115
+
116
+ /**
117
+ * Establish the database connection.
118
+ *
119
+ * Prefer using \`getDatabase()\` which handles caching automatically.
120
+ * Use this directly only if you need to force a new connection.
121
+ */
122
+ export async function connect(): Promise<Surreal> {
123
+ if (db) return db;
124
+
125
+ ${U}
126
+
127
+ await db.connect(${H}, ${W});
128
+
129
+ return db;
130
+ }
131
+
132
+ /**
133
+ * Close the database connection.
134
+ *
135
+ * Call this when shutting down your application gracefully.
136
+ */
137
+ export async function close(): Promise<void> {
138
+ if (db) {
139
+ await db.close();
140
+ db = null;
141
+ connectionPromise = null;
142
+ }
143
+ }
144
+
145
+ // =============================================================================
146
+ // ORM Configuration
147
+ // =============================================================================
148
+
149
+ // Configure the ORM to use this database connection.
150
+ // This enables implicit database usage in model methods:
151
+ // await User.select({ limit: 10 }) // No need to pass db
152
+ Unreal.configure({ getDatabase });
153
+ `}import{Command as l2}from"@commander-js/extra-typings";import{existsSync as f0,mkdirSync as r2,writeFileSync as o2,readFileSync as s2,readdirSync as i2,unlinkSync as a2}from"node:fs";import{join as D1}from"node:path";import{Surreal as _1}from"surrealdb";import{existsSync as j1}from"node:fs";import{resolve as C0}from"node:path";m();import{existsSync as Y1,readFileSync as q2}from"node:fs";import{join as E0}from"node:path";import{createJiti as W2}from"jiti";var H2=W2(import.meta.url,{interopDefault:!0});async function T0($){return H2.import($)}async function r($=process.cwd()){let X=E0($,"unreal.config.json"),Q=E0($,"unreal.config.ts");if(Y1(X))try{let J=q2(X,"utf-8");return{path:JSON.parse(J).path||"./unreal"}}catch(J){console.warn("Warning: Found unreal.config.json but failed to load it:",J instanceof Error?J.message:String(J))}if(Y1(Q))try{return{path:(await T0(Q)).default.schema?.output?.replace("/tables","")||"./unreal"}}catch(J){console.warn("Warning: Found unreal.config.ts but failed to load it:",J instanceof Error?J.message:String(J))}return null}function A2($){return E0($.path||"./unreal","tables")}function M0($){return E0($.path||"./unreal","surreal.ts")}function G1(){B.error("No configuration found."),B.info("Please run 'unreal init' to create a configuration file first."),B.newline(),process.exit(1)}async function n($){let{cliOutput:X,config:Q,allowPrompt:J=!0}=$;if(X)return X;if(Q?.path)return B.dim("✓ Loaded configuration from unreal.config.json"),B.newline(),A2(Q);if(Q&&!Q.path)B.warn("Configuration found but 'path' is not set."),B.dim("Tip: Run 'unreal init' to set up your project properly"),B.newline();else if(!Q)B.dim("No configuration found."),B.dim("Tip: Run 'unreal init' to set up a project with saved settings"),B.newline();if(J){let{promptText:Z}=await Promise.resolve().then(() => (Y0(),B1));return await Z("Schema directory path:","./unreal/tables")||"./unreal/tables"}return"./unreal/tables"}Y0();m();async function o($){let{cliOptions:X,config:Q,allowPrompt:J=!0,exitOnFailure:Z=!0,skipAutoConfig:Y=!1}=$;if(X.url||X.username||X.password||X.namespace||X.database||X.authLevel||X.embedded){let G={url:X.url,username:X.username,password:X.password,namespace:X.namespace,database:X.database,authLevel:X.authLevel,embedded:X.embedded},j=await V0(G);return U1(j)}if(Q&&!Y){let G=C0(process.cwd(),M0(Q));if(j1(G))return z1(G)}if(J){let G=Q?j1(C0(process.cwd(),M0(Q))):!1,j=await k0("Connection method:",[{title:G?"Use config (surreal.ts)":"Use config (surreal.ts) - not found",value:"config",disabled:!G},{title:"Enter connection details manually",value:"manual"}]);if(!j)process.exit(0);if(j==="config"&&Q){let W=C0(process.cwd(),M0(Q));return z1(W)}let U=await V0({});return U1(U)}if(Z)G1();return null}async function z1($){let X=B.spin("Loading database client from surreal.ts...");try{try{(await import("dotenv")).config({quiet:!0})}catch{}let Q=await T0($),J;if(Q.getDatabase)J=await Q.getDatabase();else if(Q.connect)J=await Q.connect();else if(Q.default&&typeof Q.default==="object"&&"getDatabase"in Q.default){let Z=Q.default;if(Z.getDatabase)J=await Z.getDatabase()}else if(Q.default)J=Q.default;if(!J)X.fail("surreal.ts must export getDatabase() or connect()"),process.exit(1);return X.succeed("Connected using surreal.ts"),J}catch(Q){X.fail("Failed to load surreal.ts"),B.error(Q instanceof Error?Q.message:String(Q)),B.newline(),B.dim("Tip: You can also provide connection flags directly:"),B.dim(" unreal <command> --url ws://localhost:8000 -u root -p root -n test -d test"),B.newline(),process.exit(1)}}async function U1($){let X;if("embedded"in $)try{let{createNodeEngines:Q}=await import("@surrealdb/node"),J=$.embedded==="memory"?"mem://":$.embedded;X=new _1({engines:Q()}),await X.connect(J,$)}catch(Q){throw Error(`Failed to initialize embedded SurrealDB. Make sure @surrealdb/node is installed and your environment supports native bindings.
154
+ Original Error: ${Q}`)}else X=new _1,await X.connect($.url,$);if($.namespace&&$.database)await X.use({namespace:$.namespace,database:$.database});return X}import{parseFieldDefinition as V2,parseIndexDefinition as O2,parseTableDefinition as E2}from"unreal-orm";function x0($,X){if(!$)throw Error(`${X}: No data returned`);return $}import y0 from"chalk";var D0=[];function i($,X,Q){D0.push({feature:$,reason:X,suggestion:Q})}function t($,X,Q){if($==="field"){if(Q.includes("TYPE object")&&Q.includes("{"))return i(`Field '${X}'`,"Object field with inline schema definition","Object fields are parsed as Field.object({}) - you may need to manually define the schema"),!1;if(Q.includes("TYPE geometry<")){let Z=Q.match(/geometry<(\w+)>/)?.[1];if(Z&&!["point","linestring","polygon","multipoint","multilinestring","multipolygon","collection","feature"].includes(Z.toLowerCase()))i(`Field '${X}'`,`Uncommon geometry type: ${Z}`,"Verify the generated Field.geometry() call is correct")}}if($==="index"){if(Q.includes("MTREE")||Q.includes("HNSW"))return i(`Index '${X}'`,"Vector index (MTREE/HNSW) detected","Vector indexes are not yet fully supported in code generation"),!1;if(Q.includes("SEARCH ANALYZER"))i(`Index '${X}'`,"Search analyzer index detected","Search indexes are parsed but may need manual configuration")}if($==="table"){if(Q.includes("CHANGEFEED"))i(`Table '${X}'`,"Changefeed configuration detected","Changefeeds are not yet supported in code generation")}if($==="event")return i(`Event '${X}'`,"Events/triggers are not yet supported","You'll need to manually create event definitions"),!1;if($==="analyzer")return i(`Analyzer '${X}'`,"Analyzers are not yet supported","Analyzer definitions will be skipped"),!1;if($==="function")return i(`Function '${X}'`,"Custom functions are not yet supported","Function definitions will be skipped"),!1;if($==="param")return i(`Parameter '${X}'`,"Database parameters are not yet supported","Parameter definitions will be skipped"),!1;return!0}function G0(){if(D0.length===0)return;console.log(y0.yellow(`
155
+ ⚠️ Warnings:
156
+ `));for(let $ of D0)if(console.log(y0.yellow(` • ${$.feature}: ${$.reason}`)),$.suggestion)console.log(y0.dim(` → ${$.suggestion}`));console.log()}function R0(){D0.length=0}async function e($){let[X]=await $.query("INFO FOR DB").collect(),Q=x0(X,"Failed to get DB info"),J=Q.tables||{};if(Q.analyzers&&Object.keys(Q.analyzers).length>0)for(let Y of Object.keys(Q.analyzers))t("analyzer",Y,Q.analyzers[Y]||"");if(Q.functions&&Object.keys(Q.functions).length>0)for(let Y of Object.keys(Q.functions))t("function",Y,Q.functions[Y]||"");if(Q.params&&Object.keys(Q.params).length>0)for(let Y of Object.keys(Q.params))t("param",Y,Q.params[Y]||"");let Z=[];for(let Y of Object.keys(J)){let _;try{let[A]=await $.query(`INFO FOR TABLE ${Y}`).collect();_=x0(A,`Failed to get info for table ${Y}`)}catch(A){console.warn(`Failed to get info for table ${Y}:`,A instanceof Error?A.message:String(A));continue}let G=J[Y];if(!G){console.warn(`No DDL found for table ${Y}`);continue}t("table",Y,G);let j=E2(G),U=[],W=_.fields||{};for(let A of Object.keys(W)){let D=W[A];if(D){t("field",A,D);try{U.push(V2(D))}catch(O){console.warn(`Failed to parse field ${A} on table ${Y}`,O)}}}let H=[],q=_.indexes||{};for(let A of Object.keys(q)){let D=q[A];if(D){if(t("index",A,D))try{H.push(O2(D))}catch(V){console.warn(`Failed to parse index ${A} on table ${Y}`,V)}}}let z=[],K=_.events||{};for(let A of Object.keys(K)){let D=K[A];if(D)t("event",A,D)}if(j.name&&j.type)Z.push({name:j.name,type:j.type,drop:j.drop||!1,schemafull:j.schemafull||!1,viewQuery:j.viewQuery,permissions:j.permissions||{},fields:U,indexes:H,events:z})}return{tables:Z}}Y0();import{compareSchemas as C2}from"unreal-orm";function I0($){let X=new Map;for(let Q of $.tables){let J=D2(Q);X.set(`${U0(Q.name)}.ts`,J)}return X}function M2($,X,Q){let J=$.matchAll(/record<(\w+)>/g);for(let Z of J){let Y=Z[1];if(Y&&Y!==X)Q.add(`import { ${U0(Y)} } from './${U0(Y)}';`)}}function D2($){let X=new Set;X.add("import { Table, Field, Index } from 'unreal-orm';"),X.add("import { surql } from 'surrealdb';");for(let Y of $.fields)M2(Y.type,$.name,X);let Q=U0($.name),J=[],Z=`${Array.from(X).join(`
157
+ `)}
158
+
159
+ `;if($.type==="VIEW"){if(Z+=`export class ${Q} extends Table.view({
160
+ `,Z+=` name: "${$.name}",
161
+ `,$.viewQuery)Z+=` as: surql\`${$.viewQuery}\`,
162
+ `;Z+=`}) {}
163
+ `}else if($.type==="RELATION"){if(Z+=`export class ${Q} extends Table.relation({
164
+ `,Z+=` name: "${$.name}",
165
+ `,$.schemafull)Z+=` schemafull: true,
166
+ `;Z+=` fields: {
167
+ `,Z+=K1($.fields," "),Z+=` },
168
+ `,Z+=`}) {}
169
+ `}else{if(Z+=`export class ${Q} extends Table.normal({
170
+ `,Z+=` name: "${$.name}",
171
+ `,$.schemafull)Z+=` schemafull: true,
172
+ `;Z+=` fields: {
173
+ `,Z+=K1($.fields," "),Z+=` },
174
+ `,Z+=`}) {}
175
+ `}if($.indexes.length>0){Z+=`
176
+ `;for(let Y of $.indexes){let G=(Y.name.includes($.name)?Y.name:`${$.name}_${Y.name}`).replace(/[^a-zA-Z0-9_]/g,"_");Z+=P2(Y,Q,G),J.push(G)}}return Z+=`
177
+ export const ${Q}Definitions = [${Q}${J.length>0?`, ${J.join(", ")}`:""}];
178
+ `,Z}function R2($){let X={children:new Map};for(let Q of $){let J=Q.name.split("."),Z=X;for(let Y of J)if(!Z.children.has(Y)){let _={children:new Map};Z.children.set(Y,_),Z=_}else Z=Z.children.get(Y);Z.field=Q}return X}function K1($,X){let Q=$.filter((Z)=>!Z.name.endsWith(".*")),J=R2(Q);return q1(J,X)}function q1($,X){let Q="";for(let[J,Z]of $.children)if(Z.children.size>0){let Y=Z.field?W1(Z.field):"";Q+=`${X}${J}: Field.object({
179
+ `,Q+=q1(Z,`${X} `),Q+=`${X}}${Y?`, ${Y}`:""}),
180
+ `}else if(Z.field)Q+=`${X}${J}: ${I2(Z.field)},
181
+ `;return Q}function W1($){let X=[];if($.default)X.push(`default: surql\`${$.default}\``);if($.value)X.push(`value: surql\`${$.value}\``);if($.assert)X.push(`assert: surql\`${$.assert}\``);return X.length>0?`{ ${X.join(", ")} }`:""}function I2($){let X=W1($),Q=$.type;if(Q.startsWith("option<")){let J=Q.match(/option<(.+)>/)?.[1];if(J)return`Field.option(${z0(J,X||"")})`}if(Q.includes(" | ")){let J=Q.split(" | ").map((Z)=>Z.trim());if(J.includes("none")){let Z=J.filter((Y)=>Y!=="none");if(Z.length===1&&Z[0])return`Field.option(${z0(Z[0],X||"")})`}return`Field.custom('${Q}'${X?`, ${X}`:""}) /* TODO: Specify union type */`}return z0(Q,X||"")}function z0($,X){let Q=X?X:"";if($==="string")return`Field.string(${Q})`;if($==="int")return`Field.int(${Q})`;if($==="float")return`Field.float(${Q})`;if($==="number")return`Field.number(${Q})`;if($==="bool")return`Field.bool(${Q})`;if($==="datetime")return`Field.datetime(${Q})`;if($==="duration")return`Field.duration(${Q})`;if($==="decimal")return`Field.decimal(${Q})`;if($==="uuid")return`Field.uuid(${Q})`;if($==="bytes")return`Field.bytes(${Q})`;if($==="any")return`Field.any(${Q})`;if($.startsWith("array<")){let J=$.slice(6,-1);return`Field.array(${z0(J,"")}${Q?`, ${Q}`:""})`}if($.startsWith("set<")){let J=$.slice(4,-1);return`Field.set(${z0(J,"")}${Q?`, ${Q}`:""})`}if($.startsWith("record<")){let J=$.match(/record<(\w+)>/);if(J?.[1]){let Z=J[1];return`Field.record(() => ${U0(Z)}${Q?`, ${Q}`:""})`}return`Field.record(() => Object${Q?`, ${Q}`:""})`}if($.startsWith("geometry<")){let J=$.match(/geometry<(\w+)>/);if(J?.[1])return`Field.geometry('${J[1]}'${Q?`, ${Q}`:""})`}if($==="geometry")return`Field.geometry('feature'${Q?`, ${Q}`:""})`;if($==="object")return`Field.object({} /* Schema not inferred */${Q?`, ${Q}`:""})`;return`Field.custom('${$}'${Q?`, ${Q}`:""}) /* TODO: Specify type, e.g., Field.custom<YourType>(...) */`}function P2($,X,Q){let J=`export const ${Q} = Index.define(() => ${X}, {
182
+ `;if(J+=` name: "${$.name}",
183
+ `,J+=` fields: [${$.columns.map((Z)=>`"${Z}"`).join(", ")}],
184
+ `,$.unique)J+=` unique: true,
185
+ `;return J+=`});
186
+ `,J}function U0($){return $.split("_").map((X)=>X.charAt(0).toUpperCase()+X.slice(1)).join("")}import{compareSchemas as F2}from"unreal-orm";function H1($,X,Q){let J=w2(X,Q);if(J.length===0)return{content:$,addedFields:[],addedIndexes:[],removedFields:[],removedIndexes:[]};let Z=$,Y=[],_=[],G=[],j=[],U=J.filter((z)=>z.type==="field_added");for(let z of U){if(!z.field)continue;let K=X.fields.find((D)=>D.name===z.field);if(!K)continue;if(K.name.includes("."))continue;if(K.name.includes("[*]"))continue;let A=L2(K);Z=v2(Z,K.name,A),Y.push(K.name)}let W=J.filter((z)=>z.type==="index_added");for(let z of W){if(!z.index)continue;let K=X.indexes.find((O)=>O.name===z.index);if(!K)continue;let A=A1(X.name),D=S2(K,A);Z=N2(Z,K.name,D,A),_.push(K.name)}let H=J.filter((z)=>z.type==="field_removed");for(let z of H){if(!z.field)continue;if(z.field.includes("."))continue;if(z.field.includes("[*]"))continue;Z=k2(Z,z.field),G.push(z.field)}let q=J.filter((z)=>z.type==="index_removed");for(let z of q){if(!z.index)continue;Z=T2(Z,z.index),j.push(z.index)}return{content:Z,addedFields:Y,addedIndexes:_,removedFields:G,removedIndexes:j}}function w2($,X){return F2({tables:[$]},{tables:[X]})}function L2($){let X=[];if($.default)X.push(`default: surql\`${$.default}\``);if($.value)X.push(`value: surql\`${$.value}\``);if($.assert)X.push(`assert: surql\`${$.assert}\``);let Q=X.length>0?`{ ${X.join(", ")} }`:"";return K0($.type,Q)}function K0($,X){let Q=X||"";if($.startsWith("option<")){let J=$.match(/option<(.+)>/)?.[1];if(J)return`Field.option(${K0(J,"")})${Q?`, ${Q}`:""}`}if($.includes(" | ")){let J=$.split(" | ").map((Z)=>Z.trim());if(J.includes("none")){let Z=J.filter((Y)=>Y!=="none");if(Z.length===1&&Z[0])return`Field.option(${K0(Z[0],"")})${Q?`, ${Q}`:""}`}}if($==="string")return`Field.string(${Q})`;if($==="int")return`Field.int(${Q})`;if($==="float")return`Field.float(${Q})`;if($==="number")return`Field.number(${Q})`;if($==="bool")return`Field.bool(${Q})`;if($==="datetime")return`Field.datetime(${Q})`;if($==="duration")return`Field.duration(${Q})`;if($==="decimal")return`Field.decimal(${Q})`;if($==="uuid")return`Field.uuid(${Q})`;if($==="bytes")return`Field.bytes(${Q})`;if($==="any")return`Field.any(${Q})`;if($.startsWith("array<")){let J=$.slice(6,-1);return`Field.array(${K0(J,"")}${Q?`, ${Q}`:""})`}if($.startsWith("set<")){let J=$.slice(4,-1);return`Field.set(${K0(J,"")}${Q?`, ${Q}`:""})`}if($.startsWith("record<")){let J=$.match(/record<(\w+)>/);if(J?.[1]){let Z=J[1];return`Field.record(() => ${A1(Z)}${Q?`, ${Q}`:""})`}}return`Field.custom('${$}'${Q?`, ${Q}`:""})`}function v2($,X,Q){let J=$.match(/fields:\s*\{/);if(!J||J.index===void 0)return $;let Z=J.index+J[0].length,Y=1,_=Z;for(let A=Z;A<$.length&&Y>0;A++){if($[A]==="{")Y++;if($[A]==="}")Y--;if(Y===0){_=A;break}}let G=$.slice(Z,_),j=G.match(/\n(\s+)\w+:/),U=j?j[1]:" ",W=G.trim(),H=W.length>0&&!W.endsWith(","),q=$,z=_;if(H){let A=G.match(/\S\s*$/);if(A&&A.index!==void 0){let D=Z+A.index+1;q=`${$.slice(0,D)},${$.slice(D)}`,z++}}let K=`
187
+ ${U}// Added from database
188
+ ${U}${X}: ${Q},`;return`${q.slice(0,z)}${K}
189
+ ${q.slice(z)}`}function N2($,X,Q,J){let Z=$.match(new RegExp(`export const ${J}Definitions\\s*=`));if(Z&&Z.index!==void 0){let Y=Z.index,_=`// Added from database
190
+ ${Q}
191
+ `,G=$.slice(0,Y)+_+$.slice(Y),j=X.replace(/[^a-zA-Z0-9_]/g,"_");return G=G.replace(new RegExp(`(export const ${J}Definitions\\s*=\\s*\\[${J})([,\\s\\w]*)(\\])`),`$1$2, ${j}$3`),G}return`${$}
192
+ // Added from database
193
+ ${Q}`}function S2($,X){let J=`export const ${$.name.replace(/[^a-zA-Z0-9_]/g,"_")} = Index.define(() => ${X}, {
194
+ `;if(J+=` name: "${$.name}",
195
+ `,J+=` fields: [${$.columns.map((Z)=>`"${Z}"`).join(", ")}],
196
+ `,$.unique)J+=` unique: true,
197
+ `;return J+=`});
198
+ `,J}function k2($,X){let Q=new RegExp(`([ \\t]*)(${b0(X)}\\s*:\\s*(?:Field\\.|\\{))`),J=$.match(Q);if(!J||J.index===void 0)return $;let Z=J[1]??"",Y=J.index+Z.length,_=0,G=0,j=0,U=Y,W=!1,H="",q=!1;for(let O=Y;O<$.length;O++){let V=$[O],R=O>0?$[O-1]:"";if((V==='"'||V==="'"||V==="`")&&R!=="\\"){if(!W&&!q)if(V==="`")q=!0;else W=!0,H=V;else if(q&&V==="`")q=!1;else if(W&&V===H)W=!1;continue}if(W||q)continue;if(V==="(")_++;if(V===")")_--;if(V==="{")G++;if(V==="}")G--;if(V==="[")j++;if(V==="]")j--;if(_===0&&j===0){if(G===0&&V===","){U=O+1;break}if(G===-1&&V==="}"){U=O;while(U>Y&&/\s/.test($[U-1]||""))U--;break}}}let A=$.slice(Y,U).split(`
199
+ `).map((O,V)=>{if(V===0)return`${Z}// ${O}`;let I=O.match(/^(\s*)/)?.[1]??"",E=O.slice(I.length);return`${I}// ${E}`}).join(`
200
+ `),D=`${Z}// Removed from database - uncomment if needed
201
+ `;return $.slice(0,Y)+D+A+$.slice(U)}function T2($,X){let Q=X.replace(/[^a-zA-Z0-9_]/g,"_"),J=new RegExp(`export\\s+const\\s+${b0(Q)}\\s*=\\s*Index\\.define`),Z=$.match(J);if(!Z||Z.index===void 0)return $;let Y=Z.index,_=0,G=0,j=Y,U=!1;for(let D=Y;D<$.length;D++){let O=$[D];if(O==="(")G++,U=!0;if(O===")")G--;if(O==="{")_++;if(O==="}")_--;if(U&&G===0&&_===0){if(j=D+1,$[D+1]===";")j=D+2;break}}let z=`// Removed from database - uncomment if needed
202
+ ${$.slice(Y,j).split(`
203
+ `).map((D)=>{let V=D.match(/^(\s*)/)?.[1]??"",R=D.slice(V.length);return`${V}// ${R}`}).join(`
204
+ `)}`,K=$.slice(0,Y)+z+$.slice(j),A=new RegExp(`,\\s*${b0(Q)}(?=[\\s,\\]])`);return K=K.replace(A,""),K}function b0($){return $.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function A1($){return $.split("_").map((X)=>X.charAt(0).toUpperCase()+X.slice(1)).join("")}import L6 from"chalk";function V1($,X,Q){let J=[],Z=I0($),Y=new Set,_=Q?C2($,Q):[];for(let G of _)Y.add(G.table);for(let[G,j]of Z){let U=X.get(G),W=G.replace(".ts","").toLowerCase();if(!U)J.push({filename:G,type:"create",newContent:j});else if(U!==j)if(Q){if(Y.has(W)){let H=$.tables.find((z)=>z.name===W),q=Q.tables.find((z)=>z.name===W);if(H&&q){let z=H1(U,H,q);J.push({filename:G,type:"update",oldContent:U,newContent:z.content,addedFields:z.addedFields,addedIndexes:z.addedIndexes,removedFields:z.removedFields,removedIndexes:z.removedIndexes})}else J.push({filename:G,type:"update",oldContent:U,newContent:j})}}else J.push({filename:G,type:"update",oldContent:U,newContent:j})}for(let G of X.keys())if(!Z.has(G))J.push({filename:G,type:"delete",oldContent:X.get(G),newContent:""});return J}import{extractTableFromModel as x2,extractIndexFromDefinition as y2,isModelClass as b2,isIndexDefinition as g2}from"unreal-orm";import{readdirSync as f2}from"node:fs";import{join as h2,resolve as m2}from"node:path";import{createJiti as p2}from"jiti";var u2=p2(import.meta.url,{interopDefault:!0});async function $0($){let X=[];for(let Q of f2($).filter((J)=>J.endsWith(".ts"))){let J=m2(h2($,Q));try{let Z=await u2.import(J),Y=new Map,_=[];for(let[,G]of Object.entries(Z))if(b2(G)){let j=x2(G);Y.set(j.name,j)}else if(g2(G)){let{index:j,tableName:U}=y2(G);_.push({index:j,tableName:U})}for(let{index:G,tableName:j}of _){let U=Y.get(j);if(U)U.indexes.push(G)}X.push(...Y.values())}catch(Z){console.warn(`Failed to import ${Q}:`,Z)}}return{tables:X}}import y from"chalk";import{diffLines as O1}from"diff";var g0=3;function E1($,X,Q){let J=[];if(!X){J.push(y.bold.green(`
205
+ +++ ${$} (new file)`)),J.push(y.dim("─".repeat(60)));let _=Q.split(`
206
+ `).slice(0,20);for(let G of _)J.push(y.green(`+ ${G}`));if(Q.split(`
207
+ `).length>20)J.push(y.dim(`... ${Q.split(`
208
+ `).length-20} more lines`));return J.push(y.dim("─".repeat(60))),J.join(`
209
+ `)}J.push(y.bold(`
210
+ --- ${$}`)),J.push(y.bold(`+++ ${$}`)),J.push(y.dim("─".repeat(60)));let Z=O1(X,Q),Y=c2(Z);if(Y.length===0)J.push(y.dim(" (no changes)"));for(let _ of Y){J.push(y.cyan(`@@ -${_.oldStart},${_.oldLines} +${_.newStart},${_.newLines} @@`));for(let G of _.lines)if(G.type==="added")J.push(y.green(`+ ${G.content}`));else if(G.type==="removed")J.push(y.red(`- ${G.content}`));else J.push(y.dim(` ${G.content}`));J.push("")}return J.push(y.dim("─".repeat(60))),J.join(`
211
+ `)}function c2($){return d2($)}function d2($){let X=[],Q=null,J=[],Z=1,Y=1;for(let _ of $){if(!_)continue;let G=_.value.split(`
212
+ `);if(G[G.length-1]==="")G.pop();for(let j of G){let U=_.added?"added":_.removed?"removed":"context";if(J.push({type:U,content:j,oldLine:U!=="added"?Z:void 0,newLine:U!=="removed"?Y:void 0}),U!=="added")Z++;if(U!=="removed")Y++}}for(let _=0;_<J.length;_++){let G=J[_];if(!G)continue;if(G.type==="added"||G.type==="removed"){if(!Q){let j=Math.max(0,_-g0),U=J.slice(j,_),W=U[0],H=W?.oldLine??G.oldLine??1,q=W?.newLine??G.newLine??1;Q={oldStart:H,newStart:q,oldLines:0,newLines:0,lines:[]};for(let z of U)if(z)Q.lines.push({type:"context",content:z.content}),Q.oldLines++,Q.newLines++}if(Q.lines.push({type:G.type,content:G.content}),G.type!=="added")Q.oldLines++;if(G.type!=="removed")Q.newLines++}else if(Q){let j=-1;for(let W=_+1;W<J.length;W++){let H=J[W];if(H&&H.type!=="context"){j=W;break}}if(j!==-1){if(j-_<=g0*2){Q.lines.push({type:"context",content:G.content}),Q.oldLines++,Q.newLines++;continue}}if(Q.lines.slice().reverse().findIndex((W)=>W.type!=="context")<g0)Q.lines.push({type:"context",content:G.content}),Q.oldLines++,Q.newLines++;else X.push(Q),Q=null}}if(Q)X.push(Q);return X}function M1($,X){if(!$)return`New file (${X.split(`
213
+ `).length} lines)`;let Q=O1($,X),J=0,Z=0;for(let _ of Q){let G=_.value.split(`
214
+ `).length-1;if(_.added)J+=G;else if(_.removed)Z+=G}if(J===0&&Z===0)return"No changes";let Y=[];if(J>0)Y.push(y.green(`+${J}`));if(Z>0)Y.push(y.red(`-${Z}`));return Y.join(" ")}m();var R1=new l2().name("pull").description("Introspect database and generate TypeScript schema").option("--url <url>","Database URL (e.g., http://localhost:8000)").option("-u, --username <username>","Database username").option("-p, --password <password>","Database password").option("-n, --namespace <namespace>","Database namespace").option("-d, --database <database>","Database name").option("--auth-level <level>","Auth level: root, namespace, or database").option("-s, --schema-dir <path>","Schema directory path").option("--embedded <mode>","Use embedded mode (memory or file path)").option("-y, --yes","Skip confirmation prompt").action(async($)=>{B.header("UnrealORM Pull","Introspect database and generate schema"),R0();let X=await r(),Q=await n({cliOutput:$.schemaDir,config:X}),J=await o({cliOptions:{url:$.url,username:$.username,password:$.password,namespace:$.namespace,database:$.database,authLevel:$.authLevel,embedded:$.embedded},config:X,skipAutoConfig:!0});if(!J)B.error("Failed to establish database connection."),process.exit(1);let Z=B.spin("Introspecting database schema..."),Y;try{Y=await e(J),Z.succeed(`Found ${Y.tables.length} table(s)`)}catch(z){Z.fail("Failed to introspect database"),B.error(z instanceof Error?z.message:String(z)),await J.close(),process.exit(1)}Z.start("Planning file changes...");let _=new Map;if(f0(Q))try{let z=i2(Q).filter((K)=>K.endsWith(".ts"));for(let K of z){let A=s2(D1(Q,K),"utf-8");_.set(K,A)}}catch(z){}let G;if(f0(Q))try{G=await $0(Q)}catch{}let j;try{j=V1(Y,_,G),Z.succeed("File changes planned")}catch(z){Z.fail("Failed to plan file changes"),B.error(z instanceof Error?z.message:String(z)),await J.close(),process.exit(1)}if(j.length===0)B.success("All files are up to date!"),await J.close(),G0(),process.exit(0);let U=j.filter((z)=>z.type==="create").length,W=j.filter((z)=>z.type==="delete").length,H=j.filter((z)=>z.type==="update").length;if(B.divider(),B.info("FILE CHANGE SUMMARY (Database -> Code)"),B.divider(),B.newline(),B.printer.log(` Total files: ${B.bold(String(j.length))}`),U>0)B.printer.log(` ${B.theme.success("+")} New files: ${U}`);if(W>0)B.printer.log(` ${B.theme.error("-")} Deleted files: ${W}`);if(H>0)B.printer.log(` ${B.theme.warning("~")} Updated files: ${H}`);B.newline();for(let z of j){let K=z.type==="create"?B.theme.success("+"):z.type==="delete"?B.theme.error("-"):B.theme.warning("~");B.printer.log(` ${K} ${z.filename}`)}B.newline();let q=[];if(!$.yes){let z=!1;B.divider(),B.info("FILE REVIEW"),B.divider(),B.newline();for(let K of j){if(!K)continue;if(z){q.push(K);continue}B.printer.clear();let A=K.type==="create"?B.theme.success("CREATE"):K.type==="delete"?B.theme.error("DELETE"):B.theme.warning("UPDATE");B.printer.log(B.bold(`[${j.indexOf(K)+1}/${j.length}] ${A}: ${K.filename}`)),B.printer.log(B.dim(` ${M1(K.oldContent,K.newContent)}`)),B.printer.log(E1(K.filename,K.oldContent,K.newContent));let D=await j0(K.filename,j.indexOf(K)+1,j.length);if(D==="cancel")B.newline(),B.warn("Operation cancelled."),await J.close(),process.exit(0);if(D==="all"){z=!0,q.push(K);for(let O of j.slice(j.indexOf(K)+1))if(O)q.push(O);break}if(D==="yes")q.push(K)}if(B.printer.clear(),q.length===0)B.warn("No files selected. Operation cancelled."),await J.close(),process.exit(0);B.divider(),B.success("APPLYING SELECTED CHANGES"),B.divider(),B.info(`Will apply ${q.length} of ${j.length} file changes`),B.newline()}else B.divider(),B.success("APPLYING ALL CHANGES (--yes flag)"),B.divider(),B.info(`Applying all ${j.length} file changes`),B.newline(),q.push(...j);Z.start("Applying file changes...");try{if(!f0(Q))r2(Q,{recursive:!0});for(let z of q){let K=D1(Q,z.filename);if(z.type==="delete")a2(K);else o2(K,z.newContent,"utf-8")}Z.succeed(`Applied ${q.length} file change(s) to ${Q}`)}catch(z){Z.fail("Failed to apply file changes"),B.error(z instanceof Error?z.message:String(z)),await J.close(),process.exit(1)}await J.close(),G0(),B.header("Schema pull complete!"),B.dim("Changes applied:");for(let z of q){let K=z.type==="create"?"+":z.type==="delete"?"-":"~";console.log(B.dim(` ${K} ${z.filename}`))}B.newline()});import{Command as e2}from"@commander-js/extra-typings";import{existsSync as $4}from"node:fs";Y0();import{compareSchemas as Q4}from"unreal-orm";function p0($,X,Q){return n2($,X,Q)}function n2($,X,Q){let J=X.tables.find((Y)=>Y.name===$.table),Z=Q.tables.find((Y)=>Y.name===$.table);switch($.type){case"table_added":{if(!J)return null;return t2(J)}case"table_removed":return`REMOVE TABLE ${$.table};`;case"table_type_changed":{if(!J)return null;return I1(J,!0)}case"field_added":{if(!J||!$.field)return null;let Y=J.fields.find((_)=>_.name===$.field);if(!Y)return null;return h0($.table,Y)}case"field_removed":return`REMOVE FIELD ${$.field} ON TABLE ${$.table};`;case"field_type_changed":case"field_default_changed":case"field_assertion_changed":{if(!J||!$.field)return null;let Y=J.fields.find((_)=>_.name===$.field);if(!Y)return null;return h0($.table,Y,!0)}case"index_added":{if(!J||!$.index)return null;let Y=J.indexes.find((_)=>_.name===$.index);if(!Y)return null;return m0($.table,Y)}case"index_removed":return`REMOVE INDEX ${$.index} ON TABLE ${$.table};`;case"index_modified":{if(!J||!$.index)return null;let Y=J.indexes.find((_)=>_.name===$.index);if(!Y)return null;return m0($.table,Y,!0)}default:return null}}function t2($){let X=[];X.push(I1($));for(let Q of $.fields){if(Q.name.includes("[*]"))continue;let J=$.type==="RELATION"&&(Q.name==="in"||Q.name==="out");X.push(h0($.name,Q,J))}for(let Q of $.indexes)X.push(m0($.name,Q));return X.join(`
215
+ `)}function I1($,X=!1){let J=[`${X?"DEFINE TABLE OVERWRITE":"DEFINE TABLE"} ${$.name}`];if($.type==="RELATION")J.push("TYPE RELATION");else if($.type==="VIEW"){if(J.push("TYPE ANY"),$.viewQuery)J.push(`AS ${$.viewQuery}`)}if($.schemafull)J.push("SCHEMAFULL");let Z=[];if($.permissions.select)Z.push(`FOR select ${$.permissions.select}`);if($.permissions.create)Z.push(`FOR create ${$.permissions.create}`);if($.permissions.update)Z.push(`FOR update ${$.permissions.update}`);if($.permissions.delete)Z.push(`FOR delete ${$.permissions.delete}`);if(Z.length>0)J.push(`PERMISSIONS ${Z.join(", ")}`);return`${J.join(" ")};`}function h0($,X,Q=!1){let Z=[`${Q?"DEFINE FIELD OVERWRITE":"DEFINE FIELD"} ${X.name} ON TABLE ${$}`];if(X.flex)Z.push("FLEXIBLE");if(X.type)Z.push(`TYPE ${X.type}`);if(X.value)Z.push(`VALUE ${X.value}`);if(X.assert)Z.push(`ASSERT ${X.assert}`);if(X.default)Z.push(`DEFAULT ${X.default}`);let Y=[];if(X.permissions.select)Y.push(`FOR select ${X.permissions.select}`);if(X.permissions.create)Y.push(`FOR create ${X.permissions.create}`);if(X.permissions.update)Y.push(`FOR update ${X.permissions.update}`);if(X.permissions.delete)Y.push(`FOR delete ${X.permissions.delete}`);if(Y.length>0)Z.push(`PERMISSIONS ${Y.join(", ")}`);return`${Z.join(" ")};`}function m0($,X,Q=!1){let Z=[`${Q?"DEFINE INDEX OVERWRITE":"DEFINE INDEX"} ${X.name} ON TABLE ${$}`];if(X.columns&&X.columns.length>0)Z.push(`FIELDS ${X.columns.join(", ")}`);if(X.unique)Z.push("UNIQUE");if(X.search)Z.push("SEARCH ANALYZER");return`${Z.join(" ")};`}m();var P1=new e2().name("push").description("Apply TypeScript schema to database").option("--url <url>","Database URL (e.g., http://localhost:8000)").option("-u, --username <username>","Database username").option("-p, --password <password>","Database password").option("-n, --namespace <namespace>","Database namespace").option("-d, --database <database>","Database name").option("--auth-level <level>","Auth level: root, namespace, or database").option("-s, --schema-dir <path>","Schema directory path").option("--embedded <mode>","Use embedded mode (memory or file path)").option("-y, --yes","Skip confirmation prompt").action(async($)=>{B.header("UnrealORM Push","Apply code schema to database"),R0();let X=await r(),Q=await n({cliOutput:$.schemaDir,config:X});if(!$4(Q))B.error(`Schema directory not found: ${Q}`),B.info("Run 'unreal pull' first to generate schema files."),B.newline(),process.exit(1);let J=await o({cliOptions:{url:$.url,username:$.username,password:$.password,namespace:$.namespace,database:$.database,authLevel:$.authLevel,embedded:$.embedded},config:X,skipAutoConfig:!0});if(!J)B.error("Failed to establish database connection."),process.exit(1);let Z=B.spin("Loading code schema..."),Y;try{Y=await $0(Q),Z.succeed(`Loaded ${Y.tables.length} table(s) from ${Q}`)}catch(z){Z.fail("Failed to load code schema"),B.error(z instanceof Error?z.message:String(z)),process.exit(1)}Z=B.spin("Introspecting database schema...");let _;try{_=await e(J),Z.succeed(`Found ${_.tables.length} table(s) in database`)}catch(z){Z.fail("Failed to introspect database"),B.error(z instanceof Error?z.message:String(z)),await J.close(),process.exit(1)}Z.start("Comparing schemas...");let G=Q4(Y,_,!0);if(Z.succeed("Comparison complete"),G.length===0)B.success("Schemas are identical. Nothing to push."),await J.close(),G0(),process.exit(0);let j=G.filter((z)=>z.type.includes("added")).length,U=G.filter((z)=>z.type.includes("removed")).length,W=G.length-j-U;if(B.divider(),B.info("CHANGE SUMMARY (Code -> Database)"),B.divider(),B.newline(),B.printer.log(` Total changes: ${B.bold(String(G.length))}`),j>0)B.printer.log(` ${B.theme.success("+")} Additions: ${j}`);if(U>0)B.printer.log(` ${B.theme.error("-")} Removals: ${U}`);if(W>0)B.printer.log(` ${B.theme.warning("~")} Modifications: ${W}`);B.newline();for(let z of G){let K=z.type.includes("added")?B.theme.success("+"):z.type.includes("removed")?B.theme.error("-"):B.theme.warning("~");B.printer.log(` ${K} ${z.description}`)}B.newline();let H=[];if(!$.yes){let z=!1;B.divider(),B.info("CHANGE REVIEW"),B.divider(),B.newline();for(let K=0;K<G.length;K++){let A=G[K];if(!A)continue;if(z){H.push(A);continue}B.printer.clear();let D=A.type.includes("added")?B.theme.success("ADD"):A.type.includes("removed")?B.theme.error("REMOVE"):B.theme.warning("MODIFY");B.printer.log(B.bold(`[${K+1}/${G.length}] ${D}: ${A.description}`));let O=p0(A,Y,_);if(O)B.printer.log(B.dim(`
216
+ \uD83D\uDCDD SurrealQL Statement:`)),B.printer.log(B.theme.secondary(` ${O}
217
+ `));else B.printer.log(B.dim(`
218
+ ⚠️ No SurrealQL generated for this change
219
+ `));let V=await j0("this change",K+1,G.length);if(V==="cancel")B.newline(),B.warn("Operation cancelled."),await J.close(),process.exit(0);if(V==="all"){z=!0,H.push(A);for(let R=K+1;R<G.length;R++){let I=G[R];if(I)H.push(I)}break}if(V==="yes")H.push(A)}if(B.printer.clear(),H.length===0)B.warn("No changes selected. Operation cancelled."),await J.close(),process.exit(0);B.divider(),B.success("APPLYING SELECTED CHANGES"),B.divider(),B.info(`Will apply ${H.length} of ${G.length} change(s)`),B.newline()}else B.divider(),B.success("APPLYING ALL CHANGES (--yes flag)"),B.divider(),B.info(`Applying all ${G.length} change(s)`),B.newline(),H.push(...G);let q=[];for(let z of H){let K=p0(z,Y,_);if(K)q.push(K)}Z.start("Applying schema changes...");try{let z=q.flatMap((K)=>K.split(`
220
+ `).filter((A)=>A.trim())).join("");await J.query(`BEGIN;${z}COMMIT;`),Z.succeed("Schema changes applied successfully")}catch(z){Z.fail("Failed to apply schema changes"),B.error(z instanceof Error?z.message:String(z)),await J.close(),process.exit(1)}await J.close(),G0(),B.header("Schema push complete!"),B.dim(`Applied ${H.length} of ${G.length} change(s) to database`),B.newline()});import{Command as X4}from"@commander-js/extra-typings";import{existsSync as u0,readFileSync as Z4,readdirSync as B4}from"node:fs";import{join as Y4}from"node:path";import p from"chalk";function w1($,X=!1){if($.length===0)return p.green("✓ Schemas are identical");let Q=[],J=new Map;for(let Z of $){let Y=J.get(Z.table)||[];Y.push(Z),J.set(Z.table,Y)}for(let[Z,Y]of J){Q.push(p.bold(`
221
+ ${Z}:`));for(let _ of Y){let G=J4(_.type),j=_.description;if(_.type.includes("added"))j=p.green(_.description);else if(_.type.includes("removed"))j=p.red(_.description);else j=p.yellow(_.description);if(Q.push(` ${G} ${j}`),X&&(_.oldValue!==void 0||_.newValue!==void 0)){if(_.oldValue!==void 0)Q.push(p.dim(" Old: ")+p.red(F1(_.oldValue)));if(_.newValue!==void 0)Q.push(p.dim(" New: ")+p.green(F1(_.newValue)))}}}return Q.join(`
222
+ `)}function J4($){if($.includes("added"))return p.green("+");if($.includes("removed"))return p.red("-");return p.yellow("~")}function F1($){if(Array.isArray($))return`[${$.join(", ")}]`;if(typeof $==="object"&&$!==null){if("query"in $&&typeof $.query==="string")return $.query;let X=JSON.stringify($);if(X.length<50)return X;return JSON.stringify($,null,2)}return String($)}m();import{compareSchemas as G4}from"unreal-orm";function _4($,X){let Q={added:[],removed:[],modified:[],unchanged:[]};for(let[J,Z]of $){let Y=Y4(X,J);if(!u0(Y))Q.added.push(J);else{let _=Z4(Y,"utf-8");if(_.trim()!==Z.trim())Q.modified.push({filename:J,databaseContent:Z,codeContent:_});else Q.unchanged.push(J)}}if(u0(X)){let J=B4(X).filter((Z)=>Z.endsWith(".ts"));for(let Z of J)if(!$.has(Z))Q.removed.push(Z)}return Q}function j4($){let X=$.databaseContent.split(`
223
+ `).length,Q=$.codeContent.split(`
224
+ `).length,J=X-Q;if(J>0)return`+${J} lines`;if(J<0)return`${J} lines`;return"content changed"}function z4($){let X={total:$.length,tables:0,fields:0,indexes:0};for(let Q of $)if(Q.type.startsWith("table_"))X.tables++;else if(Q.type.startsWith("field_"))X.fields++;else if(Q.type.startsWith("index_"))X.indexes++;return X}function U4($){let{added:X,removed:Q,modified:J,unchanged:Z}=$;if(B.header("Schema Diff Summary"),X.length>0){console.log(B.theme.success(`+ Added (${X.length}):`));for(let _ of X)console.log(` + ${_}`);B.newline()}if(Q.length>0){console.log(B.theme.error(`- Removed (${Q.length}):`));for(let _ of Q)console.log(` - ${_}`);B.newline()}if(J.length>0){console.log(B.theme.warning(`~ Modified (${J.length}):`));for(let _ of J)console.log(` ~ ${_.filename}`),console.log(B.dim(` Database: from database (${j4(_)})`)),console.log(B.dim(" Code: current file"));B.newline()}if(Z.length>0){console.log(B.theme.dim(`= Unchanged (${Z.length}):`));let _=Z.join(", ");console.log(B.dim(` ${_}`)),B.newline()}if(X.length>0||Q.length>0||J.length>0)console.log(B.bold(`${X.length+Q.length+J.length} file(s) changed, ${Z.length} unchanged`)),B.newline(),B.info('Run "unreal pull" to sync your code schema with the database.');else B.success("Code schema is in sync with database")}var L1=new X4().name("diff").description("Compare TypeScript schema with database schema").option("--url <url>","Database URL (e.g., http://localhost:8000)").option("-u, --username <username>","Database username").option("-p, --password <password>","Database password").option("-n, --namespace <namespace>","Database namespace").option("-d, --database <database>","Database name").option("--auth-level <level>","Auth level: root, namespace, or database").option("-s, --schema-dir <path>","Schema directory path").option("-e, --embedded <mode>","Use embedded mode (memory or file path)").option("--detailed","Show detailed field-level changes").action(async($)=>{try{B.header("UnrealORM Diff","Compare code vs database schema");let X=await r(),Q=await n({cliOutput:$.schemaDir,config:X}),J=await o({cliOptions:{url:$.url,username:$.username,password:$.password,namespace:$.namespace,database:$.database,authLevel:$.authLevel,embedded:$.embedded},config:X,skipAutoConfig:!0});if(!J)B.error("Failed to establish database connection."),process.exit(1);let Z=B.spin("Introspecting database schema"),Y=await e(J);Z.succeed("Introspected database schema");let _=null;if(u0(Q)){let G=B.spin("Parsing code schema");try{_=await $0(Q),G.succeed("Parsed code schema")}catch(j){G.fail("Could not parse code schema"),B.warn(`${j instanceof Error?j.message:String(j)}`),B.dim("Falling back to file-based comparison"),B.newline()}}if(_){let G=G4(Y,_);if(G.length===0){B.success("No schema differences detected. Code and database schemas are in sync."),await J.close();return}let j=z4(G),U=w1(G,$.detailed);B.divider(),B.info("Schema Changes"),B.divider(),B.newline(),console.log(U);let W=[];if(j.fields>0)W.push(B.theme.warning(`${j.fields} field(s)`));if(j.indexes>0)W.push(B.theme.info(`${j.indexes} index(es)`));if(j.tables>0)W.push(B.theme.primary(`${j.tables} table(s)`));if(B.newline(),console.log(B.bold(`${j.total} change(s): ${W.join(", ")}`)),!$.detailed&&j.total>0)B.newline(),B.dim("Tip: Use --detailed flag to see old/new values for changes");B.newline(),console.log(B.theme.secondary("Run"),B.bold("unreal pull"),B.theme.secondary("or"),B.bold("unreal push"),B.theme.secondary("to sync your code schema with the database.")),B.newline()}else{let G=I0(Y),j=_4(G,Q);U4(j)}await J.close()}catch(X){B.error("Error:",X),process.exit(1)}});import{Command as V4}from"@commander-js/extra-typings";import{promises as O4,existsSync as E4}from"node:fs";import c0 from"node:path";import{promises as K4}from"node:fs";import{parseTableDefinition as q4,parseFieldDefinition as W4,parseIndexDefinition as H4}from"unreal-orm";var N1={};function v1($){return{name:$,type:"NORMAL",schemafull:!0,drop:!1,permissions:N1,fields:[],indexes:[],events:[]}}async function S1($){let X=await K4.readFile($,"utf-8");return A4(X)}function A4($){let X=new Map,Q=$.split(";").map((J)=>J.trim()).filter((J)=>J.length>0);for(let J of Q){let Z=J.replace(/\s+/g," ").trim();if(Z.toUpperCase().startsWith("DEFINE TABLE")){let Y=q4(J);if(Y.name)X.set(Y.name,{name:Y.name,type:Y.type??"NORMAL",schemafull:Y.schemafull??!0,drop:Y.drop??!1,permissions:Y.permissions??N1,viewQuery:Y.viewQuery,fields:[],indexes:[],events:[]})}else if(Z.toUpperCase().startsWith("DEFINE FIELD")){let Y=W4(J),_=J.match(/ON\s+(?:TABLE\s+)?(\w+)/i);if(_?.[1]){let G=_[1],j=X.get(G);if(!j)j=v1(G),X.set(G,j);j.fields.push(Y)}}else if(Z.toUpperCase().startsWith("DEFINE INDEX")){let Y=H4(J),_=J.match(/ON\s+(?:TABLE\s+)?(\w+)/i);if(_?.[1]){let G=_[1],j=X.get(G);if(!j)j=v1(G),X.set(G,j);j.indexes.push(Y)}}}return{tables:Array.from(X.values())}}Y0();m();var T1=new V4("mermaid").description("Generate a Mermaid ERD diagram from TypeScript schema, database, or .surql file").option("-o, --output <path>","Output file path for .mermaid file").option("-s, --schema-dir <path>","Schema directory path (for --code mode)").option("-c, --config <path>","Path to config file").option("--stdout","Print to stdout instead of file").option("--code","Use TypeScript schema definitions").option("--db","Use database connection (introspect live database)").option("--surql <path>","Use a .surql schema file").option("--url <url>","Database URL (implies --db)").option("-u, --username <username>","Database username").option("-p, --password <password>","Database password").option("-n, --namespace <namespace>","Database namespace").option("-d, --database <database>","Database name").option("--auth-level <level>","Auth level: root, namespace, or database").option("--embedded <mode>","Use embedded mode (memory or file path)").action(async($)=>{B.header("Mermaid ERD Generator","Visualize your schema");let X=B.spin("Loading configuration...");try{let Q=await r($.config);if(Q)X.succeed("Configuration loaded");else X.info("No configuration file found (using defaults/flags)");let J=$.output;if(!J&&!$.stdout)X.stop(),J=await O0("Output file path:",Q?c0.join(Q.path,"schema.mermaid"):"./unreal/schema.mermaid");let Z=$.url||$.username||$.password||$.namespace||$.database||$.embedded,Y;if($.surql)Y="surql";else if($.db||Z)Y="database";else if($.code)Y="code";if(!Y){if(X.stop(),Y=await S0("Schema source:",[{title:"TypeScript schema (./unreal/tables/)",value:"code"},{title:"Database (introspect live database)",value:"database"},{title:"SurrealQL file (.surql)",value:"surql"}]),!Y)process.exit(0)}let _;if(Y==="code"){X.stop();let j=await n({cliOutput:$.schemaDir,config:Q});X.start(`Extracting schema from ${j}...`),_=await $0(j),X.succeed(`Found ${_.tables.length} tables from TypeScript schema`)}else if(Y==="database"){X.stop();let j=await o({cliOptions:{url:$.url,username:$.username,password:$.password,namespace:$.namespace,database:$.database,authLevel:$.authLevel,embedded:$.embedded},config:Q,skipAutoConfig:!0});if(!j)B.error("Failed to establish database connection."),process.exit(1);X.start("Introspecting database schema...");try{_=await e(j),X.succeed(`Found ${_.tables.length} tables from database`)}finally{await j.close()}}else{let j=typeof $.surql==="string"?$.surql:"";if(!j)X.stop(),j=await O0("Path to .surql file:","./schema.surql");let U=c0.resolve(process.cwd(),j);if(!E4(U))X.fail(`File not found: ${U}`),process.exit(1);X.start(`Parsing ${j}...`),_=await S1(U),X.succeed(`Found ${_.tables.length} tables from .surql file`)}X.start("Generating Mermaid diagram...");let G=M4(_);if(X.succeed("Diagram generated"),$.stdout)console.log(`
225
+ ${G}`);else{let j=c0.resolve(process.cwd(),J||"./unreal/schema.mermaid");await O4.writeFile(j,G),B.success(`Saved to ${j}`),B.dim(`Tip: Preview with VS Code Mermaid extension,
226
+ https://mermiko.com, or https://mermaid.live`)}}catch(Q){X.fail("Failed to generate diagram"),B.error(Q instanceof Error?Q.message:String(Q)),process.exit(1)}});function M4($){let X=["erDiagram"],Q=$.tables.filter((G)=>G.type==="NORMAL"),J=$.tables.filter((G)=>G.type==="RELATION"),Z=$.tables.filter((G)=>G.type==="VIEW"),Y=[],_=new Map;for(let G of $.tables){let j=new Set;for(let U of G.indexes){let W=U.columns[0];if(U.unique&&U.columns.length===1&&W)j.add(W)}if(j.size>0&&G.name)_.set(G.name,j)}if(Q.length>0){X.push(" %% === TABLES ===");for(let G of Q){let j=k1(G,_);X.push(...j.lines),Y.push(...j.relationships)}}if(J.length>0){X.push(" %% === RELATIONS (Graph Edges) ===");for(let G of J){let j=D4(G,_);X.push(...j.lines),Y.push(...j.relationships)}}if(Z.length>0){X.push(" %% === VIEWS ===");for(let G of Z){let j=k1(G,_);X.push(...j.lines)}}if(Y.length>0)X.push(""),X.push(" %% === RELATIONSHIPS ==="),X.push(...Y);return X.join(`
227
+ `)}function k1($,X){let Q=[],J=[],Z=$.fields.filter((G)=>!G.name.includes(".")&&!G.name.includes("[")),Y=u($.name),_=X.get($.name)??new Set;Q.push(` ${Y} {`);for(let G of Z){let j=q0(G.type),U=u(G.name),W=C1(G,_),q=G.name==="id"||G.assert?.includes("!= NONE")?`*${U}`:U,z=` ${j} ${q}`;if(W)z+=` ${W}`;Q.push(z);let K=G.type.match(/^record<(\w+)>$/);if(K?.[1]){let A=u(K[1]),D=G.assert?.includes("!= NONE"),O=_.has(G.name),V=D?"--":"..",E=`${O?"|":"}"}${D?"|":"o"}`,w="||";J.push(` ${Y} ${E}${V}|| ${A} : "${G.name}"`)}}return Q.push(" }"),Q.push(""),{lines:Q,relationships:J}}function D4($,X){let Q=[],J=[],Z=u($.name),Y=X.get($.name)??new Set,_=$.fields.find((H)=>H.name==="in"),G=$.fields.find((H)=>H.name==="out"),j=_?.type.match(/^record<(\w+)>$/)?.[1],U=G?.type.match(/^record<(\w+)>$/)?.[1],W=$.fields.filter((H)=>H.name!=="in"&&H.name!=="out"&&!H.name.includes(".")&&!H.name.includes("["));if(W.length===0){if(j&&U){let H=u(j),q=u(U);J.push(` ${H} }|--|{ ${q} : "${$.name}"`)}return{lines:[],relationships:J}}if(Q.push(` ${Z} {`),_&&j)Q.push(` ${u(j)} *in FK`);if(G&&U)Q.push(` ${u(U)} *out FK`);for(let H of W){let q=q0(H.type),z=u(H.name),K=C1(H,Y),D=H.name==="id"||H.assert?.includes("!= NONE")?`*${z}`:z,O=` ${q} ${D}`;if(K)O+=` ${K}`;Q.push(O)}if(Q.push(" }"),Q.push(""),j&&U){let H=u(j),q=u(U);J.push(` ${H} ||--o{ ${Z} : "in"`),J.push(` ${Z} }o--|| ${q} : "out"`)}return{lines:Q,relationships:J}}function u($){return $.replace(/[^a-zA-Z0-9_]/g,"_")}function q0($){if($.startsWith("record<"))return"record";if($==="record")return"record";if($.startsWith("array<")){let Q=$.slice(6,-1);return`array_${q0(Q)}`}if($==="array")return"array";if($.startsWith("option<")){let Q=$.slice(7,-1);return q0(Q)}if($.startsWith("set<")){let Q=$.slice(4,-1);return`set_${q0(Q)}`}if($.startsWith("geometry<"))return`geo_${$.slice(9,-1)}`;if($.startsWith("range<"))return"range";if($.includes("|"))return"enum";return{string:"string",int:"int",float:"float",bool:"bool",datetime:"datetime",duration:"duration",decimal:"decimal",number:"number",object:"object",array:"array",any:"any",bytes:"bytes",uuid:"uuid",ulid:"ulid",geometry:"geometry",point:"point",line:"line",polygon:"polygon",multipoint:"multipoint",multiline:"multiline",multipolygon:"multipolygon",collection:"collection",null:"null",none:"none"}[$]||$}function C1($,X){let Q=[];if($.name==="id")Q.push("PK");if($.type.startsWith("record<"))Q.push("FK");if(X.has($.name))Q.push("UK");return Q.join(",")}m();import{Command as R4}from"@commander-js/extra-typings";var x1="https://github.com/Jimpex/unreal-orm",y1=new R4("github").description("Open the UnrealORM GitHub repository").action(async()=>{let{exec:$}=await import("node:child_process"),{platform:X}=await import("node:os"),Q=X()==="win32"?"start":X()==="darwin"?"open":"xdg-open";$(`${Q} ${x1}`,(J)=>{if(J)B.info(`Visit: ${x1}`)})});m();import{Command as I4}from"@commander-js/extra-typings";var b1="https://unreal-orm.jimpex.dev",g1=new I4("docs").description("Open the UnrealORM documentation").action(async()=>{let{exec:$}=await import("node:child_process"),{platform:X}=await import("node:os"),Q=X()==="win32"?"start":X()==="darwin"?"open":"xdg-open";$(`${Q} ${b1}`,(J)=>{if(J)B.info(`Visit: ${b1}`)})});import{Command as S4}from"@commander-js/extra-typings";m();var f1="\x1B[?25l",d0="\x1B[?25h";function h1(){process.stdout.write("\x1B[?1049h\x1B[?7l\x1B[H\x1B[J")}function l0(){process.stdout.write("\x1B[?7h\x1B[?1049l")}function c(){let $=process.stdout.rows||24;process.stdout.write(`\x1B[1;${$}r\x1B[H\x1B[J`)}function J0(){let $=process.stdout.rows||24;process.stdout.write(`\x1B[1;${$}r\x1B[H\x1B[J`)}async function d(){return new Promise(($)=>{let X=process.stdin,Q=X.isRaw;X.setRawMode(!0),X.resume(),X.setEncoding("utf8");let J=(Z)=>{if(X.setRawMode(Q),X.pause(),X.removeListener("data",J),Z==="\x03")process.stdout.write("\x1B[?25h"),process.exit(0);$(Z)};X.once("data",J)})}var r0="\x1BCANCEL";async function P0($,X=""){process.stdout.write("\x1B[?25h"),process.stdout.write($);let Q=X;if(X)process.stdout.write(X);return new Promise((J)=>{let Z=process.stdin;Z.setRawMode(!0),Z.resume(),Z.setEncoding("utf8");let Y=(_)=>{if(_==="\x03")process.stdout.write("\x1B[?25h"),process.exit(0);if(_==="\r"||_===`
228
+ `)Z.setRawMode(!1),Z.pause(),Z.removeListener("data",Y),process.stdout.write(`
229
+ `),process.stdout.write("\x1B[?25l"),J(Q);else if(_==="\x1B")Z.setRawMode(!1),Z.pause(),Z.removeListener("data",Y),process.stdout.write(`
230
+ `),process.stdout.write("\x1B[?25l"),J(r0);else if(_===""||_==="\b"){if(Q.length>0)Q=Q.slice(0,-1),process.stdout.write("\b \b")}else if(_>=" "&&_<="~")Q+=_,process.stdout.write(_)};Z.on("data",Y)})}function F0($){return $===r0}async function w0($,X){let Q=$.split(`
231
+ `),J=0,Z=0,Y=0,_=-1,G=process.stdout.rows||24,j=process.stdout.columns||80,U=G-6,W=3,H=(O,V)=>{process.stdout.write(`\x1B[${O};${V}H`)},q=(O,V)=>{H(O,1),process.stdout.write(`\x1B[2K${V}`)},z=()=>{J0(),console.log(` \x1B[1m${X.title}\x1B[0m`),console.log(` \x1B[90m${X.subtitle}\x1B[0m`),console.log(`\x1B[90m${"─".repeat(Math.min(j,80))}\x1B[0m`);let O=Math.min(Y+U,Q.length);for(let V=Y;V<O;V++)K(V);for(let V=O-Y;V<U;V++)console.log("\x1B[90m ~\x1B[0m");D(),_=Y},K=(O)=>{let V=Q[O]??"",R=String(O+1).padStart(3," "),I=O===J,E=V;if(E.length>j-8)E=`${E.slice(0,j-11)}...`;if(I){let w=E.slice(0,Z),P=E[Z]??" ",F=E.slice(Z+1);console.log(`\x1B[90m${R}\x1B[0m \x1B[36m${w}\x1B[7m${P}\x1B[0m${F}`)}else console.log(`\x1B[90m${R}\x1B[0m ${E}`)},A=(O)=>{let V=Y;if(J<Y)Y=J;else if(J>=Y+U)Y=J-U+1;if(Y!==V||Y!==_){z();return}if(O!==void 0&&O!==J&&O>=Y&&O<Y+U){let N=W+1+(O-Y),v=Q[O]??"",C=String(O+1).padStart(3," "),S=v;if(S.length>j-8)S=`${S.slice(0,j-11)}...`;q(N,`\x1B[90m${C}\x1B[0m ${S}`)}let R=W+1+(J-Y),I=Q[J]??"",E=String(J+1).padStart(3," "),w=I;if(w.length>j-8)w=`${w.slice(0,j-11)}...`;let P=w.slice(0,Z),F=w[Z]??" ",L=w.slice(Z+1);q(R,`\x1B[90m${E}\x1B[0m \x1B[36m${P}\x1B[7m${F}\x1B[0m${L}`),D()},D=()=>{let O=W+U+1,V=Math.min(Y+U,Q.length),R=`Ln ${J+1}, Col ${Z+1}`,I=Q.length>U?` | ${Y+1}-${V}/${Q.length}`:"";q(O,`\x1B[90m ${R}${I} | Ctrl+S save | Esc cancel\x1B[0m`)};return process.stdout.write("\x1B[?25h"),z(),new Promise((O)=>{let V=process.stdin;V.setRawMode(!0),V.resume(),V.setEncoding("utf8");let R=(E)=>{V.setRawMode(!1),V.pause(),V.removeListener("data",I),process.stdout.write("\x1B[?25l"),O(E)},I=(E)=>{let w=J,P=Q[J]??"",F=!1;if(E==="\x03")process.stdout.write("\x1B[?25h"),process.exit(0);if(E==="\x13"){R(Q.join(`
232
+ `));return}if(E==="\x1B"&&E.length===1){R(r0);return}if(E==="\x1B[A"){if(J>0)J--,Z=Math.min(Z,(Q[J]??"").length)}else if(E==="\x1B[B"){if(J<Q.length-1)J++,Z=Math.min(Z,(Q[J]??"").length)}else if(E==="\x1B[C"){if(Z<P.length)Z++;else if(J<Q.length-1)J++,Z=0}else if(E==="\x1B[D"){if(Z>0)Z--;else if(J>0)J--,Z=(Q[J]??"").length}else if(E==="\x1B[H"||E==="\x1B[1~")Z=0;else if(E==="\x1B[F"||E==="\x1B[4~")Z=P.length;else if(E==="\x1B[5~")J=Math.max(0,J-U),Z=Math.min(Z,(Q[J]??"").length);else if(E==="\x1B[6~")J=Math.min(Q.length-1,J+U),Z=Math.min(Z,(Q[J]??"").length);else if(E==="\r"||E===`
233
+ `){let L=P.slice(0,Z),N=P.slice(Z);Q[J]=L,Q.splice(J+1,0,N),J++,Z=0,F=!0}else if(E===""||E==="\b"){if(Z>0)Q[J]=P.slice(0,Z-1)+P.slice(Z),Z--;else if(J>0){let L=Q[J-1]??"";Z=L.length,Q[J-1]=L+P,Q.splice(J,1),J--,F=!0}}else if(E==="\x1B[3~"){if(Z<P.length)Q[J]=P.slice(0,Z)+P.slice(Z+1);else if(J<Q.length-1)Q[J]=`${P}${Q[J+1]??""}`,Q.splice(J+1,1),F=!0}else if(E==="\t")Q[J]=`${P.slice(0,Z)} ${P.slice(Z)}`,Z+=2;else if(E.length===1&&E>=" "&&E<="~")Q[J]=`${P.slice(0,Z)}${E}${P.slice(Z)}`,Z++;if(F)z();else A(w)};V.on("data",I)})}import _0 from"chalk";var M={primary:_0.hex("#FF00A0"),dim:_0.gray,highlight:_0.cyan,success:_0.green,warning:_0.yellow,error:_0.red},k={topLeft:"┌",topRight:"┐",bottomLeft:"└",bottomRight:"┘",horizontal:"─",vertical:"│",teeRight:"├",teeLeft:"┤",teeDown:"┬",teeUp:"┴",cross:"┼"};import P4 from"chalk";function s($,X){let Q=Math.min(process.stdout.columns||80,80);if(console.log(M.primary.bold(` ${$}`)),X)console.log(M.dim(` ${X}`));console.log(M.dim(k.horizontal.repeat(Q)))}function p1($,X,Q,J){console.log(M.dim(` ${k.topLeft}${Q.map((Y)=>k.horizontal.repeat(Y)).join(k.teeDown)}${k.topRight}`));let Z=$.map((Y,_)=>m1(Y,Q[_]??10)).join(M.dim(k.vertical));console.log(`${M.dim(` ${k.vertical}`)}${P4.bold(Z)}${M.dim(k.vertical)}`),console.log(M.dim(` ${k.teeRight}${Q.map((Y)=>k.horizontal.repeat(Y)).join(k.cross)}${k.teeLeft}`));for(let Y=0;Y<X.length;Y++){let _=X[Y];if(!_)continue;let j=Y===J?M.primary("▸ "):" ",U=_.map((W,H)=>m1(W,Q[H]??10)).join(M.dim(k.vertical));console.log(`${j}${M.dim(k.vertical)}${U}${M.dim(k.vertical)}`)}console.log(M.dim(` ${k.bottomLeft}${Q.map((Y)=>k.horizontal.repeat(Y)).join(k.teeUp)}${k.bottomRight}`))}function m1($,X){let Q=L0($);if(Q.length>=X)return`${F4($,X-1)}…`;return $+" ".repeat(X-Q.length)}function F4($,X){let Q=0,J=0,Z=/\x1b\[[0-9;]*m/g;while(J<$.length&&Q<X){Z.lastIndex=J;let _=Z.exec($);if(_&&_.index===J)J=Z.lastIndex;else Q++,J++}let Y=$.slice(0,J);if($.includes("\x1B[")&&!Y.endsWith("\x1B[0m"))return`${Y}\x1B[0m`;return Y}function L0($){return $.replace(/\x1b\[[0-9;]*m/g,"")}async function W0($){c(),s("Confirm",""),console.log(""),console.log(M.warning(` ${$}`)),console.log(""),console.log(M.dim(" y yes • n no"));let X=await d();return X==="y"||X==="Y"}async function u1($,X){return c(),s("Confirm Action",""),console.log(""),console.log(M.warning(` ${$}`)),console.log(""),await P0(" > ")===X}async function H0($){c(),s("Error",""),console.log(""),console.log(M.error(` ${$}`)),console.log(""),console.log(M.dim(" Press any key to continue...")),await d()}async function c1($){c(),s("Success",""),console.log(""),console.log(M.success(` ${$}`)),console.log(""),console.log(M.dim(" Press any key to continue...")),await d()}function l1($){if($==="timeout")return M.warning("timeout");if($==="?")return M.dim("?");if($>=1e6)return M.highlight(`${($/1e6).toFixed(1)}M`);if($>=1000)return M.highlight(`${($/1000).toFixed(1)}K`);return M.highlight(String($))}function A0($,X=40){if($===void 0||$===null)return M.dim("null");if(Array.isArray($)){if($.length===0)return M.dim("[]");if($.length<=5){let Z=`[${$.map((Y)=>d1(Y)).join(", ")}]`;if(Z.length>X)return M.dim(`[${$.length} items]`);return M.dim(Z)}return M.dim(`[${$.length} items]`)}if(typeof $==="object"){let J=String($);if(J!=="[object Object]"){if(J.length>X)return M.dim(`${J.slice(0,X-3)}...`);return M.dim(J)}let Z=Object.keys($);if(Z.length===0)try{let Y=JSON.stringify($);if(Y.length>X)return M.dim(`${Y.slice(0,X-3)}...`);return M.dim(Y)}catch{return M.dim("{}")}if(Z.length<=5){let _=`{${Z.map((G)=>`${G}: ${d1($[G])}`).join(", ")}}`;if(_.length>X)return M.dim(`{${Z.length} fields}`);return M.dim(_)}return M.dim(`{${Z.length} fields}`)}if(typeof $==="boolean")return $?M.success("true"):M.error("false");if(typeof $==="number")return M.highlight(String($));let Q=String($).replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t");if(Q.length>X)return`${Q.slice(0,X-3)}...`;return Q}function d1($){if($===void 0||$===null)return"null";if(Array.isArray($))return`[${$.length}]`;if(typeof $==="object"){let X=String($);if(X!=="[object Object]"){if(X.length>15)return`${X.slice(0,12)}...`;return X}let Q=Object.keys($);if(Q.length===0)try{let J=JSON.stringify($);if(J.length>15)return`${J.slice(0,12)}...`;return J}catch{return"{}"}return`{${Q.length}}`}if(typeof $==="string"){let X=$.replace(/\n/g,"\\n");if(X.length>15)return`"${X.slice(0,12)}..."`;return`"${X}"`}return String($)}function o0($){if(!$)return"";try{return JSON.parse($)}catch{if($==="true")return!0;if($==="false")return!1;if($==="null")return null;let X=Number($);if(!Number.isNaN(X)&&$.trim()!=="")return X;return $}}async function r1($,X,Q){let J=Q.id?String(Q.id):"unknown",Z=0,Y={...Q},_={...Q},G=[],j=()=>Object.keys(_).sort((q,z)=>{if(q==="id")return-1;if(z==="id")return 1;return q.localeCompare(z)}),U=(q)=>{for(let z of G){if(z.type==="add"&&z.key===q)return"added";if(z.type==="edit"&&z.key===q)return"edited";if(z.type==="remove"&&z.key===q)return"removed"}return null},W=()=>G.length>0,H=(q=!1)=>{if(q)c();else J0();let z=process.stdout.rows||24,K=process.stdout.columns||80,A=Math.max(3,z-5),D=G.length,O=D>0?`${D} changes • s save • x discard`:X;s(`Record: ${J}`,O);let V=j(),R=Math.min(Math.max(...V.map((F)=>F.length),8),20),I=K-R-6,E=0;if(Z>=A)E=Z-A+1;let w=Math.min(E+A,V.length);for(let F=E;F<w;F++){let L=V[F];if(!L)continue;let N=_[L],v=F===Z,C=U(L),S=v?M.primary("▸ "):" ",b;if(C==="added")b=M.success(`+ ${L.slice(0,R-2).padEnd(R-2)}`);else if(C==="edited")b=M.warning(`~ ${L.slice(0,R-2).padEnd(R-2)}`);else if(C==="removed")b=M.error(`- ${L.slice(0,R-2).padEnd(R-2)}`);else if(v)b=M.primary.bold(L.slice(0,R).padEnd(R));else b=M.highlight(L.slice(0,R).padEnd(R));let e1=A0(N,I);console.log(`${S}${b} ${e1}`)}let P=V.length>A?`${E+1}-${w}/${V.length} • `:"";console.log(M.dim(` ${P}↑↓ nav • e edit • + add • - del • d delete • b back • q quit`))};H(!0);while(!0){let q=await d(),z=j();if(q==="q"){if(W()){if(!await W0("Discard unsaved changes?")){H();continue}}throw Error("EXIT")}if(q==="b"||q==="\x1B"){if(W()){if(!await W0("Discard unsaved changes?")){H();continue}}return"back"}if(q==="\x1B[A"||q==="k")Z=Math.max(0,Z-1),H();else if(q==="\x1B[B"||q==="j")Z=Math.min(z.length-1,Z+1),H();else if(q==="e"||q==="\r"||q===`
234
+ `){let K=z[Z];if(K&&K!=="id"){let A=_[K],D=await w4(K,A);if(D!==void 0){let O=Y[K];if(JSON.stringify(D)!==JSON.stringify(O)){let V=G.findIndex((R)=>R.type==="edit"&&R.key===K);if(V>=0)G.splice(V,1);G.push({type:"edit",key:K,oldValue:O,newValue:D})}else{let V=G.findIndex((R)=>R.type==="edit"&&R.key===K);if(V>=0)G.splice(V,1)}_[K]=D}H()}else if(K==="id")await H0("Cannot edit the id field"),H()}else if(q==="+"||q==="="){let K=await L4();if(K)_[K.key]=K.value,G.push({type:"add",key:K.key,value:K.value});H()}else if(q==="-"||q==="_"){let K=z[Z];if(K&&K!=="id"){if(U(K)==="added"){let D=G.findIndex((O)=>O.type==="add"&&O.key===K);if(D>=0)G.splice(D,1);delete _[K]}else G.push({type:"remove",key:K,oldValue:Y[K]}),delete _[K];Z=Math.min(Z,z.length-2),H()}else if(K==="id")await H0("Cannot remove the id field"),H()}else if(q==="u"||q==="U"){let K=G.pop();if(K){if(K.type==="edit")_[K.key]=K.oldValue;else if(K.type==="add")delete _[K.key];else if(K.type==="remove")_[K.key]=K.oldValue}H()}else if(q==="x"||q==="X"){if(W()){if(await W0("Discard all changes?")){G.length=0;for(let A of Object.keys(_))delete _[A];Object.assign(_,Y)}H()}}else if(q==="s"||q==="S"){if(W()){if(await W0(`Save ${G.length} change${G.length>1?"s":""}?`))try{let A=[],D=[],O={};for(let R of G)if(R.type==="edit"||R.type==="add"){let I=`p_${R.key.replace(/[^a-zA-Z0-9]/g,"_")}`;A.push(`\`${R.key}\` = $${I}`),O[I]=R.type==="edit"?R.newValue:R.value}else if(R.type==="remove")D.push(`\`${R.key}\``);let V=`UPDATE ${J}`;if(A.length>0)V+=` SET ${A.join(", ")}`;if(D.length>0)V+=` UNSET ${D.join(", ")}`;V+=` TIMEOUT ${$.timeout}s`,await $.db.query(V,O).collect(),G.length=0;for(let R of Object.keys(Y))delete Y[R];Object.assign(Y,_),await c1("Changes saved successfully")}catch(A){await H0(`Failed to save: ${A instanceof Error?A.message:String(A)}`)}H()}}else if(q==="d"||q==="D")if(await u1(`Delete record ${J}? Type "delete" to confirm:`,"delete"))try{return await $.db.query(`DELETE ${J} TIMEOUT ${$.timeout}s`).collect(),"deleted"}catch(A){await H0(`Failed to delete: ${A instanceof Error?A.message:String(A)}`),H()}else H()}}async function w4($,X){let Q=typeof X==="object"?JSON.stringify(X,null,2):String(X??""),J=await w0(Q,{title:`Edit: ${$}`,subtitle:"Arrows to move • Type to edit • Ctrl+S save • Esc cancel"});if(F0(J))return;return o0(J)}async function L4(){let $=await w0("",{title:"Add Field - Enter Name",subtitle:"Type field name • Ctrl+S confirm • Esc cancel"});if(F0($)||!$.trim())return null;let X=await w0("",{title:`Add Field: ${$.trim()}`,subtitle:"Type value (JSON for objects/arrays) • Ctrl+S confirm • Esc cancel"});if(F0(X))return null;return{key:$.trim(),value:o0(X)}}async function o1($,X,Q){let J=0,Z=0,Y=[],_=[],G=!0,j=!0,U=Q,W=async()=>{G=!0,H(j),j=!1;let[q]=await $.db.query(`SELECT * FROM \`${X}\` LIMIT ${$.pageSize} START ${J} TIMEOUT ${$.timeout}s`).collect();Y=q||[];let z=new Set(["id"]);for(let K of Y)for(let A of Object.keys(K))z.add(A);_=Array.from(z),Z=Math.min(Z,Math.max(0,Y.length-1)),G=!1,H()},H=(q=!1)=>{if(q)c();else J0();let z=process.stdout.rows||24,K=Math.max(3,z-9),A=Y.slice(0,K),D=U!==void 0?` (${U} records)`:"",O=Math.floor(J/$.pageSize)+1,V=U!==void 0?Math.ceil(U/$.pageSize):"?";if(s(`Table: ${X}${D}`,`Page ${O}/${V}`),G){console.log(M.dim(" Loading records..."));return}if(Y.length===0){console.log(M.dim(" No records found.")),console.log(M.dim(" b back • q quit"));return}let R=process.stdout.columns||80,I=Math.floor(R/_.length)-1,E=_.map((N)=>{let v=N.length;for(let C of A){let S=A0(C[N]);v=Math.max(v,L0(S).length)}return Math.min(v+2,I)}),w=A.map((N,v)=>_.map((C)=>{let S=A0(N[C]);return v===Z?M.primary(L0(S)):S}));p1(_,w,E,Z);let P=J+A.length,F=U!==void 0?`/${U}`:"",L=J+Z+1;console.log(M.dim(` ${L}${F} • ${J+1}-${P} • ↑↓ select • Enter view • ←→ page • b back • q quit`))};await W();while(!0){let q=await d();if(q==="q")throw Error("EXIT");if(q==="b"||q==="\x1B")return;if(q==="\x1B[A"||q==="k"){if(Z>0)Z--,H();else if(J>0)J=Math.max(0,J-$.pageSize),Z=$.pageSize-1,await W()}else if(q==="\x1B[B"||q==="j"){if(Z<Y.length-1)Z++,H();else if(U===void 0||J+Y.length<U)J+=$.pageSize,Z=0,await W()}else if(q==="\x1B[D"||q==="h"||q==="["){if(J>0)J=Math.max(0,J-$.pageSize),Z=0,await W()}else if(q==="\x1B[C"||q==="l"||q==="]"){if(U===void 0||J+$.pageSize<U)J+=$.pageSize,Z=0,await W()}else if(q==="\r"||q===`
235
+ `){let z=Y[Z];if(z)if(await r1($,X,z)==="deleted")await W();else await W()}else if(q==="g")J=0,Z=0,await W();else if(q==="G"&&U!==void 0)J=Math.max(0,Math.floor((U-1)/$.pageSize)*$.pageSize),Z=0,await W()}}async function v4($,X,Q){return $.query(`SELECT count() FROM \`${X}\` GROUP ALL TIMEOUT ${Q}s`).collect().then((J)=>J[0]?.[0]?.count??"timeout").catch(()=>"timeout")}async function N4($,X,Q,J,Z){let Y=0,_=async()=>{while(Y<X.length){let j=Y++,U=X[j];if(!U)continue;U.count=await v4($,U.name,Q),Z()}},G=Array.from({length:Math.min(J,X.length)},()=>_());await Promise.all(G)}async function s1($){let X=0,Q=[],J=[],Z=!0,Y="",_=async()=>{Z=!0,G(!0);let[U]=await $.db.query("INFO FOR DB").collect(),W=U;if(!W?.tables)throw Error("Failed to retrieve database info");Q=Object.keys(W.tables).sort().map((q)=>({name:q,count:"?"})),J=Q,Z=!1,G(),await N4($.db,Q,$.timeout,$.concurrency,G)},G=(U=!1)=>{if(U)c();else J0();let W=process.stdout.rows||24,H=Math.max(5,W-4),q=Y?` ${M.highlight(`[filter: ${Y}]`)}`:"";if(s(`Tables${q}`,`${J.length} tables`),Z){console.log(M.dim(" Loading tables..."));return}if(J.length===0){if(Y)console.log(M.warning(` No tables matching "${Y}"`)),console.log(M.dim(" Press Esc to clear filter"));else console.log(M.warning(" No tables found in database."));return}let z=0;if(X>=H)z=X-H+1;let K=Math.min(z+H,J.length);for(let D=z;D<K;D++){let O=J[D];if(!O)continue;let V=D===X,R=V?M.primary("▸ "):" ",I=V?M.primary.bold(O.name):O.name,E=l1(O.count);console.log(`${R}${I} ${M.dim("(")}${E}${M.dim(")")}`)}let A=J.length>H?`${z+1}-${K}/${J.length} • `:"";console.log(M.dim(` ${A}↑↓ nav • Enter select • / filter • r refresh • q quit`))};if(await _(),J.length===0&&!Y){await d();return}let j=()=>{if(Y){let U=Y.toLowerCase();J=Q.filter((W)=>W.name.toLowerCase().includes(U))}else J=Q;X=Math.min(X,Math.max(0,J.length-1))};while(!0){let U=await d();if(U==="q")throw Error("EXIT");if(U==="\x1B"){if(Y)Y="",j(),G();else throw Error("EXIT");continue}if(U==="\x1B[A"||U==="k")X=Math.max(0,X-1),G();else if(U==="\x1B[B"||U==="j")X=Math.min(J.length-1,X+1),G();else if(U==="\r"||U===`
236
+ `){let W=J[X];if(W){let H=typeof W.count==="number"?W.count:void 0;await o1($,W.name,H),G(!0)}}else if(U==="g")X=0,G();else if(U==="G")X=J.length-1,G();else if(U==="r"||U==="R")Y="",X=0,await _();else if(U==="/")G(),Y=await P0(M.highlight(" Filter: ")),j(),G()}}var k4=15,s0=5,i1=100,i0=3,a0=5,a1=new S4("view").description("Interactive TUI for browsing database tables and records").option("--url <url>","Database URL").option("-u, --username <username>","Database username").option("-p, --password <password>","Database password").option("-n, --namespace <namespace>","Database namespace").option("-d, --database <database>","Database name").option("--auth-level <level>","Authentication level (root, namespace, database)").option("-e, --embedded <mode>","Use embedded mode (memory or file path)").option("--page-size <size>",`Records per page (${s0}-${i1}, default: auto)`).option("--timeout <seconds>",`Query timeout in seconds (default: ${i0})`).option("--concurrency <count>",`Max concurrent count queries (default: ${a0})`).action(async($)=>{B.header("Database Viewer","Interactive table browser");let X=await r(),Q=await o({cliOptions:{url:$.url,username:$.username,password:$.password,namespace:$.namespace,database:$.database,authLevel:$.authLevel,embedded:$.embedded},config:X,skipAutoConfig:!0});if(!Q)return;let J=process.stdout.rows||24,Z=k4;if($.pageSize){let j=Number.parseInt($.pageSize,10);if(!Number.isNaN(j))Z=Math.max(s0,Math.min(i1,j))}else Z=Math.max(s0,Math.min(J-10,30));let Y=$.timeout?Math.max(1,Number.parseInt($.timeout,10)||i0):i0,_=$.concurrency?Math.max(1,Number.parseInt($.concurrency,10)||a0):a0,G={db:Q,pageSize:Z,terminalHeight:J,timeout:Y,concurrency:_};h1(),process.stdout.write(f1);try{await s1(G)}catch(j){if(j instanceof Error&&j.message==="EXIT");else{process.stdout.write(d0),l0(),B.error(j instanceof Error?j.message:String(j)),await Q.close();return}}process.stdout.write(d0),l0(),await Q.close()});m();import{createRequire as T4}from"node:module";var n0=T4(import.meta.url);function C4(){try{return n0("../../package.json").version}catch{return"unknown"}}var t0=C4(),x4="https://registry.npmjs.org";async function y4($,X="alpha"){try{let Q=await fetch(`${x4}/${$}`);if(!Q.ok)return null;let J=await Q.json();return J["dist-tags"][X]??J["dist-tags"].latest??null}catch{return null}}async function n1($,X,Q="alpha"){let J=await y4($,Q);if(!J)return null;return{current:X,latest:J,isOutdated:J!==X}}function b4(){try{let $=n0.resolve("unreal-orm/package.json",{paths:[process.cwd()]});return n0($).version}catch{return null}}async function t1(){if(process.env.CI||process.env.UNREAL_SKIP_UPDATE_CHECK)return;try{let[$,X]=await Promise.all([n1("@unreal-orm/cli",t0,"alpha"),(async()=>{let J=b4();if(!J)return null;return n1("unreal-orm",J,"alpha")})()]),Q=[];if($?.isOutdated)Q.push(` @unreal-orm/cli: ${B.dim($.current)} → ${B.theme.success($.latest)}`);if(X?.isOutdated)Q.push(` unreal-orm: ${B.dim(X.current)} → ${B.theme.success(X.latest)}`);if(Q.length>0){B.newline(),B.warn("\uD83D\uDCE6 Updates available:");for(let J of Q)console.log(J);B.dim("\n Run `npm update @unreal-orm/cli unreal-orm` to update\n")}}catch{}}var a=new g4().name("unreal").description("UnrealORM CLI for SurrealDB").version(t0).hook("postAction",async()=>{await t1()});a.addCommand(Z1);a.addCommand(R1);a.addCommand(P1);a.addCommand(L1);a.addCommand(T1);a.addCommand(g1);a.addCommand(a1);a.addCommand(y1);a.parse();
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@unreal-orm/cli",
3
+ "version": "1.0.0-alpha.3",
4
+ "description": "CLI tools for UnrealORM - schema introspection, diffing, and migrations for SurrealDB",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "unreal": "dist/index.js"
9
+ },
10
+ "publishConfig": {
11
+ "access": "public",
12
+ "tag": "alpha"
13
+ },
14
+ "scripts": {
15
+ "build": "bun build ./src/index.ts --outdir ./dist --target node --format esm --packages external --minify",
16
+ "prepublishOnly": "bun run build",
17
+ "publish:flow": "bun run build && bun publish"
18
+ },
19
+ "dependencies": {
20
+ "@commander-js/extra-typings": "^14.0.0",
21
+ "chalk": "^5.6.2",
22
+ "commander": "^14.0.2",
23
+ "diff": "^8.0.2",
24
+ "dotenv": "^17.2.3",
25
+ "jiti": "^2.6.1",
26
+ "ora": "^9.0.0",
27
+ "prompts": "^2.4.2",
28
+ "unreal-orm": "1.0.0-alpha.2"
29
+ },
30
+ "devDependencies": {
31
+ "@types/bun": "latest",
32
+ "@types/diff": "^8.0.0",
33
+ "@types/prompts": "^2.4.9"
34
+ },
35
+ "peerDependencies": {
36
+ "surrealdb": "^2.0.0-alpha.14",
37
+ "typescript": "^5"
38
+ },
39
+ "keywords": ["surrealdb", "orm", "cli", "schema", "migrations", "unreal-orm"],
40
+ "author": "Jimpex <contact@jimpex.dev> (https://jimpex.dev)",
41
+ "license": "ISC",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/jimpex/unreal-orm.git",
45
+ "directory": "packages/unreal-cli"
46
+ },
47
+ "bugs": {
48
+ "url": "https://github.com/jimpex/unreal-orm/issues"
49
+ },
50
+ "homepage": "https://unreal-orm.jimpex.dev",
51
+ "files": ["dist", "README.md", "LICENSE"]
52
+ }