@north-light/cli 0.3.539 → 0.3.540

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.
@@ -11,6 +11,8 @@ Changes to `@north-light/sdk` that can change what an existing app sees. Newest
11
11
 
12
12
  ## 0.3.539
13
13
 
14
+ `exchangeIdentity` now returns the verified identity when the directory's token answer also carries a runtime connection. It used to throw `oauth_exchange_mismatch`, so no member could sign in to an app held by a team with a runtime grant (the directory gives that app a connection on every sign-in). The SDK revokes the unneeded refresh token best-effort; revocation removes only that token, never the grant. `exchangeCode` still refuses a sign-in-only answer.
15
+
14
16
  A run started with no `kind` and no `model`, in a profile with no `default_kind` (every app's own default profile), now starts as the `general` kind on the `medium` rung. It used to start as `developer` on that kind's model (`openai/medium`). `profile.list` reports `general` as such a profile's `default_kind`. On an app-paid grant the run lands on the app's `medium` inference rung, where it used to land on `strong`. Pass `model` on `run.start` to keep another rung.
15
17
 
16
18
  Profiles name the machine environment they run on. Additive: no request or response an existing app sends or reads changes.
@@ -76,7 +76,7 @@ Then set your own session for the person. The SDK does not manage your sessions.
76
76
 
77
77
  ### Scopes decide what comes back
78
78
 
79
- A sign-in that asks only for `openid`, optionally with `email` and `profile`, creates no connection. Finish it with `oauth.exchangeIdentity(...)`, which returns the verified `Identity` (`sub`, and `email`, `name` and `picture` when approved and present). A sign-in that asks for runtime scopes such as `crtr:llm` finishes with `exchangeCode`. Each method refuses the other's answer with `oauth_exchange_mismatch`.
79
+ A sign-in that asks only for `openid`, optionally with `email` and `profile`, creates no connection. Finish it with `oauth.exchangeIdentity(...)`, which returns the verified `Identity` (`sub`, and `email`, `name` and `picture` when approved and present). A sign-in that asks for runtime scopes such as `crtr:llm` finishes with `exchangeCode`. `exchangeCode` refuses a sign-in-only answer with `oauth_exchange_mismatch`; `exchangeIdentity` accepts an answer that also carries a connection, returns the identity, and revokes the unneeded refresh token.
80
80
 
81
81
  ### When the directory refuses to sign someone in
82
82
 
@@ -119,7 +119,7 @@ It needs the app registered with the `app_token_for_user` operation, and an acti
119
119
 
120
120
  ## Signing in a visitor
121
121
 
122
- A person who only needs to be recognized, not connected, signs in with identity only: request `openid`, optionally with `email` and `profile`, and no runtime scope. Finish with `exchangeIdentity`, not `exchangeCode`. An `Identity` is not a connection: no runtime URL, grant or refresh token, nothing goes in the store, and you keep your own session. To act for that person later, send them through `authorizeUrl` again with the runtime scopes you need.
122
+ A person who only needs to be recognized, not connected, signs in with identity only: request `openid`, optionally with `email` and `profile`, and no runtime scope. Finish with `exchangeIdentity`, not `exchangeCode`. An `Identity` is not a connection: no runtime URL, grant or refresh token (if the directory answers with one anyway, `exchangeIdentity` revokes the refresh token), nothing goes in the store, and you keep your own session. To act for that person later, send them through `authorizeUrl` again with the runtime scopes you need.
123
123
 
124
124
  ## Checked and not checked
125
125
 
@@ -18,7 +18,7 @@ Codes the SDK raises itself are listed in `sdkErrorCodes`, and `CrouterError.cod
18
18
  | Code | Means | What to do |
19
19
  |---|---|---|
20
20
  | `id_token_invalid` | An ID token failed verification (signature, issuer, audience, expiry, missing or mismatched nonce), or a sign-in-only answer had no ID token. A JWKS that can't be fetched or is malformed is not this code: that error is thrown as is. | Restart the sign-in. |
21
- | `oauth_exchange_mismatch` | The wrong exchange call: `exchangeCode` on a sign-in-only answer, or `exchangeIdentity` on an answer that carries a connection. | Use the call that matches the scopes you requested ([[northlight-apps/guides/many-users]]). |
21
+ | `oauth_exchange_mismatch` | `exchangeCode` got a sign-in-only answer (no connection). | Finish a sign-in-only request with `exchangeIdentity` ([[northlight-apps/guides/many-users]]). |
22
22
  | `oauth_nonce_missing` | `exchangeIdentity` was called without the `nonce` from `authorizeUrl`. | Save the nonce in the visitor's session and pass it back. |
23
23
  | `oauth_state_mismatch` | The callback's `state` was missing or differed from the saved one. | Refuse the callback. |
24
24
  | `not_connected` | `oauth.client(userId)` or a refresh found no stored connection for that person. | Show "sign in again". |
@@ -18,7 +18,7 @@ Keep the connection and refresh token on the server, never in a visitor's browse
18
18
 
19
19
  ## Signing in a visitor
20
20
 
21
- A visitor who only needs to be recognized, not connected, signs in with identity only. Request `openid`, adding `email` for their email and `profile` for their name and photo, and no runtime scope. The directory shows one line ("Know who you are on Northlight"), writes no grant, and answers with an ID token and an access token usable only at `/userinfo`: no refresh token, grant or runtime URL. Finish that sign-in with `exchangeIdentity`, not `exchangeCode`:
21
+ A visitor who only needs to be recognized, not connected, signs in with identity only. Request `openid`, adding `email` for their email and `profile` for their name and photo, and no runtime scope. The directory shows one line ("Know who you are on Northlight"), writes no grant, and answers with an ID token and an access token usable only at `/userinfo`: no refresh token, grant or runtime URL. (An app held by a team with a runtime grant gets a connection on every sign-in; `exchangeIdentity` still returns only the identity and revokes the unneeded refresh token.) Finish that sign-in with `exchangeIdentity`, not `exchangeCode`:
22
22
 
23
23
  ```ts
24
24
  const {url, codeVerifier, state, nonce} = await oauth.authorizeUrl({scopes: ['openid', 'email', 'profile'], state: sessionState});
@@ -36,7 +36,7 @@ visitor.picture; // an https URL, present only when 'profile' was approved
36
36
 
37
37
  The SDK checks the ID token's ES256 signature against the directory's JWKS, its issuer, that `aud` is your client id, that it has not expired, and that its `nonce` equals the one `authorizeUrl` returned. `nonce` is required. Any failure throws `CrouterError` code `id_token_invalid`. If the directory's JWKS can't be fetched or is malformed, that error is thrown as is.
38
38
 
39
- An `Identity` is not a connection. Nothing is stored in a `ConnectionStore` and nothing refreshes; your app keeps its own session for the visitor, and the visitor's runtime can't be called on their behalf. To act for the visitor later, send them through `authorizeUrl` again with the runtime scopes you need and finish with `exchangeCode`, which returns a `Connection`. Each call refuses the other's answer with code `oauth_exchange_mismatch`. If `exchangeIdentity` refuses an answer that carries a connection, the directory has already recorded that grant; it shows in the person's approved apps until they or your app revoke it.
39
+ An `Identity` is not a connection. Nothing is stored in a `ConnectionStore` and nothing refreshes; your app keeps its own session for the visitor, and the visitor's runtime can't be called on their behalf. To act for the visitor later, send them through `authorizeUrl` again with the runtime scopes you need and finish with `exchangeCode`, which returns a `Connection`. `exchangeCode` refuses a sign-in-only answer with code `oauth_exchange_mismatch`.
40
40
 
41
41
  ## Whose action a call records
42
42
 
@@ -49,7 +49,7 @@ Then set your own session for the person. The SDK does not manage your sessions.
49
49
 
50
50
  ### Scopes decide what comes back
51
51
 
52
- A sign-in that asks only for `openid`, optionally with `email` and `profile`, creates no connection. Finish it with `oauth.exchangeIdentity(...)`, which returns the verified `Identity` (`sub`, and `email`, `name` and `picture` when approved and present). A sign-in that asks for runtime scopes such as `crtr:llm` finishes with `exchangeCode`. Each method refuses the other's answer with `oauth_exchange_mismatch`.
52
+ A sign-in that asks only for `openid`, optionally with `email` and `profile`, creates no connection. Finish it with `oauth.exchangeIdentity(...)`, which returns the verified `Identity` (`sub`, and `email`, `name` and `picture` when approved and present). A sign-in that asks for runtime scopes such as `crtr:llm` finishes with `exchangeCode`. `exchangeCode` refuses a sign-in-only answer with `oauth_exchange_mismatch`; `exchangeIdentity` accepts an answer that also carries a connection, returns the identity, and revokes the unneeded refresh token.
53
53
 
54
54
  ### When the directory refuses to sign someone in
55
55
 
@@ -116,7 +116,7 @@ It needs the app registered with the `app_token_for_user` operation, and an acti
116
116
 
117
117
  ## Signing in a visitor
118
118
 
119
- A person who only needs to be recognized, not connected, signs in with identity only: request `openid`, optionally with `email` and `profile`, and no runtime scope. Finish with `exchangeIdentity`, not `exchangeCode`. An `Identity` is not a connection: no runtime URL, grant or refresh token, nothing goes in the store, and you keep your own session. To act for that person later, send them through `authorizeUrl` again with the runtime scopes you need.
119
+ A person who only needs to be recognized, not connected, signs in with identity only: request `openid`, optionally with `email` and `profile`, and no runtime scope. Finish with `exchangeIdentity`, not `exchangeCode`. An `Identity` is not a connection: no runtime URL, grant or refresh token (if the directory answers with one anyway, `exchangeIdentity` revokes the refresh token), nothing goes in the store, and you keep your own session. To act for that person later, send them through `authorizeUrl` again with the runtime scopes you need.
120
120
 
121
121
  ## Checked and not checked
122
122
 
@@ -16,7 +16,7 @@ Codes the SDK raises itself are listed in `sdkErrorCodes`, and `CrouterError.cod
16
16
  | Code | Means | What to do |
17
17
  |---|---|---|
18
18
  | `id_token_invalid` | An ID token failed verification (signature, issuer, audience, expiry, missing or mismatched nonce), or a sign-in-only answer had no ID token. A JWKS that can't be fetched or is malformed is not this code: that error is thrown as is. | Restart the sign-in. |
19
- | `oauth_exchange_mismatch` | The wrong exchange call: `exchangeCode` on a sign-in-only answer, or `exchangeIdentity` on an answer that carries a connection. | Use the call that matches the scopes you requested ([Many users](/docs/guides/many-users#signing-in-a-visitor)). |
19
+ | `oauth_exchange_mismatch` | `exchangeCode` got a sign-in-only answer (no connection). | Finish a sign-in-only request with `exchangeIdentity` ([Many users](/docs/guides/many-users#signing-in-a-visitor)). |
20
20
  | `oauth_nonce_missing` | `exchangeIdentity` was called without the `nonce` from `authorizeUrl`. | Save the nonce in the visitor's session and pass it back. |
21
21
  | `oauth_state_mismatch` | The callback's `state` was missing or differed from the saved one. | Refuse the callback. |
22
22
  | `not_connected` | `oauth.client(userId)` or a refresh found no stored connection for that person. | Show "sign in again". |
@@ -16,7 +16,7 @@ Keep the connection and refresh token on the server, never in a visitor's browse
16
16
 
17
17
  ## Signing in a visitor
18
18
 
19
- A visitor who only needs to be recognized, not connected, signs in with identity only. Request `openid`, adding `email` for their email and `profile` for their name and photo, and no runtime scope. The directory shows one line ("Know who you are on Northlight"), writes no grant, and answers with an ID token and an access token usable only at `/userinfo`: no refresh token, grant or runtime URL. Finish that sign-in with `exchangeIdentity`, not `exchangeCode`:
19
+ A visitor who only needs to be recognized, not connected, signs in with identity only. Request `openid`, adding `email` for their email and `profile` for their name and photo, and no runtime scope. The directory shows one line ("Know who you are on Northlight"), writes no grant, and answers with an ID token and an access token usable only at `/userinfo`: no refresh token, grant or runtime URL. (An app held by a team with a runtime grant gets a connection on every sign-in; `exchangeIdentity` still returns only the identity and revokes the unneeded refresh token.) Finish that sign-in with `exchangeIdentity`, not `exchangeCode`:
20
20
 
21
21
  ```ts
22
22
  const {url, codeVerifier, state, nonce} = await oauth.authorizeUrl({scopes: ['openid', 'email', 'profile'], state: sessionState});
@@ -34,7 +34,7 @@ visitor.picture; // an https URL, present only when 'profile' was approved
34
34
 
35
35
  The SDK checks the ID token's ES256 signature against the directory's JWKS, its issuer, that `aud` is your client id, that it has not expired, and that its `nonce` equals the one `authorizeUrl` returned. `nonce` is required. Any failure throws `CrouterError` code `id_token_invalid`. If the directory's JWKS can't be fetched or is malformed, that error is thrown as is.
36
36
 
37
- An `Identity` is not a connection. Nothing is stored in a `ConnectionStore` and nothing refreshes; your app keeps its own session for the visitor, and the visitor's runtime can't be called on their behalf. To act for the visitor later, send them through `authorizeUrl` again with the runtime scopes you need and finish with `exchangeCode`, which returns a `Connection`. Each call refuses the other's answer with code `oauth_exchange_mismatch`. If `exchangeIdentity` refuses an answer that carries a connection, the directory has already recorded that grant; it shows in the person's approved apps until they or your app revoke it.
37
+ An `Identity` is not a connection. Nothing is stored in a `ConnectionStore` and nothing refreshes; your app keeps its own session for the visitor, and the visitor's runtime can't be called on their behalf. To act for the visitor later, send them through `authorizeUrl` again with the runtime scopes you need and finish with `exchangeCode`, which returns a `Connection`. `exchangeCode` refuses a sign-in-only answer with code `oauth_exchange_mismatch`.
38
38
 
39
39
  ## Whose action a call records
40
40
 
@@ -9,6 +9,8 @@ Changes to `@north-light/sdk` that can change what an existing app sees. Newest
9
9
 
10
10
  ## 0.3.539
11
11
 
12
+ `exchangeIdentity` now returns the verified identity when the directory's token answer also carries a runtime connection. It used to throw `oauth_exchange_mismatch`, so no member could sign in to an app held by a team with a runtime grant (the directory gives that app a connection on every sign-in). The SDK revokes the unneeded refresh token best-effort; revocation removes only that token, never the grant. `exchangeCode` still refuses a sign-in-only answer.
13
+
12
14
  A run started with no `kind` and no `model`, in a profile with no `default_kind` (every app's own default profile), now starts as the `general` kind on the `medium` rung. It used to start as `developer` on that kind's model (`openai/medium`). `profile.list` reports `general` as such a profile's `default_kind`. On an app-paid grant the run lands on the app's `medium` inference rung, where it used to land on `strong`. Pass `model` on `run.start` to keep another rung.
13
15
 
14
16
  Profiles name the machine environment they run on. Additive: no request or response an existing app sends or reads changes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.539",
3
+ "version": "0.3.540",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -140,7 +140,7 @@
140
140
  },
141
141
  "license": "UNLICENSED",
142
142
  "dependencies": {
143
- "@north-light/identity": "0.3.539",
143
+ "@north-light/identity": "0.3.540",
144
144
  "@earendil-works/pi-agent-core": "1.1.0",
145
145
  "@earendil-works/pi-ai": "1.1.0",
146
146
  "@earendil-works/pi-coding-agent": "1.1.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/identity",
3
- "version": "0.3.539",
3
+ "version": "0.3.540",
4
4
  "description": "Northlight access-token verification and scope rules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.539",
3
+ "version": "0.3.540",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/cli",
9
- "version": "0.3.539",
9
+ "version": "0.3.540",
10
10
  "hasInstallScript": true,
11
11
  "license": "UNLICENSED",
12
12
  "workspaces": [
@@ -24,7 +24,7 @@
24
24
  "@milkdown/preset-gfm": "^7.22.3",
25
25
  "@milkdown/prose": "^7.22.3",
26
26
  "@milkdown/utils": "^7.22.3",
27
- "@north-light/identity": "0.3.539",
27
+ "@north-light/identity": "0.3.540",
28
28
  "cron-parser": "^5.6.0",
29
29
  "esbuild": "^0.27.7",
30
30
  "jose": "^6.2.12",
@@ -12455,17 +12455,17 @@
12455
12455
  },
12456
12456
  "packages/crouter-api": {
12457
12457
  "name": "@north-light/api",
12458
- "version": "0.3.539",
12458
+ "version": "0.3.540",
12459
12459
  "license": "UNLICENSED"
12460
12460
  },
12461
12461
  "packages/crouter-env-docker": {
12462
12462
  "name": "@north-light/env-docker",
12463
- "version": "0.3.539",
12463
+ "version": "0.3.540",
12464
12464
  "license": "UNLICENSED"
12465
12465
  },
12466
12466
  "packages/crouter-identity": {
12467
12467
  "name": "@north-light/identity",
12468
- "version": "0.3.539",
12468
+ "version": "0.3.540",
12469
12469
  "license": "UNLICENSED",
12470
12470
  "dependencies": {
12471
12471
  "jose": "^6.2.1"
@@ -12473,20 +12473,20 @@
12473
12473
  },
12474
12474
  "packages/crouter-plugin": {
12475
12475
  "name": "@north-light/plugin",
12476
- "version": "0.3.539",
12476
+ "version": "0.3.540",
12477
12477
  "license": "UNLICENSED",
12478
12478
  "dependencies": {
12479
- "@north-light/api": "0.3.539",
12480
- "@north-light/identity": "0.3.539"
12479
+ "@north-light/api": "0.3.540",
12480
+ "@north-light/identity": "0.3.540"
12481
12481
  }
12482
12482
  },
12483
12483
  "packages/crouter-sdk": {
12484
12484
  "name": "@north-light/sdk",
12485
- "version": "0.3.539",
12485
+ "version": "0.3.540",
12486
12486
  "license": "UNLICENSED",
12487
12487
  "dependencies": {
12488
- "@north-light/api": "0.3.539",
12489
- "@north-light/identity": "0.3.539",
12488
+ "@north-light/api": "0.3.540",
12489
+ "@north-light/identity": "0.3.540",
12490
12490
  "jose": "^6.2.1"
12491
12491
  },
12492
12492
  "bin": {