@north-light/cli 0.3.418 → 0.3.419
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/builtin-memory/crouter-sdk/client.md +16 -0
- package/dist/builtin-memory/crouter-sdk/release-notes.md +10 -0
- package/dist/builtin-memory/crouter-sdk/testing.md +23 -1
- package/docs/sdk/client.md +16 -0
- package/docs/sdk/release-notes.md +10 -0
- package/docs/sdk/testing.md +23 -1
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +12 -12
|
@@ -42,6 +42,21 @@ const client = await oauth.client(connection.userId);
|
|
|
42
42
|
|
|
43
43
|
`state: callbackState` comes from the redirect query, while `expectedState` is the value saved in the app's session when `authorizeUrl()` ran. `exchangeCode` and `exchangeIdentity` refuse a missing or different value with `CrouterError` code `oauth_state_mismatch` **before** sending the code to the token endpoint. Persist the expected value across redirects and tie it to the user's session; never use the callback's `state` for both arguments.
|
|
44
44
|
|
|
45
|
+
### When sign-in is refused: apps in testing
|
|
46
|
+
|
|
47
|
+
A new app is in testing until Northlight verifies it. When someone who is not the app's admin or a named tester signs in, the directory redirects to your `redirectUri` with `error=access_denied`, `error_description=app_in_testing` and your `state`, and issues no code. `authorizationRefusalOf` reads it from the callback's query (a `URL`, `URLSearchParams`, query string, or parsed object) and returns `{code: 'app_in_testing', error: 'access_denied', state}`, else `null`:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import {authorizationRefusalOf} from '@north-light/sdk';
|
|
51
|
+
|
|
52
|
+
const refused = authorizationRefusalOf(new URL(request.url));
|
|
53
|
+
if (refused) {
|
|
54
|
+
// check refused.state against the saved state, then show "this app is in testing; ask its developer to add you"
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
A person who pressed Cancel (`access_denied` with no reason) returns `null`. Test the path with [[crouter-sdk/testing]].
|
|
59
|
+
|
|
45
60
|
### Keep sign-in secrets out of HTTP logs
|
|
46
61
|
|
|
47
62
|
If your app uses `nestjs-pino` / `pino-http`, its default serializers can log the full `/auth/callback?code=…&state=…` URL and query, plus response headers including the session `set-cookie` and a redirect `location` containing OAuth `state`. Redacting only authorization and cookie **request** headers does not protect these values. Use bounded serializers for *all* routes, not just the callback: log only request method, path without query string, and id; log only response status. For example:
|
|
@@ -107,6 +122,7 @@ A `Refusal` is `{kind, code, userId, grantId, error}`. `kind` reads this table;
|
|
|
107
122
|
|---|---|---|---|
|
|
108
123
|
| `grant_removed` | `removed` | The person removed your app, deleted their account, or a provider-connected registration disconnected them. The runtime has deleted your app's space, runs, schedules and shares. | You may delete what you keep for that person. Do not call `runs.delete`: the runs are already gone. If they connect again, they see the consent page and start fresh. |
|
|
109
124
|
| `grant_suspended` | `paused` | Your app's access for that person is paused. Nothing was deleted; your app's sandboxes are stopped. | Keep everything you store for that person, stop calling for them, and show that the app is paused. If they connect again, the same grant comes back with every run, file and schedule. |
|
|
125
|
+
| `app_in_testing` | `paused` | Your app is still in testing (not verified by Northlight) and this person is not its admin or a named tester: they were removed as a tester, or their email or phone stopped matching one. Their grant is revoked, not removed; nothing was deleted and your app's sandboxes are stopped. | Keep everything you store for that person, stop calling for them, and tell them the app is in testing and the developer must add them. If the developer adds them back and they sign in again, the same space comes back. |
|
|
110
126
|
| `refresh_token_expired` | `reconnect` | The refresh token went 90 days without use. The grant is still active. | Keep everything. Run the connect flow again; the consent page is skipped. Prevent it with `refreshIdleConnections` (below). |
|
|
111
127
|
| `refresh_token_reused` | `reconnect` | Two of your app's processes raced on one refresh token, and the directory ended the grant's refresh tokens. The grant is still active. | Keep everything. Fix the store's `lock`, then reconnect (consent is skipped); without the fix the race recurs. |
|
|
112
128
|
| `grant_revoked` | `reconnect` | The directory refused without naming a reason: a refresh token it never issued to your app, one your app revoked through `revoke`, or one whose record was purged. The runtime also answers `grant_revoked` when the grant is not active in its last sync; the connected client then refreshes once, so you normally receive the directory's specific code instead. | Keep everything and reconnect. Never delete data on `grant_revoked`: it does not say anything was removed. |
|
|
@@ -9,6 +9,16 @@ when-and-why-to-read: When you need Release notes, this knowledge should be read
|
|
|
9
9
|
|
|
10
10
|
Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
|
|
11
11
|
|
|
12
|
+
## 0.3.419
|
|
13
|
+
|
|
14
|
+
### Testing mode: `app_in_testing` (additive)
|
|
15
|
+
|
|
16
|
+
Not breaking: no type or wire shape an app reads is removed or changed.
|
|
17
|
+
|
|
18
|
+
- An app Northlight has not verified is in testing: only its admin and named testers can sign in. A refused sign-in redirects with `error=access_denied`, `error_description=app_in_testing`; a refused refresh answers `invalid_grant` `app_in_testing`. The refresh refusal is a new `Refusal` with `code: 'app_in_testing'` and `kind: 'paused'`, like `grant_suspended`: keep the person's data. If you `switch` exhaustively on `refusal.code`, add the case. See [[crouter-sdk/client]].
|
|
19
|
+
- New `authorizationRefusalOf(callback)` reads the sign-in refusal from the callback's query and returns `AuthorizationRefusal` (`{code: 'app_in_testing', error: 'access_denied', state}`), else `null`. See [[crouter-sdk/client]].
|
|
20
|
+
- `@north-light/sdk/testing`: `cloud.testing` (`enable`, `disable`, `active`, `addTester`, `removeTester`, `testers`, `allowed`), `cloud.authorize(userId, {redirectUri, state})`, `user.setAccount({email, emailVerified, phone})`, and `'app_in_testing'` in `FakeRefusalCode`. The fake directory now serves `grant_type=authorization_code` for codes `cloud.authorize` issued. See [[crouter-sdk/testing]].
|
|
21
|
+
|
|
12
22
|
## 0.3.415
|
|
13
23
|
|
|
14
24
|
### Monthly spend cap enforced; `usage.get` (additive; one behavior change)
|
|
@@ -89,12 +89,34 @@ Idempotency follows the runtime too: the same `Idempotency-Key` with the same bo
|
|
|
89
89
|
|
|
90
90
|
## Refusals
|
|
91
91
|
|
|
92
|
-
- `user.refuse(code)` leaves the grant alone: the directory refuses each refresh with `code` (`grant_removed`, `grant_suspended`, `refresh_token_expired`, `refresh_token_reused`, `grant_revoked`), and tokens issued before the call get 401, so the next call refreshes and is refused. `refuse('ok')` clears it.
|
|
92
|
+
- `user.refuse(code)` leaves the grant alone: the directory refuses each refresh with `code` (`grant_removed`, `grant_suspended`, `app_in_testing`, `refresh_token_expired`, `refresh_token_reused`, `grant_revoked`), and tokens issued before the call get 401, so the next call refreshes and is refused. `refuse('ok')` clears it.
|
|
93
93
|
- `grant.revoke('grant_removed')` deactivates the grant: calls answer 401 `grant_revoked`, held reads wake to it, open streams get an error frame, and the next refresh is refused with that code.
|
|
94
94
|
- `user.expireTokens()` forces a refresh without a refusal.
|
|
95
95
|
|
|
96
96
|
The real `OAuth2Client` handles all of it: your `onRefusal` runs with the refusal, the stored connection is removed, and the thrown error has `refusalOf(e)` set. `await cloud.refusalError(code)` returns that exact error for unit tests that need the value.
|
|
97
97
|
|
|
98
|
+
## Testing mode
|
|
99
|
+
|
|
100
|
+
An unverified third-party app is *in testing* on crouter cloud: only its admin and up to 100 named testers can sign in, and anyone else is refused. `cloud.testing` puts the fake's app in that state so your app can test the refusal.
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
cloud.user('user:tess').setAccount({ email: 'tess@example.com' }); // the identifiers the account holds
|
|
104
|
+
cloud.testing.addTester({ email: 'Tess@Example.com' }); // or {phone: '+15551234567'}; false if already present
|
|
105
|
+
cloud.testing.enable({ admin: 'user:me' }); // in testing; revokes active grants of people not allowed
|
|
106
|
+
|
|
107
|
+
const back = cloud.authorize('user:stranger', { redirectUri, state }); // the redirect the browser follows back to your app
|
|
108
|
+
authorizationRefusalOf(back); // {code: 'app_in_testing', error: 'access_denied', state}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
- `cloud.testing.enable({admin?})` / `disable()` / `active`. `enable` returns the user ids whose active grants it revoked.
|
|
112
|
+
- `addTester({email} | {phone})` stores the entry (email trimmed and lowercased, phone E.164). The 101st entry throws. `removeTester(ref)` returns `{removed, revoked}`: a removed tester's active grant is revoked, not deleted, and the fake keeps their runs.
|
|
113
|
+
- `cloud.testing.allowed(userId)`: not in testing, the admin, or a tester entry matches the account: an `email` entry needs `emailVerified` (default true when `email` is set), a `phone` entry matches `setAccount({phone})`.
|
|
114
|
+
- A refresh for an active grant whose person is not allowed answers `invalid_grant` `app_in_testing`, and so does a refresh after the grant was revoked this way. `oauth.client(id)` rejects with an `AuthenticationError` (`code: 'app_in_testing'`, `refusalOf(e).kind === 'paused'`) and `onRefusal` runs. Keep the person's data.
|
|
115
|
+
- `cloud.authorize(userId, {redirectUri, state, scopes?})` stands in for the browser round trip. An allowed person gets an active grant and a redirect with `code` and `state`; give `code` to `oauth.exchangeCode`. A person who is not allowed gets `error=access_denied`, `error_description=app_in_testing` and `state`, and nothing is written. A person revoked by `removeTester` who is allowed again gets access back by `authorize`.
|
|
116
|
+
- When a person's email or phone stops matching (`setAccount`), nothing is revoked; their next refresh and `authorize` are refused.
|
|
117
|
+
|
|
118
|
+
In your callback handler, check `authorizationRefusalOf(url)` before reading `code`.
|
|
119
|
+
|
|
98
120
|
## Memory and providers
|
|
99
121
|
|
|
100
122
|
`user.memory.put({name, body, privacy = 'public', kind = 'knowledge', ...})` and `remove(name)`. Without `crtr:memory:manage:user` in the grant, only `public` documents are listed and others read as 404, as on the runtime. List items carry the full `MemoryListItem` fields.
|
package/docs/sdk/client.md
CHANGED
|
@@ -40,6 +40,21 @@ const client = await oauth.client(connection.userId);
|
|
|
40
40
|
|
|
41
41
|
`state: callbackState` comes from the redirect query, while `expectedState` is the value saved in the app's session when `authorizeUrl()` ran. `exchangeCode` and `exchangeIdentity` refuse a missing or different value with `CrouterError` code `oauth_state_mismatch` **before** sending the code to the token endpoint. Persist the expected value across redirects and tie it to the user's session; never use the callback's `state` for both arguments.
|
|
42
42
|
|
|
43
|
+
### When sign-in is refused: apps in testing
|
|
44
|
+
|
|
45
|
+
A new app is in testing until Northlight verifies it. When someone who is not the app's admin or a named tester signs in, the directory redirects to your `redirectUri` with `error=access_denied`, `error_description=app_in_testing` and your `state`, and issues no code. `authorizationRefusalOf` reads it from the callback's query (a `URL`, `URLSearchParams`, query string, or parsed object) and returns `{code: 'app_in_testing', error: 'access_denied', state}`, else `null`:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import {authorizationRefusalOf} from '@north-light/sdk';
|
|
49
|
+
|
|
50
|
+
const refused = authorizationRefusalOf(new URL(request.url));
|
|
51
|
+
if (refused) {
|
|
52
|
+
// check refused.state against the saved state, then show "this app is in testing; ask its developer to add you"
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
A person who pressed Cancel (`access_denied` with no reason) returns `null`. Test the path with [`cloud.testing`](./testing.md#testing-mode).
|
|
57
|
+
|
|
43
58
|
### Keep sign-in secrets out of HTTP logs
|
|
44
59
|
|
|
45
60
|
If your app uses `nestjs-pino` / `pino-http`, its default serializers can log the full `/auth/callback?code=…&state=…` URL and query, plus response headers including the session `set-cookie` and a redirect `location` containing OAuth `state`. Redacting only authorization and cookie **request** headers does not protect these values. Use bounded serializers for *all* routes, not just the callback: log only request method, path without query string, and id; log only response status. For example:
|
|
@@ -105,6 +120,7 @@ A `Refusal` is `{kind, code, userId, grantId, error}`. `kind` reads this table;
|
|
|
105
120
|
|---|---|---|---|
|
|
106
121
|
| `grant_removed` | `removed` | The person removed your app, deleted their account, or a provider-connected registration disconnected them. The runtime has deleted your app's space, runs, schedules and shares. | You may delete what you keep for that person. Do not call `runs.delete`: the runs are already gone. If they connect again, they see the consent page and start fresh. |
|
|
107
122
|
| `grant_suspended` | `paused` | Your app's access for that person is paused. Nothing was deleted; your app's sandboxes are stopped. | Keep everything you store for that person, stop calling for them, and show that the app is paused. If they connect again, the same grant comes back with every run, file and schedule. |
|
|
123
|
+
| `app_in_testing` | `paused` | Your app is still in testing (not verified by Northlight) and this person is not its admin or a named tester: they were removed as a tester, or their email or phone stopped matching one. Their grant is revoked, not removed; nothing was deleted and your app's sandboxes are stopped. | Keep everything you store for that person, stop calling for them, and tell them the app is in testing and the developer must add them. If the developer adds them back and they sign in again, the same space comes back. |
|
|
108
124
|
| `refresh_token_expired` | `reconnect` | The refresh token went 90 days without use. The grant is still active. | Keep everything. Run the connect flow again; the consent page is skipped. Prevent it with `refreshIdleConnections` (below). |
|
|
109
125
|
| `refresh_token_reused` | `reconnect` | Two of your app's processes raced on one refresh token, and the directory ended the grant's refresh tokens. The grant is still active. | Keep everything. Fix the store's `lock`, then reconnect (consent is skipped); without the fix the race recurs. |
|
|
110
126
|
| `grant_revoked` | `reconnect` | The directory refused without naming a reason: a refresh token it never issued to your app, one your app revoked through `revoke`, or one whose record was purged. The runtime also answers `grant_revoked` when the grant is not active in its last sync; the connected client then refreshes once, so you normally receive the directory's specific code instead. | Keep everything and reconnect. Never delete data on `grant_revoked`: it does not say anything was removed. |
|
|
@@ -7,6 +7,16 @@ description: Behavior changes in @north-light/sdk that an app must act on, newes
|
|
|
7
7
|
|
|
8
8
|
Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
|
|
9
9
|
|
|
10
|
+
## 0.3.419
|
|
11
|
+
|
|
12
|
+
### Testing mode: `app_in_testing` (additive)
|
|
13
|
+
|
|
14
|
+
Not breaking: no type or wire shape an app reads is removed or changed.
|
|
15
|
+
|
|
16
|
+
- An app Northlight has not verified is in testing: only its admin and named testers can sign in. A refused sign-in redirects with `error=access_denied`, `error_description=app_in_testing`; a refused refresh answers `invalid_grant` `app_in_testing`. The refresh refusal is a new `Refusal` with `code: 'app_in_testing'` and `kind: 'paused'`, like `grant_suspended`: keep the person's data. If you `switch` exhaustively on `refusal.code`, add the case. See [When a refresh is refused](./client.md#when-a-refresh-is-refused).
|
|
17
|
+
- New `authorizationRefusalOf(callback)` reads the sign-in refusal from the callback's query and returns `AuthorizationRefusal` (`{code: 'app_in_testing', error: 'access_denied', state}`), else `null`. See [When sign-in is refused](./client.md#when-sign-in-is-refused-apps-in-testing).
|
|
18
|
+
- `@north-light/sdk/testing`: `cloud.testing` (`enable`, `disable`, `active`, `addTester`, `removeTester`, `testers`, `allowed`), `cloud.authorize(userId, {redirectUri, state})`, `user.setAccount({email, emailVerified, phone})`, and `'app_in_testing'` in `FakeRefusalCode`. The fake directory now serves `grant_type=authorization_code` for codes `cloud.authorize` issued. See [Testing mode](./testing.md#testing-mode).
|
|
19
|
+
|
|
10
20
|
## 0.3.415
|
|
11
21
|
|
|
12
22
|
### Monthly spend cap enforced; `usage.get` (additive; one behavior change)
|
package/docs/sdk/testing.md
CHANGED
|
@@ -87,12 +87,34 @@ Idempotency follows the runtime too: the same `Idempotency-Key` with the same bo
|
|
|
87
87
|
|
|
88
88
|
## Refusals
|
|
89
89
|
|
|
90
|
-
- `user.refuse(code)` leaves the grant alone: the directory refuses each refresh with `code` (`grant_removed`, `grant_suspended`, `refresh_token_expired`, `refresh_token_reused`, `grant_revoked`), and tokens issued before the call get 401, so the next call refreshes and is refused. `refuse('ok')` clears it.
|
|
90
|
+
- `user.refuse(code)` leaves the grant alone: the directory refuses each refresh with `code` (`grant_removed`, `grant_suspended`, `app_in_testing`, `refresh_token_expired`, `refresh_token_reused`, `grant_revoked`), and tokens issued before the call get 401, so the next call refreshes and is refused. `refuse('ok')` clears it.
|
|
91
91
|
- `grant.revoke('grant_removed')` deactivates the grant: calls answer 401 `grant_revoked`, held reads wake to it, open streams get an error frame, and the next refresh is refused with that code.
|
|
92
92
|
- `user.expireTokens()` forces a refresh without a refusal.
|
|
93
93
|
|
|
94
94
|
The real `OAuth2Client` handles all of it: your `onRefusal` runs with the refusal, the stored connection is removed, and the thrown error has `refusalOf(e)` set. `await cloud.refusalError(code)` returns that exact error for unit tests that need the value.
|
|
95
95
|
|
|
96
|
+
## Testing mode
|
|
97
|
+
|
|
98
|
+
An unverified third-party app is *in testing* on crouter cloud: only its admin and up to 100 named testers can sign in, and anyone else is refused. `cloud.testing` puts the fake's app in that state so your app can test the refusal.
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
cloud.user('user:tess').setAccount({ email: 'tess@example.com' }); // the identifiers the account holds
|
|
102
|
+
cloud.testing.addTester({ email: 'Tess@Example.com' }); // or {phone: '+15551234567'}; false if already present
|
|
103
|
+
cloud.testing.enable({ admin: 'user:me' }); // in testing; revokes active grants of people not allowed
|
|
104
|
+
|
|
105
|
+
const back = cloud.authorize('user:stranger', { redirectUri, state }); // the redirect the browser follows back to your app
|
|
106
|
+
authorizationRefusalOf(back); // {code: 'app_in_testing', error: 'access_denied', state}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- `cloud.testing.enable({admin?})` / `disable()` / `active`. `enable` returns the user ids whose active grants it revoked.
|
|
110
|
+
- `addTester({email} | {phone})` stores the entry (email trimmed and lowercased, phone E.164). The 101st entry throws. `removeTester(ref)` returns `{removed, revoked}`: a removed tester's active grant is revoked, not deleted, and the fake keeps their runs.
|
|
111
|
+
- `cloud.testing.allowed(userId)`: not in testing, the admin, or a tester entry matches the account: an `email` entry needs `emailVerified` (default true when `email` is set), a `phone` entry matches `setAccount({phone})`.
|
|
112
|
+
- A refresh for an active grant whose person is not allowed answers `invalid_grant` `app_in_testing`, and so does a refresh after the grant was revoked this way. `oauth.client(id)` rejects with an `AuthenticationError` (`code: 'app_in_testing'`, `refusalOf(e).kind === 'paused'`) and `onRefusal` runs. Keep the person's data.
|
|
113
|
+
- `cloud.authorize(userId, {redirectUri, state, scopes?})` stands in for the browser round trip. An allowed person gets an active grant and a redirect with `code` and `state`; give `code` to `oauth.exchangeCode`. A person who is not allowed gets `error=access_denied`, `error_description=app_in_testing` and `state`, and nothing is written. A person revoked by `removeTester` who is allowed again gets access back by `authorize`.
|
|
114
|
+
- When a person's email or phone stops matching (`setAccount`), nothing is revoked; their next refresh and `authorize` are refused.
|
|
115
|
+
|
|
116
|
+
In your callback handler, check `authorizationRefusalOf(url)` before reading `code`.
|
|
117
|
+
|
|
96
118
|
## Memory and providers
|
|
97
119
|
|
|
98
120
|
`user.memory.put({name, body, privacy = 'public', kind = 'knowledge', ...})` and `remove(name)`. Without `crtr:memory:manage:user` in the grant, only `public` documents are listed and others read as 404, as on the runtime. List items carry the full `MemoryListItem` fields.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.419",
|
|
4
4
|
"description": "crtr — agent runtime with memory, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
},
|
|
135
135
|
"license": "UNLICENSED",
|
|
136
136
|
"dependencies": {
|
|
137
|
-
"@north-light/identity": "0.3.
|
|
137
|
+
"@north-light/identity": "0.3.419",
|
|
138
138
|
"@earendil-works/pi-agent-core": "1.1.0",
|
|
139
139
|
"@earendil-works/pi-ai": "1.1.0",
|
|
140
140
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.419",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/cli",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.419",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "UNLICENSED",
|
|
12
12
|
"workspaces": [
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"@earendil-works/pi-ai": "1.1.0",
|
|
19
19
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
|
20
20
|
"@earendil-works/pi-tui": "1.1.0",
|
|
21
|
-
"@north-light/identity": "0.3.
|
|
21
|
+
"@north-light/identity": "0.3.419",
|
|
22
22
|
"cron-parser": "^5.6.0",
|
|
23
23
|
"esbuild": "^0.27.7",
|
|
24
24
|
"jose": "^6.2.12",
|
|
@@ -12095,17 +12095,17 @@
|
|
|
12095
12095
|
},
|
|
12096
12096
|
"packages/crouter-api": {
|
|
12097
12097
|
"name": "@north-light/api",
|
|
12098
|
-
"version": "0.3.
|
|
12098
|
+
"version": "0.3.419",
|
|
12099
12099
|
"license": "UNLICENSED"
|
|
12100
12100
|
},
|
|
12101
12101
|
"packages/crouter-env-docker": {
|
|
12102
12102
|
"name": "@north-light/env-docker",
|
|
12103
|
-
"version": "0.3.
|
|
12103
|
+
"version": "0.3.419",
|
|
12104
12104
|
"license": "UNLICENSED"
|
|
12105
12105
|
},
|
|
12106
12106
|
"packages/crouter-identity": {
|
|
12107
12107
|
"name": "@north-light/identity",
|
|
12108
|
-
"version": "0.3.
|
|
12108
|
+
"version": "0.3.419",
|
|
12109
12109
|
"license": "UNLICENSED",
|
|
12110
12110
|
"dependencies": {
|
|
12111
12111
|
"jose": "^6.2.1"
|
|
@@ -12113,20 +12113,20 @@
|
|
|
12113
12113
|
},
|
|
12114
12114
|
"packages/crouter-plugin": {
|
|
12115
12115
|
"name": "@north-light/plugin",
|
|
12116
|
-
"version": "0.3.
|
|
12116
|
+
"version": "0.3.419",
|
|
12117
12117
|
"license": "UNLICENSED",
|
|
12118
12118
|
"dependencies": {
|
|
12119
|
-
"@north-light/api": "0.3.
|
|
12120
|
-
"@north-light/identity": "0.3.
|
|
12119
|
+
"@north-light/api": "0.3.419",
|
|
12120
|
+
"@north-light/identity": "0.3.419"
|
|
12121
12121
|
}
|
|
12122
12122
|
},
|
|
12123
12123
|
"packages/crouter-sdk": {
|
|
12124
12124
|
"name": "@north-light/sdk",
|
|
12125
|
-
"version": "0.3.
|
|
12125
|
+
"version": "0.3.419",
|
|
12126
12126
|
"license": "UNLICENSED",
|
|
12127
12127
|
"dependencies": {
|
|
12128
|
-
"@north-light/api": "0.3.
|
|
12129
|
-
"@north-light/identity": "0.3.
|
|
12128
|
+
"@north-light/api": "0.3.419",
|
|
12129
|
+
"@north-light/identity": "0.3.419",
|
|
12130
12130
|
"jose": "^6.2.1"
|
|
12131
12131
|
},
|
|
12132
12132
|
"bin": {
|