@velarscript/cli 0.14.1 → 0.14.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velarscript/cli",
3
- "version": "0.14.1",
3
+ "version": "0.14.3",
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.14.1",
34
- "@velarscript/core": "0.14.1",
35
- "@velarscript/desktop": "0.14.1",
36
- "@velarscript/node": "0.14.1",
37
- "@velarscript/server": "0.14.1",
38
- "@velarscript/web": "0.14.1",
39
- "create-velar": "0.14.1",
33
+ "@velarscript/compiler": "0.14.3",
34
+ "@velarscript/core": "0.14.3",
35
+ "@velarscript/desktop": "0.14.3",
36
+ "@velarscript/node": "0.14.3",
37
+ "@velarscript/server": "0.14.3",
38
+ "@velarscript/web": "0.14.3",
39
+ "create-velar": "0.14.3",
40
40
  "esbuild": "^0.28.1",
41
41
  "playwright": "^1.58.2"
42
42
  }
@@ -157,7 +157,11 @@ repeated fields for `List<scalar>` properties; duplicate scalar fields fail.
157
157
  `input.upload` returns an `Upload` whose bytes are valid only for the request
158
158
  lifetime; copy or persist them before retaining data. `security.apiKey`,
159
159
  `basic`, `bearer`, `oauth2`, and `openId` parse credentials and also
160
- feed OpenAPI security schemes.
160
+ feed OpenAPI security schemes. They do not verify a password, token signature,
161
+ issuer, audience, session, or user record. An application using the explicit
162
+ Server extension composes a descriptor with its installed verifier through
163
+ `authenticate`; low-level Node code may perform the same policy in an ordinary
164
+ request Provider.
161
165
 
162
166
  `provide(inputs, resolve, scope="request", release=null, eager=false)` declares
163
167
  a dependency as data. A request-scoped provider resolves once per request even
@@ -13,7 +13,7 @@ browser application activates `@velarscript/web`:
13
13
  ```json
14
14
  {
15
15
  "dependencies": {
16
- "@velarscript/server": "0.14.1"
16
+ "@velarscript/server": "0.14.2"
17
17
  }
18
18
  }
19
19
  ```
@@ -103,6 +103,50 @@ types, and application validation still owns domain ranges and invariants.
103
103
  Environment variables may form an explicit deployment override layer, but
104
104
  secrets do not belong in application configuration.
105
105
 
106
+ ## Request authentication
107
+
108
+ Node's `security` values own credential extraction, malformed-input rejection,
109
+ 401 challenges, and OpenAPI descriptions. Server's `authenticate` composes one
110
+ of those descriptors with an application- or package-provided verifier:
111
+
112
+ ```velar
113
+ import {authenticate} from "velar/server"
114
+ import {input, security} from "velar/serve"
115
+
116
+ type Principal:
117
+ subject: string
118
+
119
+ const exampleTokens: Map<string, Principal> = Map([
120
+ ["example-test-token", {subject: "user-1"}],
121
+ ])
122
+
123
+ async def verifyAccessToken(token: string) -> Principal?:
124
+ // A deployed application replaces this test map with an installed verifier.
125
+ return exampleTokens.get(token)
126
+
127
+ const currentPrincipal = authenticate(security.bearer(), verifyAccessToken)
128
+
129
+ export server accountRoutes:
130
+ @get(p"/me", principal=input.dependency(currentPrincipal)) => {
131
+ subject: principal.subject,
132
+ }
133
+ ```
134
+
135
+ `authenticate(credential, verify)` accepts only a `security.apiKey`, `basic`,
136
+ `bearer`, `oauth2`, or `openId` descriptor. `verify` must return
137
+ `Promise<Identity?>`. It resolves once per request: `null` becomes the same
138
+ opaque `not_authenticated` 401 response and `WWW-Authenticate` challenge as a
139
+ missing credential, while a non-null value becomes the typed request Provider
140
+ result. A thrown verifier failure remains an opaque 500 because a key-service,
141
+ database, or network failure is not proof of an invalid credential.
142
+
143
+ The verified identity shape belongs to the application. JWT/JWK and OIDC
144
+ verification, password hashing, signed sessions, and vendor integrations are
145
+ explicit installed packages; user storage, tenant membership, roles,
146
+ permissions, revocation, and resource-level authorization remain application
147
+ policy. Do not place secrets in `application.yml`, invent a universal `User`
148
+ record, or turn authentication into new route syntax or `@` roles.
149
+
106
150
  ## Abstract database connection lifecycle
