@beignet/core 0.0.1 → 0.0.3
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 +27 -0
- package/README.md +202 -8
- package/dist/application/index.d.ts +93 -9
- package/dist/application/index.d.ts.map +1 -1
- package/dist/application/index.js +11 -11
- package/dist/application/index.js.map +1 -1
- package/dist/client/client.d.ts +73 -12
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +37 -12
- package/dist/client/client.js.map +1 -1
- package/dist/client/index.d.ts +12 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +6 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/types.d.ts +69 -8
- package/dist/client/types.d.ts.map +1 -1
- package/dist/config/index.d.ts +84 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +36 -0
- package/dist/config/index.js.map +1 -1
- package/dist/contracts/contract-builder.d.ts +49 -22
- package/dist/contracts/contract-builder.d.ts.map +1 -1
- package/dist/contracts/contract-builder.js +48 -21
- package/dist/contracts/contract-builder.js.map +1 -1
- package/dist/contracts/contract-group.d.ts +35 -19
- package/dist/contracts/contract-group.d.ts.map +1 -1
- package/dist/contracts/contract-group.js +35 -19
- package/dist/contracts/contract-group.js.map +1 -1
- package/dist/contracts/contract-like.d.ts +4 -4
- package/dist/contracts/contract-like.d.ts.map +1 -1
- package/dist/contracts/contract-like.js +2 -1
- package/dist/contracts/contract-like.js.map +1 -1
- package/dist/contracts/index.d.ts +28 -0
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +12 -0
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/openapi-meta.d.ts +8 -8
- package/dist/contracts/openapi-meta.d.ts.map +1 -1
- package/dist/contracts/path-template.d.ts +27 -0
- package/dist/contracts/path-template.d.ts.map +1 -1
- package/dist/contracts/path-template.js +6 -0
- package/dist/contracts/path-template.js.map +1 -1
- package/dist/contracts/types.d.ts +104 -10
- package/dist/contracts/types.d.ts.map +1 -1
- package/dist/contracts/types.js +15 -0
- package/dist/contracts/types.js.map +1 -1
- package/dist/contracts/utils.d.ts +6 -0
- package/dist/contracts/utils.d.ts.map +1 -1
- package/dist/contracts/utils.js +6 -0
- package/dist/contracts/utils.js.map +1 -1
- package/dist/domain/entity.d.ts +22 -11
- package/dist/domain/entity.d.ts.map +1 -1
- package/dist/domain/entity.js +5 -1
- package/dist/domain/entity.js.map +1 -1
- package/dist/domain/events.d.ts +5 -2
- package/dist/domain/events.d.ts.map +1 -1
- package/dist/domain/events.js +4 -1
- package/dist/domain/events.js.map +1 -1
- package/dist/domain/value-object.d.ts +19 -9
- package/dist/domain/value-object.d.ts.map +1 -1
- package/dist/domain/value-object.js +5 -1
- package/dist/domain/value-object.js.map +1 -1
- package/dist/errors/catalog.d.ts +40 -16
- package/dist/errors/catalog.d.ts.map +1 -1
- package/dist/errors/catalog.js +18 -7
- package/dist/errors/catalog.js.map +1 -1
- package/dist/errors/response.d.ts +16 -4
- package/dist/errors/response.d.ts.map +1 -1
- package/dist/errors/response.js +3 -3
- package/dist/errors/response.js.map +1 -1
- package/dist/errors/validation.d.ts +10 -1
- package/dist/errors/validation.d.ts.map +1 -1
- package/dist/errors/validation.js +3 -0
- package/dist/errors/validation.js.map +1 -1
- package/dist/events/index.d.ts +133 -0
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +30 -0
- package/dist/events/index.js.map +1 -1
- package/dist/idempotency/index.d.ts +355 -0
- package/dist/idempotency/index.d.ts.map +1 -0
- package/dist/idempotency/index.js +360 -0
- package/dist/idempotency/index.js.map +1 -0
- package/dist/jobs/index.d.ts +248 -4
- package/dist/jobs/index.d.ts.map +1 -1
- package/dist/jobs/index.js +183 -1
- package/dist/jobs/index.js.map +1 -1
- package/dist/mail/index.d.ts +149 -0
- package/dist/mail/index.d.ts.map +1 -1
- package/dist/mail/index.js +30 -0
- package/dist/mail/index.js.map +1 -1
- package/dist/notifications/index.d.ts +369 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/index.js +310 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/openapi/index.d.ts +132 -16
- package/dist/openapi/index.d.ts.map +1 -1
- package/dist/openapi/index.js +1 -1
- package/dist/openapi/index.js.map +1 -1
- package/dist/outbox/index.d.ts +474 -0
- package/dist/outbox/index.d.ts.map +1 -0
- package/dist/outbox/index.js +538 -0
- package/dist/outbox/index.js.map +1 -0
- package/dist/pagination/index.d.ts +166 -0
- package/dist/pagination/index.d.ts.map +1 -0
- package/dist/pagination/index.js +96 -0
- package/dist/pagination/index.js.map +1 -0
- package/dist/ports/audit.d.ts +271 -0
- package/dist/ports/audit.d.ts.map +1 -1
- package/dist/ports/audit.js +128 -0
- package/dist/ports/audit.js.map +1 -1
- package/dist/ports/auth.d.ts +70 -0
- package/dist/ports/auth.d.ts.map +1 -1
- package/dist/ports/auth.js +30 -0
- package/dist/ports/auth.js.map +1 -1
- package/dist/ports/cache.d.ts +41 -0
- package/dist/ports/cache.d.ts.map +1 -1
- package/dist/ports/cache.js +10 -0
- package/dist/ports/cache.js.map +1 -1
- package/dist/ports/clock.d.ts +38 -0
- package/dist/ports/clock.d.ts.map +1 -1
- package/dist/ports/clock.js +20 -0
- package/dist/ports/clock.js.map +1 -1
- package/dist/ports/id-generator.d.ts +37 -0
- package/dist/ports/id-generator.d.ts.map +1 -1
- package/dist/ports/id-generator.js +22 -0
- package/dist/ports/id-generator.js.map +1 -1
- package/dist/ports/index.d.ts +83 -0
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js +41 -5
- package/dist/ports/index.js.map +1 -1
- package/dist/ports/logger.d.ts +56 -0
- package/dist/ports/logger.d.ts.map +1 -1
- package/dist/ports/logger.js +17 -0
- package/dist/ports/logger.js.map +1 -1
- package/dist/ports/policy.d.ts +132 -0
- package/dist/ports/policy.d.ts.map +1 -1
- package/dist/ports/policy.js +45 -0
- package/dist/ports/policy.js.map +1 -1
- package/dist/ports/rate-limit.d.ts +25 -0
- package/dist/ports/rate-limit.d.ts.map +1 -1
- package/dist/ports/rate-limit.js +10 -0
- package/dist/ports/rate-limit.js.map +1 -1
- package/dist/ports/redaction.d.ts +101 -0
- package/dist/ports/redaction.d.ts.map +1 -1
- package/dist/ports/redaction.js +59 -0
- package/dist/ports/redaction.js.map +1 -1
- package/dist/ports/storage.d.ts +100 -0
- package/dist/ports/storage.d.ts.map +1 -1
- package/dist/ports/storage.js +10 -0
- package/dist/ports/storage.js.map +1 -1
- package/dist/ports/testing.d.ts +47 -0
- package/dist/ports/testing.d.ts.map +1 -1
- package/dist/ports/testing.js +23 -0
- package/dist/ports/testing.js.map +1 -1
- package/dist/ports/unit-of-work.d.ts +60 -3
- package/dist/ports/unit-of-work.d.ts.map +1 -1
- package/dist/ports/unit-of-work.js +11 -2
- package/dist/ports/unit-of-work.js.map +1 -1
- package/dist/providers/instrumentation.d.ts +205 -1
- package/dist/providers/instrumentation.d.ts.map +1 -1
- package/dist/providers/instrumentation.js +14 -0
- package/dist/providers/instrumentation.js.map +1 -1
- package/dist/providers/provider.d.ts +14 -1
- package/dist/providers/provider.d.ts.map +1 -1
- package/dist/providers/provider.js.map +1 -1
- package/dist/schedules/index.d.ts +246 -0
- package/dist/schedules/index.d.ts.map +1 -1
- package/dist/schedules/index.js +27 -0
- package/dist/schedules/index.js.map +1 -1
- package/dist/server/health.d.ts +14 -5
- package/dist/server/health.d.ts.map +1 -1
- package/dist/server/health.js +5 -2
- package/dist/server/health.js.map +1 -1
- package/dist/server/hooks/auth.d.ts +68 -26
- package/dist/server/hooks/auth.d.ts.map +1 -1
- package/dist/server/hooks/auth.js +44 -55
- package/dist/server/hooks/auth.js.map +1 -1
- package/dist/server/hooks/cors.d.ts +27 -0
- package/dist/server/hooks/cors.d.ts.map +1 -1
- package/dist/server/hooks/cors.js +12 -0
- package/dist/server/hooks/cors.js.map +1 -1
- package/dist/server/hooks/errors.d.ts +15 -6
- package/dist/server/hooks/errors.d.ts.map +1 -1
- package/dist/server/hooks/errors.js.map +1 -1
- package/dist/server/hooks/index.d.ts +4 -1
- package/dist/server/hooks/index.d.ts.map +1 -1
- package/dist/server/hooks/index.js +3 -0
- package/dist/server/hooks/index.js.map +1 -1
- package/dist/server/hooks/logging.d.ts +36 -0
- package/dist/server/hooks/logging.d.ts.map +1 -1
- package/dist/server/hooks/logging.js +6 -0
- package/dist/server/hooks/logging.js.map +1 -1
- package/dist/server/hooks/rate-limit.d.ts +33 -0
- package/dist/server/hooks/rate-limit.d.ts.map +1 -1
- package/dist/server/hooks/rate-limit.js +11 -0
- package/dist/server/hooks/rate-limit.js.map +1 -1
- package/dist/server/http.d.ts +222 -0
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +20 -1
- package/dist/server/http.js.map +1 -1
- package/dist/server/index.d.ts +19 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +7 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/openapi.d.ts +5 -3
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/server/openapi.js +4 -2
- package/dist/server/openapi.js.map +1 -1
- package/dist/server/providers/loadProviderConfig.d.ts +9 -0
- package/dist/server/providers/loadProviderConfig.d.ts.map +1 -1
- package/dist/server/providers/loadProviderConfig.js +9 -0
- package/dist/server/providers/loadProviderConfig.js.map +1 -1
- package/dist/server/server.d.ts +159 -19
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +72 -31
- package/dist/server/server.js.map +1 -1
- package/dist/testing/index.d.ts +171 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +127 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/uploads/client.d.ts +278 -0
- package/dist/uploads/client.d.ts.map +1 -0
- package/dist/uploads/client.js +428 -0
- package/dist/uploads/client.js.map +1 -0
- package/dist/uploads/index.d.ts +361 -0
- package/dist/uploads/index.d.ts.map +1 -0
- package/dist/uploads/index.js +543 -0
- package/dist/uploads/index.js.map +1 -0
- package/package.json +31 -2
- package/src/application/index.ts +85 -22
- package/src/client/client.ts +73 -12
- package/src/client/index.ts +12 -0
- package/src/client/types.ts +70 -9
- package/src/config/index.ts +86 -0
- package/src/contracts/contract-builder.ts +49 -22
- package/src/contracts/contract-group.ts +35 -19
- package/src/contracts/contract-like.ts +4 -4
- package/src/contracts/index.ts +28 -1
- package/src/contracts/openapi-meta.ts +8 -8
- package/src/contracts/path-template.ts +27 -0
- package/src/contracts/types.ts +111 -10
- package/src/contracts/utils.ts +6 -0
- package/src/domain/entity.ts +22 -11
- package/src/domain/events.ts +5 -2
- package/src/domain/value-object.ts +19 -9
- package/src/errors/catalog.ts +40 -16
- package/src/errors/response.ts +16 -4
- package/src/errors/validation.ts +10 -1
- package/src/events/index.ts +134 -0
- package/src/idempotency/index.ts +767 -0
- package/src/jobs/index.ts +437 -5
- package/src/mail/index.ts +149 -0
- package/src/notifications/index.ts +771 -0
- package/src/openapi/index.ts +133 -16
- package/src/outbox/index.ts +1104 -0
- package/src/pagination/index.ts +278 -0
- package/src/ports/audit.ts +271 -0
- package/src/ports/auth.ts +70 -0
- package/src/ports/cache.ts +41 -0
- package/src/ports/clock.ts +38 -0
- package/src/ports/id-generator.ts +37 -0
- package/src/ports/index.ts +106 -11
- package/src/ports/logger.ts +56 -0
- package/src/ports/policy.ts +133 -0
- package/src/ports/rate-limit.ts +25 -0
- package/src/ports/redaction.ts +101 -0
- package/src/ports/storage.ts +100 -0
- package/src/ports/testing.ts +47 -0
- package/src/ports/unit-of-work.ts +60 -3
- package/src/providers/instrumentation.ts +211 -1
- package/src/providers/provider.ts +14 -1
- package/src/schedules/index.ts +247 -0
- package/src/server/health.ts +14 -5
- package/src/server/hooks/auth.ts +105 -120
- package/src/server/hooks/cors.ts +27 -0
- package/src/server/hooks/errors.ts +15 -6
- package/src/server/hooks/index.ts +4 -5
- package/src/server/hooks/logging.ts +36 -0
- package/src/server/hooks/rate-limit.ts +33 -0
- package/src/server/http.ts +249 -1
- package/src/server/index.ts +19 -1
- package/src/server/openapi.ts +5 -3
- package/src/server/providers/loadProviderConfig.ts +9 -0
- package/src/server/server.ts +296 -30
- package/src/testing/index.ts +348 -0
- package/src/uploads/client.ts +861 -0
- package/src/uploads/index.ts +1067 -0
package/src/server/hooks/auth.ts
CHANGED
|
@@ -1,147 +1,132 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
type AuthSession,
|
|
4
|
-
AuthUnauthorizedError,
|
|
5
|
-
} from "../../ports";
|
|
6
|
-
import type { HttpRequestLike, HttpResponse, ServerHook } from "../types";
|
|
1
|
+
import { AuthUnauthorizedError } from "../../ports";
|
|
2
|
+
import type { HttpRequestLike, RouteHook } from "../types";
|
|
7
3
|
|
|
8
4
|
type MaybePromise<T> = T | Promise<T>;
|
|
9
5
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export type CtxWithAuthPort = {
|
|
14
|
-
ports: {
|
|
15
|
-
auth: AuthPort;
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Arguments passed to auth route-hook callbacks.
|
|
8
|
+
*/
|
|
19
9
|
export type AuthHookArgs<Ctx> = {
|
|
10
|
+
/**
|
|
11
|
+
* Framework-neutral request.
|
|
12
|
+
*/
|
|
20
13
|
req: HttpRequestLike;
|
|
14
|
+
/**
|
|
15
|
+
* Current route handler context.
|
|
16
|
+
*/
|
|
21
17
|
ctx: Ctx;
|
|
18
|
+
/**
|
|
19
|
+
* Matched contract metadata and schemas.
|
|
20
|
+
*/
|
|
22
21
|
contract: {
|
|
23
22
|
metadata?: Record<string, unknown>;
|
|
24
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Parsed path parameters.
|
|
26
|
+
*/
|
|
25
27
|
path: unknown;
|
|
28
|
+
/**
|
|
29
|
+
* Parsed query parameters.
|
|
30
|
+
*/
|
|
26
31
|
query: unknown;
|
|
32
|
+
/**
|
|
33
|
+
* Parsed request headers.
|
|
34
|
+
*/
|
|
27
35
|
headers: unknown;
|
|
36
|
+
/**
|
|
37
|
+
* Parsed request body.
|
|
38
|
+
*/
|
|
28
39
|
body: unknown;
|
|
29
40
|
};
|
|
30
41
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
export type AuthHooksOptions<Ctx, Session> = {
|
|
42
|
+
/**
|
|
43
|
+
* Options for route-scoped auth hooks.
|
|
44
|
+
*/
|
|
45
|
+
export type AuthHooksOptions<Ctx, AddedCtx extends object> = {
|
|
46
|
+
/**
|
|
47
|
+
* Hook name prefix used in diagnostics.
|
|
48
|
+
*/
|
|
40
49
|
name?: string;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
) => MaybePromise<
|
|
50
|
+
/**
|
|
51
|
+
* Resolve authenticated context additions for the current request.
|
|
52
|
+
*
|
|
53
|
+
* Return `null` when the request is unauthenticated. Required hooks will
|
|
54
|
+
* reject that request; optional hooks will add no auth context.
|
|
55
|
+
*/
|
|
56
|
+
resolve: (args: AuthHookArgs<Ctx>) => MaybePromise<AddedCtx | null>;
|
|
48
57
|
};
|
|
49
58
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
): Promise<unknown | null> {
|
|
68
|
-
const auth = (args.ctx as { ports?: { auth?: AuthPort } }).ports?.auth;
|
|
69
|
-
if (!auth) {
|
|
70
|
-
throw new Error(
|
|
71
|
-
"createAuthHooks requires ctx.ports.auth or an explicit getSession option.",
|
|
72
|
-
);
|
|
73
|
-
}
|
|
59
|
+
/**
|
|
60
|
+
* Route-scoped auth hook set.
|
|
61
|
+
*/
|
|
62
|
+
export type AuthRouteHooks<Ctx, AddedCtx extends object> = {
|
|
63
|
+
/**
|
|
64
|
+
* Mark a route as intentionally public.
|
|
65
|
+
*/
|
|
66
|
+
public: () => RouteHook<Ctx, Record<string, never>>;
|
|
67
|
+
/**
|
|
68
|
+
* Resolve auth when present and add optional auth fields to the handler ctx.
|
|
69
|
+
*/
|
|
70
|
+
optional: () => RouteHook<Ctx, Partial<AddedCtx>>;
|
|
71
|
+
/**
|
|
72
|
+
* Require auth and add authenticated fields to the handler ctx.
|
|
73
|
+
*/
|
|
74
|
+
required: () => RouteHook<Ctx, AddedCtx>;
|
|
75
|
+
};
|
|
74
76
|
|
|
75
|
-
|
|
77
|
+
function toAuthArgs<Ctx>(
|
|
78
|
+
args: Parameters<RouteHook<Ctx, object>["resolve"]>[0],
|
|
79
|
+
): AuthHookArgs<Ctx> {
|
|
80
|
+
return {
|
|
81
|
+
req: args.req,
|
|
82
|
+
ctx: args.ctx,
|
|
83
|
+
contract: args.contract,
|
|
84
|
+
path: args.path,
|
|
85
|
+
query: args.query,
|
|
86
|
+
headers: args.headers,
|
|
87
|
+
body: args.body,
|
|
88
|
+
};
|
|
76
89
|
}
|
|
77
90
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Create route-scoped authentication hooks.
|
|
93
|
+
*
|
|
94
|
+
* Use `auth.required()` on routes that require an authenticated actor and
|
|
95
|
+
* `auth.optional()` where handlers can use auth when present. The returned
|
|
96
|
+
* route hooks enrich handler `ctx`; business authorization still belongs in
|
|
97
|
+
* feature policies or use cases.
|
|
98
|
+
*
|
|
99
|
+
* @param options - Auth resolution callback and optional diagnostic name.
|
|
100
|
+
* @returns Public, optional, and required route-hook factories.
|
|
101
|
+
*/
|
|
102
|
+
export function createAuthHooks<Ctx, AddedCtx extends object>(
|
|
103
|
+
options: AuthHooksOptions<Ctx, AddedCtx>,
|
|
104
|
+
): AuthRouteHooks<Ctx, AddedCtx> {
|
|
105
|
+
const name = options.name ?? "auth";
|
|
81
106
|
|
|
82
|
-
export function createAuthHooks<Ctx extends CtxWithAuthPort>(
|
|
83
|
-
options?: AuthHooksOptions<Ctx, InferAuthSession<Ctx["ports"]["auth"]>>,
|
|
84
|
-
): ServerHook<Ctx, Ctx["ports"]>;
|
|
85
|
-
export function createAuthHooks<Ctx, Session>(
|
|
86
|
-
options: AuthHooksOptions<Ctx, Session> & {
|
|
87
|
-
getSession: (args: AuthHookArgs<Ctx>) => MaybePromise<Session | null>;
|
|
88
|
-
},
|
|
89
|
-
): ServerHook<Ctx>;
|
|
90
|
-
export function createAuthHooks<Ctx, Session>(
|
|
91
|
-
options: AuthHooksOptions<Ctx, Session> = {},
|
|
92
|
-
): ServerHook<Ctx> {
|
|
93
107
|
return {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
};
|
|
113
|
-
const mode = modeFromInput(
|
|
114
|
-
options.mode ? await options.mode(args) : defaultMode(args),
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
if (mode === "public") {
|
|
118
|
-
return undefined;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const session = options.getSession
|
|
122
|
-
? await options.getSession(args)
|
|
123
|
-
: ((await defaultGetSession(args)) as Session | null);
|
|
124
|
-
const isAuthenticated =
|
|
125
|
-
options.isAuthenticated?.(session) ?? defaultIsAuthenticated(session);
|
|
126
|
-
|
|
127
|
-
if (mode === "required" && !isAuthenticated) {
|
|
128
|
-
if (options.unauthorized) {
|
|
129
|
-
return {
|
|
130
|
-
ctx,
|
|
131
|
-
response: await options.unauthorized({ ...args, session }),
|
|
132
|
-
};
|
|
108
|
+
public: () => ({
|
|
109
|
+
name: `${name}.public`,
|
|
110
|
+
resolve: () => undefined,
|
|
111
|
+
}),
|
|
112
|
+
optional: () => ({
|
|
113
|
+
name: `${name}.optional`,
|
|
114
|
+
resolve: async (args) => {
|
|
115
|
+
const additions = await options.resolve(toAuthArgs(args));
|
|
116
|
+
|
|
117
|
+
return additions ?? undefined;
|
|
118
|
+
},
|
|
119
|
+
}),
|
|
120
|
+
required: () => ({
|
|
121
|
+
name: `${name}.required`,
|
|
122
|
+
resolve: async (args) => {
|
|
123
|
+
const additions = await options.resolve(toAuthArgs(args));
|
|
124
|
+
if (!additions) {
|
|
125
|
+
throw new AuthUnauthorizedError();
|
|
133
126
|
}
|
|
134
127
|
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (!options.assign) {
|
|
139
|
-
return undefined;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return {
|
|
143
|
-
ctx: await options.assign({ ...args, session }),
|
|
144
|
-
};
|
|
145
|
-
},
|
|
128
|
+
return additions;
|
|
129
|
+
},
|
|
130
|
+
}),
|
|
146
131
|
};
|
|
147
132
|
}
|
package/src/server/hooks/cors.ts
CHANGED
|
@@ -4,10 +4,25 @@
|
|
|
4
4
|
|
|
5
5
|
import type { HttpRequestLike, ServerHook } from "../types";
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* CORS configuration for `createCorsHooks(...)`.
|
|
9
|
+
*/
|
|
7
10
|
export interface CorsConfig {
|
|
11
|
+
/**
|
|
12
|
+
* Allowed origins. Use `"*"` to allow any origin.
|
|
13
|
+
*/
|
|
8
14
|
origins?: string[] | "*";
|
|
15
|
+
/**
|
|
16
|
+
* Allowed HTTP methods.
|
|
17
|
+
*/
|
|
9
18
|
methods?: string[];
|
|
19
|
+
/**
|
|
20
|
+
* Allowed request headers.
|
|
21
|
+
*/
|
|
10
22
|
headers?: string[];
|
|
23
|
+
/**
|
|
24
|
+
* Whether credentialed requests are allowed.
|
|
25
|
+
*/
|
|
11
26
|
credentials?: boolean;
|
|
12
27
|
}
|
|
13
28
|
|
|
@@ -28,6 +43,12 @@ function appendVaryOrigin(headers: Record<string, string>): void {
|
|
|
28
43
|
headers[varyKey] = current ? `${current}, Origin` : "Origin";
|
|
29
44
|
}
|
|
30
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Apply CORS response headers to a mutable header record.
|
|
48
|
+
*
|
|
49
|
+
* When credentials are enabled with wildcard origins, the request origin is
|
|
50
|
+
* reflected and `Vary: Origin` is appended.
|
|
51
|
+
*/
|
|
31
52
|
export function applyCorsHeaders(
|
|
32
53
|
headers: Record<string, string>,
|
|
33
54
|
req: HttpRequestLike,
|
|
@@ -62,6 +83,12 @@ export function applyCorsHeaders(
|
|
|
62
83
|
}
|
|
63
84
|
}
|
|
64
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Create CORS hooks for preflight and regular responses.
|
|
88
|
+
*
|
|
89
|
+
* `OPTIONS` requests short-circuit with a 204 response. All other responses are
|
|
90
|
+
* decorated in `beforeSend`.
|
|
91
|
+
*/
|
|
65
92
|
export function createCorsHooks<Ctx>(config: CorsConfig): ServerHook<Ctx> {
|
|
66
93
|
return {
|
|
67
94
|
name: "cors",
|
|
@@ -7,30 +7,39 @@ import type { AppEnvironment } from "../health";
|
|
|
7
7
|
import { getRequestIdFromContext } from "./utils";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Re-export AppEnvironment for convenience
|
|
10
|
+
* Re-export `AppEnvironment` for convenience.
|
|
11
11
|
*/
|
|
12
12
|
export type { AppEnvironment } from "../health";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* Framework-neutral response produced by an error mapper.
|
|
16
16
|
*/
|
|
17
17
|
export interface ErrorMappingResult {
|
|
18
|
+
/**
|
|
19
|
+
* HTTP status code.
|
|
20
|
+
*/
|
|
18
21
|
status: number;
|
|
22
|
+
/**
|
|
23
|
+
* Response body.
|
|
24
|
+
*/
|
|
19
25
|
body: unknown;
|
|
26
|
+
/**
|
|
27
|
+
* Response headers.
|
|
28
|
+
*/
|
|
20
29
|
headers?: Record<string, string>;
|
|
21
30
|
}
|
|
22
31
|
|
|
23
32
|
/**
|
|
24
|
-
* Error mapping configuration
|
|
33
|
+
* Error mapping configuration.
|
|
25
34
|
*/
|
|
26
35
|
export interface ErrorMappingConfig<Ctx> {
|
|
27
|
-
/** Custom error mapper function */
|
|
36
|
+
/** Custom error mapper function. */
|
|
28
37
|
mapErrorToResponse?: (err: unknown, ctx: Ctx) => ErrorMappingResult;
|
|
29
38
|
|
|
30
|
-
/** Include stack traces in error responses
|
|
39
|
+
/** Include stack traces in error responses. Defaults to true in dev/test. */
|
|
31
40
|
includeStackInResponse?: boolean;
|
|
32
41
|
|
|
33
|
-
/** Application environment */
|
|
42
|
+
/** Application environment. */
|
|
34
43
|
env?: AppEnvironment;
|
|
35
44
|
}
|
|
36
45
|
|
|
@@ -7,12 +7,8 @@ import type { ServerHook } from "../http";
|
|
|
7
7
|
|
|
8
8
|
export {
|
|
9
9
|
type AuthHookArgs,
|
|
10
|
-
type AuthHookAssignArgs,
|
|
11
|
-
type AuthHookMode,
|
|
12
|
-
type AuthHookModeInput,
|
|
13
10
|
type AuthHooksOptions,
|
|
14
|
-
type
|
|
15
|
-
type CtxWithAuthPort,
|
|
11
|
+
type AuthRouteHooks,
|
|
16
12
|
createAuthHooks,
|
|
17
13
|
} from "./auth";
|
|
18
14
|
export {
|
|
@@ -36,6 +32,9 @@ export {
|
|
|
36
32
|
type RateLimitOptions,
|
|
37
33
|
} from "./rate-limit";
|
|
38
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Flatten hook arrays into a single hook list.
|
|
37
|
+
*/
|
|
39
38
|
export function composeHooks<Ctx, Ports extends AnyPorts = AnyPorts>(
|
|
40
39
|
...hooks: (ServerHook<Ctx, Ports> | readonly ServerHook<Ctx, Ports>[])[]
|
|
41
40
|
): ServerHook<Ctx, Ports>[] {
|
|
@@ -6,21 +6,51 @@ import type { HttpContractConfig } from "../../contracts";
|
|
|
6
6
|
import type { HttpRequestLike, ServerHook } from "../types";
|
|
7
7
|
import { getRequestIdFromContext } from "./utils";
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Minimal logger shape accepted by `createLoggingHooks(...)`.
|
|
11
|
+
*/
|
|
9
12
|
export interface Logger {
|
|
13
|
+
/**
|
|
14
|
+
* Log an informational event.
|
|
15
|
+
*/
|
|
10
16
|
info: (...args: unknown[]) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Log an error event.
|
|
19
|
+
*/
|
|
11
20
|
error: (...args: unknown[]) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Log a warning event.
|
|
23
|
+
*/
|
|
12
24
|
warn?: (...args: unknown[]) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Log a debug event.
|
|
27
|
+
*/
|
|
13
28
|
debug?: (...args: unknown[]) => void;
|
|
14
29
|
}
|
|
15
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Logging hook configuration.
|
|
33
|
+
*/
|
|
16
34
|
export interface LoggingConfig<Ctx> {
|
|
35
|
+
/**
|
|
36
|
+
* Logger used when custom lifecycle callbacks are not provided.
|
|
37
|
+
*/
|
|
17
38
|
logger?: Logger;
|
|
39
|
+
/**
|
|
40
|
+
* Response header name used to expose `ctx.requestId` when present.
|
|
41
|
+
*/
|
|
18
42
|
requestIdHeader?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Custom request-start observer.
|
|
45
|
+
*/
|
|
19
46
|
onRequestStart?: (args: {
|
|
20
47
|
ctx?: Ctx;
|
|
21
48
|
req: HttpRequestLike;
|
|
22
49
|
contract?: HttpContractConfig;
|
|
23
50
|
}) => void;
|
|
51
|
+
/**
|
|
52
|
+
* Custom request-end observer.
|
|
53
|
+
*/
|
|
24
54
|
onRequestEnd?: (args: {
|
|
25
55
|
ctx?: Ctx;
|
|
26
56
|
req: HttpRequestLike;
|
|
@@ -31,6 +61,12 @@ export interface LoggingConfig<Ctx> {
|
|
|
31
61
|
}) => void;
|
|
32
62
|
}
|
|
33
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Create request logging hooks.
|
|
66
|
+
*
|
|
67
|
+
* Logging observer errors are intentionally ignored so logging cannot break
|
|
68
|
+
* request handling.
|
|
69
|
+
*/
|
|
34
70
|
export function createLoggingHooks<Ctx>(
|
|
35
71
|
config: LoggingConfig<Ctx>,
|
|
36
72
|
): ServerHook<Ctx> {
|
|
@@ -7,10 +7,16 @@ import { AppError, httpErrors } from "../../errors";
|
|
|
7
7
|
import type { ActivityActor, RateLimitPort } from "../../ports";
|
|
8
8
|
import type { HttpRequestLike, ServerHook } from "../types";
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Ports required by rate-limit hooks.
|
|
12
|
+
*/
|
|
10
13
|
export type RateLimitPorts = {
|
|
11
14
|
rateLimit: RateLimitPort;
|
|
12
15
|
};
|
|
13
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Minimal context shape required for user-scoped rate limits.
|
|
19
|
+
*/
|
|
14
20
|
export type CtxWithRateLimit = {
|
|
15
21
|
ports: RateLimitPorts;
|
|
16
22
|
actor?: ActivityActor;
|
|
@@ -18,16 +24,32 @@ export type CtxWithRateLimit = {
|
|
|
18
24
|
|
|
19
25
|
type EarlyRateLimitScope = Exclude<RateLimitScope, "user">;
|
|
20
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Options for `createRateLimitHooks(...)`.
|
|
29
|
+
*/
|
|
21
30
|
export interface RateLimitOptions<Ctx> {
|
|
31
|
+
/**
|
|
32
|
+
* Build a rate-limit key after context exists.
|
|
33
|
+
*
|
|
34
|
+
* This is used for user-scoped limits and any late key strategy.
|
|
35
|
+
*/
|
|
22
36
|
key?: (args: {
|
|
23
37
|
ctx: Ctx;
|
|
24
38
|
req: HttpRequestLike;
|
|
25
39
|
scope: RateLimitScope;
|
|
26
40
|
}) => string;
|
|
41
|
+
/**
|
|
42
|
+
* Build a rate-limit key before request parsing and context creation.
|
|
43
|
+
*
|
|
44
|
+
* This is used for global and IP-scoped limits.
|
|
45
|
+
*/
|
|
27
46
|
earlyKey?: (args: {
|
|
28
47
|
req: HttpRequestLike;
|
|
29
48
|
scope: EarlyRateLimitScope;
|
|
30
49
|
}) => string;
|
|
50
|
+
/**
|
|
51
|
+
* Resolve a client IP from the raw request.
|
|
52
|
+
*/
|
|
31
53
|
getClientIp?: (req: HttpRequestLike) => string | undefined;
|
|
32
54
|
}
|
|
33
55
|
|
|
@@ -112,6 +134,17 @@ async function enforceRateLimit(
|
|
|
112
134
|
);
|
|
113
135
|
}
|
|
114
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Create metadata-driven rate-limit hooks.
|
|
139
|
+
*
|
|
140
|
+
* The hook reads `contract.metadata.rateLimit`. Global and IP-scoped limits run
|
|
141
|
+
* in `onRequest` before context creation; user-scoped limits run in
|
|
142
|
+
* `beforeHandle` after `ctx.actor` is available. Exceeded limits throw the
|
|
143
|
+
* framework `TooManyRequests` app error.
|
|
144
|
+
*
|
|
145
|
+
* @param options - Optional key builders and client-IP resolver.
|
|
146
|
+
* @returns A server hook backed by `ctx.ports.rateLimit`.
|
|
147
|
+
*/
|
|
115
148
|
export function createRateLimitHooks<Ctx extends CtxWithRateLimit>(
|
|
116
149
|
options: RateLimitOptions<Ctx> = {},
|
|
117
150
|
): ServerHook<Ctx, RateLimitPorts> {
|