@velarscript/cli 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/version.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export declare const VELAR_VERSION = "0.17.0";
1
+ export declare const VELAR_VERSION = "0.18.0";
2
2
  export { VELAR_STANDARD_API_VERSION } from "@velarscript/core";
3
3
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
- export const VELAR_VERSION = "0.17.0";
1
+ export const VELAR_VERSION = "0.18.0";
2
2
  export { VELAR_STANDARD_API_VERSION } from "@velarscript/core";
3
3
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velarscript/cli",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "The VelarScript command-line compiler, dev server, test runner, and language server.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -30,13 +30,13 @@
30
30
  "velar": "./dist/cli.js"
31
31
  },
32
32
  "dependencies": {
33
- "@velarscript/compiler": "0.17.0",
34
- "@velarscript/core": "0.17.0",
35
- "@velarscript/desktop": "0.17.0",
36
- "@velarscript/node": "0.17.0",
37
- "@velarscript/server": "0.17.0",
38
- "@velarscript/web": "0.17.0",
39
- "create-velar": "0.17.0",
33
+ "@velarscript/compiler": "0.18.0",
34
+ "@velarscript/core": "0.18.0",
35
+ "@velarscript/desktop": "0.18.0",
36
+ "@velarscript/node": "0.18.0",
37
+ "@velarscript/server": "0.18.0",
38
+ "@velarscript/web": "0.18.0",
39
+ "create-velar": "0.18.0",
40
40
  "esbuild": "^0.28.1",
41
41
  "playwright": "^1.58.2"
42
42
  }
@@ -52,7 +52,6 @@ export async def start():
52
52
  host: "127.0.0.1",
53
53
  port: 3000,
54
54
  http: routes,
55
- path: "/api/events",
56
55
  origins: ["https://app.example.com"],
57
56
  maxBodyBytes: 16777216,
58
57
  })
@@ -69,7 +68,7 @@ second runtime configuration source.
69
68
  `@` remains the language-wide annotation introducer, and `@name` is a context
70
69
  annotation with a compiler-owned compile-time role. In a `server` block, the
71
70
  available annotations are `@get`, `@post`, `@put`, `@patch`, `@delete`,
72
- `@notFound`, and `@response`. They are not decorators, functions, imports, user-defined
71
+ `@websocket`, `@notFound`, and `@response`. They are not decorators, functions, imports, user-defined
73
72
  annotations, first-class values, or user extension points.
74
73
 
75
74
  ## Routes and checked inputs
@@ -84,23 +83,24 @@ type CreateArticle:
84
83
 
85
84
  export server articles:
86
85
  /// Reports whether this service is ready.
87
- @get(path=p"/health") => {ok: true}
86
+ @get(p"/health") => {ok: true}
88
87
 
89
- @get(path=p"/articles/{id:number}?{details:bool?}"):
90
- const id = path.params.id
88
+ @get(p"/articles/{id:number}?{details:bool?}"):
91
89
  if id < 1:
92
90
  throw HttpProblem({status: 404, code: "article.not_found", title: "Article not found"})
93
- return {id, details: path.query.details ?? false}
91
+ return {id, details: details ?? false}
94
92
 
95
- @post(path=p"/articles", input: CreateArticle):
93
+ @post(p"/articles", input: CreateArticle):
96
94
  return created({id: 1, title: input.title})
97
95
 
