aiplang 2.6.2 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,98 +1,139 @@
1
- # aiplang — syntax reference
2
- File extension: `.aip` (e.g. `app.aip`, `home.aip`)
3
- Generate ONLY aiplang code. No React, HTML, or other frameworks. No explanations unless asked.
1
+ # aiplang — LLM reference
2
+ Generate ONLY `.aip` syntax. Zero explanation. Zero React. Zero HTML frameworks.
4
3
 
5
- ## File structure
4
+ ## Config directives (before model/api/pages)
6
5
  ```
7
- ~env VAR required # env validation
8
- ~db sqlite ./app.db # or: postgres $DATABASE_URL
6
+ ~env VAR required # fail if missing
7
+ ~db sqlite ./app.db # or: postgres $DATABASE_URL
9
8
  ~auth jwt $JWT_SECRET expire=7d
10
- ~mail smtp host=x user=$U pass=$P
11
- ~s3 $KEY secret=$S bucket=$B region=us-east-1 prefix=uploads/ maxSize=10mb
9
+ ~mail smtp host=x user=$U pass=$P from=no-reply@x.com
10
+ ~s3 $KEY secret=$S bucket=$B region=us-east-1 prefix=up/ maxSize=10mb allow=image/jpeg,image/png
12
11
  ~stripe $KEY webhook=$WH success=/ok cancel=/pricing
13
12
  ~plan free=price_x pro=price_y
14
13
  ~admin /admin
15
14
  ~use cors origins=https://x.com
16
15
  ~use rate-limit max=100 window=60s
17
16
  ~use helmet | ~use logger | ~use compression
18
- ~plugin ./my-plugin.js
17
+ ~plugin ./plugins/custom.js
18
+ ```
19
19
 
20
+ ## Model
21
+ ```
20
22
  model Name {
21
- id : uuid : pk auto
22
- field : type : modifier
23
- ~soft-delete
24
- ~belongs OtherModel
23
+ id : uuid : pk auto
24
+ field : text : required
25
+ email : text : required unique
26
+ password : text : required hashed
27
+ count : int : default=0
28
+ price : float
29
+ active : bool : default=true
30
+ at : timestamp
31
+ data : json
32
+ kind : enum : a,b,c : default=a
33
+ ~soft-delete # adds deleted_at, filters from queries
34
+ ~belongs OtherModel # adds other_model_id FK
25
35
  }
26
- # types: uuid text int float bool timestamp json enum
27
- # modifiers: pk auto required unique hashed default=val index
36
+ ```
37
+ Types: `uuid text int float bool timestamp json enum`
38
+ Modifiers: `pk auto required unique hashed default=val index`
28
39
 
