@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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,129 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [14.1.0] - 2026-05-21
|
|
4
|
+
|
|
5
|
+
### ⬆️ Dependencies
|
|
6
|
+
|
|
7
|
+
- Bump `ajv` to `^8.20.0`.
|
|
8
|
+
- Bump dev `vitest` to `^4.1.5`.
|
|
9
|
+
- Adds `@furystack/cross-node-bus` as a runtime dependency. Resolves to the in-process default bus unless an adapter is bound.
|
|
10
|
+
- Bumped `@furystack/cache` to its new major version. The removed `obsoleteRange` / `removeRange` APIs are not used by `@furystack/rest-service`, so no source changes were required. See the `@furystack/cache` changelog for the migration if you import the cache directly alongside this package.
|
|
11
|
+
- Added `@furystack/cache` as a runtime dependency (`workspace:^`). Used internally by `UserResolutionCache`; not part of `@furystack/rest-service`'s public API surface.
|
|
12
|
+
- Bumped `ws` from `^8.20.0` to `^8.20.1` (dev dependency used in tests).
|
|
13
|
+
- Bumped `@types/node` to `^25.9.1` and `vitest` to `^4.1.7`. Dev-tooling only.
|
|
14
|
+
|
|
15
|
+
### 📚 Documentation
|
|
16
|
+
|
|
17
|
+
- Rewrote JSDoc across the public API — built-in actions (`getCurrentUser`, `isAuthenticated`, `logout`, `passwordLoginAction`, `errorAction`, `notFoundAction`), `authenticate`, `authorize`, `validate`, `HttpAuthenticationSettings`, `HttpUserContext`, the login response strategy, and the request-action implementation — to follow the new value-test guidance: dropped restate-the-type narration, kept intent / trade-offs / constraints around session handling, validation, and error mapping.
|
|
18
|
+
- Expanded `UserResolutionCache` JSDoc to cross-link `invalidateByUser` and document the multi-node trade-off.
|
|
19
|
+
|
|
20
|
+
### ✨ Features
|
|
21
|
+
|
|
22
|
+
### `IdentityEventBus` — cross-node identity invalidation
|
|
23
|
+
|
|
24
|
+
A typed wrapper over `@furystack/cross-node-bus` that bridges the per-process `UserResolutionCache` to a shared bus, so logouts, role flips, password resets and account deletions invalidate cached identities on every node — not just the one that originated the change. Collapses the staleness window from `userCacheTtlMs` (default 30 s) to bus latency (single-digit ms with Redis pub/sub).
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { IdentityEventBus } from '@furystack/rest-service'
|
|
28
|
+
|
|
29
|
+
const bus = injector.get(IdentityEventBus)
|
|
30
|
+
await bus.publish({ type: 'userRolesChanged', username: 'alice' })
|
|
31
|
+
// → invalidates every cached entry that resolved to alice on this node
|
|
32
|
+
// AND every sibling node, synchronously locally and at bus speed remotely.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Supported event variants (`IdentityEvent`):
|
|
36
|
+
|
|
37
|
+
- `userLoggedOut` / `sessionInvalidated` — drop the cache entry for a single session id.
|
|
38
|
+
- `userRolesChanged` / `userDeleted` / `passwordChanged` — drop every cached entry that resolved to the named user, regardless of which session originally populated it.
|
|
39
|
+
|
|
40
|
+
**Self-delivery contract:** `publish()` applies the matching local invalidation and fires local subscribers synchronously **before** awaiting the bus broadcast. Sibling nodes receive the message via a `subscribeRemoteOnly` bridge — own publishes never round-trip through the transport, so duplicate work is impossible.
|
|
41
|
+
|
|
42
|
+
`HttpUserContext.cookieLogout` now broadcasts `userLoggedOut` on the bus instead of dropping the local cache directly. Apps that have not bound a transport adapter run against the in-process default `CrossNodeBus` and behave exactly as before.
|
|
43
|
+
|
|
44
|
+
### `UserResolutionCache.invalidateByUser(username)`
|
|
45
|
+
|
|
46
|
+
Drops every cached entry that resolved to `username`, backed by the cache's reverse tag index — no per-call O(n) scan. Use after role / password / account-state changes that must take effect immediately on the next request, instead of waiting for the TTL window to elapse.
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
const userCache = injector.get(UserResolutionCache)
|
|
50
|
+
userCache.invalidateByUser('alice')
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For multi-node deployments, prefer publishing the corresponding `IdentityEvent` on `IdentityEventBus` — it calls `invalidateByUser` locally and on every sibling.
|
|
54
|
+
|
|
55
|
+
### `identity-cache-keys` exports
|
|
56
|
+
|
|
57
|
+
New module exporting the cache-key / cache-tag shapes shared by the cookie-auth provider, `UserResolutionCache`, and `IdentityEventBus`:
|
|
58
|
+
|
|
59
|
+
- `SessionCacheKey` (type) — `` `cookie:${string}` ``.
|
|
60
|
+
- `UserCacheTag` (type) — `` `user:${string}` ``.
|
|
61
|
+
- `sessionCacheKey(sessionId)` — builds the cookie-auth cache key.
|
|
62
|
+
- `userCacheTag(username)` — builds the user-resolution cache tag.
|
|
63
|
+
|
|
64
|
+
Centralising these strings means the local-vs-replicated invalidation paths cannot drift.
|
|
65
|
+
|
|
66
|
+
### Short-TTL user-resolution cache for `HttpUserContext`
|
|
67
|
+
|
|
68
|
+
`HttpUserContext.getCurrentUser` now consults a singleton `UserResolutionCache` before walking the configured authentication providers. Successful resolutions are cached per-process under a key produced by the matching provider (e.g. session id for cookie auth) and expire after `HttpAuthenticationSettings.userCacheTtlMs` (default **30 000 ms**, capacity **10 000** entries).
|
|
69
|
+
|
|
70
|
+
This bounds cross-instance staleness for out-of-band identity changes — session invalidation on a sibling node, role mutation in storage, etc. — while sharply cutting the auth-store load on chatty clients (every authenticated request used to walk the provider chain on every call).
|
|
71
|
+
|
|
72
|
+
**New configuration on `HttpAuthenticationSettings`:**
|
|
73
|
+
|
|
74
|
+
| Field | Default | Effect |
|
|
75
|
+
| ------------------- | ------- | ------------------------------------------------------------- |
|
|
76
|
+
| `userCacheTtlMs` | `30000` | TTL for cached `User` entries. `0` disables caching entirely. |
|
|
77
|
+
| `userCacheCapacity` | `10000` | LRU capacity ceiling. |
|
|
78
|
+
|
|
79
|
+
### Cache-key contract on `AuthenticationProvider`
|
|
80
|
+
|
|
81
|
+
Added an optional `getCacheKey?(request): string | null` method to `AuthenticationProvider`. Providers that opt in produce stable per-identity keys consumed by the user-resolution cache; providers that omit it (or return `null`) cause the request to bypass the cache.
|
|
82
|
+
|
|
83
|
+
Built-in providers:
|
|
84
|
+
|
|
85
|
+
- **`createCookieAuthProvider`** — keys requests by `cookie:${sessionId}`. Cache hits skip both the session-store and user-store lookups.
|
|
86
|
+
- **`createBasicAuthProvider`** — intentionally does **not** opt in. Caching by username would skip password verification on every cache hit.
|
|
87
|
+
- **`createJwtAuthProvider`** (in `@furystack/auth-jwt`) — also intentionally does **not** opt in. See the `@furystack/auth-jwt` changelog for the rationale (token expiry / revocation must be re-checked per request).
|
|
88
|
+
|
|
89
|
+
### `UserResolutionCache` token
|
|
90
|
+
|
|
91
|
+
Exported a new singleton DI token. Consumers can call `injector.get(UserResolutionCache).invalidate(cacheKey)` to drop a specific entry (e.g. after an out-of-band role mutation), or `invalidateAll()` to flush every entry.
|
|
92
|
+
|
|
93
|
+
`HttpUserContext.cookieLogout` automatically invalidates the local cache entry for the logged-out session, so the very next request on the same node re-authenticates immediately. Sibling nodes still rely on TTL expiry.
|
|
94
|
+
|
|
95
|
+
**Example — invalidate after an admin mutates roles in storage:**
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { UserResolutionCache, UserDataSet } from '@furystack/rest-service'
|
|
99
|
+
|
|
100
|
+
await injector.get(UserDataSet).update(injector, 'alice', { roles: ['admin'] })
|
|
101
|
+
injector.get(UserResolutionCache).invalidate(`cookie:${sessionId}`)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### ♻️ Refactoring
|
|
105
|
+
|
|
106
|
+
### `HttpUserContext` no longer maintains a per-request `WeakMap`
|
|
107
|
+
|
|
108
|
+
The previous `WeakMap<headers, Promise<User>>` cache (per-`HttpUserContext`-instance) has been removed in favor of the shared `UserResolutionCache`. With the request-scoped HUC, the WeakMap was effectively single-shot per request anyway. Anonymous-style requests (no provider yields a key) now bypass the cache entirely instead of being dedup-cached for the lifetime of the HUC instance.
|
|
109
|
+
|
|
110
|
+
## [14.0.0] - 2026-04-25
|
|
111
|
+
|
|
112
|
+
### 💥 Breaking Changes
|
|
113
|
+
|
|
114
|
+
Server managers are gone — every subsystem is now a DI token. See the [v7 migration guide](../../docs/migrations/v7-functional-di.md) for rationale, recipes, and pitfalls.
|
|
115
|
+
|
|
116
|
+
- Removed the `ServerManager`, `ApiManager`, `StaticServerManager`, and `ProxyManager` classes. They are replaced by:
|
|
117
|
+
- `HttpServerPoolToken` — shared HTTP server pool (singleton).
|
|
118
|
+
- `ServerTelemetryToken` — event hub for `onApiRequestError`, `onProxyFailed`, `onWebSocketActionFailed`, `onWebSocketProxyFailed`. Subscribe via `injector.get(ServerTelemetryToken).subscribe(...)`.
|
|
119
|
+
- `HttpAuthenticationSettings` interface + token.
|
|
120
|
+
- `HttpUserContext` interface + token.
|
|
121
|
+
- `useRestService` / `useHttpAuthentication` / `useStaticFiles` / `useProxy` keep their public shapes; internals are fully token-based.
|
|
122
|
+
- Endpoint generators (`createGetCollectionEndpoint`, `createGetEntityEndpoint`, `createPostEndpoint`, `createPatchEndpoint`, `createDeleteEndpoint`) now take a `DataSetToken` from `@furystack/repository` instead of `{ model, primaryKey }`.
|
|
123
|
+
- `UserStore` and `SessionStore` are throw-by-default. Apps must bind concrete persistent stores at bootstrap.
|
|
124
|
+
- `HttpUserContext.user` is no longer a shared field. Per-request identity is stored in a `WeakMap<request.headers, Promise<User>>` so ancestor-cached instances don't leak identity across scopes.
|
|
125
|
+
- `useHttpAuthentication` takes a `userDataSet: DataSetToken` — the old `getUserDataSet(injector)` / `getSessionDataSet(injector)` callbacks are gone.
|
|
126
|
+
|
|
3
127
|
## [13.0.0] - 2026-04-22
|
|
4
128
|
|
|
5
129
|
### 💥 Breaking Changes
|
package/README.md
CHANGED
|
@@ -19,8 +19,8 @@ Start by importing your custom API endpoint interface (see `@furystack/rest`) an
|
|
|
19
19
|
Usage example – authenticated GET, GET collection, and POST APIs for a custom entity that has a physical store and repository set up:
|
|
20
20
|
|
|
21
21
|
```ts
|
|
22
|
-
import { MyApi, MyEntity } from 'my-common-package'
|
|
23
|
-
import {
|
|
22
|
+
import { MyApi, MyEntity, MyEntityDataSet } from 'my-common-package'
|
|
23
|
+
import { createInjector } from '@furystack/inject'
|
|
24
24
|
import {
|
|
25
25
|
createGetCollectionEndpoint,
|
|
26
26
|
createGetEntityEndpoint,
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
useRestService,
|
|
31
31
|
} from '@furystack/rest-service'
|
|
32
32
|
|
|
33
|
-
const myInjector =
|
|
33
|
+
const myInjector = createInjector()
|
|
34
34
|
useHttpAuthentication(myInjector)
|
|
35
35
|
await useRestService<MyApi>({
|
|
36
36
|
injector: myInjector,
|
|
@@ -45,20 +45,24 @@ await useRestService<MyApi>({
|
|
|
45
45
|
api: {
|
|
46
46
|
// Endpoints that can be called with GET HTTP method
|
|
47
47
|
GET: {
|
|
48
|
-
'/my-entities': Authenticate()(createGetCollectionEndpoint(
|
|
49
|
-
'/my-entities/:id': Authenticate()(createGetEntityEndpoint(
|
|
48
|
+
'/my-entities': Authenticate()(createGetCollectionEndpoint(MyEntityDataSet)),
|
|
49
|
+
'/my-entities/:id': Authenticate()(createGetEntityEndpoint(MyEntityDataSet)),
|
|
50
50
|
},
|
|
51
51
|
// Endpoints that can be called with POST HTTP method
|
|
52
52
|
POST: {
|
|
53
|
-
'/my-entities': Authenticate()(createPostEndpoint(
|
|
53
|
+
'/my-entities': Authenticate()(createPostEndpoint(MyEntityDataSet)),
|
|
54
54
|
},
|
|
55
55
|
},
|
|
56
56
|
})
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
Endpoint generators now take a `DataSetToken` directly. Define the token
|
|
60
|
+
once with `defineDataSet` in a shared module and import it in both the
|
|
61
|
+
server and any generators that need it.
|
|
62
|
+
|
|
63
|
+
### Endpoint Generators (Based on DataSets)
|
|
60
64
|
|
|
61
|
-
If you use the underlying layers of FuryStack (`
|
|
65
|
+
If you use the underlying layers of FuryStack (`defineStore` → `defineDataSet`) for an entity type, you can easily create some CRUD endpoints for them. These include:
|
|
62
66
|
|
|
63
67
|
- createDeleteEndpoint()
|
|
64
68
|
- createGetCollectionEndpoint()
|
|
@@ -66,7 +70,7 @@ If you use the underlying layers of FuryStack (`PhysicalStore` -> `Repository`)
|
|
|
66
70
|
- createPatchEndpoint()
|
|
67
71
|
- createPostEndpoint()
|
|
68
72
|
|
|
69
|
-
|
|
73
|
+
Each generator takes a `DataSetToken` and resolves it via the per-request injector. Authorization, hooks, and events configured on the DataSet apply transparently.
|
|
70
74
|
|
|
71
75
|
### Custom Endpoint Implementation
|
|
72
76
|
|
|
@@ -109,9 +113,10 @@ export interface MyApiWithCustomEndpoint extends RestApi {
|
|
|
109
113
|
|
|
110
114
|
/** In the Backend code */
|
|
111
115
|
|
|
116
|
+
import { createInjector } from '@furystack/inject'
|
|
112
117
|
import { JsonResult, useRestService } from '@furystack/rest-service'
|
|
113
118
|
|
|
114
|
-
const i =
|
|
119
|
+
const i = createInjector()
|
|
115
120
|
|
|
116
121
|
await useRestService<MyApiWithCustomEndpoint>({
|
|
117
122
|
injector: i,
|
|
@@ -139,7 +144,8 @@ await useRestService<MyApiWithCustomEndpoint>({
|
|
|
139
144
|
|
|
140
145
|
console.log('The headers are:', headers) /** {foo: 'asd', bar: 2, baz: false} */
|
|
141
146
|
|
|
142
|
-
const
|
|
147
|
+
const httpUser = injector.get(HttpUserContext) // Injector is scoped to the Request
|
|
148
|
+
const currentUser = await httpUser.getCurrentUser()
|
|
143
149
|
console.log('The current user is:', currentUser)
|
|
144
150
|
|
|
145
151
|
return JsonResult({ success: true }, 200)
|
|
@@ -208,21 +214,32 @@ In that way, you will get full validation for _all_ defined endpoint data (heade
|
|
|
208
214
|
You can use the built-in authentication that comes with this package. It contains a session (~cookie) based authentication and Basic Auth. You can use it with the `useHttpAuthentication()` helper:
|
|
209
215
|
|
|
210
216
|
```ts
|
|
211
|
-
import {
|
|
212
|
-
import {
|
|
213
|
-
|
|
217
|
+
import { createInjector } from '@furystack/inject'
|
|
218
|
+
import { useHttpAuthentication, useRestService, UserStore, SessionStore } from '@furystack/rest-service'
|
|
219
|
+
// Persistent store factories and your app-specific DataSet tokens
|
|
220
|
+
import { applicationUserStoreFactory, applicationSessionStoreFactory, ApplicationUserDataSet } from './my-app/stores.js'
|
|
221
|
+
|
|
222
|
+
const myInjector = createInjector()
|
|
223
|
+
|
|
224
|
+
// Wire persistent stores behind the throw-by-default tokens
|
|
225
|
+
myInjector.bind(UserStore, applicationUserStoreFactory)
|
|
226
|
+
myInjector.bind(SessionStore, applicationSessionStoreFactory)
|
|
214
227
|
|
|
215
|
-
const myInjector = new Injector()
|
|
216
228
|
useHttpAuthentication(myInjector, {
|
|
217
|
-
cookieName: 'sessionId',
|
|
218
|
-
enableBasicAuth: true,
|
|
219
|
-
|
|
220
|
-
getUserDataSet: (injector) => getDataSetFor(injector, ApplicationUserModel, 'username'),
|
|
221
|
-
getSessionDataSet: (injector) => getDataSetFor(injector, MySessionModel, 'sessionId'),
|
|
229
|
+
cookieName: 'sessionId',
|
|
230
|
+
enableBasicAuth: true,
|
|
231
|
+
userDataSet: ApplicationUserDataSet,
|
|
222
232
|
})
|
|
233
|
+
|
|
223
234
|
await useRestService<MyApi>({ injector: myInjector, ...apiOptions })
|
|
224
235
|
```
|
|
225
236
|
|
|
237
|
+
`useHttpAuthentication` binds the `HttpAuthenticationSettings` and
|
|
238
|
+
`HttpUserContext` tokens. Your app is responsible for binding the
|
|
239
|
+
`UserStore` / `SessionStore` tokens (which throw by default) to concrete
|
|
240
|
+
persistent implementations, and for passing the `DataSetToken` that backs
|
|
241
|
+
user lookups.
|
|
242
|
+
|
|
226
243
|
### Static File Serving
|
|
227
244
|
|
|
228
245
|
You can serve static files using the `useStaticFiles` helper:
|
|
@@ -322,14 +339,14 @@ The proxy server acts as an intermediary, forwarding requests and responses whil
|
|
|
322
339
|
|
|
323
340
|
**Error Handling and Monitoring:**
|
|
324
341
|
|
|
325
|
-
|
|
342
|
+
Proxy failures are routed through the `ServerTelemetryToken`, which is a
|
|
343
|
+
singleton event hub shared by every `useXxx` helper in this package:
|
|
326
344
|
|
|
327
345
|
```ts
|
|
328
|
-
import {
|
|
346
|
+
import { ServerTelemetryToken } from '@furystack/rest-service'
|
|
329
347
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
proxyManager.subscribe('onProxyFailed', ({ from, to, error }) => {
|
|
348
|
+
const telemetry = injector.get(ServerTelemetryToken)
|
|
349
|
+
telemetry.subscribe('onProxyFailed', ({ from, to, error }) => {
|
|
333
350
|
console.error(`Proxy failed: ${from} -> ${to}`, error)
|
|
334
351
|
// Send to your logging service
|
|
335
352
|
})
|
|
@@ -369,11 +386,13 @@ When enabled, the proxy will forward WebSocket upgrade requests to the target se
|
|
|
369
386
|
- Timeout configuration (applies to upgrade handshake)
|
|
370
387
|
- Error monitoring via `onWebSocketProxyFailed` events
|
|
371
388
|
|
|
372
|
-
Monitor WebSocket proxy errors:
|
|
389
|
+
Monitor WebSocket proxy errors via the same telemetry token:
|
|
373
390
|
|
|
374
391
|
```ts
|
|
375
|
-
|
|
376
|
-
|
|
392
|
+
import { ServerTelemetryToken } from '@furystack/rest-service'
|
|
393
|
+
|
|
394
|
+
const telemetry = injector.get(ServerTelemetryToken)
|
|
395
|
+
telemetry.subscribe('onWebSocketProxyFailed', ({ from, to, error }) => {
|
|
377
396
|
console.error(`WebSocket proxy failed: ${from} -> ${to}`, error)
|
|
378
397
|
})
|
|
379
398
|
```
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { RequestAction } from '../request-action-implementation.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Default error handler. Maps thrown errors to HTTP responses:
|
|
4
|
+
*
|
|
5
|
+
* - {@link SchemaValidationError} → 400 with `{ message, errors }`
|
|
6
|
+
* - {@link RequestError} → its `responseCode` with `{ message }`
|
|
7
|
+
* - {@link AuthorizationError} → 403 with `{ message }`
|
|
8
|
+
* - other `Error` → 500 with `{ message }`
|
|
9
|
+
* - non-Error throwables → 500 with a generic message
|
|
5
10
|
*/
|
|
6
11
|
export declare const ErrorAction: RequestAction<{
|
|
7
12
|
body: unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-action.d.ts","sourceRoot":"","sources":["../../src/actions/error-action.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AAIxE
|
|
1
|
+
{"version":3,"file":"error-action.d.ts","sourceRoot":"","sources":["../../src/actions/error-action.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AAIxE;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC;IACtC,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAC5B,CAoBA,CAAA"}
|
|
@@ -3,8 +3,13 @@ import { AuthorizationError } from '@furystack/core';
|
|
|
3
3
|
import { JsonResult } from '../request-action-implementation.js';
|
|
4
4
|
import { SchemaValidationError } from '../schema-validator/schema-validation-error.js';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Default error handler. Maps thrown errors to HTTP responses:
|
|
7
|
+
*
|
|
8
|
+
* - {@link SchemaValidationError} → 400 with `{ message, errors }`
|
|
9
|
+
* - {@link RequestError} → its `responseCode` with `{ message }`
|
|
10
|
+
* - {@link AuthorizationError} → 403 with `{ message }`
|
|
11
|
+
* - other `Error` → 500 with `{ message }`
|
|
12
|
+
* - non-Error throwables → 500 with a generic message
|
|
8
13
|
*/
|
|
9
14
|
export const ErrorAction = async ({ getBody }) => {
|
|
10
15
|
const body = await getBody();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-action.js","sourceRoot":"","sources":["../../src/actions/error-action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAA;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gDAAgD,CAAA;AAEtF
|
|
1
|
+
{"version":3,"file":"error-action.js","sourceRoot":"","sources":["../../src/actions/error-action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAA;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gDAAgD,CAAA;AAEtF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,WAAW,GAGnB,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;IACzB,MAAM,IAAI,GAAG,MAAM,OAAO,EAAE,CAAA;IAE5B,IAAI,IAAI,YAAY,qBAAqB,EAAE,CAAC;QAC1C,OAAO,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,CAAA;IACxE,CAAC;IAED,IAAI,IAAI,YAAY,YAAY,EAAE,CAAC;QACjC,OAAO,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,YAAY,CAAC,CAAA;IACjE,CAAC;IAED,IAAI,IAAI,YAAY,kBAAkB,EAAE,CAAC;QACvC,OAAO,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAA;IACnD,CAAC;IAED,IAAI,IAAI,YAAY,KAAK,EAAE,CAAC;QAC1B,OAAO,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAA;IACnD,CAAC;IAED,OAAO,UAAU,CAAC,EAAE,OAAO,EAAE,8BAA8B,EAAE,EAAE,GAAG,CAAC,CAAA;AACrE,CAAC,CAAA"}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type { User } from '@furystack/core';
|
|
2
2
|
import type { RequestAction } from '../request-action-implementation.js';
|
|
3
|
-
/**
|
|
4
|
-
* Action that returns the current authenticated user
|
|
5
|
-
* @param injector The injector from the current stack
|
|
6
|
-
*/
|
|
3
|
+
/** Returns the current authenticated user; 401 if no user is bound. */
|
|
7
4
|
export declare const GetCurrentUser: RequestAction<{
|
|
8
5
|
result: User;
|
|
9
6
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-current-user.d.ts","sourceRoot":"","sources":["../../src/actions/get-current-user.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAG3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AAGxE
|
|
1
|
+
{"version":3,"file":"get-current-user.d.ts","sourceRoot":"","sources":["../../src/actions/get-current-user.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAG3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AAGxE,uEAAuE;AACvE,eAAO,MAAM,cAAc,EAAE,aAAa,CAAC;IACzC,MAAM,EAAE,IAAI,CAAA;CACb,CAGC,CAAA"}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { getCurrentUser } from '@furystack/core';
|
|
2
2
|
import { Authenticate } from '../authenticate.js';
|
|
3
3
|
import { JsonResult } from '../request-action-implementation.js';
|
|
4
|
-
/**
|
|
5
|
-
* Action that returns the current authenticated user
|
|
6
|
-
* @param injector The injector from the current stack
|
|
7
|
-
*/
|
|
4
|
+
/** Returns the current authenticated user; 401 if no user is bound. */
|
|
8
5
|
export const GetCurrentUser = Authenticate()(async ({ injector }) => {
|
|
9
6
|
const user = await getCurrentUser(injector);
|
|
10
7
|
return JsonResult(user);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-current-user.js","sourceRoot":"","sources":["../../src/actions/get-current-user.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAA;AAEhE
|
|
1
|
+
{"version":3,"file":"get-current-user.js","sourceRoot":"","sources":["../../src/actions/get-current-user.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAA;AAEhE,uEAAuE;AACvE,MAAM,CAAC,MAAM,cAAc,GAEtB,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;IACzC,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAA;IAC3C,OAAO,UAAU,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC,CAAC,CAAA"}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IdentityContext } from '@furystack/core';
|
|
2
|
+
import { createInjector } from '@furystack/inject';
|
|
2
3
|
import { usingAsync } from '@furystack/utils';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
3
5
|
import { GetCurrentUser } from './get-current-user.js';
|
|
4
|
-
import { IdentityContext } from '@furystack/core';
|
|
5
|
-
import { describe, it, expect } from 'vitest';
|
|
6
6
|
describe('getCurrentUser', () => {
|
|
7
7
|
const request = { url: 'https://google.com' };
|
|
8
8
|
const response = {};
|
|
9
|
-
it('
|
|
9
|
+
it('returns the current user in a JSON result', async () => {
|
|
10
10
|
const testUser = { Name: 'Userke' };
|
|
11
|
-
await usingAsync(
|
|
12
|
-
i.
|
|
11
|
+
await usingAsync(createInjector(), async (i) => {
|
|
12
|
+
i.bind(IdentityContext, () => ({
|
|
13
|
+
getCurrentUser: () => Promise.resolve(testUser),
|
|
14
|
+
isAuthenticated: () => Promise.resolve(true),
|
|
15
|
+
isAuthorized: () => Promise.resolve(true),
|
|
16
|
+
}));
|
|
13
17
|
const result = await GetCurrentUser({ injector: i, request, response });
|
|
14
18
|
expect(result.statusCode).toBe(200);
|
|
15
19
|
expect(result.chunk).toEqual(testUser);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-current-user.spec.js","sourceRoot":"","sources":["../../src/actions/get-current-user.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"get-current-user.spec.js","sourceRoot":"","sources":["../../src/actions/get-current-user.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEtD,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,MAAM,OAAO,GAAG,EAAE,GAAG,EAAE,oBAAoB,EAAqB,CAAA;IAChE,MAAM,QAAQ,GAAG,EAAoB,CAAA;IAErC,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,QAAQ,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAA;QACnC,MAAM,UAAU,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YAC7C,CAAC,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;gBAC7B,cAAc,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,QAAiB,CAAC;gBACxD,eAAe,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;gBAC5C,YAAY,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;aAC1C,CAAC,CAAC,CAAA;YACH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAA;YACvE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACnC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QACxC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { RequestAction } from '../request-action-implementation.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* @returns A standard authentication result
|
|
3
|
+
* Returns `{ isAuthenticated: boolean }`. Unauthenticated callers receive
|
|
4
|
+
* a 200 with `false` rather than a 401 — use this when the client needs to
|
|
5
|
+
* branch on auth state without triggering a re-login flow.
|
|
7
6
|
*/
|
|
8
7
|
export declare const IsAuthenticated: RequestAction<{
|
|
9
8
|
result: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-authenticated.d.ts","sourceRoot":"","sources":["../../src/actions/is-authenticated.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AAGxE
|
|
1
|
+
{"version":3,"file":"is-authenticated.d.ts","sourceRoot":"","sources":["../../src/actions/is-authenticated.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AAGxE;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,aAAa,CAAC;IAAE,MAAM,EAAE;QAAE,eAAe,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,CAGnF,CAAA"}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { isAuthenticated } from '@furystack/core';
|
|
2
2
|
import { JsonResult } from '../request-action-implementation.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* @returns A standard authentication result
|
|
4
|
+
* Returns `{ isAuthenticated: boolean }`. Unauthenticated callers receive
|
|
5
|
+
* a 200 with `false` rather than a 401 — use this when the client needs to
|
|
6
|
+
* branch on auth state without triggering a re-login flow.
|
|
8
7
|
*/
|
|
9
8
|
export const IsAuthenticated = async ({ injector }) => {
|
|
10
9
|
const isAuthenticatedResult = await isAuthenticated(injector);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-authenticated.js","sourceRoot":"","sources":["../../src/actions/is-authenticated.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAA;AAEhE
|
|
1
|
+
{"version":3,"file":"is-authenticated.js","sourceRoot":"","sources":["../../src/actions/is-authenticated.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAA;AAEhE;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAA4D,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;IAC7G,MAAM,qBAAqB,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAA;IAC7D,OAAO,UAAU,CAAC,EAAE,eAAe,EAAE,qBAAqB,EAAE,CAAC,CAAA;AAC/D,CAAC,CAAA"}
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IdentityContext } from '@furystack/core';
|
|
2
|
+
import { createInjector } from '@furystack/inject';
|
|
2
3
|
import { usingAsync } from '@furystack/utils';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
3
5
|
import { IsAuthenticated } from './is-authenticated.js';
|
|
4
|
-
import { IdentityContext } from '@furystack/core';
|
|
5
|
-
import { describe, it, expect } from 'vitest';
|
|
6
6
|
describe('isAuthenticated', () => {
|
|
7
7
|
const request = { url: 'https://google.com' };
|
|
8
8
|
const response = {};
|
|
9
|
-
it('
|
|
10
|
-
await usingAsync(
|
|
11
|
-
i.
|
|
9
|
+
it('returns the authentication status from the identity context', async () => {
|
|
10
|
+
await usingAsync(createInjector(), async (i) => {
|
|
11
|
+
i.bind(IdentityContext, () => ({
|
|
12
|
+
isAuthenticated: () => Promise.resolve(true),
|
|
13
|
+
isAuthorized: () => Promise.resolve(true),
|
|
14
|
+
getCurrentUser: () => Promise.reject(new Error('not needed')),
|
|
15
|
+
}));
|
|
12
16
|
const result = await IsAuthenticated({ injector: i, request, response });
|
|
13
17
|
expect(result.statusCode).toBe(200);
|
|
14
18
|
expect(result.chunk).toEqual({ isAuthenticated: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-authenticated.spec.js","sourceRoot":"","sources":["../../src/actions/is-authenticated.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"is-authenticated.spec.js","sourceRoot":"","sources":["../../src/actions/is-authenticated.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAEvD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,MAAM,OAAO,GAAG,EAAE,GAAG,EAAE,oBAAoB,EAAqB,CAAA;IAChE,MAAM,QAAQ,GAAG,EAAoB,CAAA;IAErC,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,UAAU,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YAC7C,CAAC,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;gBAC7B,eAAe,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;gBAC5C,YAAY,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;gBACzC,cAAc,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;aAC9D,CAAC,CAAC,CAAA;YACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAA;YACxE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACnC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAA;QACzD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createInjector } from '@furystack/inject';
|
|
2
|
+
import { EventHub } from '@furystack/utils';
|
|
2
3
|
import { usingAsync } from '@furystack/utils';
|
|
3
4
|
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
-
import { HttpUserContext } from '../http-user-context.js';
|
|
5
|
+
import { HttpUserContext as HttpUserContextToken } from '../http-user-context.js';
|
|
5
6
|
import { LogoutAction } from './logout.js';
|
|
6
7
|
describe('LogoutAction', () => {
|
|
7
8
|
const request = { url: 'https://google.com' };
|
|
8
9
|
const response = {};
|
|
9
|
-
it('
|
|
10
|
-
await usingAsync(
|
|
11
|
-
const cookieLogout = vi.fn(async () =>
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
it('delegates to HttpUserContext.cookieLogout and returns an empty result', async () => {
|
|
11
|
+
await usingAsync(createInjector(), async (i) => {
|
|
12
|
+
const cookieLogout = vi.fn(async () => {
|
|
13
|
+
/* noop */
|
|
14
|
+
});
|
|
15
|
+
const stub = Object.assign(new EventHub(), { cookieLogout });
|
|
16
|
+
i.bind(HttpUserContextToken, () => stub);
|
|
15
17
|
const result = await LogoutAction({ request, response, injector: i });
|
|
16
18
|
expect(result.statusCode).toBe(200);
|
|
17
19
|
expect(result.chunk).toBe(undefined);
|
|
18
|
-
expect(cookieLogout).
|
|
20
|
+
expect(cookieLogout).toHaveBeenCalled();
|
|
19
21
|
});
|
|
20
22
|
});
|
|
21
23
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout-action.spec.js","sourceRoot":"","sources":["../../src/actions/logout-action.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"logout-action.spec.js","sourceRoot":"","sources":["../../src/actions/logout-action.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAEjD,OAAO,EAAE,eAAe,IAAI,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,MAAM,OAAO,GAAG,EAAE,GAAG,EAAE,oBAAoB,EAAqB,CAAA;IAChE,MAAM,QAAQ,GAAG,EAAoB,CAAA;IAErC,EAAE,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;QACrF,MAAM,UAAU,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YAC7C,MAAM,YAAY,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE;gBACpC,UAAU;YACZ,CAAC,CAAC,CAAA;YACF,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,QAAQ,EAAE,EAAE,EAAE,YAAY,EAAE,CAA+B,CAAA;YAC1F,CAAC,CAAC,IAAI,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;YAExC,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAA;YACrE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACnC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YACpC,MAAM,CAAC,YAAY,CAAC,CAAC,gBAAgB,EAAE,CAAA;QACzC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/esm/actions/logout.d.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import type { RequestAction } from '../request-action-implementation.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* @param root0.injector The injector from the context
|
|
6
|
-
* @param root0.request The current Request object
|
|
7
|
-
* @param root0.response The Response object
|
|
8
|
-
* @returns An empty result that indicates the success
|
|
3
|
+
* Logs out via {@link HttpUserContext.cookieLogout} — clears the session
|
|
4
|
+
* cookie and removes the session row from the session DataSet.
|
|
9
5
|
*/
|
|
10
6
|
export declare const LogoutAction: RequestAction<{
|
|
11
7
|
result: unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/actions/logout.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AAGxE
|
|
1
|
+
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/actions/logout.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AAGxE;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,aAAa,CAAC;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,CAG3D,CAAA"}
|
package/esm/actions/logout.js
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import { HttpUserContext } from '../http-user-context.js';
|
|
2
2
|
import { EmptyResult } from '../request-action-implementation.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* @param root0.injector The injector from the context
|
|
7
|
-
* @param root0.request The current Request object
|
|
8
|
-
* @param root0.response The Response object
|
|
9
|
-
* @returns An empty result that indicates the success
|
|
4
|
+
* Logs out via {@link HttpUserContext.cookieLogout} — clears the session
|
|
5
|
+
* cookie and removes the session row from the session DataSet.
|
|
10
6
|
*/
|
|
11
7
|
export const LogoutAction = async ({ injector, request, response }) => {
|
|
12
|
-
await injector.
|
|
8
|
+
await injector.get(HttpUserContext).cookieLogout(request, response);
|
|
13
9
|
return EmptyResult();
|
|
14
10
|
};
|
|
15
11
|
//# sourceMappingURL=logout.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/actions/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AAEjE
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/actions/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AAEjE;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAuC,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE;IACxG,MAAM,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IACnE,OAAO,WAAW,EAAE,CAAA;AACtB,CAAC,CAAA"}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { RequestAction } from '../request-action-implementation.js';
|
|
2
|
-
/**
|
|
3
|
-
* @returns The standard Not Found action result
|
|
4
|
-
*/
|
|
2
|
+
/** Default `404` action. Returns `{ error: 'Content not found' }`. */
|
|
5
3
|
export declare const NotFoundAction: RequestAction<{
|
|
6
4
|
result: {
|
|
7
5
|
error: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"not-found-action.d.ts","sourceRoot":"","sources":["../../src/actions/not-found-action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AAGxE
|
|
1
|
+
{"version":3,"file":"not-found-action.d.ts","sourceRoot":"","sources":["../../src/actions/not-found-action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AAGxE,sEAAsE;AACtE,eAAO,MAAM,cAAc,EAAE,aAAa,CAAC;IAAE,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAOvE,CAAA"}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { JsonResult } from '../request-action-implementation.js';
|
|
2
|
-
/**
|
|
3
|
-
* @returns The standard Not Found action result
|
|
4
|
-
*/
|
|
2
|
+
/** Default `404` action. Returns `{ error: 'Content not found' }`. */
|
|
5
3
|
export const NotFoundAction = async () => {
|
|
6
4
|
return JsonResult({
|
|
7
5
|
error: 'Content not found',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"not-found-action.js","sourceRoot":"","sources":["../../src/actions/not-found-action.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAA;AAEhE
|
|
1
|
+
{"version":3,"file":"not-found-action.js","sourceRoot":"","sources":["../../src/actions/not-found-action.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAA;AAEhE,sEAAsE;AACtE,MAAM,CAAC,MAAM,cAAc,GAAiD,KAAK,IAAI,EAAE;IACrF,OAAO,UAAU,CACf;QACE,KAAK,EAAE,mBAAmB;KAC3B,EACD,GAAG,CACJ,CAAA;AACH,CAAC,CAAA"}
|