@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getPort } from '@furystack/core/port-generator';
|
|
2
|
-
import {
|
|
2
|
+
import { createInjector } from '@furystack/inject';
|
|
3
3
|
import { createClient } from '@furystack/rest-client-fetch';
|
|
4
4
|
import { usingAsync } from '@furystack/utils';
|
|
5
5
|
import { describe, expect, it } from 'vitest';
|
|
@@ -8,7 +8,7 @@ import { JsonResult } from './request-action-implementation.js';
|
|
|
8
8
|
const createEchoApiServer = async () => {
|
|
9
9
|
const port = getPort();
|
|
10
10
|
const root = '/api';
|
|
11
|
-
const injector =
|
|
11
|
+
const injector = createInjector();
|
|
12
12
|
await useRestService({
|
|
13
13
|
injector,
|
|
14
14
|
port,
|
|
@@ -40,115 +40,57 @@ const createEchoApiServer = async () => {
|
|
|
40
40
|
};
|
|
41
41
|
};
|
|
42
42
|
describe('REST Integration tests with FETCH client', () => {
|
|
43
|
-
it('
|
|
43
|
+
it('executes a parameterless GET request', async () => {
|
|
44
44
|
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
45
|
-
const result = await client({
|
|
46
|
-
method: 'GET',
|
|
47
|
-
action: '/plain',
|
|
48
|
-
});
|
|
45
|
+
const result = await client({ method: 'GET', action: '/plain' });
|
|
49
46
|
expect(result.response.status).toBe(200);
|
|
50
47
|
expect(result.result).toEqual({});
|
|
51
48
|
});
|
|
52
49
|
});
|
|
53
|
-
it('
|
|
50
|
+
it('passes headers through', async () => {
|
|
54
51
|
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
55
|
-
const
|
|
56
|
-
const result = await client({
|
|
57
|
-
method: 'GET',
|
|
58
|
-
action: '/headers',
|
|
59
|
-
headers: {
|
|
60
|
-
value,
|
|
61
|
-
},
|
|
62
|
-
});
|
|
52
|
+
const result = await client({ method: 'GET', action: '/headers', headers: { value: 'hello' } });
|
|
63
53
|
expect(result.response.status).toBe(200);
|
|
64
|
-
expect(result.result.headers.value).
|
|
54
|
+
expect(result.result.headers.value).toBe('hello');
|
|
65
55
|
});
|
|
66
56
|
});
|
|
67
|
-
it('
|
|
57
|
+
it('serialises url params', async () => {
|
|
68
58
|
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
method: 'GET',
|
|
72
|
-
action: '/query',
|
|
73
|
-
query: {
|
|
74
|
-
someObject: {
|
|
75
|
-
foo: value,
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
expect(result.response.status).toBe(200);
|
|
80
|
-
expect(result.result.query.someObject.foo).toEqual(value);
|
|
59
|
+
const result = await client({ method: 'GET', action: '/urlParams/:id', url: { id: '42' } });
|
|
60
|
+
expect(result.result.url.id).toBe('42');
|
|
81
61
|
});
|
|
82
62
|
});
|
|
83
|
-
it('
|
|
63
|
+
it('serialises a structured query', async () => {
|
|
84
64
|
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
85
|
-
const value = 'value3';
|
|
86
65
|
const result = await client({
|
|
87
66
|
method: 'GET',
|
|
88
|
-
action: '/
|
|
89
|
-
|
|
90
|
-
id: value,
|
|
91
|
-
},
|
|
92
|
-
});
|
|
93
|
-
expect(result.response.status).toBe(200);
|
|
94
|
-
expect(result.result.url.id).toEqual(value);
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
it('should execute a request for a segment', async () => {
|
|
98
|
-
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
99
|
-
const result = await client({
|
|
100
|
-
method: 'GET',
|
|
101
|
-
action: '/segment',
|
|
102
|
-
});
|
|
103
|
-
expect(result.response.status).toBe(200);
|
|
104
|
-
expect(result.result.name).toEqual('segment');
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
it('should execute a request for a subsegment', async () => {
|
|
108
|
-
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
109
|
-
const result = await client({
|
|
110
|
-
method: 'GET',
|
|
111
|
-
action: '/segment/subsegment',
|
|
67
|
+
action: '/query',
|
|
68
|
+
query: { someObject: { foo: 'bar' } },
|
|
112
69
|
});
|
|
113
|
-
expect(result.
|
|
114
|
-
expect(result.result.name).toEqual('segment-subsegment');
|
|
70
|
+
expect(result.result.query.someObject.foo).toBe('bar');
|
|
115
71
|
});
|
|
116
72
|
});
|
|
117
|
-
it('
|
|
73
|
+
it('dispatches plain and multi-segment URLs correctly', async () => {
|
|
118
74
|
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
119
|
-
|
|
120
|
-
|
|
75
|
+
expect((await client({ method: 'GET', action: '/segment' })).result.name).toBe('segment');
|
|
76
|
+
expect((await client({ method: 'GET', action: '/segment/subsegment' })).result.name).toBe('segment-subsegment');
|
|
77
|
+
const subsegment = await client({
|
|
121
78
|
method: 'GET',
|
|
122
79
|
action: '/segment/:id/subsegment',
|
|
123
|
-
url: {
|
|
124
|
-
id: value,
|
|
125
|
-
},
|
|
80
|
+
url: { id: 'abc' },
|
|
126
81
|
});
|
|
127
|
-
expect(result.
|
|
128
|
-
expect(
|
|
129
|
-
expect(result.result.url.name).toEqual('segment-subsegment');
|
|
82
|
+
expect(subsegment.result.url.id).toBe('abc');
|
|
83
|
+
expect(subsegment.result.url.name).toBe('segment-subsegment');
|
|
130
84
|
});
|
|
131
85
|
});
|
|
132
|
-
it('
|
|
86
|
+
it('forwards POST bodies', async () => {
|
|
133
87
|
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
134
88
|
const result = await client({
|
|
135
|
-
method: '
|
|
136
|
-
action: '/
|
|
137
|
-
|
|
138
|
-
});
|
|
139
|
-
expect(result.response.status).toBe(200);
|
|
140
|
-
expect(result.result.url.optionalId).toBeUndefined();
|
|
141
|
-
expect(result.result.name).toEqual('optional-id');
|
|
142
|
-
const result2 = await client({
|
|
143
|
-
method: 'GET',
|
|
144
|
-
action: '/segment{/:optionalId}?/optionalSubsegment/',
|
|
145
|
-
url: {
|
|
146
|
-
optionalId: 'value',
|
|
147
|
-
},
|
|
89
|
+
method: 'POST',
|
|
90
|
+
action: '/body',
|
|
91
|
+
body: { foo: 'hi', bar: 42 },
|
|
148
92
|
});
|
|
149
|
-
expect(
|
|
150
|
-
expect(result2.result.url.optionalId).toEqual('value');
|
|
151
|
-
expect(result2.result.name).toEqual('optional-id');
|
|
93
|
+
expect(result.result.body).toEqual({ foo: 'hi', bar: 42 });
|
|
152
94
|
});
|
|
153
95
|
});
|
|
154
96
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rest.integration.test.js","sourceRoot":"","sources":["../src/rest.integration.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AACxD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"rest.integration.test.js","sourceRoot":"","sources":["../src/rest.integration.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAElD,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;AAwB/D,MAAM,mBAAmB,GAAG,KAAK,IAAI,EAAE;IACrC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAA;IACtB,MAAM,IAAI,GAAG,MAAM,CAAA;IACnB,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAA;IACjC,MAAM,cAAc,CAAU;QAC5B,QAAQ;QACR,IAAI;QACJ,IAAI;QACJ,GAAG,EAAE;YACH,GAAG,EAAE;gBACH,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;gBACpC,UAAU,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;gBAC1D,QAAQ,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC;gBACnE,gBAAgB,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,CAAC;gBACjF,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;gBACvD,qBAAqB,EAAE,KAAK,IAAI,EAAE,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC;gBAC7E,yBAAyB,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CACpD,UAAU,CAAC,EAAE,GAAG,EAAE,EAAE,GAAG,YAAY,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE,EAAE,CAAC;gBACxE,6CAA6C,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CACxE,UAAU,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;aAC3D;YACD,IAAI,EAAE;gBACJ,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,EAAE,EAAE,CAAC;aACtE;SACF;KACF,CAAC,CAAA;IACF,MAAM,MAAM,GAAG,YAAY,CAAU;QACnC,WAAW,EAAE,oBAAoB,IAAI,MAAM;KAC5C,CAAC,CAAA;IACF,OAAO;QACL,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;QACnE,IAAI;QACJ,IAAI;QACJ,MAAM;KACP,CAAA;AACH,CAAC,CAAA;AAED,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;IACxD,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,UAAU,CAAC,MAAM,mBAAmB,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;YACjE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;YAChE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACxC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACnC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;QACtC,MAAM,UAAU,CAAC,MAAM,mBAAmB,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;YACjE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;YAC/F,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACxC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACnD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;QACrC,MAAM,UAAU,CAAC,MAAM,mBAAmB,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;YACjE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;YAC3F,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACzC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,UAAU,CAAC,MAAM,mBAAmB,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;YACjE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC;gBAC1B,MAAM,EAAE,KAAK;gBACb,MAAM,EAAE,QAAQ;gBAChB,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;aACtC,CAAC,CAAA;YACF,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACxD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,UAAU,CAAC,MAAM,mBAAmB,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;YACjE,MAAM,CAAC,CAAC,MAAM,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YACzF,MAAM,CAAC,CAAC,MAAM,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;YAC/G,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC;gBAC9B,MAAM,EAAE,KAAK;gBACb,MAAM,EAAE,yBAAyB;gBACjC,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE;aACnB,CAAC,CAAA;YACF,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAC5C,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;QAC/D,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,UAAU,CAAC,MAAM,mBAAmB,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;YACjE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC;gBAC1B,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,OAAO;gBACf,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;aAC7B,CAAC,CAAA;YACF,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAA;QAC5D,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type Token } from '@furystack/inject';
|
|
2
|
+
import { EventHub, type ListenerErrorPayload } from '@furystack/utils';
|
|
3
|
+
import type { IncomingMessage, ServerResponse } from 'http';
|
|
4
|
+
import type { Data, WebSocket } from 'ws';
|
|
5
|
+
/**
|
|
6
|
+
* Union of every server-lifecycle event the rest-service runtime emits.
|
|
7
|
+
* The HTTP server pool, proxy runtime and websocket-api all forward into
|
|
8
|
+
* this single hub so subscribers can observe every source from one place.
|
|
9
|
+
*/
|
|
10
|
+
export type ServerTelemetryEvents = {
|
|
11
|
+
onServerListening: {
|
|
12
|
+
url: string;
|
|
13
|
+
port: number;
|
|
14
|
+
hostName?: string;
|
|
15
|
+
};
|
|
16
|
+
onServerClosed: {
|
|
17
|
+
url: string;
|
|
18
|
+
};
|
|
19
|
+
/** Tuple-shaped to match the underlying Node `request` callback signature. */
|
|
20
|
+
onRequestFailed: [unknown, IncomingMessage, ServerResponse<IncomingMessage>];
|
|
21
|
+
onProxyFailed: {
|
|
22
|
+
from: string;
|
|
23
|
+
to: string;
|
|
24
|
+
error: unknown;
|
|
25
|
+
};
|
|
26
|
+
onWebSocketProxyFailed: {
|
|
27
|
+
from: string;
|
|
28
|
+
to: string;
|
|
29
|
+
error: unknown;
|
|
30
|
+
};
|
|
31
|
+
onWebSocketActionFailed: {
|
|
32
|
+
error: unknown;
|
|
33
|
+
data?: Data;
|
|
34
|
+
socket?: WebSocket;
|
|
35
|
+
};
|
|
36
|
+
onListenerError: ListenerErrorPayload;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Application-facing telemetry surface. Extends {@link EventHub} so
|
|
40
|
+
* subscribers use the standard `addListener` / `subscribe` API.
|
|
41
|
+
*/
|
|
42
|
+
export declare class ServerTelemetry extends EventHub<ServerTelemetryEvents> {
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* DI token for the shared {@link ServerTelemetry} instance. Scoped so each
|
|
46
|
+
* injector tree (in particular, each test) gets an isolated event stream.
|
|
47
|
+
*/
|
|
48
|
+
export declare const ServerTelemetryToken: Token<ServerTelemetry, 'scoped'>;
|
|
49
|
+
//# sourceMappingURL=server-telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-telemetry.d.ts","sourceRoot":"","sources":["../src/server-telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAC7D,OAAO,EAAE,QAAQ,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAA;AAC3D,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,IAAI,CAAA;AAEzC;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,iBAAiB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACnE,cAAc,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/B,8EAA8E;IAC9E,eAAe,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,cAAc,CAAC,eAAe,CAAC,CAAC,CAAA;IAC5E,aAAa,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAA;IAC3D,sBAAsB,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAA;IACpE,uBAAuB,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,SAAS,CAAA;KAAE,CAAA;IAC5E,eAAe,EAAE,oBAAoB,CAAA;CACtC,CAAA;AAED;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,QAAQ,CAAC,qBAAqB,CAAC;CAAG;AAEvE;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,eAAe,EAAE,QAAQ,CAWhE,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defineService } from '@furystack/inject';
|
|
2
|
+
import { EventHub } from '@furystack/utils';
|
|
3
|
+
/**
|
|
4
|
+
* Application-facing telemetry surface. Extends {@link EventHub} so
|
|
5
|
+
* subscribers use the standard `addListener` / `subscribe` API.
|
|
6
|
+
*/
|
|
7
|
+
export class ServerTelemetry extends EventHub {
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* DI token for the shared {@link ServerTelemetry} instance. Scoped so each
|
|
11
|
+
* injector tree (in particular, each test) gets an isolated event stream.
|
|
12
|
+
*/
|
|
13
|
+
export const ServerTelemetryToken = defineService({
|
|
14
|
+
name: 'furystack/rest-service/ServerTelemetry',
|
|
15
|
+
lifetime: 'scoped',
|
|
16
|
+
factory: ({ onDispose }) => {
|
|
17
|
+
const telemetry = new ServerTelemetry();
|
|
18
|
+
// Disposal is delegated to the injector via `onDispose`; the telemetry
|
|
19
|
+
// outlives this factory invocation and is torn down on scope teardown.
|
|
20
|
+
// eslint-disable-next-line furystack/prefer-using-wrapper
|
|
21
|
+
onDispose(() => telemetry[Symbol.dispose]());
|
|
22
|
+
return telemetry;
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=server-telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-telemetry.js","sourceRoot":"","sources":["../src/server-telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAc,MAAM,mBAAmB,CAAA;AAC7D,OAAO,EAAE,QAAQ,EAA6B,MAAM,kBAAkB,CAAA;AAoBtE;;;GAGG;AACH,MAAM,OAAO,eAAgB,SAAQ,QAA+B;CAAG;AAEvE;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAqC,aAAa,CAAC;IAClF,IAAI,EAAE,wCAAwC;IAC9C,QAAQ,EAAE,QAAQ;IAClB,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;QACzB,MAAM,SAAS,GAAG,IAAI,eAAe,EAAE,CAAA;QACvC,uEAAuE;QACvE,uEAAuE;QACvE,0DAA0D;QAC1D,SAAS,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAC5C,OAAO,SAAS,CAAA;IAClB,CAAC;CACF,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-telemetry.spec.d.ts","sourceRoot":"","sources":["../src/server-telemetry.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createInjector } from '@furystack/inject';
|
|
2
|
+
import { usingAsync } from '@furystack/utils';
|
|
3
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { ServerTelemetry, ServerTelemetryToken } from './server-telemetry.js';
|
|
5
|
+
describe('ServerTelemetry', () => {
|
|
6
|
+
it('ServerTelemetryToken resolves to a ServerTelemetry EventHub and is cached per scope', async () => {
|
|
7
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
8
|
+
const a = injector.get(ServerTelemetryToken);
|
|
9
|
+
const b = injector.get(ServerTelemetryToken);
|
|
10
|
+
expect(a).toBe(b);
|
|
11
|
+
expect(a).toBeInstanceOf(ServerTelemetry);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
it('Emitted events are dispatched to subscribers', async () => {
|
|
15
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
16
|
+
const telemetry = injector.get(ServerTelemetryToken);
|
|
17
|
+
const onListening = vi.fn();
|
|
18
|
+
telemetry.subscribe('onServerListening', onListening);
|
|
19
|
+
telemetry.emit('onServerListening', { url: 'http://localhost:1', port: 1 });
|
|
20
|
+
expect(onListening).toHaveBeenCalledWith({ url: 'http://localhost:1', port: 1 });
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
it('Disposes cleanly with the injector and stops routing events', async () => {
|
|
24
|
+
const injector = createInjector();
|
|
25
|
+
const telemetry = injector.get(ServerTelemetryToken);
|
|
26
|
+
const onClosed = vi.fn();
|
|
27
|
+
telemetry.subscribe('onServerClosed', onClosed);
|
|
28
|
+
await injector[Symbol.asyncDispose]();
|
|
29
|
+
// After the owning injector is disposed, emit on the captured reference
|
|
30
|
+
// should still work (the EventHub is disposed separately via onDispose,
|
|
31
|
+
// but listeners are cleared). The key guarantee: previously-attached
|
|
32
|
+
// listeners receive nothing new after dispose.
|
|
33
|
+
telemetry.emit('onServerClosed', { url: 'http://localhost:2' });
|
|
34
|
+
expect(onClosed).not.toHaveBeenCalled();
|
|
35
|
+
});
|
|
36
|
+
it('Scopes have isolated telemetry instances', async () => {
|
|
37
|
+
await usingAsync(createInjector(), async (root) => {
|
|
38
|
+
const scope1 = root.createScope();
|
|
39
|
+
const scope2 = root.createScope();
|
|
40
|
+
try {
|
|
41
|
+
const t1 = scope1.get(ServerTelemetryToken);
|
|
42
|
+
const t2 = scope2.get(ServerTelemetryToken);
|
|
43
|
+
expect(t1).not.toBe(t2);
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
await scope1[Symbol.asyncDispose]();
|
|
47
|
+
await scope2[Symbol.asyncDispose]();
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
//# sourceMappingURL=server-telemetry.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-telemetry.spec.js","sourceRoot":"","sources":["../src/server-telemetry.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,182 +1,118 @@
|
|
|
1
|
-
import { Injector } from '@furystack/inject';
|
|
2
|
-
import { sleepAsync, usingAsync } from '@furystack/utils';
|
|
3
|
-
import { ServerManager } from './server-manager.js';
|
|
4
|
-
import { StaticServerManager } from './static-server-manager.js';
|
|
5
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
6
1
|
import { getPort } from '@furystack/core/port-generator';
|
|
7
|
-
|
|
2
|
+
import { createInjector } from '@furystack/inject';
|
|
3
|
+
import { sleepAsync, usingAsync } from '@furystack/utils';
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { useStaticFiles } from './helpers.js';
|
|
6
|
+
import { HttpServerPoolToken } from './http-server-pool.js';
|
|
7
|
+
import { buildStaticSiteServerApi } from './static-site-runtime.js';
|
|
8
|
+
describe('useStaticFiles / buildStaticSiteServerApi', () => {
|
|
8
9
|
describe('Top level routing', () => {
|
|
9
|
-
it('
|
|
10
|
-
await usingAsync(
|
|
11
|
-
const staticServerManager = injector.getInstance(StaticServerManager);
|
|
10
|
+
it('responds 404 without a fallback', async () => {
|
|
11
|
+
await usingAsync(createInjector(), async (i) => {
|
|
12
12
|
const port = getPort();
|
|
13
|
-
await
|
|
14
|
-
baseUrl: '/',
|
|
15
|
-
path: '.',
|
|
16
|
-
port,
|
|
17
|
-
});
|
|
13
|
+
await useStaticFiles({ injector: i, baseUrl: '/', path: '.', port });
|
|
18
14
|
const result = await fetch(`http://127.0.0.1:${port}/not-found.html`);
|
|
19
15
|
expect(result.ok).toBe(false);
|
|
20
16
|
expect(result.status).toBe(404);
|
|
21
|
-
expect(result
|
|
22
|
-
|
|
23
|
-
expect(body).toBe('Not found');
|
|
17
|
+
expect(result.headers.get('content-type')).toBe('text/plain');
|
|
18
|
+
expect(await result.text()).toBe('Not found');
|
|
24
19
|
});
|
|
25
20
|
});
|
|
26
|
-
it('
|
|
27
|
-
await usingAsync(
|
|
28
|
-
const staticServerManager = injector.getInstance(StaticServerManager);
|
|
21
|
+
it('falls back to the configured file and returns its content-type', async () => {
|
|
22
|
+
await usingAsync(createInjector(), async (i) => {
|
|
29
23
|
const port = getPort();
|
|
30
|
-
await
|
|
24
|
+
await useStaticFiles({
|
|
25
|
+
injector: i,
|
|
31
26
|
baseUrl: '/',
|
|
32
27
|
path: '.',
|
|
33
28
|
fallback: 'package.json',
|
|
34
29
|
port,
|
|
35
|
-
headers: {
|
|
36
|
-
'custom-header': 'custom-value',
|
|
37
|
-
},
|
|
30
|
+
headers: { 'custom-header': 'custom-value' },
|
|
38
31
|
});
|
|
39
32
|
const result = await fetch(`http://localhost:${port}/not-found.html`);
|
|
40
33
|
expect(result.headers.get('content-type')).toBe('application/json');
|
|
41
34
|
expect(result.headers.get('custom-header')).toBe('custom-value');
|
|
42
35
|
});
|
|
43
36
|
});
|
|
44
|
-
it('
|
|
45
|
-
await usingAsync(
|
|
46
|
-
const staticServerManager = injector.getInstance(StaticServerManager);
|
|
37
|
+
it('falls back for the root url when no index exists', async () => {
|
|
38
|
+
await usingAsync(createInjector(), async (i) => {
|
|
47
39
|
const port = getPort();
|
|
48
|
-
await
|
|
40
|
+
await useStaticFiles({
|
|
41
|
+
injector: i,
|
|
49
42
|
baseUrl: '/',
|
|
50
43
|
path: '.',
|
|
51
44
|
fallback: 'package.json',
|
|
52
45
|
port,
|
|
53
|
-
headers: {
|
|
54
|
-
'custom-header': 'custom-value',
|
|
55
|
-
},
|
|
46
|
+
headers: { 'custom-header': 'custom-value' },
|
|
56
47
|
});
|
|
57
48
|
const result = await fetch(`http://localhost:${port}`);
|
|
58
49
|
expect(result.headers.get('content-type')).toBe('application/json');
|
|
59
50
|
expect(result.headers.get('custom-header')).toBe('custom-value');
|
|
60
51
|
});
|
|
61
52
|
});
|
|
62
|
-
it('
|
|
63
|
-
await usingAsync(
|
|
64
|
-
const staticServerManager = injector.getInstance(StaticServerManager);
|
|
53
|
+
it('serves an existing file from the root directory', async () => {
|
|
54
|
+
await usingAsync(createInjector(), async (i) => {
|
|
65
55
|
const port = getPort();
|
|
66
|
-
await
|
|
67
|
-
baseUrl: '/',
|
|
68
|
-
path: '.',
|
|
69
|
-
port,
|
|
70
|
-
headers: {
|
|
71
|
-
'custom-header': 'custom-value',
|
|
72
|
-
},
|
|
73
|
-
});
|
|
56
|
+
await useStaticFiles({ injector: i, baseUrl: '/', path: '.', port });
|
|
74
57
|
const result = await fetch(`http://localhost:${port}/README.md`);
|
|
75
58
|
expect(result.headers.get('content-type')).toBe('text/markdown');
|
|
76
|
-
expect(result.headers.get('custom-header')).toBe('custom-value');
|
|
77
59
|
});
|
|
78
60
|
});
|
|
79
|
-
it('
|
|
80
|
-
await usingAsync(
|
|
81
|
-
const staticServerManager = injector.getInstance(StaticServerManager);
|
|
61
|
+
it('serves files from subdirectories', async () => {
|
|
62
|
+
await usingAsync(createInjector(), async (i) => {
|
|
82
63
|
const port = getPort();
|
|
83
|
-
await
|
|
84
|
-
baseUrl: '/',
|
|
85
|
-
path: '.',
|
|
86
|
-
port,
|
|
87
|
-
});
|
|
64
|
+
await useStaticFiles({ injector: i, baseUrl: '/', path: '.', port });
|
|
88
65
|
const result = await fetch(`http://localhost:${port}/packages/utils/README.md`);
|
|
89
66
|
expect(result.headers.get('content-type')).toBe('text/markdown');
|
|
90
67
|
});
|
|
91
68
|
});
|
|
92
69
|
});
|
|
93
70
|
describe('Non-top level routing', () => {
|
|
94
|
-
it('
|
|
95
|
-
await usingAsync(
|
|
96
|
-
const staticServerManager = injector.getInstance(StaticServerManager);
|
|
71
|
+
it('leaves requests outside the base url to the next api in the chain', async () => {
|
|
72
|
+
await usingAsync(createInjector(), async (i) => {
|
|
97
73
|
const port = getPort();
|
|
98
|
-
await
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
server.apis[0].onRequest = vi.fn();
|
|
74
|
+
const serverApi = await useStaticFiles({ injector: i, baseUrl: '/bundle', path: '.', port });
|
|
75
|
+
const record = await i.get(HttpServerPoolToken).acquire({ port });
|
|
76
|
+
const onRequest = vi.fn();
|
|
77
|
+
// Swap in a spy to observe non-matching requests never reach the handler.
|
|
78
|
+
serverApi.onRequest = onRequest;
|
|
79
|
+
record.apis[0] = serverApi;
|
|
105
80
|
fetch(`http://localhost:${port}/bundleToAnotherFolder/not-found.html`).catch(() => {
|
|
106
|
-
|
|
81
|
+
// Expected to fail: the server has no matching API and drops the socket.
|
|
107
82
|
});
|
|
108
83
|
await sleepAsync(100);
|
|
109
|
-
expect(
|
|
84
|
+
expect(onRequest).not.toHaveBeenCalled();
|
|
110
85
|
});
|
|
111
86
|
});
|
|
112
|
-
it('
|
|
113
|
-
await usingAsync(
|
|
114
|
-
const staticServerManager = injector.getInstance(StaticServerManager);
|
|
87
|
+
it('returns 404 under a sub-base url when the file is missing and no fallback is set', async () => {
|
|
88
|
+
await usingAsync(createInjector(), async (i) => {
|
|
115
89
|
const port = getPort();
|
|
116
|
-
await
|
|
117
|
-
baseUrl: '/bundle',
|
|
118
|
-
path: '.',
|
|
119
|
-
port,
|
|
120
|
-
});
|
|
90
|
+
await useStaticFiles({ injector: i, baseUrl: '/bundle', path: '.', port });
|
|
121
91
|
const result = await fetch(`http://localhost:${port}/bundle/not-found.html`);
|
|
122
92
|
expect(result.ok).toBe(false);
|
|
123
93
|
expect(result.status).toBe(404);
|
|
124
94
|
expect(result.headers.get('content-type')).toBe('text/plain');
|
|
125
|
-
|
|
126
|
-
expect(body).toBe('Not found');
|
|
95
|
+
expect(await result.text()).toBe('Not found');
|
|
127
96
|
});
|
|
128
97
|
});
|
|
129
|
-
it('
|
|
130
|
-
await usingAsync(
|
|
131
|
-
const staticServerManager = injector.getInstance(StaticServerManager);
|
|
98
|
+
it('serves the configured fallback under a sub-base url', async () => {
|
|
99
|
+
await usingAsync(createInjector(), async (i) => {
|
|
132
100
|
const port = getPort();
|
|
133
|
-
await
|
|
134
|
-
baseUrl: '/bundle',
|
|
135
|
-
path: '.',
|
|
136
|
-
fallback: 'package.json',
|
|
137
|
-
port,
|
|
138
|
-
});
|
|
101
|
+
await useStaticFiles({ injector: i, baseUrl: '/bundle', path: '.', fallback: 'package.json', port });
|
|
139
102
|
const result = await fetch(`http://localhost:${port}/bundle/not-found.html`);
|
|
140
103
|
expect(result.headers.get('content-type')).toBe('application/json');
|
|
141
104
|
});
|
|
142
105
|
});
|
|
143
|
-
it('Should return a defined file from a root directory', async () => {
|
|
144
|
-
await usingAsync(new Injector(), async (injector) => {
|
|
145
|
-
const staticServerManager = injector.getInstance(StaticServerManager);
|
|
146
|
-
const port = getPort();
|
|
147
|
-
await staticServerManager.addStaticSite({
|
|
148
|
-
baseUrl: '/',
|
|
149
|
-
path: '.',
|
|
150
|
-
port,
|
|
151
|
-
});
|
|
152
|
-
const result = await fetch(`http://localhost:${port}/README.md`);
|
|
153
|
-
expect(result.headers.get('content-type')).toBe('text/markdown');
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
it('Should return a defined file from a subdirectory', async () => {
|
|
157
|
-
await usingAsync(new Injector(), async (injector) => {
|
|
158
|
-
const staticServerManager = injector.getInstance(StaticServerManager);
|
|
159
|
-
const port = getPort();
|
|
160
|
-
await staticServerManager.addStaticSite({
|
|
161
|
-
baseUrl: '/',
|
|
162
|
-
path: '.',
|
|
163
|
-
port,
|
|
164
|
-
});
|
|
165
|
-
const result = await fetch(`http://localhost:${port}/packages/utils/README.md`);
|
|
166
|
-
expect(result.headers.get('content-type')).toBe('text/markdown');
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
106
|
});
|
|
170
107
|
describe('shouldExec', () => {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
expect(
|
|
108
|
+
const api = (baseUrl) => buildStaticSiteServerApi({ baseUrl, path: '.', port: 0 });
|
|
109
|
+
it('does not match when the request method is missing', () => {
|
|
110
|
+
expect(api('/').shouldExec({ req: { url: '/' }, res: {} })).toBe(false);
|
|
174
111
|
});
|
|
175
|
-
it('
|
|
176
|
-
|
|
177
|
-
expect(staticServerManager.shouldExec('/')({ req: { method: 'POST', url: '/' } })).toBe(false);
|
|
112
|
+
it('does not match non-GET methods', () => {
|
|
113
|
+
expect(api('/').shouldExec({ req: { method: 'POST', url: '/' }, res: {} })).toBe(false);
|
|
178
114
|
});
|
|
179
|
-
[
|
|
115
|
+
const positiveCases = [
|
|
180
116
|
['/', '/'],
|
|
181
117
|
['/', '/index.html'],
|
|
182
118
|
['/', '/subdir'],
|
|
@@ -186,17 +122,16 @@ describe('StaticServerManager', () => {
|
|
|
186
122
|
['/subdir', '/subdir/'],
|
|
187
123
|
['/subdir', '/subdir/file.js'],
|
|
188
124
|
['/subdir', '/subdir/s2/file.js'],
|
|
189
|
-
]
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
expect(shouldExec).toBe(true);
|
|
125
|
+
];
|
|
126
|
+
positiveCases.forEach(([baseUrl, url]) => it(`matches GET '${url}' against base '${baseUrl}'`, () => {
|
|
127
|
+
expect(api(baseUrl).shouldExec({ req: { method: 'GET', url }, res: {} })).toBe(true);
|
|
193
128
|
}));
|
|
194
|
-
it('
|
|
195
|
-
const
|
|
196
|
-
expect(
|
|
197
|
-
expect(
|
|
198
|
-
expect(
|
|
199
|
-
expect(
|
|
129
|
+
it('does not match unrelated urls under a non-root base', () => {
|
|
130
|
+
const subdir = api('/subdir');
|
|
131
|
+
expect(subdir.shouldExec({ req: { method: 'GET', url: '/' }, res: {} })).toBe(false);
|
|
132
|
+
expect(subdir.shouldExec({ req: { method: 'GET', url: '/other/index.html' }, res: {} })).toBe(false);
|
|
133
|
+
expect(subdir.shouldExec({ req: { method: 'GET', url: '/subdir2' }, res: {} })).toBe(false);
|
|
134
|
+
expect(subdir.shouldExec({ req: { method: 'GET', url: '/subdir2/index.html' }, res: {} })).toBe(false);
|
|
200
135
|
});
|
|
201
136
|
});
|
|
202
137
|
});
|