98
96
  ```
99
97
 
100
- `p"..."` is a first-class `RoutePattern`. A route receives one compiler-owned
101
- `path` value: `path.params` contains typed path captures, `path.query` contains
102
- typed query fields, `path.definition` and `str(path)` return the complete
103
- declaration. Query shorthand `?{details:bool?}` uses the field name on the
98
+ `p"..."` is a first-class `RoutePattern`. An inline pattern projects its typed
99
+ path captures and query fields directly as immutable handler locals. A pattern
100
+ stored elsewhere must use an explicit binding such as `@get(articlePath as
101
+ route)`; its `RouteMatch` contains `pattern`, `pathname`, `params`, and `query`,
102
+ and `str(route)` or `str(route.pattern)` returns the complete declaration. Query shorthand
103
+ `?{details:bool?}` uses the field name on the
104
104
  wire; `?details={details:bool?}` spells it explicitly, and
105
105
  `?include-details={details:bool?}` maps a different wire name. The trailing
106
106
  `?` makes a query field optional; without it the framework rejects a missing
@@ -109,8 +109,10 @@ an ASCII half-width `:` and accept `string`, `number`, `bool`, or a named enum.
109
109
  The explicit same-name form remains valid but reports advisory `A11`; its
110
110
  mechanical fix removes the redundant `details=` prefix. Different-name aliases
111
111
  do not report it.
112
- Route catalogs may keep patterns in exported `const` objects and routes may
113
- refer to those members directly.
112
+ Route catalogs may keep patterns in exported `const` objects. Referenced
113
+ patterns require `as name` so the compiler never injects identifiers that are
114
+ hidden inside another declaration. The old `path=` spelling is an error with a
115
+ mechanical fix to the positional form and `as path`.
114
116
 
115
117
  On `POST`, `PUT`, or `PATCH`, one concrete Data parameter is the
116
118
  checked JSON body. A `Request` parameter explicitly requests the complete
@@ -184,13 +186,13 @@ const currentUser = provide(
184
186
  )
185
187
 
186
188
  server account:
187
- @get(path=p"/me",
189
+ @get(p"/me",
188
190
  user=input.dependency(currentUser),
189
191
  tenant=input.header("x-tenant"),
190
192
  session=input.cookie("session", default=null),
191
193
  ) => {id: user.id, tenant, session}
192
194
 
193
- @post(path=p"/images",
195
+ @post(p"/images",
194
196
  metadata=input.form(UploadMetadata),
195
197
  image=input.upload("image", maxBytes=8_388_608),
196
198
  ) => {title: metadata.title, filename: image.filename}
@@ -308,13 +310,33 @@ total stream are bounded. SSE accepts text or checked
308
310
  root-contained, streamed reads with validators and one byte range.
309
311
 
310
312
  `velar/websocket.listen({http: app, ...})` serves a `ServeApp` and WebSocket
311
- upgrades on one native server and owns the application lifecycle. Set
313
+ upgrades on one native server and owns the application lifecycle. A declarative
314
+ session belongs in the route table:
315
+
316
+ ```velar
317
+ import {WebSocketConnection} from "velar/websocket"
318
+
319
+ server realtime:
320
+ @websocket(p"/worlds/{worldId:string}/realtime", connection: WebSocketConnection):
321
+ async for message in connection:
322
+ await connection.send(message)
323
+ ```
324
+
325
+ Matching, path/query decoding, dependencies, security, headers, cookies, and
326
+ the optional `Request` are resolved before upgrade. Exactly one
327
+ `WebSocketConnection` is supplied by the framework, the handler must finish
328
+ with `null`, and its lifetime is joined with shutdown. Inline patterns project
329
+ captures directly; referenced patterns require `as route`. A listener whose app
330
+ contains these routes rejects its legacy single `path` option and does not offer
331
+ accepted sessions through `WebSocketServer.next()`.
332
+
333
+ Set
312
334
  `maxBodyBytes` to the supplied application value. `origins` contains exact
313
335
  canonical HTTP/HTTPS origins. The default rejects any upgrade carrying
314
336
  `Origin`; no-Origin non-browser clients remain allowed. Use `["*"]` only for an
315
337
  intentional unrestricted policy. A rejected browser origin receives 403 before
316
338
  it consumes connection-queue capacity. Connections are pull-based. Always
317
- consume `next()`, handle backpressure, and stop the server.
339
+ consume each connection's `next()`, handle backpressure, and stop the server.
318
340
 
319
341
  ## Tests
320
342
 
@@ -13,7 +13,7 @@ browser application activates `@velarscript/web`:
13
13
  ```json
14
14
  {
15
15
  "dependencies": {
16
- "@velarscript/server": "0.17.0"
16
+ "@velarscript/server": "0.18.0"
17
17
  }
18
18
  }
19
19
  ```
@@ -62,7 +62,7 @@ All three fields are optional. Their defaults are `127.0.0.1`, `3000`, and
62
62
  import {application} from "velar/server"
63
63
 
64
64
  export server routes:
65
- @get(path=p"/health") => {status: "ready"}
65
+ @get(p"/health") => {status: "ready"}
66
66
 
67
67
  export const start = application(routes)
68
68
  ```
@@ -127,7 +127,7 @@ async def verifyAccessToken(token: string) -> Principal?:
127
127
  const currentPrincipal = authenticate(security.bearer(), verifyAccessToken)
128
128
 
129
129
  export server accountRoutes:
130
- @get(path=p"/me", principal=input.dependency(currentPrincipal)) => {
130
+ @get(p"/me", principal=input.dependency(currentPrincipal)) => {
131
131
  subject: principal.subject,
132
132
  }
133
133
  ```
@@ -168,7 +168,7 @@ const connection = database(
168
168
  )
169
169
 
170
170
  export server databaseRoutes:
171
- @get(path=p"/database", value=input.dependency(connection)) => {name: value.name}
171
+ @get(p"/database", value=input.dependency(connection)) => {name: value.name}
172
172
  ```
173
173
 
174
174
  The framework owns only this connect/inject/disconnect lifecycle. Concrete
@@ -179,8 +179,9 @@ syntax to `@velarscript/server` or `@velarscript/node`.
179
179
 
180
180
  ## Custom shared HTTP/WebSocket startup
181
181
 
182
- A service that needs one custom shared HTTP/WebSocket listener may load the same
183
- typed configuration and export an exact zero-argument async startup function:
182
+ A service whose route table contains `@websocket` declarations may load the
183
+ same typed configuration and export an exact zero-argument async startup
184
+ function for the shared HTTP/WebSocket listener:
184
185
 
185
186
  ```velar fragment
186
187
  import {configuration} from "velar/server"
@@ -201,7 +202,6 @@ export async def start():
201
202
  host: settings.server.host,
202
203
  port: settings.server.port,
203
204
  http: routes,
204
- path: "/events",
205
205
  origins: ["https://app.example.com"],
206
206
  maxBodyBytes: settings.server.maxBodyBytes,
207
207
  })
@@ -209,7 +209,9 @@ export async def start():
209
209
 
210
210
  The result must be exactly `Promise<WebSocketServer>`. The launcher supplies no
211
211
  host, port, or body-limit arguments; the root application configuration remains
212
- the single runtime authority.
212
+ the single runtime authority. Each `@websocket` RoutePattern owns its own path,
213
+ typed captures, admission inputs, and session handler, so this declarative mode
214
+ does not accept the listener's legacy single `path` option.
213
215
 
214
216
  Use direct `serve(app, port=0)` in tests or embedded low-level adapters. Use
215
217
  `velar/server-test` only from `*.test.vel`. Route, provider, transport,