107
151
 
108
152
  `database(connect, disconnect)` creates an eager application-scoped
package/skill/ai-skill.md CHANGED
@@ -62,13 +62,16 @@ protects these names. Capabilities stay explicit imports. Durations use `ms` or
62
62
  Use checked binary, random, and task APIs. Project-specific codecs, storage,
63
63
  and algorithms come from project-owned modules or dependencies. A direct
64
64
  `for index in range(...):` is a native counter; range as a value is a List. Use `UInt16Buffer` for 16-bit numeric state,
65
- `UInt8Buffer` for compact data, and bounded `UInt32Builder`/`Float32Builder` values for variable-size numeric output.
65
+ `UInt8Buffer` for compact data, and bounded `UInt32Builder`/`Float32Builder` values for variable-size numeric output. A fixed numeric buffer's `values()` returns one fresh `List<number>` snapshot; do not write an index loop just to copy it.
66
66
 
67
67
  ## Project setup
68
68
 
69
69
  A VelarScript project is a directory containing a `velar.json` manifest. Let
70
70
  the toolchain write it — `velar create my-lib --template library` scaffolds a
71
- Core source library; other templates select their own framework brief. Each writes
71
+ Core library whose release keeps `.vel` source plus a frozen ABI-1 JavaScript
72
+ artifact; `velar build-library` regenerates its JS, source map, portable type
73
+ interface, and hash receipt. Later toolchains load that interface and JS before
74
+ considering source fallback. Other templates select their own framework brief. Each writes
72
75
  `velar.json`, a `package.json` whose scripts are the gates, a `src/` tree, a
73
76
  passing test, and an `AGENTS.md`.
74
77
 
@@ -99,8 +102,11 @@ module; the body may `await` directly and needs no `export`. A file that declare
99
102
 
100
103
  Everything in this table was hit by real models writing Vel blind. Most rows
101
104
  produce a teaching diagnostic, so `velar check` will catch them; the rows
102
- marked **A1**, **A2**, **A3**, **A5**, and **A6** are answered by an advisory
103
- instead, which reports without failing the check. Two rows are still silent —
105
+ marked **A1**, **A2**, **A3**, **A5**, **A6**, **A7**, **A8**, and **A9** are
106
+ answered by an advisory instead, which reports without failing the check. A7
107
+ through A9 are canonical-form checks rather than foreign-language traps: they
108
+ fire only for a proven collection conversion, existential List query, or exact
109
+ record projection. Two rows are still silent —
104
110
  nothing is reported at all and the program runs with the other meaning:
105
111
  `a // b` where the divisor is a name rather than arithmetic, and a collection
106
112
  `==` between two bindings, since only a collection literal written inside the
@@ -118,6 +124,9 @@ well, but it is a guarantee rather than a trap.
118
124
  | `interface X:`, `record X:`, `struct X:` | `type X:` — one keyword for record shapes and aliases. |
119
125
  | `items.length` | `items.size` (also on strings, Sets, Maps). |
120
126
  | `items.push(x)` | `items.append(x)`. There is no `splice`/`shift`/`unshift`/mutating `sort`; use `insert`, `pop`, `remove`, `extend`, and the copying `sorted()`/`reversed()`. |
