@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/server.ts
CHANGED
|
@@ -31,6 +31,7 @@ import type {
|
|
|
31
31
|
HttpResponse,
|
|
32
32
|
HttpResponseLike,
|
|
33
33
|
ResolvedRoute,
|
|
34
|
+
RouteHook,
|
|
34
35
|
ServerCaughtErrorHook,
|
|
35
36
|
ServerHook,
|
|
36
37
|
ServerUnhandledErrorMapper,
|
|
@@ -42,44 +43,130 @@ import {
|
|
|
42
43
|
} from "./providers";
|
|
43
44
|
|
|
44
45
|
/**
|
|
45
|
-
* Route
|
|
46
|
+
* Route registration for one contract.
|
|
47
|
+
*
|
|
48
|
+
* Route definitions connect a contract to the handler that implements it. Most
|
|
49
|
+
* apps keep these in `features/<feature>/routes.ts` and compose them with
|
|
50
|
+
* `defineRoutes(...)`.
|
|
46
51
|
*/
|
|
47
|
-
export type RouteDef<
|
|
52
|
+
export type RouteDef<
|
|
53
|
+
Ctx,
|
|
54
|
+
CLike extends ContractLike = ContractLike,
|
|
55
|
+
Hooks extends readonly RouteHook<Ctx, object>[] = readonly RouteHook<
|
|
56
|
+
Ctx,
|
|
57
|
+
object
|
|
58
|
+
>[],
|
|
59
|
+
> = {
|
|
60
|
+
/**
|
|
61
|
+
* Contract builder or plain contract config for this route.
|
|
62
|
+
*/
|
|
48
63
|
contract: CLike;
|
|
49
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Route-scoped hooks that run after group hooks and before the handler.
|
|
66
|
+
*/
|
|
67
|
+
hooks?: Hooks;
|
|
68
|
+
/**
|
|
69
|
+
* Handler that implements the contract.
|
|
70
|
+
*/
|
|
71
|
+
handle: Handler<Ctx & AddedCtxFromHooks<Hooks>, ResolveContract<CLike>>;
|
|
50
72
|
};
|
|
51
73
|
|
|
74
|
+
type AddedCtxFromHook<Hook> =
|
|
75
|
+
Hook extends RouteHook<infer _Ctx, infer AddedCtx> ? AddedCtx : unknown;
|
|
76
|
+
|
|
77
|
+
type UnionToIntersection<Union> = (
|
|
78
|
+
Union extends unknown
|
|
79
|
+
? (value: Union) => void
|
|
80
|
+
: never
|
|
81
|
+
) extends (value: infer Intersection) => void
|
|
82
|
+
? Intersection
|
|
83
|
+
: never;
|
|
84
|
+
|
|
85
|
+
type AddedCtxFromHooks<Hooks extends readonly unknown[]> =
|
|
86
|
+
Hooks extends readonly []
|
|
87
|
+
? unknown
|
|
88
|
+
: UnionToIntersection<AddedCtxFromHook<Hooks[number]>>;
|
|
89
|
+
|
|
90
|
+
// biome-ignore lint/suspicious/noExplicitAny: route contract types are erased at collection boundaries
|
|
91
|
+
type AnyRouteDef = RouteDef<any, any>;
|
|
92
|
+
|
|
93
|
+
// biome-ignore lint/suspicious/noExplicitAny: route contract types are erased at collection boundaries
|
|
94
|
+
type PlainRouteDef<Ctx> = RouteDef<Ctx, any, readonly []>;
|
|
95
|
+
|
|
96
|
+
// biome-ignore lint/suspicious/noExplicitAny: route contract types are erased at collection boundaries
|
|
97
|
+
type AnyContractRouteDef<Ctx> = RouteDef<Ctx, any>;
|
|
98
|
+
|
|
52
99
|
const ROUTE_GROUP_KIND = "beignet.route-group";
|
|
53
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Named collection of related route registrations.
|
|
103
|
+
*
|
|
104
|
+
* Route groups colocate feature routes and can apply scoped route hooks to
|
|
105
|
+
* every route in the group. `defineRoutes(...)` flattens them before server
|
|
106
|
+
* registration while preserving those hooks.
|
|
107
|
+
*/
|
|
54
108
|
export type RouteGroup<
|
|
55
109
|
Ctx,
|
|
56
|
-
|
|
57
|
-
Routes extends readonly RouteDef<Ctx, any>[] = readonly RouteDef<Ctx, any>[],
|
|
110
|
+
Routes extends readonly AnyRouteDef[] = readonly AnyRouteDef[],
|
|
58
111
|
> = {
|
|
112
|
+
/**
|
|
113
|
+
* Internal marker used by `defineRoutes(...)`.
|
|
114
|
+
*/
|
|
59
115
|
kind: typeof ROUTE_GROUP_KIND;
|
|
116
|
+
/**
|
|
117
|
+
* Human-readable group name.
|
|
118
|
+
*/
|
|
60
119
|
name: string;
|
|
120
|
+
/**
|
|
121
|
+
* Hooks applied to every route in this group.
|
|
122
|
+
*/
|
|
123
|
+
hooks?: readonly RouteHook<Ctx, object>[];
|
|
124
|
+
/**
|
|
125
|
+
* Route definitions in this group.
|
|
126
|
+
*/
|
|
61
127
|
routes: Routes;
|
|
62
128
|
};
|
|
63
129
|
|
|
64
130
|
type RouteInput<Ctx> =
|
|
65
|
-
|
|
66
|
-
|
|
|
67
|
-
|
|
68
|
-
|
|
131
|
+
| AnyContractRouteDef<Ctx>
|
|
132
|
+
| AnyRouteDef
|
|
133
|
+
| RouteGroup<Ctx, readonly AnyRouteDef[]>;
|
|
134
|
+
|
|
135
|
+
type ContextualRouteInput<Ctx> =
|
|
136
|
+
| PlainRouteDef<Ctx>
|
|
137
|
+
| RouteGroup<Ctx, readonly AnyRouteDef[]>;
|
|
138
|
+
|
|
139
|
+
type RouteGroupBuilder<Ctx> = {
|
|
140
|
+
<
|
|
141
|
+
const GroupHooks extends readonly RouteHook<Ctx, object>[] = readonly [],
|
|
142
|
+
const R extends readonly PlainRouteDef<
|
|
143
|
+
Ctx & AddedCtxFromHooks<GroupHooks>
|
|
144
|
+
>[] = readonly PlainRouteDef<Ctx & AddedCtxFromHooks<GroupHooks>>[],
|
|
145
|
+
>(group: {
|
|
146
|
+
name: string;
|
|
147
|
+
hooks?: GroupHooks;
|
|
148
|
+
routes: R;
|
|
149
|
+
}): RouteGroup<Ctx, R>;
|
|
150
|
+
<
|
|
151
|
+
const GroupHooks extends readonly RouteHook<Ctx, object>[] = readonly [],
|
|
152
|
+
const R extends readonly AnyRouteDef[] = readonly AnyRouteDef[],
|
|
153
|
+
>(group: {
|
|
154
|
+
name: string;
|
|
155
|
+
hooks?: GroupHooks;
|
|
156
|
+
routes: R;
|
|
157
|
+
}): RouteGroup<Ctx, R>;
|
|
158
|
+
};
|
|
69
159
|
|
|
70
160
|
type RoutesFromInput<Input> =
|
|
71
|
-
|
|
72
|
-
Input extends RouteGroup<any, infer Routes>
|
|
161
|
+
Input extends RouteGroup<infer _Ctx, infer Routes>
|
|
73
162
|
? Routes
|
|
74
|
-
:
|
|
75
|
-
Input extends RouteDef<any, any>
|
|
163
|
+
: Input extends AnyRouteDef
|
|
76
164
|
? readonly [Input]
|
|
77
165
|
: readonly [];
|
|
78
166
|
|
|
79
167
|
type FlattenRouteInputs<Inputs extends readonly unknown[]> =
|
|
80
168
|
number extends Inputs["length"]
|
|
81
|
-
?
|
|
82
|
-
readonly RouteDef<any, any>[]
|
|
169
|
+
? readonly AnyRouteDef[]
|
|
83
170
|
: Inputs extends readonly [infer First, ...infer Rest]
|
|
84
171
|
? readonly [...RoutesFromInput<First>, ...FlattenRouteInputs<Rest>]
|
|
85
172
|
: readonly [];
|
|
@@ -97,11 +184,30 @@ type ContractsFromRouteList<
|
|
|
97
184
|
: never;
|
|
98
185
|
};
|
|
99
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Define one route registration with hook-aware handler typing.
|
|
189
|
+
*
|
|
190
|
+
* Direct route objects are still supported. Use this helper when route-scoped
|
|
191
|
+
* hooks enrich `ctx` for a single handler and you want TypeScript to infer the
|
|
192
|
+
* added fields.
|
|
193
|
+
*/
|
|
194
|
+
export function defineRoute<Ctx>() {
|
|
195
|
+
return <
|
|
196
|
+
CLike extends ContractLike,
|
|
197
|
+
const Hooks extends readonly RouteHook<Ctx, object>[] = readonly [],
|
|
198
|
+
>(
|
|
199
|
+
route: RouteDef<Ctx, CLike, Hooks>,
|
|
200
|
+
): RouteDef<Ctx, CLike, Hooks> => route;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Options for creating a Beignet server instance.
|
|
205
|
+
*/
|
|
100
206
|
export type CreateServerOptions<
|
|
101
207
|
Ctx,
|
|
102
208
|
Ports extends AnyPorts,
|
|
103
209
|
// biome-ignore lint/suspicious/noExplicitAny: route contract types are erased at this level
|
|
104
|
-
Routes extends readonly RouteDef<
|
|
210
|
+
Routes extends readonly RouteDef<any, any>[] = readonly RouteDef<any, any>[],
|
|
105
211
|
Providers extends readonly ServiceProvider<
|
|
106
212
|
unknown,
|
|
107
213
|
// biome-ignore lint/suspicious/noExplicitAny: provider config types are erased at this level
|
|
@@ -109,21 +215,53 @@ export type CreateServerOptions<
|
|
|
109
215
|
AnyPorts
|
|
110
216
|
>[] = readonly [],
|
|
111
217
|
> = {
|
|
218
|
+
/**
|
|
219
|
+
* App-owned ports available to context creation, hooks, and handlers.
|
|
220
|
+
*/
|
|
112
221
|
ports: Ports;
|
|
222
|
+
/**
|
|
223
|
+
* Providers installed during server startup.
|
|
224
|
+
*
|
|
225
|
+
* Provider ports are merged into `ports` before request handling and are
|
|
226
|
+
* stopped in reverse setup order when `server.stop()` runs.
|
|
227
|
+
*/
|
|
113
228
|
providers?: Providers;
|
|
114
229
|
|
|
115
|
-
|
|
230
|
+
/**
|
|
231
|
+
* Runtime env used by providers. Defaults to `process.env`.
|
|
232
|
+
*/
|
|
116
233
|
providerEnv?: Record<string, string | undefined>;
|
|
234
|
+
/**
|
|
235
|
+
* Provider config overrides keyed by provider name.
|
|
236
|
+
*/
|
|
117
237
|
providerConfig?: Record<string, unknown>;
|
|
118
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Create request context after a route is matched.
|
|
241
|
+
*
|
|
242
|
+
* The `ports` argument includes app ports plus ports provided during server
|
|
243
|
+
* startup.
|
|
244
|
+
*/
|
|
119
245
|
createContext: (args: {
|
|
120
246
|
req: HttpRequestLike;
|
|
121
247
|
ports: Ports & ProvidedPortsOfList<Providers>;
|
|
122
248
|
contract?: HttpContractConfig;
|
|
123
249
|
}) => Ctx | Promise<Ctx>;
|
|
250
|
+
/**
|
|
251
|
+
* Server hooks that wrap every registered route.
|
|
252
|
+
*/
|
|
124
253
|
hooks?: ServerHook<Ctx, Ports & ProvidedPortsOfList<Providers>>[];
|
|
254
|
+
/**
|
|
255
|
+
* Route list to register up front.
|
|
256
|
+
*/
|
|
125
257
|
routes?: Routes;
|
|
258
|
+
/**
|
|
259
|
+
* Global caught-error observer.
|
|
260
|
+
*/
|
|
126
261
|
onCaughtError?: ServerCaughtErrorHook<Ctx>;
|
|
262
|
+
/**
|
|
263
|
+
* Global mapper for unexpected errors not handled by app error catalogs.
|
|
264
|
+
*/
|
|
127
265
|
mapUnhandledError?: ServerUnhandledErrorMapper<Ctx>;
|
|
128
266
|
};
|
|
129
267
|
|
|
@@ -133,13 +271,31 @@ interface RouteBuilder<Ctx, C extends HttpContractConfig> {
|
|
|
133
271
|
) => (req: HttpRequestLike) => Promise<HttpResponse>;
|
|
134
272
|
}
|
|
135
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Runtime server object returned by `createServer(...)`.
|
|
276
|
+
*/
|
|
136
277
|
export interface ServerInstance<Ctx, Ports extends AnyPorts = AnyPorts> {
|
|
278
|
+
/**
|
|
279
|
+
* Catch-all request handler for platform adapters.
|
|
280
|
+
*/
|
|
137
281
|
api: (req: HttpRequestLike) => Promise<HttpResponse>;
|
|
282
|
+
/**
|
|
283
|
+
* Register and build a single route handler imperatively.
|
|
284
|
+
*/
|
|
138
285
|
route: <CLike extends ContractLike>(
|
|
139
286
|
contractLike: CLike,
|
|
140
287
|
) => RouteBuilder<Ctx, ResolveContract<CLike>>;
|
|
288
|
+
/**
|
|
289
|
+
* Contract configs registered through the `routes` option.
|
|
290
|
+
*/
|
|
141
291
|
contracts: readonly HttpContractConfig[];
|
|
292
|
+
/**
|
|
293
|
+
* Stop installed providers in reverse setup order.
|
|
294
|
+
*/
|
|
142
295
|
stop: () => Promise<void>;
|
|
296
|
+
/**
|
|
297
|
+
* Final app ports after provider setup.
|
|
298
|
+
*/
|
|
143
299
|
ports: Ports;
|
|
144
300
|
}
|
|
145
301
|
|
|
@@ -559,6 +715,7 @@ function buildHandler<
|
|
|
559
715
|
contract: C,
|
|
560
716
|
userHandler: Handler<Ctx, C>,
|
|
561
717
|
hooks: ServerHook<Ctx, FinalPorts>[],
|
|
718
|
+
routeHooks: readonly RouteHook<unknown, object>[] = [],
|
|
562
719
|
optionsOverrides?: {
|
|
563
720
|
skipRoutePreparation?: boolean;
|
|
564
721
|
},
|
|
@@ -1130,6 +1287,39 @@ function buildHandler<
|
|
|
1130
1287
|
}
|
|
1131
1288
|
}
|
|
1132
1289
|
|
|
1290
|
+
if (!result) {
|
|
1291
|
+
for (const hook of routeHooks) {
|
|
1292
|
+
try {
|
|
1293
|
+
const additions = await hook.resolve({
|
|
1294
|
+
req,
|
|
1295
|
+
ctx: currentCtx,
|
|
1296
|
+
contract,
|
|
1297
|
+
path,
|
|
1298
|
+
query,
|
|
1299
|
+
headers,
|
|
1300
|
+
body,
|
|
1301
|
+
});
|
|
1302
|
+
if (additions && typeof additions === "object") {
|
|
1303
|
+
currentCtx = {
|
|
1304
|
+
...(currentCtx as object),
|
|
1305
|
+
...additions,
|
|
1306
|
+
} as Ctx;
|
|
1307
|
+
}
|
|
1308
|
+
} catch (error) {
|
|
1309
|
+
result = await resolveErrorResult(
|
|
1310
|
+
error,
|
|
1311
|
+
currentCtx,
|
|
1312
|
+
pathValue,
|
|
1313
|
+
queryValue,
|
|
1314
|
+
headersValue,
|
|
1315
|
+
bodyValue,
|
|
1316
|
+
{ owner: "framework" },
|
|
1317
|
+
);
|
|
1318
|
+
break;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1133
1323
|
if (!result) {
|
|
1134
1324
|
try {
|
|
1135
1325
|
result = {
|
|
@@ -1234,11 +1424,23 @@ function buildHandler<
|
|
|
1234
1424
|
};
|
|
1235
1425
|
}
|
|
1236
1426
|
|
|
1427
|
+
/**
|
|
1428
|
+
* Create a Beignet server instance.
|
|
1429
|
+
*
|
|
1430
|
+
* The server owns route registration, provider setup/startup, request
|
|
1431
|
+
* validation, hook execution, response validation, and framework error mapping.
|
|
1432
|
+
* Use adapter packages such as `@beignet/next` to expose `server.api` to a
|
|
1433
|
+
* specific runtime.
|
|
1434
|
+
*
|
|
1435
|
+
* @param options - Ports, providers, routes, hooks, context factory, and error
|
|
1436
|
+
* mapping hooks for the server.
|
|
1437
|
+
* @returns A started server instance with final ports and a catch-all handler.
|
|
1438
|
+
*/
|
|
1237
1439
|
export async function createServer<
|
|
1238
1440
|
Ctx,
|
|
1239
1441
|
Ports extends AnyPorts,
|
|
1240
1442
|
// biome-ignore lint/suspicious/noExplicitAny: route contract types are erased at this level
|
|
1241
|
-
Routes extends readonly RouteDef<
|
|
1443
|
+
Routes extends readonly RouteDef<any, any>[] = readonly RouteDef<any, any>[],
|
|
1242
1444
|
Providers extends readonly ServiceProvider<
|
|
1243
1445
|
unknown,
|
|
1244
1446
|
// biome-ignore lint/suspicious/noExplicitAny: provider config types are erased at this level
|
|
@@ -1292,6 +1494,7 @@ export async function createServer<
|
|
|
1292
1494
|
const registerRoute = <C extends HttpContractConfig>(
|
|
1293
1495
|
contract: C,
|
|
1294
1496
|
handler: Handler<Ctx, C>,
|
|
1497
|
+
routeHooks: readonly RouteHook<unknown, object>[] = [],
|
|
1295
1498
|
): void => {
|
|
1296
1499
|
if (contract.body && !methodSupportsRequestBody(contract.method)) {
|
|
1297
1500
|
throw new Error(
|
|
@@ -1322,6 +1525,7 @@ export async function createServer<
|
|
|
1322
1525
|
contract,
|
|
1323
1526
|
handler,
|
|
1324
1527
|
hooks,
|
|
1528
|
+
routeHooks,
|
|
1325
1529
|
);
|
|
1326
1530
|
registry.push({
|
|
1327
1531
|
contract,
|
|
@@ -1354,7 +1558,11 @@ export async function createServer<
|
|
|
1354
1558
|
try {
|
|
1355
1559
|
for (const route of options.routes) {
|
|
1356
1560
|
const contract = resolveContract(route.contract);
|
|
1357
|
-
registerRoute(
|
|
1561
|
+
registerRoute(
|
|
1562
|
+
contract,
|
|
1563
|
+
route.handle as Handler<Ctx, typeof contract>,
|
|
1564
|
+
route.hooks as readonly RouteHook<unknown, object>[] | undefined,
|
|
1565
|
+
);
|
|
1358
1566
|
}
|
|
1359
1567
|
} catch (error) {
|
|
1360
1568
|
try {
|
|
@@ -1428,6 +1636,7 @@ export async function createServer<
|
|
|
1428
1636
|
notFoundContract,
|
|
1429
1637
|
async () => errorResponse(404, "NOT_FOUND", "Not found"),
|
|
1430
1638
|
hooks,
|
|
1639
|
+
[],
|
|
1431
1640
|
{ skipRoutePreparation: true },
|
|
1432
1641
|
);
|
|
1433
1642
|
|
|
@@ -1447,14 +1656,27 @@ export async function createServer<
|
|
|
1447
1656
|
}
|
|
1448
1657
|
|
|
1449
1658
|
/**
|
|
1450
|
-
*
|
|
1451
|
-
*
|
|
1659
|
+
* Define and flatten route registrations with strong type inference.
|
|
1660
|
+
*
|
|
1661
|
+
* Pass route definitions and route groups here before `createServer(...)`.
|
|
1662
|
+
* Group entries are flattened so downstream tooling receives one route list.
|
|
1452
1663
|
*
|
|
1453
1664
|
* @example
|
|
1665
|
+
* ```ts
|
|
1454
1666
|
* const routes = defineRoutes<AppContext>([
|
|
1455
|
-
* { contract:
|
|
1667
|
+
* { contract: listPosts, handle: async ({ ctx }) => ctx.posts.list() },
|
|
1456
1668
|
* ]);
|
|
1669
|
+
* ```
|
|
1457
1670
|
*/
|
|
1671
|
+
export function defineRoutes<
|
|
1672
|
+
Ctx,
|
|
1673
|
+
const R extends
|
|
1674
|
+
readonly ContextualRouteInput<Ctx>[] = readonly ContextualRouteInput<Ctx>[],
|
|
1675
|
+
>(routes: R): FlattenRouteInputs<R>;
|
|
1676
|
+
export function defineRoutes<
|
|
1677
|
+
Ctx,
|
|
1678
|
+
const R extends readonly RouteInput<Ctx>[] = readonly RouteInput<Ctx>[],
|
|
1679
|
+
>(routes: R): FlattenRouteInputs<R>;
|
|
1458
1680
|
export function defineRoutes<
|
|
1459
1681
|
Ctx,
|
|
1460
1682
|
const R extends readonly RouteInput<Ctx>[] = readonly RouteInput<Ctx>[],
|
|
@@ -1463,7 +1685,12 @@ export function defineRoutes<
|
|
|
1463
1685
|
|
|
1464
1686
|
for (const route of routes) {
|
|
1465
1687
|
if (isRouteGroup(route)) {
|
|
1466
|
-
|
|
1688
|
+
for (const groupRoute of route.routes) {
|
|
1689
|
+
flattened.push({
|
|
1690
|
+
...groupRoute,
|
|
1691
|
+
hooks: [...(route.hooks ?? []), ...(groupRoute.hooks ?? [])],
|
|
1692
|
+
});
|
|
1693
|
+
}
|
|
1467
1694
|
} else {
|
|
1468
1695
|
flattened.push(route);
|
|
1469
1696
|
}
|
|
@@ -1473,8 +1700,10 @@ export function defineRoutes<
|
|
|
1473
1700
|
}
|
|
1474
1701
|
|
|
1475
1702
|
/**
|
|
1476
|
-
* Extract contract configs from a route list.
|
|
1477
|
-
*
|
|
1703
|
+
* Extract contract configs from a route list.
|
|
1704
|
+
*
|
|
1705
|
+
* Use this to drive clients, OpenAPI, and docs from the same route list passed
|
|
1706
|
+
* to `createServer(...)`.
|
|
1478
1707
|
*/
|
|
1479
1708
|
export function contractsFromRoutes<
|
|
1480
1709
|
// biome-ignore lint/suspicious/noExplicitAny: route contract types are erased at this level
|
|
@@ -1486,27 +1715,64 @@ export function contractsFromRoutes<
|
|
|
1486
1715
|
}
|
|
1487
1716
|
|
|
1488
1717
|
/**
|
|
1489
|
-
*
|
|
1718
|
+
* Define a named group of related route registrations.
|
|
1490
1719
|
*
|
|
1491
1720
|
* Route groups are flattened by defineRoutes, so createServer still receives
|
|
1492
|
-
* a regular route list while app code can keep feature route wiring
|
|
1721
|
+
* a regular route list while app code can keep feature route wiring and scoped
|
|
1722
|
+
* hooks colocated.
|
|
1493
1723
|
*
|
|
1494
1724
|
* @example
|
|
1495
|
-
*
|
|
1725
|
+
* ```ts
|
|
1726
|
+
* const todoRoutes = defineRouteGroup<AppContext>()({
|
|
1496
1727
|
* name: "todos",
|
|
1728
|
+
* hooks: [auth.optional()],
|
|
1497
1729
|
* routes: [
|
|
1498
|
-
* { contract: listTodos, handle: async ({ ctx }) =>
|
|
1730
|
+
* { contract: listTodos, handle: async ({ ctx }) => ctx.todos.list() },
|
|
1499
1731
|
* ]
|
|
1500
1732
|
* });
|
|
1733
|
+
* ```
|
|
1501
1734
|
*/
|
|
1735
|
+
export function defineRouteGroup<Ctx>(): RouteGroupBuilder<Ctx>;
|
|
1502
1736
|
export function defineRouteGroup<
|
|
1503
1737
|
Ctx,
|
|
1504
1738
|
// biome-ignore lint/suspicious/noExplicitAny: route contract types are erased at this level
|
|
1505
1739
|
const R extends readonly RouteDef<Ctx, any>[] = readonly RouteDef<Ctx, any>[],
|
|
1506
|
-
>(group: {
|
|
1740
|
+
>(group: {
|
|
1741
|
+
name: string;
|
|
1742
|
+
hooks?: readonly RouteHook<Ctx, object>[];
|
|
1743
|
+
routes: R;
|
|
1744
|
+
}): RouteGroup<Ctx, R>;
|
|
1745
|
+
export function defineRouteGroup<
|
|
1746
|
+
Ctx,
|
|
1747
|
+
// biome-ignore lint/suspicious/noExplicitAny: route contract types are erased at this level
|
|
1748
|
+
const R extends readonly RouteDef<any, any>[] = readonly RouteDef<any, any>[],
|
|
1749
|
+
>(group?: {
|
|
1750
|
+
name: string;
|
|
1751
|
+
hooks?: readonly RouteHook<Ctx, object>[];
|
|
1752
|
+
routes: R;
|
|
1753
|
+
}): RouteGroup<Ctx, R> | RouteGroupBuilder<Ctx> {
|
|
1754
|
+
const createGroup = <
|
|
1755
|
+
const GroupHooks extends readonly RouteHook<Ctx, object>[] = readonly [],
|
|
1756
|
+
const GroupRoutes extends readonly AnyRouteDef[] = readonly AnyRouteDef[],
|
|
1757
|
+
>(input: {
|
|
1758
|
+
name: string;
|
|
1759
|
+
hooks?: GroupHooks;
|
|
1760
|
+
routes: GroupRoutes;
|
|
1761
|
+
}): RouteGroup<Ctx, GroupRoutes> => ({
|
|
1762
|
+
kind: ROUTE_GROUP_KIND,
|
|
1763
|
+
name: input.name,
|
|
1764
|
+
hooks: input.hooks,
|
|
1765
|
+
routes: input.routes,
|
|
1766
|
+
});
|
|
1767
|
+
|
|
1768
|
+
if (!group) {
|
|
1769
|
+
return createGroup;
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1507
1772
|
return {
|
|
1508
1773
|
kind: ROUTE_GROUP_KIND,
|
|
1509
1774
|
name: group.name,
|
|
1775
|
+
hooks: group.hooks,
|
|
1510
1776
|
routes: group.routes,
|
|
1511
1777
|
};
|
|
1512
1778
|
}
|