29
- api METHOD /path/:id {
30
- ~guard auth | admin | subscribed | owner
31
- ~validate field required | field email | field min=8 | field numeric
32
- ~query page=1 limit=20
40
+ ## API ALWAYS one blank line between ops, return is last
41
+ ```
42
+ api POST /path {
43
+ ~guard auth # auth | admin | subscribed | owner
44
+ ~validate field required | field email | field min=8 | field max=100 | field numeric | field in:a,b,c
33
45
  ~unique Model field $body.field | 409
34
- ~hash field
35
- ~check password $body.pw $user.pw | 401
46
+ ~hash field # bcrypt the field before insert
47
+ ~check password $body.pw $user.pw | 401 # bcrypt compare
48
+ ~query page=1 limit=20 # query params with defaults
36
49
  ~mail $user.email "Subject" "Body"
37
50
  ~dispatch jobName $body
38
51
  ~emit event.name $body
39
- $var = Model.findBy(field=$body.field)
40
- insert Model($body)
41
- update Model($id, $body)
42
- delete Model($id)
43
- restore Model($id)
44
- return $inserted | $updated | $auth.user | Model.all(order=created_at desc)
45
- return Model.paginate($page, $limit)
46
- return Model.count() | Model.sum(field) | Model.avg(field)
52
+ $var = Model.findBy(field=$body.field) # assign to $var
53
+ $var = Model.find($params.id)
54
+ insert Model($body) # sets $inserted
55
+ update Model($params.id, $body) # sets $updated
56
+ delete Model($params.id) # soft or hard delete
57
+ restore Model($params.id)
58
+ return $inserted 201 # status optional, default 200
59
+ return $updated
60
+ return $var
61
+ return $auth.user
62
+ return jwt($inserted) 201 # return JWT token
47
63
  return jwt($user) 200
64
+ return Model.all(order=created_at desc)
65
+ return Model.paginate($page, $limit)
66
+ return Model.count()
67
+ return Model.sum(field)
68
+ return Model.findBy(field=$body.field)
48
69
  }
70
+ ```
49
71
 
50
- %id theme /route # dark | light | acid | #bg,#text,#accent
51
- ~theme accent=#hex bg=#hex text=#hex font=Name radius=1rem surface=#hex navbg=#hex
52
- @var = [] # state: [] or {} or "string" or 0
53
- ~mount GET /api => @var
54
- ~interval 10000 GET /api => @var
55
-
56
- blocks...
57
- --- # page separator
72
+ ## Pages
73
+ ```
74
+ %id theme /route # id=any, theme=dark|light|acid|#bg,#text,#accent, route=/path
75
+ ~theme accent=#hex bg=#hex text=#hex font=Name radius=1rem surface=#hex navbg=#hex spacing=5rem
76
+ @list = [] # reactive state — [] for arrays, {} for objects, "str", 0
77
+ @obj = {}
78
+ ~mount GET /api/path => @list # fetch on page load → assign to @list
79
+ ~mount GET /api/path => @obj
80
+ ~interval 15000 GET /api/path => @obj # repeat every N ms (always pair with ~mount)
58
81
  ```
59
82
 
60
83
  ## All blocks
61
84
  ```
62
85
  nav{Brand>/path:Link>/path:Link}
63
- hero{Title|Sub>/path:CTA} | hero{Title|Sub>/path:CTA|img:https://url}
64
- stats{@val:Label|99%:Uptime|$0:Free}
86
+ hero{Title|Subtitle>/path:CTA}
87
+ hero{Title|Sub>/path:CTA|img:https://url} # split layout with image
88
+ stats{@obj.field:Label|99%:Uptime|$0:Free}
65
89
  row2{icon>Title>Body} | row3{...} | row4{...}
66
90
  sect{Title|Optional body}
67
- table @list { Col:field | edit PUT /api/{id} | delete /api/{id} | empty: msg }
68
- form POST /api => @list.push($result) { Label:type:placeholder | Label:select:a,b,c }
69
- form POST /api => redirect /path { Label:type | Label:password }
70
- pricing{Name>Price>Desc>/path:CTA|Name>Price>Desc>/path:CTA}
71
- faq{Question?>Answer.|Q2?>A2.}
72
- testimonial{Name, Role @ Co|"Quote."|img:https://url}
73
- gallery{https://img1|https://img2|https://img3}
74
- btn{Label > METHOD /api/path} | btn{Label > DELETE /api > confirm:Sure?}
91
+ table @list { Col:field | Col:field | edit PUT /api/path/{id} | delete /api/path/{id} | empty: msg }
92
+ form POST /api/path => @list.push($result) { Label:type:placeholder | Label:select:a,b,c }
93
+ form POST /api/path => redirect /dashboard { Label:type | Label:password }
94
+ pricing{Name>$0/mo>Desc>/path:CTA | Name>$19/mo>Desc>/path:CTA}
95
+ faq{Question?>Answer. | Q2?>A2.}
96
+ testimonial{Name, Role|"Quote."|img:https://url}
97
+ gallery{https://img1 | https://img2 | https://img3}
98
+ btn{Label > METHOD /api/path}
99
+ btn{Label > DELETE /api/path > confirm:Are you sure?}
75
100
  select @filterVar { All | Active | Inactive }
76
101
  if @var { blocks }
77
- raw{<div>any HTML</div>}
102
+ raw{<div>any HTML or embed</div>}
78
103
  foot{© 2025 Name>/path:Link}
79
104
  ```
80
105
 
81
- ## Block modifiers (any block)
82
- `animate:fade-up | fade-in | blur-in | slide-left | slide-right | zoom-in | stagger`
83
- `class:my-class`
106
+ ## Animate any block
107
+ `block{...} animate:fade-up` · `animate:fade-in` · `animate:blur-in` · `animate:stagger` · `animate:slide-left` · `animate:zoom-in`
84
108
 
85
- ## S3 auto-routes
86
- `POST /api/upload` · `DELETE /api/upload/:key` · `GET /api/upload/presign?key=x`
109
+ ## Multiple pages — separate with ---
110
+ ```
111
+ %home dark /
112
+ nav{...}
113
+ hero{...}
114
+ ---
115
+ %dashboard dark /dashboard
116
+ @data = []
117
+ ~mount GET /api/data => @data
118
+ table @data { ... }
119
+ ---
120
+ %login dark /login
121
+ form POST /api/auth/login => redirect /dashboard { Email:email | Password:password }
122
+ ```
87
123
 
88
- ## Stripe auto-routes
89
- `POST /api/stripe/checkout` · `POST /api/stripe/portal` · `GET /api/stripe/subscription`
124
+ ## Icons (use in row blocks)
125
+ `rocket bolt shield chart star check globe gear fire money bell mail user lock eye tag search home`
90
126
 
91
- ## Rules
92
- 1. Dark theme default
93
- 2. `@var = []` + `~mount` for all dynamic data
94
- 3. Tables always have `edit` + `delete` unless readonly
95
- 4. Forms: `=> @list.push($result)` or `=> redirect /path`
96
- 5. `~theme` before `%` declarations
97
- 6. Separate pages with `---`
98
- 7. Full-stack: `~db` + `~auth` + `model` + `api` before pages
127
+ ## S3 auto-routes (generated when ~s3 configured)
128
+ `POST /api/upload` · `DELETE /api/upload/:key` · `GET /api/upload/presign?key=x&expires=3600`
129
+
130
+ ## Stripe auto-routes (generated when ~stripe configured)
131
+ `POST /api/stripe/checkout {plan,email}` · `POST /api/stripe/portal` · `GET /api/stripe/subscription` · `POST /api/stripe/webhook`
132
+ Webhooks auto-handled: checkout.completed sets user.plan, subscription.deleted → resets to free
133
+
134
+ ## Run
135
+ ```bash
136
+ npx aiplang start app.aip # full-stack
137
+ npx aiplang serve # frontend dev
138
+ npx aiplang build pages/ # static build
139
+ ```
package/bin/aiplang.js CHANGED
@@ -5,7 +5,7 @@ const fs = require('fs')
5
5
  const path = require('path')
6
6
  const http = require('http')
7
7
 
8
- const VERSION = '2.6.2'
8
+ const VERSION = '2.7.0'
9
9
  const RUNTIME_DIR = path.join(__dirname, '..', 'runtime')
10
10
  const cmd = process.argv[2]
11
11
  const args = process.argv.slice(3)
@@ -121,6 +121,23 @@ api GET /api/me {
121
121
  return $auth.user
122
122
  }
123
123
 
124
+ api GET /api/users {
125
+ ~guard admin
126
+ ~query page=1
127
+ return User.paginate($page, 20)
128
+ }
129
+
130
+ api PUT /api/users/:id {
131
+ ~guard admin
132
+ update User($id, $body)
133
+ return $updated
134
+ }
135
+
136
+ api DELETE /api/users/:id {
137
+ ~guard admin
138
+ delete User($id)
139
+ }
140
+
124
141
  api GET /api/stats {
125
142
  return User.count()
126
143
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiplang",
3
- "version": "2.6.2",
3
+ "version": "2.7.0",
4
4
  "description": "AI-first full-stack language. Frontend + Backend + DB + Auth in one file. Competes with Laravel.",
5
5
  "keywords": [
6
6
  "aiplang",
package/server/server.js CHANGED
@@ -1435,7 +1435,7 @@ async function startServer(aipFile, port = 3000) {
1435
1435
 
1436
1436
  // Health
1437
1437
  srv.addRoute('GET', '/health', (req, res) => res.json(200, {
1438
- status:'ok', version:'2.6.2',
1438
+ status:'ok', version:'2.7.0',
1439
1439
  models: app.models.map(m=>m.name),
1440
1440
  routes: app.apis.length, pages: app.pages.length,
1441
1441
  admin: app.admin?.prefix || null,