@raiyyan/brisk 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +467 -0
- package/LICENSE +21 -0
- package/README.md +1417 -2
- package/dist/bin/brisk.d.ts +3 -0
- package/dist/bin/brisk.d.ts.map +1 -0
- package/dist/bin/brisk.js +13 -0
- package/dist/bin/brisk.js.map +1 -0
- package/dist/src/cli/agents.d.ts +7 -0
- package/dist/src/cli/agents.d.ts.map +1 -0
- package/dist/src/cli/agents.js +55 -0
- package/dist/src/cli/agents.js.map +1 -0
- package/dist/src/cli/cli.d.ts +5 -0
- package/dist/src/cli/cli.d.ts.map +1 -0
- package/dist/src/cli/cli.js +127 -0
- package/dist/src/cli/cli.js.map +1 -0
- package/dist/src/cli/client.d.ts +12 -0
- package/dist/src/cli/client.d.ts.map +1 -0
- package/dist/src/cli/client.js +76 -0
- package/dist/src/cli/client.js.map +1 -0
- package/dist/src/cli/generate.d.ts +9 -0
- package/dist/src/cli/generate.d.ts.map +1 -0
- package/dist/src/cli/generate.js +39 -0
- package/dist/src/cli/generate.js.map +1 -0
- package/dist/src/cli/init.d.ts +19 -0
- package/dist/src/cli/init.d.ts.map +1 -0
- package/dist/src/cli/init.js +125 -0
- package/dist/src/cli/init.js.map +1 -0
- package/dist/src/cli/names.d.ts +14 -0
- package/dist/src/cli/names.d.ts.map +1 -0
- package/dist/src/cli/names.js +25 -0
- package/dist/src/cli/names.js.map +1 -0
- package/dist/src/cli/system.d.ts +35 -0
- package/dist/src/cli/system.d.ts.map +1 -0
- package/dist/src/cli/system.js +83 -0
- package/dist/src/cli/system.js.map +1 -0
- package/dist/src/cli/templates/auth.d.ts +4 -0
- package/dist/src/cli/templates/auth.d.ts.map +1 -0
- package/dist/src/cli/templates/auth.js +90 -0
- package/dist/src/cli/templates/auth.js.map +1 -0
- package/dist/src/cli/templates/database.d.ts +4 -0
- package/dist/src/cli/templates/database.d.ts.map +1 -0
- package/dist/src/cli/templates/database.js +107 -0
- package/dist/src/cli/templates/database.js.map +1 -0
- package/dist/src/cli/templates/docker.d.ts +4 -0
- package/dist/src/cli/templates/docker.d.ts.map +1 -0
- package/dist/src/cli/templates/docker.js +102 -0
- package/dist/src/cli/templates/docker.js.map +1 -0
- package/dist/src/cli/templates/feature.d.ts +8 -0
- package/dist/src/cli/templates/feature.d.ts.map +1 -0
- package/dist/src/cli/templates/feature.js +145 -0
- package/dist/src/cli/templates/feature.js.map +1 -0
- package/dist/src/cli/templates/project.d.ts +24 -0
- package/dist/src/cli/templates/project.d.ts.map +1 -0
- package/dist/src/cli/templates/project.js +166 -0
- package/dist/src/cli/templates/project.js.map +1 -0
- package/dist/src/client/client.d.ts +64 -0
- package/dist/src/client/client.d.ts.map +1 -0
- package/dist/src/client/client.js +143 -0
- package/dist/src/client/client.js.map +1 -0
- package/dist/src/client/index.d.ts +8 -0
- package/dist/src/client/index.d.ts.map +1 -0
- package/dist/src/client/index.js +7 -0
- package/dist/src/client/index.js.map +1 -0
- package/dist/src/config/env.d.ts +28 -0
- package/dist/src/config/env.d.ts.map +1 -0
- package/dist/src/config/env.js +35 -0
- package/dist/src/config/env.js.map +1 -0
- package/dist/src/config/logger.d.ts +32 -0
- package/dist/src/config/logger.d.ts.map +1 -0
- package/dist/src/config/logger.js +31 -0
- package/dist/src/config/logger.js.map +1 -0
- package/dist/src/di/container.d.ts +186 -0
- package/dist/src/di/container.d.ts.map +1 -0
- package/dist/src/di/container.js +208 -0
- package/dist/src/di/container.js.map +1 -0
- package/dist/src/di/index.d.ts +8 -0
- package/dist/src/di/index.d.ts.map +1 -0
- package/dist/src/di/index.js +8 -0
- package/dist/src/di/index.js.map +1 -0
- package/dist/src/errors/http-errors.d.ts +295 -0
- package/dist/src/errors/http-errors.d.ts.map +1 -0
- package/dist/src/errors/http-errors.js +311 -0
- package/dist/src/errors/http-errors.js.map +1 -0
- package/dist/src/errors/index.d.ts +8 -0
- package/dist/src/errors/index.d.ts.map +1 -0
- package/dist/src/errors/index.js +8 -0
- package/dist/src/errors/index.js.map +1 -0
- package/dist/src/http/app.d.ts +200 -0
- package/dist/src/http/app.d.ts.map +1 -0
- package/dist/src/http/app.js +45 -0
- package/dist/src/http/app.js.map +1 -0
- package/dist/src/http/context.d.ts +66 -0
- package/dist/src/http/context.d.ts.map +1 -0
- package/dist/src/http/context.js +96 -0
- package/dist/src/http/context.js.map +1 -0
- package/dist/src/http/controller.d.ts +178 -0
- package/dist/src/http/controller.d.ts.map +1 -0
- package/dist/src/http/controller.js +317 -0
- package/dist/src/http/controller.js.map +1 -0
- package/dist/src/http/error-handler.d.ts +59 -0
- package/dist/src/http/error-handler.d.ts.map +1 -0
- package/dist/src/http/error-handler.js +124 -0
- package/dist/src/http/error-handler.js.map +1 -0
- package/dist/src/http/instance.d.ts +14 -0
- package/dist/src/http/instance.d.ts.map +1 -0
- package/dist/src/http/instance.js +309 -0
- package/dist/src/http/instance.js.map +1 -0
- package/dist/src/http/middleware.d.ts +54 -0
- package/dist/src/http/middleware.d.ts.map +1 -0
- package/dist/src/http/middleware.js +101 -0
- package/dist/src/http/middleware.js.map +1 -0
- package/dist/src/http/openapi.d.ts +34 -0
- package/dist/src/http/openapi.d.ts.map +1 -0
- package/dist/src/http/openapi.js +123 -0
- package/dist/src/http/openapi.js.map +1 -0
- package/dist/src/http/path-params.d.ts +24 -0
- package/dist/src/http/path-params.d.ts.map +1 -0
- package/dist/src/http/path-params.js +2 -0
- package/dist/src/http/path-params.js.map +1 -0
- package/dist/src/http/routes.d.ts +119 -0
- package/dist/src/http/routes.d.ts.map +1 -0
- package/dist/src/http/routes.js +2 -0
- package/dist/src/http/routes.js.map +1 -0
- package/dist/src/http/server.d.ts +23 -0
- package/dist/src/http/server.d.ts.map +1 -0
- package/dist/src/http/server.js +22 -0
- package/dist/src/http/server.js.map +1 -0
- package/dist/src/index.d.ts +22 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +19 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/testing/index.d.ts +7 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +7 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/testing/test-client.d.ts +65 -0
- package/dist/src/testing/test-client.d.ts.map +1 -0
- package/dist/src/testing/test-client.js +77 -0
- package/dist/src/testing/test-client.js.map +1 -0
- package/package.json +88 -3
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { PackageManager } from "../system.ts";
|
|
2
|
+
export declare const PACKAGE = "@raiyyan/brisk";
|
|
3
|
+
export declare const IMPORTS_MARKER = "// @brisk:imports";
|
|
4
|
+
export declare const CONTROLLERS_MARKER = "// @brisk:controllers";
|
|
5
|
+
export declare const REGISTRY = "src/features/index.ts";
|
|
6
|
+
/** What `brisk init` was asked to set up. */
|
|
7
|
+
export interface InitOptions {
|
|
8
|
+
db: "none" | "sqlite" | "postgres";
|
|
9
|
+
auth: boolean;
|
|
10
|
+
docker: boolean;
|
|
11
|
+
ci: boolean;
|
|
12
|
+
web: boolean;
|
|
13
|
+
pm: PackageManager;
|
|
14
|
+
}
|
|
15
|
+
/** Everything a set of options adds to a project. */
|
|
16
|
+
export interface Plan {
|
|
17
|
+
files: Record<string, string>;
|
|
18
|
+
dependencies: string[];
|
|
19
|
+
devDependencies: string[];
|
|
20
|
+
scripts: Record<string, string>;
|
|
21
|
+
}
|
|
22
|
+
/** Composes the base project with every chosen option. */
|
|
23
|
+
export declare function projectPlan(options: InitOptions): Plan;
|
|
24
|
+
//# sourceMappingURL=project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../../../src/cli/templates/project.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAKnD,eAAO,MAAM,OAAO,mBAAmB,CAAC;AACxC,eAAO,MAAM,cAAc,sBAAsB,CAAC;AAClD,eAAO,MAAM,kBAAkB,0BAA0B,CAAC;AAC1D,eAAO,MAAM,QAAQ,0BAA0B,CAAC;AAEhD,6CAA6C;AAC7C,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,EAAE,EAAE,OAAO,CAAC;IACZ,GAAG,EAAE,OAAO,CAAC;IACb,EAAE,EAAE,cAAc,CAAC;CACpB;AAED,qDAAqD;AACrD,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,0DAA0D;AAC1D,wBAAgB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CA+BtD"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { authFiles } from "./auth.js";
|
|
2
|
+
import { databaseFiles } from "./database.js";
|
|
3
|
+
import { dockerFiles } from "./docker.js";
|
|
4
|
+
export const PACKAGE = "@raiyyan/brisk";
|
|
5
|
+
export const IMPORTS_MARKER = "// @brisk:imports";
|
|
6
|
+
export const CONTROLLERS_MARKER = "// @brisk:controllers";
|
|
7
|
+
export const REGISTRY = "src/features/index.ts";
|
|
8
|
+
/** Composes the base project with every chosen option. */
|
|
9
|
+
export function projectPlan(options) {
|
|
10
|
+
const plan = {
|
|
11
|
+
files: {
|
|
12
|
+
"src/env.ts": envTemplate(options),
|
|
13
|
+
"src/app.ts": appTemplate(options),
|
|
14
|
+
"src/main.ts": mainTemplate,
|
|
15
|
+
[REGISTRY]: registryTemplate,
|
|
16
|
+
".env.example": envExample(options),
|
|
17
|
+
"tsconfig.json": tsconfigTemplate,
|
|
18
|
+
"vitest.config.ts": vitestTemplate(options),
|
|
19
|
+
".gitignore": "node_modules\n.env\ncoverage\n*.db\n*.db-*\n",
|
|
20
|
+
},
|
|
21
|
+
dependencies: [PACKAGE],
|
|
22
|
+
devDependencies: ["typescript", "@types/node", "vitest"],
|
|
23
|
+
scripts: {
|
|
24
|
+
dev: "node --watch src/main.ts",
|
|
25
|
+
start: "node src/main.ts",
|
|
26
|
+
typecheck: "tsc --noEmit",
|
|
27
|
+
test: "vitest run",
|
|
28
|
+
brisk: "brisk",
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
if (options.db !== "none")
|
|
32
|
+
merge(plan, databaseFiles(options.db));
|
|
33
|
+
if (options.auth)
|
|
34
|
+
merge(plan, authFiles());
|
|
35
|
+
if (options.docker || options.ci)
|
|
36
|
+
merge(plan, dockerFiles(options));
|
|
37
|
+
if (options.web) {
|
|
38
|
+
plan.files["public/.gitkeep"] = "";
|
|
39
|
+
plan.dependencies.push("express", "cors", "express-rate-limit");
|
|
40
|
+
plan.devDependencies.push("@types/express", "@types/cors", "pino-pretty");
|
|
41
|
+
}
|
|
42
|
+
return plan;
|
|
43
|
+
}
|
|
44
|
+
function merge(plan, extra) {
|
|
45
|
+
Object.assign(plan.files, extra.files);
|
|
46
|
+
plan.dependencies.push(...(extra.dependencies ?? []));
|
|
47
|
+
plan.devDependencies.push(...(extra.devDependencies ?? []));
|
|
48
|
+
Object.assign(plan.scripts, extra.scripts);
|
|
49
|
+
}
|
|
50
|
+
function envTemplate({ db, auth, web }) {
|
|
51
|
+
const lines = [
|
|
52
|
+
` NODE_ENV: z.enum(["development", "test", "production"]).default("development"),`,
|
|
53
|
+
` PORT: z.coerce.number().int().positive().default(3000),`,
|
|
54
|
+
` LOG_LEVEL: z.enum(["fatal", "error", "warn", "info", "debug", "trace", "silent"]).default("info"),`,
|
|
55
|
+
];
|
|
56
|
+
if (db === "sqlite")
|
|
57
|
+
lines.push(` DATABASE_PATH: z.string().min(1).default("data.db"),`);
|
|
58
|
+
if (db === "postgres") {
|
|
59
|
+
lines.push(` DATABASE_URL: z.url(),`, ` DATABASE_POOL_SIZE: z.coerce.number().int().positive().default(10),`);
|
|
60
|
+
}
|
|
61
|
+
if (auth) {
|
|
62
|
+
lines.push(` /** HMAC key for access tokens: 32+ random characters (\`openssl rand -base64 48\`). */`, ` AUTH_SECRET: z.string().min(32),`, ` AUTH_TOKEN_TTL_SECONDS: z.coerce.number().int().positive().default(3600),`);
|
|
63
|
+
}
|
|
64
|
+
if (web) {
|
|
65
|
+
lines.push(` /** Browser origin allowed to call the API, such as http://localhost:5173. */`, ` WEB_ORIGIN: z.url().default("http://localhost:5173"),`, ` RATE_LIMIT_PER_MINUTE: z.coerce.number().int().positive().default(300),`);
|
|
66
|
+
}
|
|
67
|
+
return `import { defineEnv, z } from "${PACKAGE}";
|
|
68
|
+
|
|
69
|
+
export const env = defineEnv({
|
|
70
|
+
${lines.join("\n")}
|
|
71
|
+
});
|
|
72
|
+
`;
|
|
73
|
+
}
|
|
74
|
+
function envExample({ db, auth, web }) {
|
|
75
|
+
const lines = ["NODE_ENV=development", "PORT=3000", "LOG_LEVEL=info"];
|
|
76
|
+
if (db === "sqlite")
|
|
77
|
+
lines.push("DATABASE_PATH=data.db");
|
|
78
|
+
if (db === "postgres")
|
|
79
|
+
lines.push("DATABASE_URL=postgres://app:app@localhost:5432/app");
|
|
80
|
+
if (auth)
|
|
81
|
+
lines.push("AUTH_SECRET=replace-with-32-or-more-random-characters");
|
|
82
|
+
if (web)
|
|
83
|
+
lines.push("WEB_ORIGIN=http://localhost:5173");
|
|
84
|
+
return `${lines.join("\n")}\n`;
|
|
85
|
+
}
|
|
86
|
+
function appTemplate({ db, web }) {
|
|
87
|
+
const imports = [`import { createLogger, defineApp } from "${PACKAGE}";`];
|
|
88
|
+
if (web) {
|
|
89
|
+
imports.push(`import cors from "cors";`, `import express from "express";`, `import { rateLimit } from "express-rate-limit";`);
|
|
90
|
+
}
|
|
91
|
+
if (db !== "none")
|
|
92
|
+
imports.push(`import { uniqueViolation } from "./database/errors.ts";`);
|
|
93
|
+
imports.push(`import { env } from "./env.ts";`, `import { controllers } from "./features/index.ts";`);
|
|
94
|
+
const options = [
|
|
95
|
+
` prefix: "/api",`,
|
|
96
|
+
` controllers,`,
|
|
97
|
+
` logger: createLogger({`,
|
|
98
|
+
` level: env.NODE_ENV === "test" ? "silent" : env.LOG_LEVEL,`,
|
|
99
|
+
...(web ? [` pretty: env.NODE_ENV === "development",`] : []),
|
|
100
|
+
` }),`,
|
|
101
|
+
` openapi: { title: "API", version: "0.1.0" },`,
|
|
102
|
+
` errors: {`,
|
|
103
|
+
...(db === "none" ? [] : [` mappers: [uniqueViolation],`]),
|
|
104
|
+
` exposeInternal: env.NODE_ENV === "development",`,
|
|
105
|
+
` },`,
|
|
106
|
+
];
|
|
107
|
+
if (web) {
|
|
108
|
+
options.push(` configureExpress: (expressApp) => {`, ` expressApp.use(cors({ origin: env.WEB_ORIGIN, credentials: true }));`, ` // Behind a proxy, set http: { trustProxy } so the limit applies per client, not per proxy.`, ` expressApp.use(rateLimit({ windowMs: 60_000, limit: env.RATE_LIMIT_PER_MINUTE, standardHeaders: "draft-8", legacyHeaders: false }));`, ` expressApp.use("/static", express.static("public", { maxAge: "1h" }));`, ` },`);
|
|
109
|
+
}
|
|
110
|
+
return `${imports.join("\n")}
|
|
111
|
+
|
|
112
|
+
export const app = defineApp({
|
|
113
|
+
${options.join("\n")}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
/** The API's type, for a frontend's typed client: \`createClient<Api>(manifest, { baseUrl })\`. */
|
|
117
|
+
export type Api = typeof app;
|
|
118
|
+
`;
|
|
119
|
+
}
|
|
120
|
+
const mainTemplate = `import { app } from "./app.ts";
|
|
121
|
+
import { env } from "./env.ts";
|
|
122
|
+
|
|
123
|
+
await app.listen(env.PORT);
|
|
124
|
+
`;
|
|
125
|
+
const registryTemplate = `${IMPORTS_MARKER}
|
|
126
|
+
|
|
127
|
+
/** Every controller by name. The names are the typed client's top level: \`api.users.get(...)\`. */
|
|
128
|
+
export const controllers = {
|
|
129
|
+
${CONTROLLERS_MARKER}
|
|
130
|
+
};
|
|
131
|
+
`;
|
|
132
|
+
const tsconfigTemplate = `${JSON.stringify({
|
|
133
|
+
compilerOptions: {
|
|
134
|
+
target: "es2024",
|
|
135
|
+
module: "nodenext",
|
|
136
|
+
moduleResolution: "nodenext",
|
|
137
|
+
strict: true,
|
|
138
|
+
exactOptionalPropertyTypes: true,
|
|
139
|
+
noUncheckedIndexedAccess: true,
|
|
140
|
+
noEmit: true,
|
|
141
|
+
allowImportingTsExtensions: true,
|
|
142
|
+
verbatimModuleSyntax: true,
|
|
143
|
+
erasableSyntaxOnly: true,
|
|
144
|
+
skipLibCheck: true,
|
|
145
|
+
types: ["node"],
|
|
146
|
+
},
|
|
147
|
+
include: ["src", "test", "vitest.config.ts"],
|
|
148
|
+
}, null, 2)}\n`;
|
|
149
|
+
function vitestTemplate({ db, auth }) {
|
|
150
|
+
const env = [`NODE_ENV: "test"`];
|
|
151
|
+
if (db === "sqlite")
|
|
152
|
+
env.push(`DATABASE_PATH: ":memory:"`);
|
|
153
|
+
if (db === "postgres")
|
|
154
|
+
env.push(`DATABASE_URL: "postgres://app:app@localhost:5432/app_test"`);
|
|
155
|
+
if (auth)
|
|
156
|
+
env.push(`AUTH_SECRET: "test-secret-that-is-at-least-32-characters-long"`);
|
|
157
|
+
return `import { defineConfig } from "vitest/config";
|
|
158
|
+
|
|
159
|
+
export default defineConfig({
|
|
160
|
+
test: {
|
|
161
|
+
env: { ${env.join(", ")} },
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
`;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../../../src/cli/templates/project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ApiOf, Client, Manifest } from "../http/routes.ts";
|
|
2
|
+
/** Options for {@link createClient}. */
|
|
3
|
+
export interface ClientOptions {
|
|
4
|
+
/** Origin of the API, such as `https://api.example.com` or `http://127.0.0.1:3000`. */
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
/** Headers for every request, such as `authorization`; a function is called per request. */
|
|
7
|
+
headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
|
8
|
+
/** The fetch to use. Default: the global `fetch`. */
|
|
9
|
+
fetch?: typeof fetch;
|
|
10
|
+
}
|
|
11
|
+
/** An app as the client sees it: its route manifest, plus its types. */
|
|
12
|
+
interface AppLike {
|
|
13
|
+
readonly manifest: Manifest;
|
|
14
|
+
readonly "~controllers"?: unknown;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A non-2xx response. Carries brisk's error body (`code`, `message`, `details`, `requestId`) when the server
|
|
18
|
+
* sent one, so callers branch on `error.code` instead of parsing messages.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* try {
|
|
23
|
+
* await api.users.create({ body });
|
|
24
|
+
* } catch (error) {
|
|
25
|
+
* if (error instanceof ApiError && error.code === "EMAIL_TAKEN") showEmailTaken();
|
|
26
|
+
* else throw error;
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare class ApiError extends Error {
|
|
31
|
+
readonly status: number;
|
|
32
|
+
readonly code: string;
|
|
33
|
+
readonly details: unknown;
|
|
34
|
+
readonly requestId: string | undefined;
|
|
35
|
+
/** The parsed response body, whatever its shape. */
|
|
36
|
+
readonly body: unknown;
|
|
37
|
+
constructor(status: number, body: unknown);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Creates a typed client for an app's routes: `api.users.get({ params: { id } })` resolves to the route's output
|
|
41
|
+
* and rejects with {@link ApiError} on a non-2xx response.
|
|
42
|
+
*
|
|
43
|
+
* In Node, pass the app or a running instance. In a browser, pass the manifest that `brisk client` writes,
|
|
44
|
+
* with the app's type, so the server's code never reaches the bundle.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* // web/src/api.ts
|
|
49
|
+
* import { createClient } from "@raiyyan/brisk/client";
|
|
50
|
+
* import type { Api } from "../../server/src/app.ts";
|
|
51
|
+
* import { manifest } from "./api.manifest.ts"; // generated by `brisk client`
|
|
52
|
+
*
|
|
53
|
+
* export const api = createClient<Api>(manifest, { baseUrl: import.meta.env.VITE_API_URL });
|
|
54
|
+
* const user = await api.users.get({ params: { id } });
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function createClient<A extends AppLike>(app: A, options: ClientOptions): Client<ApiOf<A>>;
|
|
58
|
+
export declare function createClient<T>(manifest: Manifest, options: ClientOptions): Client<ApiOf<T>>;
|
|
59
|
+
/** Fills `:name`, `*name` and optional `{...}` groups from `params`, encoding every segment. */
|
|
60
|
+
export declare function toPath(path: string, params: Record<string, unknown>): string;
|
|
61
|
+
/** `{ tag: ["a", "b"], page: 2 }` gives `?tag=a&tag=b&page=2`; `undefined` and `null` are left out. */
|
|
62
|
+
export declare function toQuery(query: Record<string, unknown> | undefined): string;
|
|
63
|
+
export {};
|
|
64
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/client/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEjE,wCAAwC;AACxC,MAAM,WAAW,aAAa;IAC5B,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC;IAChB,4FAA4F;IAC5F,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACpG,qDAAqD;IACrD,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,wEAAwE;AACxE,UAAU,OAAO;IACf,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CACnC;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAEvB,YAAY,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EASxC;CACF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAClG,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AA0C9F,gGAAgG;AAChG,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAY5E;AAED,uGAAuG;AACvG,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,CAU1E"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A non-2xx response. Carries brisk's error body (`code`, `message`, `details`, `requestId`) when the server
|
|
3
|
+
* sent one, so callers branch on `error.code` instead of parsing messages.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* try {
|
|
8
|
+
* await api.users.create({ body });
|
|
9
|
+
* } catch (error) {
|
|
10
|
+
* if (error instanceof ApiError && error.code === "EMAIL_TAKEN") showEmailTaken();
|
|
11
|
+
* else throw error;
|
|
12
|
+
* }
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export class ApiError extends Error {
|
|
16
|
+
status;
|
|
17
|
+
code;
|
|
18
|
+
details;
|
|
19
|
+
requestId;
|
|
20
|
+
/** The parsed response body, whatever its shape. */
|
|
21
|
+
body;
|
|
22
|
+
constructor(status, body) {
|
|
23
|
+
const error = errorBody(body);
|
|
24
|
+
super(error?.message ?? `Request failed with status ${status}`);
|
|
25
|
+
this.name = "ApiError";
|
|
26
|
+
this.status = status;
|
|
27
|
+
this.code = error?.code ?? "HTTP_ERROR";
|
|
28
|
+
this.details = error?.details;
|
|
29
|
+
this.requestId = error?.requestId;
|
|
30
|
+
this.body = body;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function createClient(source, options) {
|
|
34
|
+
const manifest = isAppLike(source) ? source.manifest : source;
|
|
35
|
+
return build(manifest, options);
|
|
36
|
+
}
|
|
37
|
+
function build(manifest, options) {
|
|
38
|
+
const client = {};
|
|
39
|
+
for (const [name, entry] of Object.entries(manifest)) {
|
|
40
|
+
client[name] = isEndpoint(entry) ? endpoint(entry[0], entry[1], options) : build(entry, options);
|
|
41
|
+
}
|
|
42
|
+
return Object.freeze(client);
|
|
43
|
+
}
|
|
44
|
+
function endpoint(method, path, options) {
|
|
45
|
+
const send = options.fetch ?? fetch;
|
|
46
|
+
const base = options.baseUrl.replace(/\/+$/, "");
|
|
47
|
+
return async (input = {}, init = {}) => {
|
|
48
|
+
const shared = typeof options.headers === "function" ? await options.headers() : options.headers;
|
|
49
|
+
const headers = new Headers(init.headers);
|
|
50
|
+
for (const [name, value] of Object.entries({ ...shared, ...input.headers }))
|
|
51
|
+
headers.set(name, value);
|
|
52
|
+
const hasBody = input.body !== undefined;
|
|
53
|
+
if (hasBody && !headers.has("content-type"))
|
|
54
|
+
headers.set("content-type", "application/json");
|
|
55
|
+
const res = await send(base + toPath(path, input.params ?? {}) + toQuery(input.query), {
|
|
56
|
+
...init,
|
|
57
|
+
method,
|
|
58
|
+
headers,
|
|
59
|
+
body: hasBody ? JSON.stringify(input.body) : null,
|
|
60
|
+
});
|
|
61
|
+
if (!res.ok)
|
|
62
|
+
throw new ApiError(res.status, await readBody(res));
|
|
63
|
+
if (!isJson(res))
|
|
64
|
+
return res.status === 204 ? undefined : res;
|
|
65
|
+
return readBody(res);
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** Fills `:name`, `*name` and optional `{...}` groups from `params`, encoding every segment. */
|
|
69
|
+
export function toPath(path, params) {
|
|
70
|
+
const filled = path.replace(/\{([^{}]*)\}/g, (_group, inner) => {
|
|
71
|
+
const names = [...inner.matchAll(/[:*]([\w$]+)/g)].map((match) => match[1] ?? "");
|
|
72
|
+
return names.every((name) => params[name] !== undefined) ? inner : "";
|
|
73
|
+
});
|
|
74
|
+
return filled.replace(/([:*])([\w$]+)/g, (_match, kind, name) => {
|
|
75
|
+
const value = params[name];
|
|
76
|
+
if (value === undefined)
|
|
77
|
+
throw new TypeError(`Missing path parameter "${name}" for ${path}`);
|
|
78
|
+
if (kind === "*" && Array.isArray(value))
|
|
79
|
+
return value.map((part) => encodeURIComponent(stringify(part))).join("/");
|
|
80
|
+
return encodeURIComponent(stringify(value));
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/** `{ tag: ["a", "b"], page: 2 }` gives `?tag=a&tag=b&page=2`; `undefined` and `null` are left out. */
|
|
84
|
+
export function toQuery(query) {
|
|
85
|
+
if (!query)
|
|
86
|
+
return "";
|
|
87
|
+
const search = new URLSearchParams();
|
|
88
|
+
for (const [key, value] of Object.entries(query)) {
|
|
89
|
+
for (const item of Array.isArray(value) ? value : [value]) {
|
|
90
|
+
if (item !== undefined && item !== null)
|
|
91
|
+
search.append(key, stringify(item));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const text = search.toString();
|
|
95
|
+
return text === "" ? "" : `?${text}`;
|
|
96
|
+
}
|
|
97
|
+
/** A path or query value as text: primitives as themselves, a `Date` as ISO, anything else as JSON. */
|
|
98
|
+
function stringify(value) {
|
|
99
|
+
if (typeof value === "string")
|
|
100
|
+
return value;
|
|
101
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint")
|
|
102
|
+
return value.toString();
|
|
103
|
+
if (value instanceof Date)
|
|
104
|
+
return value.toISOString();
|
|
105
|
+
return JSON.stringify(value);
|
|
106
|
+
}
|
|
107
|
+
const JSON_TYPE = /^application\/(?:[\w.-]+\+)?json\b/i;
|
|
108
|
+
function isJson(res) {
|
|
109
|
+
return JSON_TYPE.test(res.headers.get("content-type") ?? "");
|
|
110
|
+
}
|
|
111
|
+
async function readBody(res) {
|
|
112
|
+
const text = await res.text();
|
|
113
|
+
if (text === "")
|
|
114
|
+
return undefined;
|
|
115
|
+
if (!isJson(res))
|
|
116
|
+
return text;
|
|
117
|
+
const parsed = JSON.parse(text);
|
|
118
|
+
return parsed;
|
|
119
|
+
}
|
|
120
|
+
function errorBody(body) {
|
|
121
|
+
if (typeof body !== "object" || body === null || !("error" in body))
|
|
122
|
+
return undefined;
|
|
123
|
+
const { error } = body;
|
|
124
|
+
if (typeof error !== "object" || error === null)
|
|
125
|
+
return undefined;
|
|
126
|
+
if (!("code" in error) || typeof error.code !== "string")
|
|
127
|
+
return undefined;
|
|
128
|
+
if (!("message" in error) || typeof error.message !== "string")
|
|
129
|
+
return undefined;
|
|
130
|
+
return {
|
|
131
|
+
code: error.code,
|
|
132
|
+
message: error.message,
|
|
133
|
+
details: "details" in error ? error.details : undefined,
|
|
134
|
+
requestId: "requestId" in error && typeof error.requestId === "string" ? error.requestId : undefined,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function isAppLike(source) {
|
|
138
|
+
return "manifest" in source && typeof source.manifest === "object" && !Array.isArray(source.manifest);
|
|
139
|
+
}
|
|
140
|
+
function isEndpoint(entry) {
|
|
141
|
+
return Array.isArray(entry);
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/client/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The typed client. Safe in browsers: it imports no server code, only types.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
export { ApiError, createClient, type ClientOptions } from "./client.ts";
|
|
7
|
+
export type { ApiOf, Call, Client, Jsonify, Manifest } from "../http/routes.ts";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACzE,YAAY,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAsB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Options for {@link defineEnv}. */
|
|
3
|
+
export interface DefineEnvOptions {
|
|
4
|
+
/** Dotenv file loaded into `process.env` when present. Default `.env`. */
|
|
5
|
+
file?: string;
|
|
6
|
+
/** An object to validate instead of `process.env`. Failures then throw instead of exiting. */
|
|
7
|
+
source?: Record<string, string | undefined>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Validates the environment once, at import, and returns it as a frozen, typed object. Loads `.env` first when
|
|
11
|
+
* the file exists. On failure it prints every invalid variable and exits, so the app never starts
|
|
12
|
+
* half-configured; under `NODE_ENV=test`, or with `source`, it throws instead.
|
|
13
|
+
*
|
|
14
|
+
* Variables are strings: use `z.coerce.number()` for numbers and `z.stringbool()` for booleans. Never
|
|
15
|
+
* `z.coerce.boolean()`, which reads `"false"` as `true`.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* export const env = defineEnv({
|
|
20
|
+
* PORT: z.coerce.number().default(3000),
|
|
21
|
+
* DATABASE_URL: z.url(),
|
|
22
|
+
* LOG_LEVEL: z.enum(["debug", "info", "warn"]).default("info"),
|
|
23
|
+
* });
|
|
24
|
+
* env.PORT; // number
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function defineEnv<T extends z.ZodRawShape>(shape: T, options?: DefineEnvOptions): Readonly<z.output<z.ZodObject<T>>>;
|
|
28
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../src/config/env.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8FAA8F;IAC9F,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC7C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAC/C,KAAK,EAAE,CAAC,EACR,OAAO,GAAE,gBAAqB,GAC7B,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAYpC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* Validates the environment once, at import, and returns it as a frozen, typed object. Loads `.env` first when
|
|
5
|
+
* the file exists. On failure it prints every invalid variable and exits, so the app never starts
|
|
6
|
+
* half-configured; under `NODE_ENV=test`, or with `source`, it throws instead.
|
|
7
|
+
*
|
|
8
|
+
* Variables are strings: use `z.coerce.number()` for numbers and `z.stringbool()` for booleans. Never
|
|
9
|
+
* `z.coerce.boolean()`, which reads `"false"` as `true`.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* export const env = defineEnv({
|
|
14
|
+
* PORT: z.coerce.number().default(3000),
|
|
15
|
+
* DATABASE_URL: z.url(),
|
|
16
|
+
* LOG_LEVEL: z.enum(["debug", "info", "warn"]).default("info"),
|
|
17
|
+
* });
|
|
18
|
+
* env.PORT; // number
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function defineEnv(shape, options = {}) {
|
|
22
|
+
const file = options.file ?? ".env";
|
|
23
|
+
if (!options.source && existsSync(file))
|
|
24
|
+
process.loadEnvFile(file);
|
|
25
|
+
const result = z.object(shape).safeParse(options.source ?? process.env);
|
|
26
|
+
if (result.success)
|
|
27
|
+
return Object.freeze(result.data);
|
|
28
|
+
const lines = result.error.issues.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`);
|
|
29
|
+
const message = `Invalid environment variables:\n${lines.join("\n")}`;
|
|
30
|
+
if (options.source || process.env["NODE_ENV"] === "test")
|
|
31
|
+
throw new Error(message);
|
|
32
|
+
console.error(`\n${message}\n\nCheck your .env file (see .env.example).\n`);
|
|
33
|
+
return process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../../src/config/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,SAAS,CACvB,KAAQ,EACR,OAAO,GAAqB,EAAE;IAE9B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC;IACpC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAEnE,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC;IACxE,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAEtD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAClG,MAAM,OAAO,GAAG,mCAAmC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IACtE,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IACnF,OAAO,CAAC,KAAK,CAAC,KAAK,OAAO,gDAAgD,CAAC,CAAC;IAC5E,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Logger as PinoLogger } from "pino";
|
|
2
|
+
/** A pino logger. In a handler, prefer `ctx.log`: it adds the request id to every line. */
|
|
3
|
+
export type Logger = PinoLogger;
|
|
4
|
+
/**
|
|
5
|
+
* The app's logger, as a token to inject. An app provides its `logger` option. A container you build yourself,
|
|
6
|
+
* as in a unit test, gets a silent logger, so services that log need no setup there.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* export class Mailer {
|
|
11
|
+
* readonly #log = inject(Logger);
|
|
12
|
+
* }
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare const Logger: import("../di/container.ts").InjectionToken<Logger>;
|
|
16
|
+
/** Options for {@link createLogger}. */
|
|
17
|
+
export interface LoggerOptions {
|
|
18
|
+
/** The lowest level written: `trace`, `debug`, `info`, `warn`, `error`, `fatal` or `silent`. Default `info`. */
|
|
19
|
+
level?: string;
|
|
20
|
+
/** Colored, human-readable lines for local development. Needs the optional `pino-pretty` package. */
|
|
21
|
+
pretty?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Creates a pino logger for an app's `logger` option: JSON lines, or pretty output in development.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* defineApp({ logger: createLogger({ level: env.LOG_LEVEL, pretty: env.NODE_ENV === "development" }) });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function createLogger({ level, pretty }?: LoggerOptions): Logger;
|
|
32
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/config/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,MAAM,IAAI,UAAU,EAAE,MAAM,MAAM,CAAC;AAGvD,2FAA2F;AAC3F,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC;AAEhC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,MAAM,qDAAiF,CAAC;AAErG,wCAAwC;AACxC,MAAM,WAAW,aAAa;IAC5B,gHAAgH;IAChH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qGAAqG;IACrG,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,EAAE,KAAc,EAAE,MAAc,EAAE,GAAE,aAAkB,GAAG,MAAM,CAO3F"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { pino } from "pino";
|
|
2
|
+
import { defineToken } from "../di/container.js";
|
|
3
|
+
/**
|
|
4
|
+
* The app's logger, as a token to inject. An app provides its `logger` option. A container you build yourself,
|
|
5
|
+
* as in a unit test, gets a silent logger, so services that log need no setup there.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* export class Mailer {
|
|
10
|
+
* readonly #log = inject(Logger);
|
|
11
|
+
* }
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export const Logger = /* @__PURE__ */ defineToken("Logger", () => pino({ level: "silent" }));
|
|
15
|
+
/**
|
|
16
|
+
* Creates a pino logger for an app's `logger` option: JSON lines, or pretty output in development.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* defineApp({ logger: createLogger({ level: env.LOG_LEVEL, pretty: env.NODE_ENV === "development" }) });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function createLogger({ level = "info", pretty = false } = {}) {
|
|
24
|
+
return pretty
|
|
25
|
+
? pino({
|
|
26
|
+
level,
|
|
27
|
+
transport: { target: "pino-pretty", options: { colorize: true, translateTime: "HH:MM:ss" } },
|
|
28
|
+
})
|
|
29
|
+
: pino({ level });
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/config/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAA6B,MAAM,MAAM,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKjD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,eAAe,CAAC,WAAW,CAAS,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;AAUrG;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,KAAK,GAAG,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,GAAkB,EAAE;IACjF,OAAO,MAAM;QACX,CAAC,CAAC,IAAI,CAAC;YACH,KAAK;YACL,SAAS,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,EAAE;SAC7F,CAAC;QACJ,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AACtB,CAAC"}
|