@raiyyan/brisk 0.1.0 → 0.2.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/AGENTS.md +135 -67
- package/README.md +467 -139
- package/dist/src/cli/agents.js +5 -5
- package/dist/src/cli/agents.js.map +1 -1
- package/dist/src/cli/cli.d.ts +1 -1
- package/dist/src/cli/cli.d.ts.map +1 -1
- package/dist/src/cli/cli.js +22 -36
- package/dist/src/cli/cli.js.map +1 -1
- package/dist/src/cli/init.d.ts +8 -11
- package/dist/src/cli/init.d.ts.map +1 -1
- package/dist/src/cli/init.js +120 -96
- package/dist/src/cli/init.js.map +1 -1
- package/dist/src/cli/render.d.ts +30 -0
- package/dist/src/cli/render.d.ts.map +1 -0
- package/dist/src/cli/render.js +101 -0
- package/dist/src/cli/render.js.map +1 -0
- package/dist/src/cli/system.d.ts +2 -2
- package/dist/src/cli/system.d.ts.map +1 -1
- package/dist/src/cli/system.js +3 -5
- package/dist/src/cli/system.js.map +1 -1
- package/dist/src/client/client.d.ts.map +1 -1
- package/dist/src/client/client.js +32 -5
- package/dist/src/client/client.js.map +1 -1
- package/dist/src/client/index.d.ts +1 -1
- package/dist/src/client/index.d.ts.map +1 -1
- package/dist/src/di/container.d.ts +10 -2
- package/dist/src/di/container.d.ts.map +1 -1
- package/dist/src/di/container.js +20 -3
- package/dist/src/di/container.js.map +1 -1
- package/dist/src/http/app.d.ts +41 -12
- package/dist/src/http/app.d.ts.map +1 -1
- package/dist/src/http/app.js.map +1 -1
- package/dist/src/http/context.d.ts +5 -5
- package/dist/src/http/context.js +5 -5
- package/dist/src/http/controller.d.ts +26 -9
- package/dist/src/http/controller.d.ts.map +1 -1
- package/dist/src/http/controller.js +25 -52
- package/dist/src/http/controller.js.map +1 -1
- package/dist/src/http/error-handler.d.ts +27 -0
- package/dist/src/http/error-handler.d.ts.map +1 -1
- package/dist/src/http/error-handler.js +26 -3
- package/dist/src/http/error-handler.js.map +1 -1
- package/dist/src/http/instance.d.ts +2 -2
- package/dist/src/http/instance.d.ts.map +1 -1
- package/dist/src/http/instance.js +107 -39
- package/dist/src/http/instance.js.map +1 -1
- package/dist/src/http/middleware.d.ts +104 -17
- package/dist/src/http/middleware.d.ts.map +1 -1
- package/dist/src/http/middleware.js +85 -26
- package/dist/src/http/middleware.js.map +1 -1
- package/dist/src/http/openapi.d.ts.map +1 -1
- package/dist/src/http/openapi.js +30 -2
- package/dist/src/http/openapi.js.map +1 -1
- package/dist/src/http/routes.d.ts +29 -7
- package/dist/src/http/routes.d.ts.map +1 -1
- package/dist/src/http/validation.d.ts +16 -0
- package/dist/src/http/validation.d.ts.map +1 -0
- package/dist/src/http/validation.js +51 -0
- package/dist/src/http/validation.js.map +1 -0
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/testing/test-client.d.ts +8 -6
- package/dist/src/testing/test-client.d.ts.map +1 -1
- package/dist/src/testing/test-client.js +3 -2
- package/dist/src/testing/test-client.js.map +1 -1
- package/package.json +3 -2
- package/starters/minimal/.env.example +3 -0
- package/starters/minimal/.oxfmtrc.json +5 -0
- package/starters/minimal/.oxlintrc.json +14 -0
- package/starters/minimal/AGENTS.md +23 -0
- package/starters/minimal/CLAUDE.md +2 -0
- package/starters/minimal/README.md +53 -0
- package/starters/minimal/_gitignore +3 -0
- package/starters/minimal/package.json +29 -0
- package/starters/minimal/src/app.ts +14 -0
- package/starters/minimal/src/env.ts +7 -0
- package/starters/minimal/src/features/index.ts +8 -0
- package/starters/minimal/src/features/notes/notes.controller.ts +38 -0
- package/starters/minimal/src/features/notes/notes.repository.ts +36 -0
- package/starters/minimal/src/features/notes/notes.schema.ts +24 -0
- package/starters/minimal/src/features/notes/notes.service.ts +33 -0
- package/starters/minimal/src/main.ts +4 -0
- package/starters/minimal/src/schemas.ts +26 -0
- package/starters/minimal/templates/feature/src/features/index.ts.controllers.insert +1 -0
- package/starters/minimal/templates/feature/src/features/index.ts.imports.insert +1 -0
- package/starters/minimal/templates/feature/src/features/{{kebab}}/{{kebab}}.controller.ts +38 -0
- package/starters/minimal/templates/feature/src/features/{{kebab}}/{{kebab}}.repository.ts +36 -0
- package/starters/minimal/templates/feature/src/features/{{kebab}}/{{kebab}}.schema.ts +24 -0
- package/starters/minimal/templates/feature/src/features/{{kebab}}/{{kebab}}.service.ts +33 -0
- package/starters/minimal/templates/feature/test/{{kebab}}.service.test.ts +20 -0
- package/starters/minimal/templates/feature/test/{{kebab}}.test.ts +35 -0
- package/starters/minimal/templates/middleware/src/middlewares/{{kebab}}.ts +12 -0
- package/starters/minimal/test/notes.service.test.ts +20 -0
- package/starters/minimal/test/notes.test.ts +35 -0
- package/starters/minimal/tsconfig.json +17 -0
- package/starters/minimal/vitest.config.ts +9 -0
- package/starters/sqlite-auth/.dockerignore +8 -0
- package/starters/sqlite-auth/.env.example +9 -0
- package/starters/sqlite-auth/.oxfmtrc.json +5 -0
- package/starters/sqlite-auth/.oxlintrc.json +14 -0
- package/starters/sqlite-auth/AGENTS.md +23 -0
- package/starters/sqlite-auth/CLAUDE.md +2 -0
- package/starters/sqlite-auth/Dockerfile +23 -0
- package/starters/sqlite-auth/README.md +93 -0
- package/starters/sqlite-auth/_gitignore +5 -0
- package/starters/sqlite-auth/compose.yaml +14 -0
- package/starters/sqlite-auth/package.json +35 -0
- package/starters/sqlite-auth/public/.gitkeep +0 -0
- package/starters/sqlite-auth/src/app.ts +39 -0
- package/starters/sqlite-auth/src/auth/tokens.ts +41 -0
- package/starters/sqlite-auth/src/database/clock.ts +4 -0
- package/starters/sqlite-auth/src/database/database.ts +29 -0
- package/starters/sqlite-auth/src/database/errors.ts +11 -0
- package/starters/sqlite-auth/src/database/migrations.ts +29 -0
- package/starters/sqlite-auth/src/env.ts +17 -0
- package/starters/sqlite-auth/src/features/auth/auth.controller.ts +28 -0
- package/starters/sqlite-auth/src/features/index.ts +12 -0
- package/starters/sqlite-auth/src/features/notes/notes.controller.ts +39 -0
- package/starters/sqlite-auth/src/features/notes/notes.repository.ts +47 -0
- package/starters/sqlite-auth/src/features/notes/notes.schema.ts +24 -0
- package/starters/sqlite-auth/src/features/notes/notes.service.ts +33 -0
- package/starters/sqlite-auth/src/features/users/admin-seed.ts +21 -0
- package/starters/sqlite-auth/src/features/users/users.controller.ts +42 -0
- package/starters/sqlite-auth/src/features/users/users.errors.ts +13 -0
- package/starters/sqlite-auth/src/features/users/users.repository.ts +77 -0
- package/starters/sqlite-auth/src/features/users/users.schema.ts +35 -0
- package/starters/sqlite-auth/src/features/users/users.service.ts +80 -0
- package/starters/sqlite-auth/src/main.ts +4 -0
- package/starters/sqlite-auth/src/middlewares/authenticate.ts +29 -0
- package/starters/sqlite-auth/src/schemas.ts +26 -0
- package/starters/sqlite-auth/templates/feature/src/database/migrations.ts.migrations.insert +5 -0
- package/starters/sqlite-auth/templates/feature/src/features/index.ts.controllers.insert +1 -0
- package/starters/sqlite-auth/templates/feature/src/features/index.ts.imports.insert +1 -0
- package/starters/sqlite-auth/templates/feature/src/features/{{kebab}}/{{kebab}}.controller.ts +39 -0
- package/starters/sqlite-auth/templates/feature/src/features/{{kebab}}/{{kebab}}.repository.ts +47 -0
- package/starters/sqlite-auth/templates/feature/src/features/{{kebab}}/{{kebab}}.schema.ts +24 -0
- package/starters/sqlite-auth/templates/feature/src/features/{{kebab}}/{{kebab}}.service.ts +33 -0
- package/starters/sqlite-auth/templates/feature/test/{{kebab}}.service.test.ts +20 -0
- package/starters/sqlite-auth/templates/feature/test/{{kebab}}.test.ts +41 -0
- package/starters/sqlite-auth/templates/middleware/src/middlewares/{{kebab}}.ts +12 -0
- package/starters/sqlite-auth/test/auth.test.ts +18 -0
- package/starters/sqlite-auth/test/helpers.ts +13 -0
- package/starters/sqlite-auth/test/notes.service.test.ts +20 -0
- package/starters/sqlite-auth/test/notes.test.ts +41 -0
- package/starters/sqlite-auth/test/users.service.test.ts +25 -0
- package/starters/sqlite-auth/test/users.test.ts +164 -0
- package/starters/sqlite-auth/tsconfig.json +17 -0
- package/starters/sqlite-auth/vitest.config.ts +15 -0
- package/dist/src/cli/generate.d.ts +0 -9
- package/dist/src/cli/generate.d.ts.map +0 -1
- package/dist/src/cli/generate.js +0 -39
- package/dist/src/cli/generate.js.map +0 -1
- package/dist/src/cli/templates/auth.d.ts +0 -4
- package/dist/src/cli/templates/auth.d.ts.map +0 -1
- package/dist/src/cli/templates/auth.js +0 -90
- package/dist/src/cli/templates/auth.js.map +0 -1
- package/dist/src/cli/templates/database.d.ts +0 -4
- package/dist/src/cli/templates/database.d.ts.map +0 -1
- package/dist/src/cli/templates/database.js +0 -107
- package/dist/src/cli/templates/database.js.map +0 -1
- package/dist/src/cli/templates/docker.d.ts +0 -4
- package/dist/src/cli/templates/docker.d.ts.map +0 -1
- package/dist/src/cli/templates/docker.js +0 -102
- package/dist/src/cli/templates/docker.js.map +0 -1
- package/dist/src/cli/templates/feature.d.ts +0 -8
- package/dist/src/cli/templates/feature.d.ts.map +0 -1
- package/dist/src/cli/templates/feature.js +0 -145
- package/dist/src/cli/templates/feature.js.map +0 -1
- package/dist/src/cli/templates/project.d.ts +0 -24
- package/dist/src/cli/templates/project.d.ts.map +0 -1
- package/dist/src/cli/templates/project.js +0 -166
- package/dist/src/cli/templates/project.js.map +0 -1
package/dist/src/http/openapi.js
CHANGED
|
@@ -23,7 +23,9 @@ const ERROR_RESPONSE = {
|
|
|
23
23
|
*/
|
|
24
24
|
export function buildOpenApi(endpoints, options) {
|
|
25
25
|
const paths = {};
|
|
26
|
+
const securitySchemes = {};
|
|
26
27
|
for (const endpoint of endpoints) {
|
|
28
|
+
Object.assign(securitySchemes, endpoint.security);
|
|
27
29
|
for (const path of openApiPaths(endpoint.path)) {
|
|
28
30
|
const item = (paths[path] ??= {});
|
|
29
31
|
item[endpoint.method] = operation(endpoint, path);
|
|
@@ -38,7 +40,10 @@ export function buildOpenApi(endpoints, options) {
|
|
|
38
40
|
},
|
|
39
41
|
...(options.servers ? { servers: options.servers } : {}),
|
|
40
42
|
paths,
|
|
41
|
-
components: {
|
|
43
|
+
components: {
|
|
44
|
+
schemas: { ErrorResponse: ERROR_RESPONSE },
|
|
45
|
+
...(Object.keys(securitySchemes).length > 0 ? { securitySchemes } : {}),
|
|
46
|
+
},
|
|
42
47
|
};
|
|
43
48
|
}
|
|
44
49
|
function operation(endpoint, path) {
|
|
@@ -64,6 +69,9 @@ function operation(endpoint, path) {
|
|
|
64
69
|
return {
|
|
65
70
|
tags: [endpoint.tag],
|
|
66
71
|
operationId: endpoint.name === undefined ? undefined : `${endpoint.tag}.${endpoint.name}`,
|
|
72
|
+
...(endpoint.security
|
|
73
|
+
? { security: [Object.fromEntries(Object.keys(endpoint.security).map((name) => [name, []]))] }
|
|
74
|
+
: {}),
|
|
67
75
|
...(parameters.length > 0 ? { parameters } : {}),
|
|
68
76
|
...(schemas.body
|
|
69
77
|
? {
|
|
@@ -111,7 +119,27 @@ function fieldParameters(schema, location) {
|
|
|
111
119
|
}
|
|
112
120
|
function jsonSchema(schema, io) {
|
|
113
121
|
const { $schema: _dialect, ...json } = z.toJSONSchema(schema, { io, unrepresentable: "any" });
|
|
114
|
-
return json;
|
|
122
|
+
return withoutFormatPatterns(json);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Removes `pattern` wherever `format` already names the type (`email`, `uuid`, `date-time`). Zod emits both,
|
|
126
|
+
* and docs UIs such as Swagger UI build example values from the regex: several KB of noise for an email.
|
|
127
|
+
*/
|
|
128
|
+
function withoutFormatPatterns(json) {
|
|
129
|
+
const result = {};
|
|
130
|
+
for (const [key, value] of Object.entries(json)) {
|
|
131
|
+
if (key === "pattern" && typeof json["format"] === "string")
|
|
132
|
+
continue;
|
|
133
|
+
result[key] = clean(value);
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
function clean(value) {
|
|
138
|
+
if (Array.isArray(value))
|
|
139
|
+
return value.map(clean);
|
|
140
|
+
if (typeof value !== "object" || value === null)
|
|
141
|
+
return value;
|
|
142
|
+
return withoutFormatPatterns({ ...value });
|
|
115
143
|
}
|
|
116
144
|
function objectProperties(json) {
|
|
117
145
|
const properties = json["properties"];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.js","sourceRoot":"","sources":["../../../src/http/openapi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAuBxB,MAAM,cAAc,GAAe;IACjC,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,OAAO,CAAC;IACnB,UAAU,EAAE;QACV,KAAK,EAAE;YACL,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,CAAC;YAC1C,UAAU,EAAE;gBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE;gBACjD,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC3B,OAAO,EAAE,EAAE;gBACX,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;aAC9B;SACF;KACF;CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,SAAwC,EAAE,OAAuB;IAC5F,MAAM,KAAK,GAA+B,EAAE,CAAC;IAC7C,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YAClC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IACD,OAAO;QACL,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE;YACJ,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;SACnF;QACD,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,KAAK;QACL,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"openapi.js","sourceRoot":"","sources":["../../../src/http/openapi.ts"],"names":[],"mappings":"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"}
|
|
@@ -43,12 +43,16 @@ type Field<K extends string, T> = [keyof T] extends [never] ? {} : {} extends T
|
|
|
43
43
|
type SchemaInput<S, Fallback> = S extends z.ZodType ? z.input<S> : Fallback;
|
|
44
44
|
/** A value a URL can carry. */
|
|
45
45
|
type UrlValue = string | number | boolean;
|
|
46
|
+
/** A value the client can write into a URL: it turns numbers, booleans, bigints and dates into text. */
|
|
47
|
+
type UrlScalar = UrlValue | bigint | Date;
|
|
48
|
+
type SchemaOutput<S, Fallback> = S extends z.ZodType ? z.output<S> : Fallback;
|
|
46
49
|
/**
|
|
47
|
-
* Path and query fields as a client writes them
|
|
48
|
-
*
|
|
50
|
+
* Path and query fields as a client writes them: the schema's input, or its output when that is something a
|
|
51
|
+
* URL can carry, so \`z.stringbool()\` takes \`true\` and \`z.coerce.number()\` takes \`2\`. A coercing schema's
|
|
52
|
+
* \`unknown\` input accepts any URL value.
|
|
49
53
|
*/
|
|
50
|
-
type UrlFields<
|
|
51
|
-
[K in keyof
|
|
54
|
+
type UrlFields<In, Out> = {
|
|
55
|
+
[K in keyof In]: unknown extends In[K] ? UrlValue | UrlValue[] : In[K] | (K extends keyof Out ? Extract<Out[K], UrlScalar | readonly UrlScalar[] | undefined> : never);
|
|
52
56
|
};
|
|
53
57
|
/**
|
|
54
58
|
* Headers a client sends: the typed ones from the route's schema, plus any others, such as the
|
|
@@ -58,7 +62,7 @@ type HeadersField<H> = H extends z.ZodType ? Field<"headers", z.input<H> & Recor
|
|
|
58
62
|
headers?: Record<string, string>;
|
|
59
63
|
};
|
|
60
64
|
/** What a client sends: path params, query, body and headers, each typed by its schema. */
|
|
61
|
-
export type RouteInput<Path extends string, P, Q, B, H> = Field<"params", UrlFields<SchemaInput<P, PathParams<Path
|
|
65
|
+
export type RouteInput<Path extends string, P, Q, B, H> = Field<"params", UrlFields<SchemaInput<P, PathParams<Path>>, SchemaOutput<P, {}>>> & Field<"query", UrlFields<SchemaInput<Q, {}>, SchemaOutput<Q, {}>>> & Field<"body", SchemaInput<B, {}>> & HeadersField<H>;
|
|
62
66
|
/** A Node stream, recognized by shape so these types never need `@types/node`. */
|
|
63
67
|
interface StreamLike {
|
|
64
68
|
pipe(...args: never[]): unknown;
|
|
@@ -113,7 +117,25 @@ type RoutesOf<C> = {
|
|
|
113
117
|
export type Client<T> = {
|
|
114
118
|
readonly [K in keyof T]: T[K] extends Route<infer I, infer O> ? Call<I, O> : Client<T[K]>;
|
|
115
119
|
};
|
|
116
|
-
/**
|
|
117
|
-
export type
|
|
120
|
+
/** A body sent as it is, without JSON encoding: a file, a form, bytes or a stream. */
|
|
121
|
+
export type RawBody = FormData | Blob | URLSearchParams | ArrayBuffer | ArrayBufferView | ReadableStream | string;
|
|
122
|
+
/** The input of {@link Call.raw}: the route's own input, with any body `fetch` accepts. */
|
|
123
|
+
type RawInput<I> = Omit<I, "body"> & {
|
|
124
|
+
body?: RawBody | (I extends {
|
|
125
|
+
body?: infer B;
|
|
126
|
+
} ? B : never);
|
|
127
|
+
};
|
|
128
|
+
type Send<I, R> = {} extends I ? (input?: I, init?: RequestInit) => Promise<R> : (input: I, init?: RequestInit) => Promise<R>;
|
|
129
|
+
/**
|
|
130
|
+
* One route as a function. It resolves to the route's output and rejects with `ApiError` on a non-2xx
|
|
131
|
+
* response; `init` passes fetch options such as `signal`.
|
|
132
|
+
*/
|
|
133
|
+
export type Call<I, O> = Send<I, O> & {
|
|
134
|
+
/**
|
|
135
|
+
* The same request, resolving to the raw `Response` whatever its status: for downloads, uploads
|
|
136
|
+
* (`body: formData`) and anything that is not JSON. The client's headers are still applied.
|
|
137
|
+
*/
|
|
138
|
+
readonly raw: Send<RawInput<I>, Response>;
|
|
139
|
+
};
|
|
118
140
|
export {};
|
|
119
141
|
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/http/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,0CAA0C;AAC1C,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErE;;;;;;;;GAQG;AACH,MAAM,WAAW,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,OAAO;IACtD,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACtD;AAED,0EAA0E;AAC1E,MAAM,WAAW,MAAM;IACrB,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;CACzC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC;CAC7E;AAED,mGAAmG;AACnG,KAAK,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GACvD,EAAE,GACF,EAAE,SAAS,CAAC,GACV;KAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;CAAE,GAChB;KAAG,CAAC,IAAI,CAAC,GAAG,CAAC;CAAE,CAAC;AAEtB,KAAK,WAAW,CAAC,CAAC,EAAE,QAAQ,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;AAE5E,+BAA+B;AAC/B,KAAK,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE1C
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/http/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Zod parsing shared by routes and middlewares. Every parse is synchronous, the fast path, unless a schema has
|
|
4
|
+
* async refinements: then it switches to `safeParseAsync` and the value comes back wrapped in {@link Pending}.
|
|
5
|
+
*/
|
|
6
|
+
/** An input whose schema needs async validation; never a value a schema can produce. */
|
|
7
|
+
export declare class Pending {
|
|
8
|
+
readonly promise: Promise<unknown>;
|
|
9
|
+
constructor(promise: Promise<unknown>);
|
|
10
|
+
}
|
|
11
|
+
export declare const settle: (value: unknown) => unknown;
|
|
12
|
+
export declare function parseInput(schema: z.ZodType | undefined, value: unknown, location: string): unknown;
|
|
13
|
+
/** A result that breaks its own response schema is a server bug: a 500, never a 400. */
|
|
14
|
+
export declare function serializeOutput(schema: z.ZodType | undefined, value: unknown): unknown;
|
|
15
|
+
export declare function safeParse(schema: z.ZodType, value: unknown): z.ZodSafeParseResult<unknown> | Promise<z.ZodSafeParseResult<unknown>>;
|
|
16
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/http/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;GAGG;AAEH,wFAAwF;AACxF,qBAAa,OAAO;IAClB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,YAAY,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EAEpC;CACF;AAED,eAAO,MAAM,MAAM,UAAW,OAAO,KAAG,OAA6D,CAAC;AAEtG,wBAAgB,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,GAAG,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAMnG;AAOD,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,GAAG,SAAS,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAItF;AAOD,wBAAgB,SAAS,CACvB,MAAM,EAAE,CAAC,CAAC,OAAO,EACjB,KAAK,EAAE,OAAO,GACb,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAOxE"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ValidationError } from "../errors/http-errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* Zod parsing shared by routes and middlewares. Every parse is synchronous, the fast path, unless a schema has
|
|
5
|
+
* async refinements: then it switches to `safeParseAsync` and the value comes back wrapped in {@link Pending}.
|
|
6
|
+
*/
|
|
7
|
+
/** An input whose schema needs async validation; never a value a schema can produce. */
|
|
8
|
+
export class Pending {
|
|
9
|
+
promise;
|
|
10
|
+
constructor(promise) {
|
|
11
|
+
this.promise = promise;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export const settle = (value) => (value instanceof Pending ? value.promise : value);
|
|
15
|
+
export function parseInput(schema, value, location) {
|
|
16
|
+
if (!schema)
|
|
17
|
+
return value;
|
|
18
|
+
const input = value ?? {};
|
|
19
|
+
const result = safeParse(schema, input);
|
|
20
|
+
if (result instanceof Promise)
|
|
21
|
+
return new Pending(result.then((settled) => unwrapInput(settled, location)));
|
|
22
|
+
return unwrapInput(result, location);
|
|
23
|
+
}
|
|
24
|
+
function unwrapInput(result, location) {
|
|
25
|
+
if (result.success)
|
|
26
|
+
return result.data;
|
|
27
|
+
throw ValidationError.fromZod(result.error, location);
|
|
28
|
+
}
|
|
29
|
+
/** A result that breaks its own response schema is a server bug: a 500, never a 400. */
|
|
30
|
+
export function serializeOutput(schema, value) {
|
|
31
|
+
if (!schema)
|
|
32
|
+
return value;
|
|
33
|
+
const result = safeParse(schema, value);
|
|
34
|
+
return result instanceof Promise ? result.then(unwrapOutput) : unwrapOutput(result);
|
|
35
|
+
}
|
|
36
|
+
function unwrapOutput(result) {
|
|
37
|
+
if (result.success)
|
|
38
|
+
return result.data;
|
|
39
|
+
throw new Error(`Response does not match its schema:\n${z.prettifyError(result.error)}`);
|
|
40
|
+
}
|
|
41
|
+
export function safeParse(schema, value) {
|
|
42
|
+
try {
|
|
43
|
+
return schema.safeParse(value);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error instanceof z.core.$ZodAsyncError)
|
|
47
|
+
return schema.safeParseAsync(value);
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../../src/http/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE3D;;;GAGG;AAEH,wFAAwF;AACxF,MAAM,OAAO,OAAO;IACT,OAAO,CAAmB;IACnC,YAAY,OAAyB;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,KAAc,EAAW,EAAE,CAAC,CAAC,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAEtG,MAAM,UAAU,UAAU,CAAC,MAA6B,EAAE,KAAc,EAAE,QAAgB;IACxF,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE,CAAC;IAC1B,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACxC,IAAI,MAAM,YAAY,OAAO;QAAE,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC5G,OAAO,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,WAAW,CAAC,MAAqC,EAAE,QAAgB;IAC1E,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC;IACvC,MAAM,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AACxD,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,eAAe,CAAC,MAA6B,EAAE,KAAc;IAC3E,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACxC,OAAO,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;AACtF,CAAC;AAED,SAAS,YAAY,CAAC,MAAqC;IACzD,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC;IACvC,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC3F,CAAC;AAED,MAAM,UAAU,SAAS,CACvB,MAAiB,EACjB,KAAc;IAEd,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,cAAc;YAAE,OAAO,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAChF,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -14,9 +14,9 @@ export { defineController, type Controller, type ControllerOptions, type GroupOp
|
|
|
14
14
|
export type { PathParams } from "./http/path-params.ts";
|
|
15
15
|
export type { ApiOf, Client, HttpMethod, Jsonify, Manifest, Route, Routes } from "./http/routes.ts";
|
|
16
16
|
export { defineEnv, type DefineEnvOptions } from "./config/env.ts";
|
|
17
|
-
export { defaultErrorFormatter, type ErrorFormatter, type ErrorMapper } from "./http/error-handler.ts";
|
|
17
|
+
export { defaultErrorFormatter, ErrorTranslator, type ErrorFormatter, type ErrorMapper, } from "./http/error-handler.ts";
|
|
18
18
|
export * from "./errors/index.ts";
|
|
19
19
|
export { createLogger, Logger, type LoggerOptions } from "./config/logger.ts";
|
|
20
|
-
export { defineMiddleware, type Middleware, type MiddlewareContext } from "./http/middleware.ts";
|
|
20
|
+
export { defineMiddleware, fromExpress, type Middleware, type MiddlewareContext, type MiddlewareInput, type MiddlewareOptions, type SecurityScheme, type SecuritySchemes, } from "./http/middleware.ts";
|
|
21
21
|
export { z } from "zod";
|
|
22
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,SAAS,EACT,KAAK,GAAG,EACR,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EACL,SAAS,EACT,WAAW,EACX,MAAM,EACN,UAAU,EACV,OAAO,EACP,KAAK,cAAc,EACnB,KAAK,KAAK,EACV,KAAK,OAAO,EACZ,KAAK,MAAM,EACX,KAAK,OAAO,EACZ,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,KAAK,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EACL,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACpG,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,SAAS,EACT,KAAK,GAAG,EACR,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EACL,SAAS,EACT,WAAW,EACX,MAAM,EACN,UAAU,EACV,OAAO,EACP,KAAK,cAAc,EACnB,KAAK,KAAK,EACV,KAAK,OAAO,EACZ,KAAK,MAAM,EACX,KAAK,OAAO,EACZ,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,KAAK,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EACL,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACpG,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,WAAW,GACjB,MAAM,yBAAyB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC"}
|
package/dist/src/index.js
CHANGED
|
@@ -11,9 +11,9 @@ export { Container, defineToken, inject, injectLazy, provide, } from "./di/index
|
|
|
11
11
|
export { getContext } from "./http/context.js";
|
|
12
12
|
export { defineController, } from "./http/controller.js";
|
|
13
13
|
export { defineEnv } from "./config/env.js";
|
|
14
|
-
export { defaultErrorFormatter } from "./http/error-handler.js";
|
|
14
|
+
export { defaultErrorFormatter, ErrorTranslator, } from "./http/error-handler.js";
|
|
15
15
|
export * from "./errors/index.js";
|
|
16
16
|
export { createLogger, Logger } from "./config/logger.js";
|
|
17
|
-
export { defineMiddleware } from "./http/middleware.js";
|
|
17
|
+
export { defineMiddleware, fromExpress, } from "./http/middleware.js";
|
|
18
18
|
export { z } from "zod";
|
|
19
19
|
//# sourceMappingURL=index.js.map
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,SAAS,GAWV,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,UAAU,EAAmB,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EACL,SAAS,EACT,WAAW,EACX,MAAM,EACN,UAAU,EACV,OAAO,GAUR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAuB,MAAM,mBAAmB,CAAC;AACpE,OAAO,EACL,gBAAgB,GAOjB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,SAAS,EAAyB,MAAM,iBAAiB,CAAC;AACnE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,SAAS,GAWV,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,UAAU,EAAmB,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EACL,SAAS,EACT,WAAW,EACX,MAAM,EACN,UAAU,EACV,OAAO,GAUR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAuB,MAAM,mBAAmB,CAAC;AACpE,OAAO,EACL,gBAAgB,GAOjB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,SAAS,EAAyB,MAAM,iBAAiB,CAAC;AACnE,OAAO,EACL,qBAAqB,EACrB,eAAe,GAGhB,MAAM,yBAAyB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,EAAsB,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EACL,gBAAgB,EAChB,WAAW,GAOZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ErrorResponse } from "../errors/http-errors.ts";
|
|
2
|
-
import type { App, AppInstance,
|
|
2
|
+
import type { App, AppInstance, CreateOptions } from "../http/app.ts";
|
|
3
3
|
import type { ApiOf, Client } from "../http/routes.ts";
|
|
4
4
|
/** A response from a {@link TestClient} raw request. */
|
|
5
5
|
export interface TestResponse {
|
|
@@ -19,15 +19,16 @@ export interface TestRequest {
|
|
|
19
19
|
}
|
|
20
20
|
type Send = (path: string, request?: TestRequest) => Promise<TestResponse>;
|
|
21
21
|
/**
|
|
22
|
-
* A client for an instance started by {@link createTestClient}
|
|
22
|
+
* A client for an instance started by {@link createTestClient}. Its type argument is the app:
|
|
23
|
+
* `TestClient<typeof app>`: the typed client as `call`, and raw requests
|
|
23
24
|
* by path for checking status codes, headers and malformed input.
|
|
24
25
|
*/
|
|
25
|
-
export interface TestClient<
|
|
26
|
+
export interface TestClient<A = unknown> {
|
|
26
27
|
readonly baseUrl: string;
|
|
27
28
|
/** The running instance, for its `container` or `server`. */
|
|
28
29
|
readonly instance: AppInstance;
|
|
29
30
|
/** The typed client: `await api.call.users.get({ params: { id } })`. Rejects with `ApiError` on non-2xx. */
|
|
30
|
-
readonly call: Client<
|
|
31
|
+
readonly call: Client<ApiOf<A>>;
|
|
31
32
|
get: Send;
|
|
32
33
|
post: Send;
|
|
33
34
|
put: Send;
|
|
@@ -38,7 +39,8 @@ export interface TestClient<Api = {}> {
|
|
|
38
39
|
}
|
|
39
40
|
/**
|
|
40
41
|
* Starts a fresh instance of the app on a random local port, with its full lifecycle, and returns a client for
|
|
41
|
-
* it. `providers`
|
|
42
|
+
* it. `providers` are added after the app's own: a value for the same token wins, so fakes replace real
|
|
43
|
+
* services, and a class is created alongside the app's. `close()` shuts the instance down gracefully.
|
|
42
44
|
*
|
|
43
45
|
* @example
|
|
44
46
|
* ```ts
|
|
@@ -51,7 +53,7 @@ export interface TestClient<Api = {}> {
|
|
|
51
53
|
* await api.close();
|
|
52
54
|
* ```
|
|
53
55
|
*/
|
|
54
|
-
export declare function createTestClient<
|
|
56
|
+
export declare function createTestClient<A extends App>(app: A, options?: CreateOptions): Promise<TestClient<A>>;
|
|
55
57
|
/**
|
|
56
58
|
* Reads the error out of a response, failing the test when the body is not an error response.
|
|
57
59
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-client.d.ts","sourceRoot":"","sources":["../../../src/testing/test-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"test-client.d.ts","sourceRoot":"","sources":["../../../src/testing/test-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEvD,wDAAwD;AACxD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,wGAAwG;IACxG,IAAI,EAAE,OAAO,CAAC;CACf;AAED,6DAA6D;AAC7D,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAKD,KAAK,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAE3E;;;;GAIG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC,GAAG,OAAO;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,4GAA4G;IAC5G,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAChC,GAAG,EAAE,IAAI,CAAC;IACV,IAAI,EAAE,IAAI,CAAC;IACX,GAAG,EAAE,IAAI,CAAC;IACV,KAAK,EAAE,IAAI,CAAC;IACZ,MAAM,EAAE,IAAI,CAAC;IACb,0CAA0C;IAC1C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,SAAS,GAAG,EAClD,GAAG,EAAE,CAAC,EACN,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CA0CxB;AAWD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,YAAY,GAAG,aAAa,CAAC,OAAO,CAAC,CAExE"}
|
|
@@ -4,7 +4,8 @@ import { createClient } from "../client/client.js";
|
|
|
4
4
|
const JSON_TYPE = /^application\/(?:[\w.-]+\+)?json\b/i;
|
|
5
5
|
/**
|
|
6
6
|
* Starts a fresh instance of the app on a random local port, with its full lifecycle, and returns a client for
|
|
7
|
-
* it. `providers`
|
|
7
|
+
* it. `providers` are added after the app's own: a value for the same token wins, so fakes replace real
|
|
8
|
+
* services, and a class is created alongside the app's. `close()` shuts the instance down gracefully.
|
|
8
9
|
*
|
|
9
10
|
* @example
|
|
10
11
|
* ```ts
|
|
@@ -46,7 +47,7 @@ export async function createTestClient(app, options = {}) {
|
|
|
46
47
|
return {
|
|
47
48
|
baseUrl,
|
|
48
49
|
instance,
|
|
49
|
-
call: createClient(instance, { baseUrl }),
|
|
50
|
+
call: createClient(instance.manifest, { baseUrl }),
|
|
50
51
|
get: send("GET"),
|
|
51
52
|
post: send("POST"),
|
|
52
53
|
put: send("PUT"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-client.js","sourceRoot":"","sources":["../../../src/testing/test-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAsBnD,sFAAsF;AACtF,MAAM,SAAS,GAAG,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"test-client.js","sourceRoot":"","sources":["../../../src/testing/test-client.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raiyyan/brisk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A small, typed, opinionated layer over Express 5 and Zod: validation, DI, lifecycle and errors without the boilerplate.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api",
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"dist",
|
|
30
30
|
"AGENTS.md",
|
|
31
31
|
"README.md",
|
|
32
|
-
"LICENSE"
|
|
32
|
+
"LICENSE",
|
|
33
|
+
"starters"
|
|
33
34
|
],
|
|
34
35
|
"type": "module",
|
|
35
36
|
"sideEffects": false,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
3
|
+
"plugins": ["typescript", "import", "unicorn", "oxc", "vitest"],
|
|
4
|
+
"categories": {
|
|
5
|
+
"correctness": "error",
|
|
6
|
+
"suspicious": "warn"
|
|
7
|
+
},
|
|
8
|
+
"rules": {
|
|
9
|
+
"typescript/no-floating-promises": "error",
|
|
10
|
+
"typescript/no-misused-promises": "error",
|
|
11
|
+
"import/no-cycle": "error"
|
|
12
|
+
},
|
|
13
|
+
"ignorePatterns": ["templates", "node_modules", "coverage"]
|
|
14
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
<!-- brisk:start -->
|
|
4
|
+
|
|
5
|
+
## Building with brisk
|
|
6
|
+
|
|
7
|
+
This app uses [brisk](https://www.npmjs.com/package/@raiyyan/brisk), a typed layer over Express 5 and Zod.
|
|
8
|
+
Before writing or changing server code, read the full guide: `node_modules/@raiyyan/brisk/AGENTS.md`.
|
|
9
|
+
|
|
10
|
+
Essentials:
|
|
11
|
+
|
|
12
|
+
- The app is declared once in `src/app.ts` with `defineApp`; `app.listen(port)` runs it, `createTestClient(app, { providers })` tests it.
|
|
13
|
+
- Routes are named: a controller's setup returns `{ list: route.get(...), create: route.post(...) }`. The names form the typed client (`api.users.create({ body })`).
|
|
14
|
+
- Validate every input with a Zod schema on the route; set `response` to a DTO schema so internal fields never leak.
|
|
15
|
+
- New code follows this project's own templates: `npx brisk g feature <name>` renders `templates/feature/`. Edit the templates when the project's conventions change.
|
|
16
|
+
- Dependencies: `readonly #repo = inject(Repository)` in class fields. No decorators, no constructor wiring.
|
|
17
|
+
- Errors: `throw new NotFoundError("…")` (or another error class) anywhere. Never try/catch to build responses; never call `next()`.
|
|
18
|
+
- Shared request logic: `defineMiddleware` returning an object types `ctx`; declare `params` or `query` it reads to get them validated first. Express middleware such as multer goes in a route's `use` through `fromExpress()`.
|
|
19
|
+
- App-wide middleware goes in `defineApp({ use })` (`fromExpress(cors())` included); handlers that are not brisk routes (static files, GraphQL, webhooks) go in `defineApp({ mount })`. Express settings go in `http.settings`.
|
|
20
|
+
- Long-lived work (WebSockets, jobs, consumers, pools) is a provider class with `onInit`, `onReady`, `onDrain`, `onShutdown`; a feature lists its own in `defineController({ providers })`.
|
|
21
|
+
- Test with `createTestClient` from `@raiyyan/brisk/testing`: `api.call.<controller>.<route>(input)` is typed; `api.post(path)` checks raw HTTP.
|
|
22
|
+
|
|
23
|
+
<!-- brisk:end -->
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# minimal
|
|
2
|
+
|
|
3
|
+
An API built with [brisk](https://github.com/MohammadRaiyyan/brisk) on Express 5 and Zod. It has no database: the example feature keeps its records in memory. Created with `npx brisk init` (the `minimal` starter).
|
|
4
|
+
|
|
5
|
+
## Run it
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cp .env.example .env
|
|
9
|
+
npm run dev
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The API listens on port 3000 under `/api`. `GET /health` is the health check and `GET /openapi.json` the OpenAPI document.
|
|
13
|
+
|
|
14
|
+
| Script | What it does |
|
|
15
|
+
| ------------------------- | ------------------------------------------ |
|
|
16
|
+
| `dev` | Runs the server and restarts it on changes |
|
|
17
|
+
| `start` | Runs the server |
|
|
18
|
+
| `test` | Runs the tests (vitest) |
|
|
19
|
+
| `typecheck` | Checks types (`tsc --noEmit`) |
|
|
20
|
+
| `lint` | oxlint |
|
|
21
|
+
| `format` / `format:check` | oxfmt |
|
|
22
|
+
| `brisk g <kind> <name>` | Generates code from `templates/<kind>/` |
|
|
23
|
+
|
|
24
|
+
Node 24 or later runs the TypeScript sources directly; there is no build step.
|
|
25
|
+
|
|
26
|
+
## Layout
|
|
27
|
+
|
|
28
|
+
| Path | What it holds |
|
|
29
|
+
| ---------------- | ------------------------------------------------------------------------------------------- |
|
|
30
|
+
| `src/env.ts` | Environment variables, validated at startup |
|
|
31
|
+
| `src/app.ts` | The app: controllers, logger, OpenAPI, error settings. `export type Api` for a typed client |
|
|
32
|
+
| `src/main.ts` | Starts the server |
|
|
33
|
+
| `src/schemas.ts` | Shared schema helpers: `isoDate()`, `PageQuery`, `page(item)` |
|
|
34
|
+
| `src/features/` | One folder per feature (schema, repository, service, controller), registered in `index.ts` |
|
|
35
|
+
| `templates/` | What `brisk g` renders: `feature` and `middleware`. Yours to edit |
|
|
36
|
+
| `test/` | HTTP tests with `createTestClient`, and service tests without HTTP |
|
|
37
|
+
|
|
38
|
+
## Add a feature
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx brisk g feature products
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
This writes `src/features/products/`, its tests, and registers the controller in `src/features/index.ts` (keep the `@brisk:` marker lines there). The repository stores records in a `Map`; replace it with your database and the service does not change.
|
|
45
|
+
|
|
46
|
+
`npx brisk g middleware tenant` writes `src/middlewares/tenant.ts`. To change what new code looks like, edit the files in `templates/`; any folder you add there becomes a new `brisk g` kind.
|
|
47
|
+
|
|
48
|
+
The `notes` feature is an example generated from `templates/feature`. Delete `src/features/notes/`, `test/notes.test.ts`, `test/notes.service.test.ts` and its two lines in `src/features/index.ts` when you no longer need it.
|
|
49
|
+
|
|
50
|
+
## Learn more
|
|
51
|
+
|
|
52
|
+
- [brisk documentation](https://github.com/MohammadRaiyyan/brisk#readme)
|
|
53
|
+
- `AGENTS.md` and `CLAUDE.md` point coding agents at the brisk guide (`npx brisk agents` refreshes them).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "starter-minimal",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "node --watch src/main.ts",
|
|
7
|
+
"start": "node src/main.ts",
|
|
8
|
+
"typecheck": "tsc --noEmit",
|
|
9
|
+
"test": "vitest run",
|
|
10
|
+
"brisk": "brisk",
|
|
11
|
+
"lint": "oxlint --type-aware",
|
|
12
|
+
"format": "oxfmt",
|
|
13
|
+
"format:check": "oxfmt --check"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@raiyyan/brisk": "workspace:*"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/node": "^26.6.6",
|
|
20
|
+
"oxfmt": "^0.78.0",
|
|
21
|
+
"oxlint": "^1.93.0",
|
|
22
|
+
"oxlint-tsgolint": "^7.0.2007",
|
|
23
|
+
"typescript": "^7.0.2",
|
|
24
|
+
"vitest": "^5.1.0"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=24"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createLogger, defineApp } from "@raiyyan/brisk";
|
|
2
|
+
import { env } from "./env.ts";
|
|
3
|
+
import { controllers } from "./features/index.ts";
|
|
4
|
+
|
|
5
|
+
export const app = defineApp({
|
|
6
|
+
prefix: "/api",
|
|
7
|
+
controllers,
|
|
8
|
+
logger: createLogger({ level: env.NODE_ENV === "test" ? "silent" : env.LOG_LEVEL }),
|
|
9
|
+
openapi: { title: "API", version: "0.1.0" },
|
|
10
|
+
errors: { exposeInternal: env.NODE_ENV === "development" },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
/** The API's type, for a frontend's typed client: `createClient<Api>(manifest, { baseUrl })`. */
|
|
14
|
+
export type Api = typeof app;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { defineEnv, z } from "@raiyyan/brisk";
|
|
2
|
+
|
|
3
|
+
export const env = defineEnv({
|
|
4
|
+
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
|
|
5
|
+
PORT: z.coerce.number().int().positive().default(3000),
|
|
6
|
+
LOG_LEVEL: z.enum(["fatal", "error", "warn", "info", "debug", "trace", "silent"]).default("info"),
|
|
7
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { notesController } from "./notes/notes.controller.ts";
|
|
2
|
+
// @brisk:imports
|
|
3
|
+
|
|
4
|
+
/** Every controller by name. The names are the typed client's top level: `api.notes.get(...)`. */
|
|
5
|
+
export const controllers = {
|
|
6
|
+
notes: notesController,
|
|
7
|
+
// @brisk:controllers
|
|
8
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { defineController, inject } from "@raiyyan/brisk";
|
|
2
|
+
import { page } from "../../schemas.ts";
|
|
3
|
+
import {
|
|
4
|
+
CreateNoteBody,
|
|
5
|
+
NoteIdParams,
|
|
6
|
+
NoteResponse,
|
|
7
|
+
ListNotesQuery,
|
|
8
|
+
UpdateNoteBody,
|
|
9
|
+
} from "./notes.schema.ts";
|
|
10
|
+
import { NotesService } from "./notes.service.ts";
|
|
11
|
+
|
|
12
|
+
export const notesController = defineController({ prefix: "/notes" }, (route) => {
|
|
13
|
+
const notes = inject(NotesService);
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
list: route.get("/", { query: ListNotesQuery, response: page(NoteResponse) }, ({ query }) =>
|
|
17
|
+
notes.list(query),
|
|
18
|
+
),
|
|
19
|
+
|
|
20
|
+
get: route.get("/:id", { params: NoteIdParams, response: NoteResponse }, ({ params }) =>
|
|
21
|
+
notes.get(params.id),
|
|
22
|
+
),
|
|
23
|
+
|
|
24
|
+
create: route.post("/", { body: CreateNoteBody, response: NoteResponse }, ({ body }) =>
|
|
25
|
+
notes.create(body),
|
|
26
|
+
),
|
|
27
|
+
|
|
28
|
+
update: route.patch(
|
|
29
|
+
"/:id",
|
|
30
|
+
{ params: NoteIdParams, body: UpdateNoteBody, response: NoteResponse },
|
|
31
|
+
({ params, body }) => notes.update(params.id, body),
|
|
32
|
+
),
|
|
33
|
+
|
|
34
|
+
remove: route.delete("/:id", { params: NoteIdParams }, async ({ params }) => {
|
|
35
|
+
await notes.remove(params.id);
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
});
|