aiplang 2.9.3 → 2.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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.9.3'
8
+ const VERSION = '2.9.4'
9
9
  const RUNTIME_DIR = path.join(__dirname, '..', 'runtime')
10
10
  const cmd = process.argv[2]
11
11
  const args = process.argv.slice(3)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiplang",
3
- "version": "2.9.3",
3
+ "version": "2.9.4",
4
4
  "description": "AI-first web language. One .aip file = complete app. Frontend + backend + database + auth.",
5
5
  "keywords": [
6
6
  "aiplang",
package/server/server.js CHANGED
@@ -325,7 +325,9 @@ function validateAndCoerce(data, schema) {
325
325
 
326
326
  // Coerce type
327
327
  if (val !== undefined && val !== null) {
328
- if (def.type === 'int') {
328
+ if (Array.isArray(val) || (typeof val === 'object' && val !== null && def.type !== 'json')) {
329
+ errors.push(`${col}: expected ${def.type}, got ${Array.isArray(val)?'array':'object'}`)
330
+ } else if (def.type === 'int') {
329
331
  const n = parseInt(val)
330
332
  if (isNaN(n)) errors.push(`${col}: expected integer, got "${val}"`)
331
333
  else out[col] = n
@@ -706,7 +708,13 @@ function parseEventLine(s) { const m=s.match(/^(\S+)\s*=>\s*(.+)$/); return{even
706
708
  function parseField(line) {
707
709
  const p=line.split(':').map(s=>s.trim())
708
710
  const f={name:p[0],type:p[1]||'text',modifiers:[],enumVals:[],default:null}
709
- for(let j=2;j<p.length;j++){const x=p[j];if(x.startsWith('default='))f.default=x.slice(8);else if(x.startsWith('enum:'))f.enumVals=x.slice(5).split(',');else if(x)f.modifiers.push(x)}
711
+ // If type is enum, p[2] contains comma-separated values directly
712
+ if (f.type === 'enum' && p[2] && !p[2].startsWith('default=') && !['required','unique','hashed','pk','auto','index'].includes(p[2])) {
713
+ f.enumVals = p[2].split(',').map(v=>v.trim()).filter(Boolean)
714
+ for(let j=3;j<p.length;j++){const x=p[j];if(x.startsWith('default='))f.default=x.slice(8);else if(x)f.modifiers.push(x)}
715
+ } else {
716
+ for(let j=2;j<p.length;j++){const x=p[j];if(x.startsWith('default='))f.default=x.slice(8);else if(x.startsWith('enum:'))f.enumVals=x.slice(5).split(',').map(v=>v.trim());else if(x)f.modifiers.push(x)}
717
+ }
710
718
  return f
711
719
  }
712
720
  function parseAPILine(line, route) {
@@ -1710,7 +1718,7 @@ async function startServer(aipFile, port = 3000) {
1710
1718
  migrateModels(app.models)
1711
1719
 
1712
1720
  // Register models
1713
- for (const m of app.models) srv.registerModel(m.name, { softDelete: m.softDelete, timestamps: true })
1721
+ for (const m of app.models) srv.registerModel(m.name, MODEL_DEFS[m.name] || { softDelete: m.softDelete, timestamps: true })
1714
1722
 
1715
1723
  // Events
1716
1724
  for (const ev of app.events) on(ev.event, (data) => console.log(`[aiplang:event] ${ev.event}:`, ev.action))
@@ -1789,7 +1797,7 @@ async function startServer(aipFile, port = 3000) {
1789
1797
 
1790
1798
  // Health
1791
1799
  srv.addRoute('GET', '/health', (req, res) => res.json(200, {
1792
- status:'ok', version:'2.9.3',
1800
+ status:'ok', version:'2.9.4',
1793
1801
  models: app.models.map(m=>m.name),
1794
1802
  routes: app.apis.length, pages: app.pages.length,
1795
1803
  admin: app.admin?.prefix || null,