@furystack/rest-service 13.0.0 → 14.1.0
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 +124 -0
- package/README.md +47 -28
- package/esm/actions/error-action.d.ts +7 -2
- package/esm/actions/error-action.d.ts.map +1 -1
- package/esm/actions/error-action.js +7 -2
- package/esm/actions/error-action.js.map +1 -1
- package/esm/actions/get-current-user.d.ts +1 -4
- package/esm/actions/get-current-user.d.ts.map +1 -1
- package/esm/actions/get-current-user.js +1 -4
- package/esm/actions/get-current-user.js.map +1 -1
- package/esm/actions/get-current-user.spec.js +10 -6
- package/esm/actions/get-current-user.spec.js.map +1 -1
- package/esm/actions/is-authenticated.d.ts +3 -4
- package/esm/actions/is-authenticated.d.ts.map +1 -1
- package/esm/actions/is-authenticated.js +3 -4
- package/esm/actions/is-authenticated.js.map +1 -1
- package/esm/actions/is-authenticated.spec.js +10 -6
- package/esm/actions/is-authenticated.spec.js.map +1 -1
- package/esm/actions/logout-action.spec.js +11 -9
- package/esm/actions/logout-action.spec.js.map +1 -1
- package/esm/actions/logout.d.ts +2 -6
- package/esm/actions/logout.d.ts.map +1 -1
- package/esm/actions/logout.js +3 -7
- package/esm/actions/logout.js.map +1 -1
- package/esm/actions/not-found-action.d.ts +1 -3
- package/esm/actions/not-found-action.d.ts.map +1 -1
- package/esm/actions/not-found-action.js +1 -3
- package/esm/actions/not-found-action.js.map +1 -1
- package/esm/actions/password-login-action.d.ts +5 -12
- package/esm/actions/password-login-action.d.ts.map +1 -1
- package/esm/actions/password-login-action.js +6 -13
- package/esm/actions/password-login-action.js.map +1 -1
- package/esm/actions/password-login-action.spec.js +23 -28
- package/esm/actions/password-login-action.spec.js.map +1 -1
- package/esm/authenticate.d.ts +5 -11
- package/esm/authenticate.d.ts.map +1 -1
- package/esm/authenticate.js +6 -12
- package/esm/authenticate.js.map +1 -1
- package/esm/authenticate.spec.js +41 -33
- package/esm/authenticate.spec.js.map +1 -1
- package/esm/authentication-providers/authentication-provider.d.ts +17 -0
- package/esm/authentication-providers/authentication-provider.d.ts.map +1 -1
- package/esm/authentication-providers/basic-auth-provider.d.ts +7 -0
- package/esm/authentication-providers/basic-auth-provider.d.ts.map +1 -1
- package/esm/authentication-providers/basic-auth-provider.js +7 -0
- package/esm/authentication-providers/basic-auth-provider.js.map +1 -1
- package/esm/authentication-providers/cookie-auth-provider.d.ts.map +1 -1
- package/esm/authentication-providers/cookie-auth-provider.js +8 -0
- package/esm/authentication-providers/cookie-auth-provider.js.map +1 -1
- package/esm/authorize.d.ts +5 -17
- package/esm/authorize.d.ts.map +1 -1
- package/esm/authorize.js +5 -17
- package/esm/authorize.js.map +1 -1
- package/esm/authorize.spec.js +34 -29
- package/esm/authorize.spec.js.map +1 -1
- package/esm/endpoint-generators/create-delete-endpoint.d.ts +6 -11
- package/esm/endpoint-generators/create-delete-endpoint.d.ts.map +1 -1
- package/esm/endpoint-generators/create-delete-endpoint.js +7 -11
- package/esm/endpoint-generators/create-delete-endpoint.js.map +1 -1
- package/esm/endpoint-generators/create-delete-endpoint.spec.js +14 -21
- package/esm/endpoint-generators/create-delete-endpoint.spec.js.map +1 -1
- package/esm/endpoint-generators/create-get-collection-endpoint.d.ts +11 -11
- package/esm/endpoint-generators/create-get-collection-endpoint.d.ts.map +1 -1
- package/esm/endpoint-generators/create-get-collection-endpoint.js +13 -12
- package/esm/endpoint-generators/create-get-collection-endpoint.js.map +1 -1
- package/esm/endpoint-generators/create-get-collection-endpoint.spec.js +43 -70
- package/esm/endpoint-generators/create-get-collection-endpoint.spec.js.map +1 -1
- package/esm/endpoint-generators/create-get-entity-endpoint.d.ts +6 -11
- package/esm/endpoint-generators/create-get-entity-endpoint.d.ts.map +1 -1
- package/esm/endpoint-generators/create-get-entity-endpoint.js +7 -11
- package/esm/endpoint-generators/create-get-entity-endpoint.js.map +1 -1
- package/esm/endpoint-generators/create-get-entity-endpoint.spec.js +16 -33
- package/esm/endpoint-generators/create-get-entity-endpoint.spec.js.map +1 -1
- package/esm/endpoint-generators/create-get-openapi-document-action.d.ts +1 -1
- package/esm/endpoint-generators/create-get-openapi-document-action.d.ts.map +1 -1
- package/esm/endpoint-generators/create-get-openapi-document-action.js +1 -1
- package/esm/endpoint-generators/create-get-openapi-document-action.js.map +1 -1
- package/esm/endpoint-generators/create-get-schema-action.d.ts +1 -1
- package/esm/endpoint-generators/create-get-schema-action.d.ts.map +1 -1
- package/esm/endpoint-generators/create-get-schema-action.js.map +1 -1
- package/esm/endpoint-generators/create-patch-endpoint.d.ts +7 -13
- package/esm/endpoint-generators/create-patch-endpoint.d.ts.map +1 -1
- package/esm/endpoint-generators/create-patch-endpoint.js +8 -13
- package/esm/endpoint-generators/create-patch-endpoint.js.map +1 -1
- package/esm/endpoint-generators/create-patch-endpoint.spec.js +10 -17
- package/esm/endpoint-generators/create-patch-endpoint.spec.js.map +1 -1
- package/esm/endpoint-generators/create-post-endpoint.d.ts +7 -13
- package/esm/endpoint-generators/create-post-endpoint.d.ts.map +1 -1
- package/esm/endpoint-generators/create-post-endpoint.js +8 -13
- package/esm/endpoint-generators/create-post-endpoint.js.map +1 -1
- package/esm/endpoint-generators/create-post-endpoint.spec.js +41 -14
- package/esm/endpoint-generators/create-post-endpoint.spec.js.map +1 -1
- package/esm/endpoint-generators/utils.d.ts +17 -2
- package/esm/endpoint-generators/utils.d.ts.map +1 -1
- package/esm/endpoint-generators/utils.js +33 -20
- package/esm/endpoint-generators/utils.js.map +1 -1
- package/esm/get-schema-from-api.d.ts +1 -1
- package/esm/get-schema-from-api.d.ts.map +1 -1
- package/esm/get-schema-from-api.js +1 -0
- package/esm/get-schema-from-api.js.map +1 -1
- package/esm/get-schema-from-api.spec.js.map +1 -1
- package/esm/helpers.d.ts +54 -88
- package/esm/helpers.d.ts.map +1 -1
- package/esm/helpers.js +90 -92
- package/esm/helpers.js.map +1 -1
- package/esm/helpers.spec.d.ts +2 -1
- package/esm/helpers.spec.d.ts.map +1 -1
- package/esm/helpers.spec.js +41 -38
- package/esm/helpers.spec.js.map +1 -1
- package/esm/http-authentication-settings.d.ts +56 -12
- package/esm/http-authentication-settings.d.ts.map +1 -1
- package/esm/http-authentication-settings.js +27 -29
- package/esm/http-authentication-settings.js.map +1 -1
- package/esm/http-server-pool.d.ts +64 -0
- package/esm/http-server-pool.d.ts.map +1 -0
- package/esm/http-server-pool.js +95 -0
- package/esm/http-server-pool.js.map +1 -0
- package/esm/http-server-pool.spec.d.ts +2 -0
- package/esm/http-server-pool.spec.d.ts.map +1 -0
- package/esm/http-server-pool.spec.js +193 -0
- package/esm/http-server-pool.spec.js.map +1 -0
- package/esm/http-user-context.d.ts +34 -44
- package/esm/http-user-context.d.ts.map +1 -1
- package/esm/http-user-context.js +75 -95
- package/esm/http-user-context.js.map +1 -1
- package/esm/http-user-context.spec.d.ts +8 -2
- package/esm/http-user-context.spec.d.ts.map +1 -1
- package/esm/http-user-context.spec.js +226 -332
- package/esm/http-user-context.spec.js.map +1 -1
- package/esm/identity-cache-keys.d.ts +28 -0
- package/esm/identity-cache-keys.d.ts.map +1 -0
- package/esm/identity-cache-keys.js +13 -0
- package/esm/identity-cache-keys.js.map +1 -0
- package/esm/identity-cache-keys.spec.d.ts +2 -0
- package/esm/identity-cache-keys.spec.d.ts.map +1 -0
- package/esm/identity-cache-keys.spec.js +21 -0
- package/esm/identity-cache-keys.spec.js.map +1 -0
- package/esm/identity-event-bus.d.ts +102 -0
- package/esm/identity-event-bus.d.ts.map +1 -0
- package/esm/identity-event-bus.js +151 -0
- package/esm/identity-event-bus.js.map +1 -0
- package/esm/identity-event-bus.spec.d.ts +2 -0
- package/esm/identity-event-bus.spec.d.ts.map +1 -0
- package/esm/identity-event-bus.spec.js +392 -0
- package/esm/identity-event-bus.spec.js.map +1 -0
- package/esm/index.d.ts +9 -4
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +9 -4
- package/esm/index.js.map +1 -1
- package/esm/login-response-strategy.d.ts +11 -10
- package/esm/login-response-strategy.d.ts.map +1 -1
- package/esm/login-response-strategy.js +7 -6
- package/esm/login-response-strategy.js.map +1 -1
- package/esm/login-response-strategy.spec.js +25 -29
- package/esm/login-response-strategy.spec.js.map +1 -1
- package/esm/openapi/generate-openapi-document.spec.js.map +1 -1
- package/esm/proxy-manager.spec.js +152 -176
- package/esm/proxy-manager.spec.js.map +1 -1
- package/esm/proxy-runtime.d.ts +27 -0
- package/esm/proxy-runtime.d.ts.map +1 -0
- package/esm/proxy-runtime.js +45 -0
- package/esm/proxy-runtime.js.map +1 -0
- package/esm/proxy-runtime.spec.d.ts +2 -0
- package/esm/proxy-runtime.spec.d.ts.map +1 -0
- package/esm/proxy-runtime.spec.js +39 -0
- package/esm/proxy-runtime.spec.js.map +1 -0
- package/esm/request-action-implementation.d.ts +25 -0
- package/esm/request-action-implementation.d.ts.map +1 -1
- package/esm/request-action-implementation.js +9 -0
- package/esm/request-action-implementation.js.map +1 -1
- package/esm/rest-api-runtime.d.ts +76 -0
- package/esm/rest-api-runtime.d.ts.map +1 -0
- package/esm/rest-api-runtime.js +131 -0
- package/esm/rest-api-runtime.js.map +1 -0
- package/esm/rest-api-runtime.spec.d.ts +2 -0
- package/esm/rest-api-runtime.spec.d.ts.map +1 -0
- package/esm/rest-api-runtime.spec.js +58 -0
- package/esm/rest-api-runtime.spec.js.map +1 -0
- package/esm/rest-service.integration.spec.d.ts +1 -1
- package/esm/rest-service.integration.spec.d.ts.map +1 -1
- package/esm/rest-service.integration.spec.js +57 -80
- package/esm/rest-service.integration.spec.js.map +1 -1
- package/esm/rest.integration.test.js +26 -84
- package/esm/rest.integration.test.js.map +1 -1
- package/esm/server-telemetry.d.ts +49 -0
- package/esm/server-telemetry.d.ts.map +1 -0
- package/esm/server-telemetry.js +25 -0
- package/esm/server-telemetry.js.map +1 -0
- package/esm/server-telemetry.spec.d.ts +2 -0
- package/esm/server-telemetry.spec.d.ts.map +1 -0
- package/esm/server-telemetry.spec.js +52 -0
- package/esm/server-telemetry.spec.js.map +1 -0
- package/esm/static-server-manager.spec.js +60 -125
- package/esm/static-server-manager.spec.js.map +1 -1
- package/esm/static-site-runtime.d.ts +21 -0
- package/esm/static-site-runtime.d.ts.map +1 -0
- package/esm/static-site-runtime.js +48 -0
- package/esm/static-site-runtime.js.map +1 -0
- package/esm/static-site-runtime.spec.d.ts +2 -0
- package/esm/static-site-runtime.spec.d.ts.map +1 -0
- package/esm/static-site-runtime.spec.js +30 -0
- package/esm/static-site-runtime.spec.js.map +1 -0
- package/esm/user-resolution-cache.d.ts +65 -0
- package/esm/user-resolution-cache.d.ts.map +1 -0
- package/esm/user-resolution-cache.js +101 -0
- package/esm/user-resolution-cache.js.map +1 -0
- package/esm/user-resolution-cache.spec.d.ts +2 -0
- package/esm/user-resolution-cache.spec.d.ts.map +1 -0
- package/esm/user-resolution-cache.spec.js +220 -0
- package/esm/user-resolution-cache.spec.js.map +1 -0
- package/esm/user-store.d.ts +39 -0
- package/esm/user-store.d.ts.map +1 -0
- package/esm/user-store.js +62 -0
- package/esm/user-store.js.map +1 -0
- package/esm/user-store.spec.d.ts +2 -0
- package/esm/user-store.spec.d.ts.map +1 -0
- package/esm/user-store.spec.js +72 -0
- package/esm/user-store.spec.js.map +1 -0
- package/esm/validate.d.ts +13 -12
- package/esm/validate.d.ts.map +1 -1
- package/esm/validate.integration.spec.js +27 -28
- package/esm/validate.integration.spec.js.map +1 -1
- package/esm/validate.js +12 -0
- package/esm/validate.js.map +1 -1
- package/package.json +14 -12
- package/src/actions/error-action.ts +7 -3
- package/src/actions/get-current-user.spec.ts +11 -10
- package/src/actions/get-current-user.ts +1 -4
- package/src/actions/is-authenticated.spec.ts +12 -7
- package/src/actions/is-authenticated.ts +3 -4
- package/src/actions/logout-action.spec.ts +12 -12
- package/src/actions/logout.ts +3 -7
- package/src/actions/not-found-action.ts +1 -3
- package/src/actions/password-login-action.spec.ts +30 -30
- package/src/actions/password-login-action.ts +6 -13
- package/src/authenticate.spec.ts +45 -51
- package/src/authenticate.ts +6 -12
- package/src/authentication-providers/authentication-provider.ts +17 -0
- package/src/authentication-providers/basic-auth-provider.ts +7 -0
- package/src/authentication-providers/cookie-auth-provider.ts +8 -0
- package/src/authorize.spec.ts +37 -39
- package/src/authorize.ts +6 -17
- package/src/endpoint-generators/create-delete-endpoint.spec.ts +16 -24
- package/src/endpoint-generators/create-delete-endpoint.ts +11 -17
- package/src/endpoint-generators/create-get-collection-endpoint.spec.ts +45 -78
- package/src/endpoint-generators/create-get-collection-endpoint.ts +17 -19
- package/src/endpoint-generators/create-get-entity-endpoint.spec.ts +17 -33
- package/src/endpoint-generators/create-get-entity-endpoint.ts +11 -17
- package/src/endpoint-generators/create-get-openapi-document-action.ts +2 -2
- package/src/endpoint-generators/create-get-schema-action.ts +1 -1
- package/src/endpoint-generators/create-patch-endpoint.spec.ts +11 -18
- package/src/endpoint-generators/create-patch-endpoint.ts +12 -23
- package/src/endpoint-generators/create-post-endpoint.spec.ts +45 -14
- package/src/endpoint-generators/create-post-endpoint.ts +13 -23
- package/src/endpoint-generators/utils.ts +36 -28
- package/src/get-schema-from-api.spec.ts +1 -1
- package/src/get-schema-from-api.ts +2 -1
- package/src/helpers.spec.ts +51 -41
- package/src/helpers.ts +140 -109
- package/src/http-authentication-settings.ts +78 -24
- package/src/http-server-pool.spec.ts +220 -0
- package/src/http-server-pool.ts +169 -0
- package/src/http-user-context.spec.ts +246 -378
- package/src/http-user-context.ts +122 -92
- package/src/identity-cache-keys.spec.ts +24 -0
- package/src/identity-cache-keys.ts +31 -0
- package/src/identity-event-bus.spec.ts +285 -0
- package/src/identity-event-bus.ts +230 -0
- package/src/index.ts +9 -4
- package/src/login-response-strategy.spec.ts +32 -31
- package/src/login-response-strategy.ts +14 -12
- package/src/openapi/generate-openapi-document.spec.ts +2 -2
- package/src/proxy-manager.spec.ts +158 -188
- package/src/proxy-runtime.spec.ts +50 -0
- package/src/proxy-runtime.ts +75 -0
- package/src/request-action-implementation.ts +25 -0
- package/src/rest-api-runtime.spec.ts +77 -0
- package/src/rest-api-runtime.ts +204 -0
- package/src/rest-service.integration.spec.ts +65 -85
- package/src/rest.integration.test.ts +27 -87
- package/src/server-telemetry.spec.ts +56 -0
- package/src/server-telemetry.ts +43 -0
- package/src/static-server-manager.spec.ts +63 -151
- package/src/static-site-runtime.spec.ts +39 -0
- package/src/static-site-runtime.ts +75 -0
- package/src/user-resolution-cache.spec.ts +241 -0
- package/src/user-resolution-cache.ts +164 -0
- package/src/user-store.spec.ts +86 -0
- package/src/user-store.ts +69 -0
- package/src/validate.integration.spec.ts +40 -35
- package/src/validate.ts +14 -12
- package/esm/api-manager.d.ts +0 -104
- package/esm/api-manager.d.ts.map +0 -1
- package/esm/api-manager.js +0 -179
- package/esm/api-manager.js.map +0 -1
- package/esm/proxy-manager.d.ts +0 -53
- package/esm/proxy-manager.d.ts.map +0 -1
- package/esm/proxy-manager.js +0 -84
- package/esm/proxy-manager.js.map +0 -1
- package/esm/server-manager.d.ts +0 -48
- package/esm/server-manager.d.ts.map +0 -1
- package/esm/server-manager.js +0 -100
- package/esm/server-manager.js.map +0 -1
- package/esm/static-server-manager.d.ts +0 -19
- package/esm/static-server-manager.d.ts.map +0 -1
- package/esm/static-server-manager.js +0 -65
- package/esm/static-server-manager.js.map +0 -1
- package/src/api-manager.ts +0 -304
- package/src/proxy-manager.ts +0 -102
- package/src/server-manager.ts +0 -135
- package/src/static-server-manager.ts +0 -90
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { getPort } from '@furystack/core/port-generator';
|
|
2
|
+
import { createInjector } from '@furystack/inject';
|
|
3
|
+
import { usingAsync } from '@furystack/utils';
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { WebSocket } from 'ws';
|
|
6
|
+
import { HttpServerPoolToken } from './http-server-pool.js';
|
|
7
|
+
import { ServerTelemetryToken } from './server-telemetry.js';
|
|
8
|
+
/** Returns a `ServerApi` that executes `handler` on every matching request. */
|
|
9
|
+
const makeApi = (handler) => ({
|
|
10
|
+
shouldExec: () => true,
|
|
11
|
+
onRequest: handler,
|
|
12
|
+
});
|
|
13
|
+
describe('HttpServerPool', () => {
|
|
14
|
+
it('Should return the cached record on subsequent acquire calls for the same url', async () => {
|
|
15
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
16
|
+
const pool = injector.get(HttpServerPoolToken);
|
|
17
|
+
const port = getPort();
|
|
18
|
+
const first = await pool.acquire({ port });
|
|
19
|
+
const second = await pool.acquire({ port });
|
|
20
|
+
expect(second).toBe(first);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
it('Should de-duplicate concurrent acquire calls into a single server creation', async () => {
|
|
24
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
25
|
+
const pool = injector.get(HttpServerPoolToken);
|
|
26
|
+
const port = getPort();
|
|
27
|
+
const [a, b, c] = await Promise.all([pool.acquire({ port }), pool.acquire({ port }), pool.acquire({ port })]);
|
|
28
|
+
expect(b).toBe(a);
|
|
29
|
+
expect(c).toBe(a);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
it('Should emit onServerListening when a new record is opened', async () => {
|
|
33
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
34
|
+
const telemetry = injector.get(ServerTelemetryToken);
|
|
35
|
+
const listening = vi.fn();
|
|
36
|
+
telemetry.subscribe('onServerListening', listening);
|
|
37
|
+
const port = getPort();
|
|
38
|
+
await injector.get(HttpServerPoolToken).acquire({ port });
|
|
39
|
+
expect(listening).toHaveBeenCalledWith({ url: `http://localhost:${port}`, port, hostName: undefined });
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
it('Should destroy the socket and route the rejection through telemetry when onUpgrade rejects', async () => {
|
|
43
|
+
const injector = createInjector();
|
|
44
|
+
try {
|
|
45
|
+
const pool = injector.get(HttpServerPoolToken);
|
|
46
|
+
const telemetry = injector.get(ServerTelemetryToken);
|
|
47
|
+
const onRequestFailed = vi.fn();
|
|
48
|
+
telemetry.subscribe('onRequestFailed', onRequestFailed);
|
|
49
|
+
const port = getPort();
|
|
50
|
+
const record = await pool.acquire({ port });
|
|
51
|
+
const rejection = new Error('upgrade boom');
|
|
52
|
+
const onUpgrade = vi.fn().mockRejectedValue(rejection);
|
|
53
|
+
record.apis.push({
|
|
54
|
+
shouldExec: () => true,
|
|
55
|
+
onRequest: () => Promise.resolve(),
|
|
56
|
+
onUpgrade,
|
|
57
|
+
});
|
|
58
|
+
const socketClosed = new Promise((resolve) => {
|
|
59
|
+
const ws = new WebSocket(`ws://127.0.0.1:${port}`);
|
|
60
|
+
ws.on('close', () => resolve());
|
|
61
|
+
ws.on('error', () => resolve());
|
|
62
|
+
});
|
|
63
|
+
await socketClosed;
|
|
64
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
65
|
+
expect(onUpgrade).toHaveBeenCalledTimes(1);
|
|
66
|
+
expect(onRequestFailed).toHaveBeenCalledTimes(1);
|
|
67
|
+
const [error] = onRequestFailed.mock.calls[0][0];
|
|
68
|
+
expect(error).toBe(rejection);
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
await injector[Symbol.asyncDispose]();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
it('Should destroy the socket when no API claims the upgrade', async () => {
|
|
75
|
+
const injector = createInjector();
|
|
76
|
+
try {
|
|
77
|
+
const pool = injector.get(HttpServerPoolToken);
|
|
78
|
+
const port = getPort();
|
|
79
|
+
await pool.acquire({ port });
|
|
80
|
+
const ws = new WebSocket(`ws://127.0.0.1:${port}`);
|
|
81
|
+
await new Promise((resolve) => {
|
|
82
|
+
ws.on('close', () => resolve());
|
|
83
|
+
ws.on('error', () => resolve());
|
|
84
|
+
});
|
|
85
|
+
expect(ws.readyState).toBe(WebSocket.CLOSED);
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
await injector[Symbol.asyncDispose]();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
it('Should destroy the raw socket when no API matches a normal request', async () => {
|
|
92
|
+
const injector = createInjector();
|
|
93
|
+
try {
|
|
94
|
+
const pool = injector.get(HttpServerPoolToken);
|
|
95
|
+
const port = getPort();
|
|
96
|
+
await pool.acquire({ port });
|
|
97
|
+
await expect(fetch(`http://127.0.0.1:${port}/nothing`)).rejects.toBeDefined();
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
await injector[Symbol.asyncDispose]();
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
it('Should surface onRequest rejections through telemetry without crashing the server', async () => {
|
|
104
|
+
const injector = createInjector();
|
|
105
|
+
try {
|
|
106
|
+
const pool = injector.get(HttpServerPoolToken);
|
|
107
|
+
const telemetry = injector.get(ServerTelemetryToken);
|
|
108
|
+
const onRequestFailed = vi.fn();
|
|
109
|
+
telemetry.subscribe('onRequestFailed', onRequestFailed);
|
|
110
|
+
const port = getPort();
|
|
111
|
+
const record = await pool.acquire({ port });
|
|
112
|
+
const rejection = new Error('request boom');
|
|
113
|
+
record.apis.push(makeApi(async ({ res }) => {
|
|
114
|
+
res.end();
|
|
115
|
+
throw rejection;
|
|
116
|
+
}));
|
|
117
|
+
await fetch(`http://127.0.0.1:${port}/test`);
|
|
118
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
119
|
+
expect(onRequestFailed).toHaveBeenCalledTimes(1);
|
|
120
|
+
const [error] = onRequestFailed.mock.calls[0][0];
|
|
121
|
+
expect(error).toBe(rejection);
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
await injector[Symbol.asyncDispose]();
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
it('Should destroy open client sockets during disposal', async () => {
|
|
128
|
+
const injector = createInjector();
|
|
129
|
+
const pool = injector.get(HttpServerPoolToken);
|
|
130
|
+
const port = getPort();
|
|
131
|
+
const record = await pool.acquire({ port });
|
|
132
|
+
record.apis.push({
|
|
133
|
+
shouldExec: () => true,
|
|
134
|
+
onRequest: async ({ res }) => {
|
|
135
|
+
res.writeHead(200);
|
|
136
|
+
res.write('streaming');
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
// Keep a client socket open so the dispose path has something to destroy.
|
|
140
|
+
const inflight = fetch(`http://127.0.0.1:${port}/slow`).catch(() => undefined);
|
|
141
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
142
|
+
await injector[Symbol.asyncDispose]();
|
|
143
|
+
await inflight;
|
|
144
|
+
});
|
|
145
|
+
it('Should absorb server.close errors during dispose without crashing', async () => {
|
|
146
|
+
const injector = createInjector();
|
|
147
|
+
const pool = injector.get(HttpServerPoolToken);
|
|
148
|
+
const port = getPort();
|
|
149
|
+
const record = await pool.acquire({ port });
|
|
150
|
+
// Force `server.close` to invoke its callback with an error -- the pool
|
|
151
|
+
// wraps every close in `Promise.allSettled`, so the rejected branch
|
|
152
|
+
// (`if (err) { reject(err); return }`) is exercised but the injector's
|
|
153
|
+
// dispose still resolves cleanly.
|
|
154
|
+
const closeError = new Error('close boom');
|
|
155
|
+
const closeSpy = vi.fn((cb) => {
|
|
156
|
+
cb?.(closeError);
|
|
157
|
+
return record.server;
|
|
158
|
+
});
|
|
159
|
+
record.server.close = closeSpy;
|
|
160
|
+
record.server.off = () => undefined;
|
|
161
|
+
await expect(injector[Symbol.asyncDispose]()).resolves.toBeUndefined();
|
|
162
|
+
expect(closeSpy).toHaveBeenCalled();
|
|
163
|
+
});
|
|
164
|
+
it('Should drain in-flight acquire promises during dispose', async () => {
|
|
165
|
+
const injector = createInjector();
|
|
166
|
+
const port = getPort();
|
|
167
|
+
const pool = injector.get(HttpServerPoolToken);
|
|
168
|
+
const inflight = pool.acquire({ port });
|
|
169
|
+
await injector[Symbol.asyncDispose]();
|
|
170
|
+
// The in-flight promise either resolved (server opened before dispose)
|
|
171
|
+
// or rejected cleanly — both are acceptable; we just assert no process
|
|
172
|
+
// crash / unhandled rejection escaped the pool's `allSettled` guard.
|
|
173
|
+
await inflight.catch(() => undefined);
|
|
174
|
+
});
|
|
175
|
+
it('Should stop tracking sockets that close before dispose', async () => {
|
|
176
|
+
const injector = createInjector();
|
|
177
|
+
try {
|
|
178
|
+
const pool = injector.get(HttpServerPoolToken);
|
|
179
|
+
const port = getPort();
|
|
180
|
+
const record = await pool.acquire({ port });
|
|
181
|
+
record.apis.push(makeApi(async ({ res }) => {
|
|
182
|
+
res.end('ok');
|
|
183
|
+
}));
|
|
184
|
+
await fetch(`http://127.0.0.1:${port}/ok`);
|
|
185
|
+
// Let the TCP socket actually flip to 'close' before we tear down.
|
|
186
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
await injector[Symbol.asyncDispose]();
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
//# sourceMappingURL=http-server-pool.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-server-pool.spec.js","sourceRoot":"","sources":["../src/http-server-pool.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { User } from '@furystack/core';
|
|
2
|
+
import { type Token } from '@furystack/inject';
|
|
2
3
|
import { EventHub, type ListenerErrorPayload } from '@furystack/utils';
|
|
3
4
|
import type { IncomingMessage } from 'http';
|
|
4
5
|
import { HttpAuthenticationSettings } from './http-authentication-settings.js';
|
|
5
|
-
import type { DefaultSession } from './models/default-session.js';
|
|
6
6
|
/**
|
|
7
|
-
* Events emitted by
|
|
7
|
+
* Events emitted by a per-request {@link HttpUserContext} instance. Since
|
|
8
|
+
* the context is scoped, each request sees its own event stream.
|
|
8
9
|
*/
|
|
9
10
|
export type HttpUserContextEvents = {
|
|
10
11
|
onLogin: {
|
|
@@ -15,56 +16,45 @@ export type HttpUserContextEvents = {
|
|
|
15
16
|
onListenerError: ListenerErrorPayload;
|
|
16
17
|
};
|
|
17
18
|
/**
|
|
18
|
-
*
|
|
19
|
+
* Request-scoped authentication/authorization facade.
|
|
20
|
+
*
|
|
21
|
+
* `HttpUserContext` consolidates identity lookup, authentication-provider
|
|
22
|
+
* walk-through and cookie session helpers behind a single object.
|
|
23
|
+
* Successful resolutions are memoized in the singleton
|
|
24
|
+
* {@link UserResolutionCache} keyed by the cache key produced by the
|
|
25
|
+
* matching {@link AuthenticationProvider} (e.g. `cookie:${sessionId}`
|
|
26
|
+
* for cookie auth) and expire after
|
|
27
|
+
* {@link HttpAuthenticationSettings.userCacheTtlMs}. Requests whose
|
|
28
|
+
* providers all opt out of caching (Basic Auth, JWT Bearer, anonymous
|
|
29
|
+
* traffic) bypass the cache and walk the provider chain on every call.
|
|
19
30
|
*/
|
|
20
|
-
export
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Returns whether the current user can be authorized with ALL of the specified roles
|
|
32
|
-
* @param request The request to be authenticated
|
|
33
|
-
* @param roles The list of roles to authorize
|
|
34
|
-
* @returns a boolean value that indicates whether the user is authorized
|
|
35
|
-
*/
|
|
36
|
-
isAuthorized(request: IncomingMessage, ...roles: string[]): Promise<boolean>;
|
|
37
|
-
/**
|
|
38
|
-
* Checks if the system contains a user with the provided name and password, throws an error otherwise
|
|
39
|
-
* @param userName The username
|
|
40
|
-
* @param password The password
|
|
41
|
-
* @returns the authenticated User
|
|
42
|
-
*/
|
|
43
|
-
authenticateUser(userName: string, password: string): Promise<import("@furystack/core").PartialResult<User, (keyof User)[]>>;
|
|
31
|
+
export interface HttpUserContext extends EventHub<HttpUserContextEvents> {
|
|
32
|
+
/** The active {@link HttpAuthenticationSettings} captured at resolve time. */
|
|
33
|
+
readonly authentication: HttpAuthenticationSettings;
|
|
34
|
+
/** Whether the current user is authenticated according to the bound providers. */
|
|
35
|
+
isAuthenticated(request: Pick<IncomingMessage, 'headers'>): Promise<boolean>;
|
|
36
|
+
/** Returns `true` when the current user has **all** of the supplied roles. */
|
|
37
|
+
isAuthorized(request: Pick<IncomingMessage, 'headers'>, ...roles: string[]): Promise<boolean>;
|
|
38
|
+
/** Verifies a username/password pair against the system `PasswordAuthenticator`. */
|
|
39
|
+
authenticateUser(userName: string, password: string): Promise<User>;
|
|
40
|
+
/** Returns the cached user for this request or resolves it via the provider chain. */
|
|
44
41
|
getCurrentUser(request: Pick<IncomingMessage, 'headers'>): Promise<User>;
|
|
42
|
+
/** Extracts the session id for `request` using the configured cookie name. */
|
|
45
43
|
getSessionIdFromRequest(request: Pick<IncomingMessage, 'headers'>): string | null;
|
|
46
|
-
/**
|
|
47
|
-
* Iterates registered authentication providers in order.
|
|
48
|
-
* - A provider returning `User` means authentication succeeded.
|
|
49
|
-
* - A provider returning `null` means it does not apply; try the next one.
|
|
50
|
-
* - A provider throwing means it owns the request but auth failed; propagate the error.
|
|
51
|
-
*/
|
|
44
|
+
/** Walks the configured authentication providers and returns the first match. */
|
|
52
45
|
authenticateRequest(request: Pick<IncomingMessage, 'headers'>): Promise<User>;
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
* @param user The user to create a session for
|
|
56
|
-
* @param serverResponse A serverResponse to set the cookie
|
|
57
|
-
* @returns the current User
|
|
58
|
-
*/
|
|
59
|
-
cookieLogin(user: User, serverResponse: {
|
|
46
|
+
/** Creates and persists a session for `user`, setting the cookie on `response`. */
|
|
47
|
+
cookieLogin(user: User, response: {
|
|
60
48
|
setHeader: (header: string, value: string) => void;
|
|
61
49
|
}): Promise<User>;
|
|
50
|
+
/** Clears the session identified by the request's cookie (if any). */
|
|
62
51
|
cookieLogout(request: Pick<IncomingMessage, 'headers'>, response: {
|
|
63
52
|
setHeader: (header: string, value: string) => void;
|
|
64
53
|
}): Promise<void>;
|
|
65
|
-
readonly authentication: HttpAuthenticationSettings<User, DefaultSession>;
|
|
66
|
-
private readonly systemInjector;
|
|
67
|
-
private readonly authenticator;
|
|
68
|
-
init(): void;
|
|
69
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* DI token for the per-request {@link HttpUserContext}. Scoped — each HTTP
|
|
57
|
+
* request resolves its own instance with a fresh `user` cache.
|
|
58
|
+
*/
|
|
59
|
+
export declare const HttpUserContext: Token<HttpUserContext, 'scoped'>;
|
|
70
60
|
//# sourceMappingURL=http-user-context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-user-context.d.ts","sourceRoot":"","sources":["../src/http-user-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"http-user-context.d.ts","sourceRoot":"","sources":["../src/http-user-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAG3C,OAAO,EAAiB,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAE7D,OAAO,EAAE,QAAQ,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAEtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AAG3C,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAA;AAI9E;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,CAAA;IACvB,QAAQ,EAAE,SAAS,CAAA;IACnB,oBAAoB,EAAE,SAAS,CAAA;IAC/B,eAAe,EAAE,oBAAoB,CAAA;CACtC,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,eAAgB,SAAQ,QAAQ,CAAC,qBAAqB,CAAC;IACtE,8EAA8E;IAC9E,QAAQ,CAAC,cAAc,EAAE,0BAA0B,CAAA;IACnD,kFAAkF;IAClF,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC5E,8EAA8E;IAC9E,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7F,oFAAoF;IACpF,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnE,sFAAsF;IACtF,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACxE,8EAA8E;IAC9E,uBAAuB,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG,MAAM,GAAG,IAAI,CAAA;IACjF,iFAAiF;IACjF,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7E,mFAAmF;IACnF,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE;QAAE,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACxG,sEAAsE;IACtE,YAAY,CACV,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,EACzC,QAAQ,EAAE;QAAE,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,GAC/D,OAAO,CAAC,IAAI,CAAC,CAAA;CACjB;AA6HD;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,eAAe,EAAE,QAAQ,CAmB3D,CAAA"}
|
package/esm/http-user-context.js
CHANGED
|
@@ -1,53 +1,50 @@
|
|
|
1
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
};
|
|
7
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
-
};
|
|
10
1
|
import { useSystemIdentityContext } from '@furystack/core';
|
|
11
|
-
import {
|
|
2
|
+
import { defineService } from '@furystack/inject';
|
|
12
3
|
import { PasswordAuthenticator, UnauthenticatedError } from '@furystack/security';
|
|
13
4
|
import { EventHub } from '@furystack/utils';
|
|
14
5
|
import { randomBytes } from 'crypto';
|
|
15
6
|
import { extractSessionIdFromCookies } from './authentication-providers/helpers.js';
|
|
16
7
|
import { HttpAuthenticationSettings } from './http-authentication-settings.js';
|
|
8
|
+
import { IdentityEventBus } from './identity-event-bus.js';
|
|
9
|
+
import { resolveUserCacheKey, UserResolutionCache } from './user-resolution-cache.js';
|
|
17
10
|
/**
|
|
18
|
-
*
|
|
11
|
+
* Internal concrete {@link EventHub}-backed implementation of
|
|
12
|
+
* {@link HttpUserContext}. Exposed via the `HttpUserContext` token;
|
|
13
|
+
* constructed by its factory.
|
|
19
14
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (users.length !== 1) {
|
|
27
|
-
throw new UnauthenticatedError();
|
|
28
|
-
}
|
|
29
|
-
return users[0];
|
|
30
|
-
};
|
|
31
|
-
user;
|
|
15
|
+
class HttpUserContextImpl extends EventHub {
|
|
16
|
+
authentication;
|
|
17
|
+
resolveAuthenticator;
|
|
18
|
+
systemInjector;
|
|
19
|
+
userCache;
|
|
20
|
+
identityEventBus;
|
|
32
21
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
22
|
+
* `authenticator` is resolved lazily so that tests (and applications) that
|
|
23
|
+
* never invoke `authenticateUser` don't need to bind password-credential
|
|
24
|
+
* stores.
|
|
25
|
+
*
|
|
26
|
+
* The shared {@link UserResolutionCache} memoizes successful authentications
|
|
27
|
+
* across requests within the process. Cache keys are produced by the
|
|
28
|
+
* configured providers via `getCacheKey`; requests whose providers all
|
|
29
|
+
* opt out (e.g. Basic Auth, anonymous traffic) bypass the cache.
|
|
35
30
|
*/
|
|
31
|
+
constructor(authentication, resolveAuthenticator, systemInjector, userCache, identityEventBus) {
|
|
32
|
+
super();
|
|
33
|
+
this.authentication = authentication;
|
|
34
|
+
this.resolveAuthenticator = resolveAuthenticator;
|
|
35
|
+
this.systemInjector = systemInjector;
|
|
36
|
+
this.userCache = userCache;
|
|
37
|
+
this.identityEventBus = identityEventBus;
|
|
38
|
+
}
|
|
36
39
|
async isAuthenticated(request) {
|
|
37
40
|
try {
|
|
38
41
|
const currentUser = await this.getCurrentUser(request);
|
|
39
42
|
return currentUser !== null;
|
|
40
43
|
}
|
|
41
|
-
catch
|
|
44
|
+
catch {
|
|
42
45
|
return false;
|
|
43
46
|
}
|
|
44
47
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Returns whether the current user can be authorized with ALL of the specified roles
|
|
47
|
-
* @param request The request to be authenticated
|
|
48
|
-
* @param roles The list of roles to authorize
|
|
49
|
-
* @returns a boolean value that indicates whether the user is authorized
|
|
50
|
-
*/
|
|
51
48
|
async isAuthorized(request, ...roles) {
|
|
52
49
|
const currentUser = await this.getCurrentUser(request);
|
|
53
50
|
for (const role of roles) {
|
|
@@ -57,14 +54,8 @@ let HttpUserContext = class HttpUserContext extends EventHub {
|
|
|
57
54
|
}
|
|
58
55
|
return true;
|
|
59
56
|
}
|
|
60
|
-
/**
|
|
61
|
-
* Checks if the system contains a user with the provided name and password, throws an error otherwise
|
|
62
|
-
* @param userName The username
|
|
63
|
-
* @param password The password
|
|
64
|
-
* @returns the authenticated User
|
|
65
|
-
*/
|
|
66
57
|
async authenticateUser(userName, password) {
|
|
67
|
-
const result = await this.
|
|
58
|
+
const result = await this.resolveAuthenticator().checkPasswordForUser(userName, password);
|
|
68
59
|
if (!result.isValid) {
|
|
69
60
|
throw new UnauthenticatedError();
|
|
70
61
|
}
|
|
@@ -75,21 +66,15 @@ let HttpUserContext = class HttpUserContext extends EventHub {
|
|
|
75
66
|
return user;
|
|
76
67
|
}
|
|
77
68
|
async getCurrentUser(request) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return this.
|
|
69
|
+
const cacheKey = resolveUserCacheKey(this.authentication, request);
|
|
70
|
+
if (!cacheKey) {
|
|
71
|
+
return this.authenticateRequest(request);
|
|
81
72
|
}
|
|
82
|
-
return this.
|
|
73
|
+
return this.userCache.resolve(cacheKey, () => this.authenticateRequest(request));
|
|
83
74
|
}
|
|
84
75
|
getSessionIdFromRequest(request) {
|
|
85
76
|
return extractSessionIdFromCookies(request, this.authentication.cookieName);
|
|
86
77
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Iterates registered authentication providers in order.
|
|
89
|
-
* - A provider returning `User` means authentication succeeded.
|
|
90
|
-
* - A provider returning `null` means it does not apply; try the next one.
|
|
91
|
-
* - A provider throwing means it owns the request but auth failed; propagate the error.
|
|
92
|
-
*/
|
|
93
78
|
async authenticateRequest(request) {
|
|
94
79
|
for (const provider of this.authentication.authenticationProviders) {
|
|
95
80
|
const user = await provider.authenticate(request);
|
|
@@ -98,63 +83,58 @@ let HttpUserContext = class HttpUserContext extends EventHub {
|
|
|
98
83
|
}
|
|
99
84
|
throw new UnauthenticatedError();
|
|
100
85
|
}
|
|
101
|
-
|
|
102
|
-
* Creates and sets up a cookie-based session for the provided user
|
|
103
|
-
* @param user The user to create a session for
|
|
104
|
-
* @param serverResponse A serverResponse to set the cookie
|
|
105
|
-
* @returns the current User
|
|
106
|
-
*/
|
|
107
|
-
async cookieLogin(user, serverResponse) {
|
|
86
|
+
async cookieLogin(user, response) {
|
|
108
87
|
const sessionId = randomBytes(32).toString('hex');
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
this.
|
|
88
|
+
const sessionDataSet = this.systemInjector.get(this.authentication.sessionDataSet);
|
|
89
|
+
await sessionDataSet.add(this.systemInjector, { sessionId, username: user.username });
|
|
90
|
+
response.setHeader('Set-Cookie', `${this.authentication.cookieName}=${sessionId}; Path=/; HttpOnly`);
|
|
112
91
|
this.emit('onLogin', { user });
|
|
113
92
|
return user;
|
|
114
93
|
}
|
|
115
94
|
async cookieLogout(request, response) {
|
|
116
|
-
this.user = undefined;
|
|
117
95
|
const sessionId = this.getSessionIdFromRequest(request);
|
|
118
96
|
response.setHeader('Set-Cookie', `${this.authentication.cookieName}=; Path=/; HttpOnly`);
|
|
119
97
|
if (sessionId) {
|
|
120
|
-
const sessionDataSet = this.
|
|
121
|
-
const sessions = await sessionDataSet.find(this.systemInjector, {
|
|
122
|
-
|
|
98
|
+
const sessionDataSet = this.systemInjector.get(this.authentication.sessionDataSet);
|
|
99
|
+
const sessions = await sessionDataSet.find(this.systemInjector, {
|
|
100
|
+
filter: { sessionId: { $eq: sessionId } },
|
|
101
|
+
});
|
|
102
|
+
await sessionDataSet.remove(this.systemInjector, ...sessions.map((s) => s.sessionId));
|
|
103
|
+
// Cross-node identity invalidation: the facade applies the local cache
|
|
104
|
+
// drop synchronously, then broadcasts so siblings collapse the
|
|
105
|
+
// staleness window from `userCacheTtlMs` to bus latency.
|
|
106
|
+
await this.identityEventBus.publish({ type: 'userLoggedOut', sessionId });
|
|
123
107
|
}
|
|
124
108
|
this.emit('onLogout', undefined);
|
|
125
109
|
}
|
|
126
|
-
|
|
127
|
-
this.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
});
|
|
132
|
-
this.getUserDataSet().addListener('onEntityRemoved', ({ key }) => {
|
|
133
|
-
if (this.user?.username === key) {
|
|
134
|
-
this.user = undefined;
|
|
135
|
-
this.emit('onSessionInvalidated', undefined);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
this.getSessionDataSet().addListener('onEntityRemoved', () => {
|
|
139
|
-
this.user = undefined;
|
|
140
|
-
this.emit('onSessionInvalidated', undefined);
|
|
110
|
+
async getUserByName(userName) {
|
|
111
|
+
const userDataSet = this.systemInjector.get(this.authentication.userDataSet);
|
|
112
|
+
const users = await userDataSet.find(this.systemInjector, {
|
|
113
|
+
filter: { username: { $eq: userName } },
|
|
114
|
+
top: 2,
|
|
141
115
|
});
|
|
116
|
+
if (users.length !== 1) {
|
|
117
|
+
throw new UnauthenticatedError();
|
|
118
|
+
}
|
|
119
|
+
return users[0];
|
|
142
120
|
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* DI token for the per-request {@link HttpUserContext}. Scoped — each HTTP
|
|
124
|
+
* request resolves its own instance with a fresh `user` cache.
|
|
125
|
+
*/
|
|
126
|
+
export const HttpUserContext = defineService({
|
|
127
|
+
name: 'furystack/rest-service/HttpUserContext',
|
|
128
|
+
lifetime: 'scoped',
|
|
129
|
+
factory: ({ inject, injector, onDispose }) => {
|
|
130
|
+
const authentication = inject(HttpAuthenticationSettings);
|
|
131
|
+
const userCache = inject(UserResolutionCache);
|
|
132
|
+
const identityEventBus = inject(IdentityEventBus);
|
|
133
|
+
const systemInjector = useSystemIdentityContext({ injector, username: 'HttpUserContext' });
|
|
134
|
+
onDispose(() => systemInjector[Symbol.asyncDispose]());
|
|
135
|
+
// Password authenticator resolution is deferred: tests that exercise only
|
|
136
|
+
// unauthenticated endpoints never have to bind credential stores.
|
|
137
|
+
return new HttpUserContextImpl(authentication, () => injector.get(PasswordAuthenticator), systemInjector, userCache, identityEventBus);
|
|
138
|
+
},
|
|
139
|
+
});
|
|
160
140
|
//# sourceMappingURL=http-user-context.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-user-context.js","sourceRoot":"","sources":["../src/http-user-context.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"http-user-context.js","sourceRoot":"","sources":["../src/http-user-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import { Injector } from '@furystack/inject';
|
|
1
|
+
import { type Injector } from '@furystack/inject';
|
|
2
|
+
/**
|
|
3
|
+
* Binds in-memory implementations for every persistent token required by
|
|
4
|
+
* the authentication subsystem (users, sessions, credentials, reset tokens)
|
|
5
|
+
* on the provided injector, then installs the default password policy and
|
|
6
|
+
* HTTP-authentication stack.
|
|
7
|
+
*/
|
|
2
8
|
export declare const prepareInjector: (i: Injector, options?: {
|
|
3
9
|
enableBasicAuth?: boolean;
|
|
4
|
-
}) =>
|
|
10
|
+
}) => void;
|
|
5
11
|
//# sourceMappingURL=http-user-context.spec.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-user-context.spec.d.ts","sourceRoot":"","sources":["../src/http-user-context.spec.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"http-user-context.spec.d.ts","sourceRoot":"","sources":["../src/http-user-context.spec.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAkBjE;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAAI,GAAG,QAAQ,EAAE,UAAU;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,KAAG,IAQtF,CAAA"}
|