@thi.ng/server 0.11.12 → 0.12.2
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/CHANGELOG.md +7 -1
- package/README.md +1 -1
- package/package.json +19 -19
- package/session/session.d.ts +17 -5
- package/session/session.js +13 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2025-
|
|
3
|
+
- **Last updated**: 2025-08-06T18:02:31Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -11,6 +11,12 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
11
11
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
12
12
|
and/or version bumps of transitive dependencies.
|
|
13
13
|
|
|
14
|
+
## [0.12.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/server@0.12.0) (2025-08-04)
|
|
15
|
+
|
|
16
|
+
#### 🚀 Features
|
|
17
|
+
|
|
18
|
+
- add `SessionOpts.onInvalid` callback ([83c15ee](https://github.com/thi-ng/umbrella/commit/83c15ee))
|
|
19
|
+
|
|
14
20
|
## [0.11.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/server@0.11.0) (2025-06-05)
|
|
15
21
|
|
|
16
22
|
#### 🚀 Features
|
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.2",
|
|
4
4
|
"description": "Minimal HTTP server with declarative routing, static file serving and freely extensible via pre/post interceptors",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -39,26 +39,26 @@
|
|
|
39
39
|
"tool:tangle": "../../node_modules/.bin/tangle src/**/*.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@thi.ng/api": "^8.
|
|
43
|
-
"@thi.ng/arrays": "^2.13.
|
|
44
|
-
"@thi.ng/cache": "^2.3.
|
|
45
|
-
"@thi.ng/checks": "^3.7.
|
|
46
|
-
"@thi.ng/errors": "^2.5.
|
|
47
|
-
"@thi.ng/file-io": "^2.2.
|
|
48
|
-
"@thi.ng/leaky-bucket": "^0.2.
|
|
49
|
-
"@thi.ng/logger": "^3.1.
|
|
50
|
-
"@thi.ng/mime": "^2.7.
|
|
51
|
-
"@thi.ng/paths": "^5.2.
|
|
52
|
-
"@thi.ng/router": "^4.1.
|
|
53
|
-
"@thi.ng/strings": "^3.9.
|
|
54
|
-
"@thi.ng/timestamp": "^1.1.
|
|
55
|
-
"@thi.ng/uuid": "^1.1.
|
|
42
|
+
"@thi.ng/api": "^8.12.1",
|
|
43
|
+
"@thi.ng/arrays": "^2.13.8",
|
|
44
|
+
"@thi.ng/cache": "^2.3.46",
|
|
45
|
+
"@thi.ng/checks": "^3.7.15",
|
|
46
|
+
"@thi.ng/errors": "^2.5.41",
|
|
47
|
+
"@thi.ng/file-io": "^2.2.6",
|
|
48
|
+
"@thi.ng/leaky-bucket": "^0.2.13",
|
|
49
|
+
"@thi.ng/logger": "^3.1.16",
|
|
50
|
+
"@thi.ng/mime": "^2.7.17",
|
|
51
|
+
"@thi.ng/paths": "^5.2.18",
|
|
52
|
+
"@thi.ng/router": "^4.1.38",
|
|
53
|
+
"@thi.ng/strings": "^3.9.21",
|
|
54
|
+
"@thi.ng/timestamp": "^1.1.20",
|
|
55
|
+
"@thi.ng/uuid": "^1.1.32"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@types/node": "^24.0
|
|
58
|
+
"@types/node": "^24.1.0",
|
|
59
59
|
"esbuild": "^0.25.8",
|
|
60
|
-
"typedoc": "^0.28.
|
|
61
|
-
"typescript": "^5.
|
|
60
|
+
"typedoc": "^0.28.9",
|
|
61
|
+
"typescript": "^5.9.2"
|
|
62
62
|
},
|
|
63
63
|
"keywords": [
|
|
64
64
|
"cookie",
|
|
@@ -167,5 +167,5 @@
|
|
|
167
167
|
"status": "alpha",
|
|
168
168
|
"year": 2024
|
|
169
169
|
},
|
|
170
|
-
"gitHead": "
|
|
170
|
+
"gitHead": "03e0d1024805407fbec5dde688b6178bbe0a2f3a\n"
|
|
171
171
|
}
|
package/session/session.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Fn } from "@thi.ng/api";
|
|
1
|
+
import type { Fn, Fn2 } from "@thi.ng/api";
|
|
2
2
|
import { ServerResponse } from "node:http";
|
|
3
3
|
import type { Interceptor, ISessionStore, RequestCtx, ServerSession } from "../api.js";
|
|
4
4
|
/**
|
|
@@ -31,6 +31,16 @@ export interface SessionOpts<CTX extends RequestCtx = RequestCtx, SESSION extend
|
|
|
31
31
|
* bytes. If given as number, generates N random bytes.
|
|
32
32
|
*/
|
|
33
33
|
secret?: number | string | Buffer;
|
|
34
|
+
/**
|
|
35
|
+
* Callback if session cookie is present, but failed validation. When this
|
|
36
|
+
* function needs to be called, its result is used as the result of
|
|
37
|
+
* {@link SessionInterceptor.pre}.
|
|
38
|
+
*
|
|
39
|
+
* @remarks
|
|
40
|
+
* The default implementation simply expires the cookie in the response and
|
|
41
|
+
* terminates the interceptor chain with a 403.
|
|
42
|
+
*/
|
|
43
|
+
onInvalid?: Fn2<CTX, SessionInterceptor<CTX, SESSION>, Promise<boolean>>;
|
|
34
44
|
}
|
|
35
45
|
/**
|
|
36
46
|
* Cached session metadata, stored in a WeakMap.
|
|
@@ -50,12 +60,13 @@ export interface SessionMeta {
|
|
|
50
60
|
*/
|
|
51
61
|
export declare class SessionInterceptor<CTX extends RequestCtx = RequestCtx, SESSION extends ServerSession = ServerSession> implements Interceptor<CTX> {
|
|
52
62
|
factory: SessionOpts<CTX, SESSION>["factory"];
|
|
63
|
+
onInvalid: Fn2<CTX, SessionInterceptor<CTX, SESSION>, Promise<boolean>>;
|
|
53
64
|
store: ISessionStore<SESSION>;
|
|
54
65
|
meta: WeakMap<SESSION, SessionMeta>;
|
|
55
66
|
secret: Buffer;
|
|
56
67
|
cookieName: string;
|
|
57
68
|
cookieOpts: string;
|
|
58
|
-
constructor({ factory, store, cookieName, cookieOpts, secret, }: SessionOpts<CTX, SESSION>);
|
|
69
|
+
constructor({ factory, store, cookieName, cookieOpts, secret, onInvalid, }: SessionOpts<CTX, SESSION>);
|
|
59
70
|
pre(ctx: CTX): Promise<boolean>;
|
|
60
71
|
/**
|
|
61
72
|
* Attempts to delete session for given ID and if successful also sets
|
|
@@ -70,9 +81,10 @@ export declare class SessionInterceptor<CTX extends RequestCtx = RequestCtx, SES
|
|
|
70
81
|
*/
|
|
71
82
|
deleteSession(ctx: CTX, sessionID: string): Promise<void>;
|
|
72
83
|
/**
|
|
73
|
-
* Creates a new session object (via configured
|
|
74
|
-
*
|
|
75
|
-
* ,
|
|
84
|
+
* Creates a new session object (via configured
|
|
85
|
+
* {@link SessionOpts.factory}), pre-computes HMAC and submits it to
|
|
86
|
+
* configured {@link SessionOpts.store}. If successful, Returns session ,
|
|
87
|
+
* otherwise returns `undefined`.
|
|
76
88
|
*
|
|
77
89
|
* @param ctx
|
|
78
90
|
*/
|
package/session/session.js
CHANGED
|
@@ -5,6 +5,7 @@ import { ServerResponse } from "node:http";
|
|
|
5
5
|
import { inMemorySessionStore } from "./memory.js";
|
|
6
6
|
class SessionInterceptor {
|
|
7
7
|
factory;
|
|
8
|
+
onInvalid;
|
|
8
9
|
store;
|
|
9
10
|
meta = /* @__PURE__ */ new WeakMap();
|
|
10
11
|
secret;
|
|
@@ -15,9 +16,15 @@ class SessionInterceptor {
|
|
|
15
16
|
store = inMemorySessionStore(),
|
|
16
17
|
cookieName = "__sid",
|
|
17
18
|
cookieOpts = "Secure;HttpOnly;SameSite=Strict;Path=/",
|
|
18
|
-
secret = 32
|
|
19
|
+
secret = 32,
|
|
20
|
+
onInvalid = async (ctx, session) => {
|
|
21
|
+
session.expireCookie(ctx);
|
|
22
|
+
ctx.res.forbidden();
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
19
25
|
}) {
|
|
20
26
|
this.factory = factory;
|
|
27
|
+
this.onInvalid = onInvalid;
|
|
21
28
|
this.store = store;
|
|
22
29
|
this.secret = isNumber(secret) ? randomBytes(secret) : isString(secret) ? Buffer.from(secret) : secret;
|
|
23
30
|
this.cookieName = cookieName;
|
|
@@ -29,9 +36,7 @@ class SessionInterceptor {
|
|
|
29
36
|
if (cookie) {
|
|
30
37
|
session = await this.validateSession(cookie);
|
|
31
38
|
if (!session) {
|
|
32
|
-
this.
|
|
33
|
-
ctx.res.forbidden();
|
|
34
|
-
return false;
|
|
39
|
+
return await this.onInvalid(ctx, this);
|
|
35
40
|
}
|
|
36
41
|
}
|
|
37
42
|
if (!session || session.ip !== ctx.req.socket.remoteAddress) {
|
|
@@ -61,9 +66,10 @@ class SessionInterceptor {
|
|
|
61
66
|
}
|
|
62
67
|
}
|
|
63
68
|
/**
|
|
64
|
-
* Creates a new session object (via configured
|
|
65
|
-
*
|
|
66
|
-
* ,
|
|
69
|
+
* Creates a new session object (via configured
|
|
70
|
+
* {@link SessionOpts.factory}), pre-computes HMAC and submits it to
|
|
71
|
+
* configured {@link SessionOpts.store}. If successful, Returns session ,
|
|
72
|
+
* otherwise returns `undefined`.
|
|
67
73
|
*
|
|
68
74
|
* @param ctx
|
|
69
75
|
*/
|