Add Session class to provide getUser() on call.session
Wraps SessionData and user into a Session class that handlers can use via call.session.getUser() instead of accessing services directly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import express, {
|
|||||||
type Response as ExpressResponse,
|
type Response as ExpressResponse,
|
||||||
} from "express";
|
} from "express";
|
||||||
import { match } from "path-to-regexp";
|
import { match } from "path-to-regexp";
|
||||||
|
import { Session } from "./auth";
|
||||||
import { cli } from "./cli";
|
import { cli } from "./cli";
|
||||||
import { contentTypes } from "./content-types";
|
import { contentTypes } from "./content-types";
|
||||||
import { httpCodes } from "./http-codes";
|
import { httpCodes } from "./http-codes";
|
||||||
@@ -68,7 +69,7 @@ routes.forEach((route: Route, _idx: number, _allRoutes: Route[]) => {
|
|||||||
parameters: { one: 1, two: 2 },
|
parameters: { one: 1, two: 2 },
|
||||||
request,
|
request,
|
||||||
user: auth.user,
|
user: auth.user,
|
||||||
session: auth.session,
|
session: new Session(auth.session, auth.user),
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -10,4 +10,11 @@ export { hashPassword, verifyPassword } from "./password";
|
|||||||
export { AuthService, type AuthResult } from "./service";
|
export { AuthService, type AuthResult } from "./service";
|
||||||
export { type AuthStore, InMemoryAuthStore } from "./store";
|
export { type AuthStore, InMemoryAuthStore } from "./store";
|
||||||
export { generateToken, hashToken, SESSION_COOKIE_NAME } from "./token";
|
export { generateToken, hashToken, SESSION_COOKIE_NAME } from "./token";
|
||||||
export * from "./types";
|
export {
|
||||||
|
type AuthMethod,
|
||||||
|
type SessionData,
|
||||||
|
type TokenId,
|
||||||
|
type TokenType,
|
||||||
|
Session,
|
||||||
|
tokenLifetimes,
|
||||||
|
} from "./types";
|
||||||
|
|||||||
@@ -62,3 +62,35 @@ export const tokenLifetimes: Record<TokenType, number> = {
|
|||||||
password_reset: 1 * 60 * 60 * 1000, // 1 hour
|
password_reset: 1 * 60 * 60 * 1000, // 1 hour
|
||||||
email_verify: 24 * 60 * 60 * 1000, // 24 hours
|
email_verify: 24 * 60 * 60 * 1000, // 24 hours
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Import here to avoid circular dependency at module load time
|
||||||
|
import { AnonymousUser, type MaybeUser } from "../user";
|
||||||
|
|
||||||
|
// Session wrapper class providing a consistent interface for handlers.
|
||||||
|
// Always present on Call (never null), but may represent an anonymous session.
|
||||||
|
export class Session {
|
||||||
|
constructor(
|
||||||
|
private readonly data: SessionData | null,
|
||||||
|
private readonly user: MaybeUser,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
getUser(): MaybeUser {
|
||||||
|
return this.user;
|
||||||
|
}
|
||||||
|
|
||||||
|
getData(): SessionData | null {
|
||||||
|
return this.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
isAuthenticated(): boolean {
|
||||||
|
return this.user !== AnonymousUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
get tokenId(): string | undefined {
|
||||||
|
return this.data?.tokenId;
|
||||||
|
}
|
||||||
|
|
||||||
|
get userId(): string | undefined {
|
||||||
|
return this.data?.userId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,19 +51,35 @@ const routes: Route[] = [
|
|||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const rrr = lr(routes)
|
||||||
|
|
||||||
|
const template=`
|
||||||
|
<html>
|
||||||
|
<head></head>
|
||||||
|
<body>
|
||||||
|
<ul>
|
||||||
|
{% for route in rrr %}
|
||||||
|
<li><a href="{{ route }}">{{ route }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`
|
||||||
|
const result = nunjucks.renderString(template,{rrr})
|
||||||
|
|
||||||
const listing = lr(routes).join(", ");
|
const listing = lr(routes).join(", ");
|
||||||
return {
|
return {
|
||||||
code,
|
code,
|
||||||
result: listing + "\n",
|
result,
|
||||||
contentType: contentTypes.text.plain,
|
contentType: contentTypes.text.html,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/whoami",
|
path: "/whoami",
|
||||||
methods: ["GET"],
|
methods: ["GET"],
|
||||||
handler: async (_call: Call): Promise<Result> => {
|
handler: async (call: Call): Promise<Result> => {
|
||||||
const me = services.session.getUser();
|
const me = call.session.getUser();
|
||||||
const template = `
|
const template = `
|
||||||
<html>
|
<html>
|
||||||
<head></head>
|
<head></head>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
} from "express";
|
} from "express";
|
||||||
import type { MatchFunction } from "path-to-regexp";
|
import type { MatchFunction } from "path-to-regexp";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import type { SessionData } from "./auth/types";
|
import type { Session } from "./auth/types";
|
||||||
import { type ContentType, contentTypes } from "./content-types";
|
import { type ContentType, contentTypes } from "./content-types";
|
||||||
import { type HttpCode, httpCodes } from "./http-codes";
|
import { type HttpCode, httpCodes } from "./http-codes";
|
||||||
import {
|
import {
|
||||||
@@ -40,7 +40,7 @@ export type Call = {
|
|||||||
parameters: object;
|
parameters: object;
|
||||||
request: ExpressRequest;
|
request: ExpressRequest;
|
||||||
user: MaybeUser;
|
user: MaybeUser;
|
||||||
session: SessionData | null;
|
session: Session;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type InternalHandler = (req: ExpressRequest) => Promise<Result>;
|
export type InternalHandler = (req: ExpressRequest) => Promise<Result>;
|
||||||
|
|||||||
Reference in New Issue
Block a user