@camstack/server 1.2.133 → 1.2.134

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.
@@ -178,6 +178,10 @@ async function resolveUser(token, authService, addonRegistry, shareTokens = null
178
178
  // and until this was carried onto the principal a refusal of one was
179
179
  // indistinguishable in the logs from a refusal of a browser session.
180
180
  const credential = (0, trpc_error_principal_js_1.readCredentialIdentity)(payload);
181
+ // What the token IS decides WHERE its scopes come from. A `session` JWT is
182
+ // governed by its user's record; anything else carries its own grant and
183
+ // must keep it — see the live-scope note on the spread below.
184
+ const principal = (0, types_1.classifyBearerPrincipal)(payload);
181
185
  return {
182
186
  id: payload.userId ?? payload.keyId ?? 'unknown',
183
187
  username: payload.username ?? 'unknown',
@@ -198,12 +202,21 @@ async function resolveUser(token, authService, addonRegistry, shareTokens = null
198
202
  // user's scopes expects the change to APPLY, and the live session
199
203
  // kept gating on the old set until re-login (2026-08-15: a user
200
204
  // granted the whole fleet kept seeing zero cameras). For non-admin
201
- // JWT principals the store's current scopes win when readable
205
+ // SESSION principals the store's current scopes win when readable
202
206
  // (memoized — see above); the JWT's copy is the fallback when the
203
207
  // user-management cap is unreachable, so a store hiccup never
204
208
  // locks anybody out mid-request.
209
+ //
210
+ // `session` ONLY, and that word is the whole fix. An ACCOUNT-LINK token
211
+ // is governed by the grant the operator consented to, not by the linking
212
+ // user's record: it always carries `isAdmin: false` (`oauth-grants.ts`
213
+ // → `baseClaims`) and its owner is normally an admin, whose record is
214
+ // deliberately unscoped — so the refresh replaced a six-scope Home
215
+ // Assistant grant with `[]` and the hub refused the component's first
216
+ // call with `Have: (none)` (2026-08-19). The user store knows nothing
217
+ // about a link and must not get a vote on one.
205
218
  ...(payload.scopes !== undefined ? { scopes: (0, types_1.normalizeTokenScopes)(payload.scopes) } : {}),
206
- ...(!payload.isAdmin
219
+ ...(!payload.isAdmin && principal.kind === 'session'
207
220
  ? await (async () => {
208
221
  const fresh = await refreshScopesFromStore(payload.userId ?? payload.keyId ?? 'unknown', addonRegistry);
209
222
  return fresh !== null ? { scopes: fresh } : {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.2.133",
3
+ "version": "1.2.134",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist",
@@ -33,19 +33,19 @@
33
33
  ]
34
34
  },
35
35
  "dependencies": {
36
- "@camstack/addon-admin-ui": "1.2.81",
37
- "@camstack/addon-agent-ui": "1.2.23",
38
- "@camstack/addon-auth": "1.2.25",
36
+ "@camstack/addon-admin-ui": "1.2.83",
37
+ "@camstack/addon-agent-ui": "1.2.24",
38
+ "@camstack/addon-auth": "1.2.26",
39
39
  "@camstack/addon-decoder-nodeav": "1.2.22",
40
40
  "@camstack/addon-notifiers": "1.2.27",
41
- "@camstack/addon-pipeline": "1.2.97",
42
- "@camstack/addon-pipeline-orchestrator": "1.2.81",
43
- "@camstack/addon-post-analysis": "1.2.96",
41
+ "@camstack/addon-pipeline": "1.2.98",
42
+ "@camstack/addon-pipeline-orchestrator": "1.2.83",
43
+ "@camstack/addon-post-analysis": "1.2.98",
44
44
  "@camstack/sdk": "1.2.25",
45
45
  "@camstack/shm-ring": "1.1.22",
46
46
  "@camstack/system": "1.2.106",
47
- "@camstack/types": "1.2.89",
48
- "@camstack/ui-library": "1.2.61",
47
+ "@camstack/types": "1.2.90",
48
+ "@camstack/ui-library": "1.2.62",
49
49
  "@fastify/compress": "^9.0.0",
50
50
  "@fastify/cookie": "^11.0.2",
51
51
  "@fastify/cors": "^11.2.0",