127
+ | Empty collection + identity-only copy loop (**A7**) | Initialize from the built-in conversion. A `Set<T>` becomes a fresh `List<T>` with `set.values()`; a List becomes a Set with `Set(list)`; List/Set/Map snapshots use `.copy()`, `.keys()`, or `.values()`; and a Record becomes a Map with `Map(record)`. The advisory requires the empty declaration immediately before a one-statement loop over a plain source name. It stays silent for transforms, filters, effects, non-empty destinations, computed sources, or any intervening statement. |
128
+ | `for item in items: if test: return true` followed by `return false` (**A8**) | `return items.some(item => test)`. The advisory requires a synchronous single-slot loop over a plain List name, an exact one-`if` body, literal `true`/`false` returns, and a non-optional bool condition built only from data reads and operators. Calls, class getters, effects, `bool?`, wider bodies, computed sources, and non-adjacent returns stay silent. |
129
+ | `return {worldId, position: sample.position, ...}` for a closed response type (**A9**) | `return Response.from(sample, {worldId})`. A concrete record Type projects only its declared fields from a statically typed record; the optional second argument is an explicit override literal. It is shallow construction, not validation: use `Type.parse` for `unknown`. A9 requires every target field, at least two same-name fields from one source, and only identifier/literal overrides; transforms, calls, spreads, partial targets, and mixed sources stay silent. `.from` emits target declaration order, so suppress A9 with a reason only when authored wire order is intentional. |
121
130
  | `{retry: 1, timeoutMs: 30}` where the type declares `timeout` | A record literal written at an annotated position is closed: an undeclared key is reported, and the nearest declared field named when one is near enough — `Type 'Options' has no field 'timeoutMs'; did you mean 'timeout'?`, against a bare `Type 'Options' has no field 'extra'` when no declared name is close. The annotation may sit on the binding, the parameter, the result, or the collection the literal is written into. A value that is not a literal stays structurally open, so passing a record that happens to carry more is unaffected. |
122
131
  | `const items = []`, `const tags = Set()` | An empty collection takes its type where it is written: `const items: List<string> = []`. A later `append`/`add`/`set` never types the declaration. A contextual position supplies it too, so `take(Set())` and `return Map()` need no annotation. |
123
132
  | `if value:` truthiness | Conditions accept only `bool`/`bool?`. Test presence explicitly: `if value != null:`. |
@@ -125,7 +134,7 @@ well, but it is a guarantee rather than a trap.
125
134
  | `switch`, or an `if`/`else if` ladder over an enum | `match` with `case _:` as the only fallback. |
126
135
  | Renaming a binding away from `type`, `json`, `from`, `match`, or `as` | Don't. Declaration words are contextual: each declares only in its own shape, so `const {type, from} = event` is ordinary code. `enum` and `case` are the exceptions — `enum` is a real VelarScript keyword and `case` is reserved by JavaScript — so neither can be a binding name; both stay fine as record fields, member names, and `match` branches. |
127
136
  | Treating `@` as a decorator, call, value, or user extension point | `@` has one meaning: `@name` qualifies the name into the closed compiler-owned namespace of the current context. Core or the active syntax-owning compiler extension owns the vocabulary; source cannot declare, import, alias, pass, or construct an `@name`. The class contracts `@dispose:` and `@iterate:` follow this one rule. |
128
- | Two statements on one line | One statement per line; there are no semicolons. The compact exceptions are `if condition: action()` and `case pattern: action()` for a single non-block branch statement. A line starting with `.` or `?.` continues the previous line, so method chains format normally. |
137
+ | Two statements on one line | One statement per line; there are no semicolons. As in Python, an ordinary executable suite may keep its one non-block statement after the colon, as in `def stop(): return`, `if condition: action()`, or `case pattern: action()`. Multiple statements, nested blocks, and structural member or branch lists use indentation. Formatting preserves the author's single-line or indented choice. A line starting with `.` or `?.` continues the previous line, so method chains format normally. |
129
138
  | `count++` | `count += 1` |
130
139
  | `call(name: value)` named argument | `call(name=value)` |
131
140
  | Importing `range` | `range(...)` is a Core prelude function and needs no import. |
@@ -208,6 +217,28 @@ def load(untrusted: unknown) -> User:
208
217
  return User.parse(untrusted)
209
218
  ```
210
219
 
220
+ Build one closed record from another typed record with the target-owned exact
221
+ projection. Overrides are explicit; surplus source fields never enter the
222
+ result:
223
+
224
+ ```velar
225
+ type SourceUser:
226
+ id: string
227
+ name: string
228
+ internalToken: string
229
+
230
+ type PublicUser:
231
+ id: string
232
+ name: string
233
+ requestId: string
234
+
235
+ def publicUser(source: SourceUser, requestId: string) -> PublicUser:
236
+ return PublicUser.from(source, {requestId})
237
+ ```
238
+
239
+ `Type.from` is shallow and compile-time checked. It does not accept `unknown`;
240
+ validate untrusted data with `Type.parse` first.
241
+
211
242
  `enum` declares finite string-backed states; a member may map an external
212
243
  wire spelling without losing its nominal identity:
213
244