fix: complete ORM port — token/oauth-client API mismatches, use published orm 0.2.8

- Use published @simpleworkjs/orm ^0.2.8 (fixes redis adapter write path)
  and model-redis ^1.6.0 instead of a local file: link that broke docker
  npm ci with a misleading "no lockfile" error.
- OtpToken.issue/verify: replace nonexistent find()/listDetail() with
  list({where}).
- routes/auth.js: ImpersonationToken.listDetail() -> list({where}).
- routes/token.js: drop listDetail() call; 404 on missing token instead
  of returning {results: null} with 200 (orm get() returns null, does
  not throw like model-redis Table.get did).
- OAuthClient: Resource has no is_valid column, so every client read as
  disabled and all /oauth/authorize requests 400'd — validity now lives
  in metadata (absent = valid). Also generate a unique slug on create
  (Resource.slug is required+unique) and use Resource.get() for lookup.
- User.login: 401 cleanly when neither uid nor username is supplied.
- models/index.js: log ORM init and surface init failures.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 02:20:49 -04:00
parent c4d7a1a8e9
commit 5dcc75195c
8 changed files with 1607 additions and 364 deletions
+2 -2
View File
@@ -203,7 +203,7 @@ router.post('/impersonate/:uid', middleware.auth, async function(req, res, next)
const target = await User.get(req.params.uid);
// Clean up any existing impersonation for this target
const existing = await ImpersonationToken.listDetail({ target_uid: target.uid });
const existing = await ImpersonationToken.list({ where: { target_uid: target.uid } });
for (const old of existing) {
if (old.is_valid && !old.isExpired) {
try { await target.removeTempPassword(old.temp_hash); } catch(_) {}
@@ -237,7 +237,7 @@ router.delete('/impersonate/:uid', middleware.auth, async function(req, res, nex
await permission.byGroup(req.user, ['app_sso_admin']);
const target = await User.get(req.params.uid);
const existing = await ImpersonationToken.listDetail({ target_uid: target.uid });
const existing = await ImpersonationToken.list({ where: { target_uid: target.uid } });
let revoked = 0;
for (const token of existing) {