@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/cli/agents.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { PACKAGE } from "./
|
|
3
|
+
import { PACKAGE } from "./system.js";
|
|
4
4
|
const GUIDE = `node_modules/${PACKAGE}/AGENTS.md`;
|
|
5
5
|
const START = "<!-- brisk:start -->";
|
|
6
6
|
const END = "<!-- brisk:end -->";
|
|
@@ -41,15 +41,15 @@ Before writing or changing server code, read the full guide: \`${GUIDE}\`.
|
|
|
41
41
|
|
|
42
42
|
Essentials:
|
|
43
43
|
|
|
44
|
-
- Features live in \`src/features/<name>/\` as \`schema.ts → repository.ts → service.ts → controller.ts\`; create them with \`npx brisk g feature <name>\`.
|
|
45
44
|
- The app is declared once in \`src/app.ts\` with \`defineApp\`; \`app.listen(port)\` runs it, \`createTestClient(app, { providers })\` tests it.
|
|
46
45
|
- Routes are named: a controller's setup returns \`{ list: route.get(...), create: route.post(...) }\`. The names form the typed client (\`api.users.create({ body })\`).
|
|
47
46
|
- Validate every input with a Zod schema on the route; set \`response\` to a DTO schema so internal fields never leak.
|
|
47
|
+
- 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.
|
|
48
48
|
- Dependencies: \`readonly #repo = inject(Repository)\` in class fields. No decorators, no constructor wiring.
|
|
49
49
|
- Errors: \`throw new NotFoundError("…")\` (or another error class) anywhere. Never try/catch to build responses; never call \`next()\`.
|
|
50
|
-
- Shared request logic: \`defineMiddleware\` returning an object types \`ctx\`
|
|
51
|
-
-
|
|
52
|
-
- Long-lived work (WebSockets, jobs, consumers, pools) is a provider class with \`onInit\`, \`onReady\`, \`onDrain\`, \`onShutdown\`.
|
|
50
|
+
- 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()\`.
|
|
51
|
+
- 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\`.
|
|
52
|
+
- Long-lived work (WebSockets, jobs, consumers, pools) is a provider class with \`onInit\`, \`onReady\`, \`onDrain\`, \`onShutdown\`; a feature lists its own in \`defineController({ providers })\`.
|
|
53
53
|
- Test with \`createTestClient\` from \`${PACKAGE}/testing\`: \`api.call.<controller>.<route>(input)\` is typed; \`api.post(path)\` checks raw HTTP.
|
|
54
54
|
`;
|
|
55
55
|
//# sourceMappingURL=agents.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../../src/cli/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../../src/cli/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,MAAM,KAAK,GAAG,gBAAgB,OAAO,YAAY,CAAC;AAClD,MAAM,KAAK,GAAG,sBAAsB,CAAC;AACrC,MAAM,GAAG,GAAG,oBAAoB,CAAC;AAEjC;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,GAAG,KAAK,KAAK,OAAO,KAAK,GAAG,EAAE,CAAC;IAC7C,MAAM,QAAQ,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAChF,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,MAAM,GACV,KAAK,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,KAAK;QACzB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC;QACrE,CAAC,CAAC,QAAQ,KAAK,EAAE;YACf,CAAC,CAAC,kBAAkB,KAAK,IAAI;YAC7B,CAAC,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,aAAa,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAElC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,MAAM,OAAO,GAAG,CAAC,YAAY,EAAE,IAAI,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IACjG,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,aAAa,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtG,CAAC;IAED,OAAO;QACL,GAAG,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,YAAY;QACtD,OAAO,CAAC,MAAM,GAAG,CAAC;YAChB,CAAC,CAAC,GAAG,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,YAAY;YACtD,CAAC,CAAC,qCAAqC;KAC1C,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,GAAG;;sDAEsC,OAAO;iEACI,KAAK;;;;;;;;;;;;;0CAa5B,OAAO;CAChD,CAAC"}
|
package/dist/src/cli/cli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CliIo } from "./system.ts";
|
|
2
2
|
export type { CliIo } from "./system.ts";
|
|
3
|
-
/** Entry point of the
|
|
3
|
+
/** Entry point of the \`brisk\` binary; resolves with the exit code. */
|
|
4
4
|
export declare function runCli(argv: readonly string[], root: string, io?: CliIo): Promise<number>;
|
|
5
5
|
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../src/cli/cli.ts"],"names":[],"mappings":"AAQA,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../src/cli/cli.ts"],"names":[],"mappings":"AAQA,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAE3D,YAAY,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAmBzC,wEAAwE;AACxE,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAE,KAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CA6DxG"}
|
package/dist/src/cli/cli.js
CHANGED
|
@@ -1,35 +1,29 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
-
import {
|
|
2
|
+
import { relative } from "node:path";
|
|
3
3
|
import { parseArgs } from "node:util";
|
|
4
4
|
import { writeAgentGuides } from "./agents.js";
|
|
5
5
|
import { generateClient, generateOpenApi } from "./client.js";
|
|
6
|
-
import {
|
|
7
|
-
import { initProject } from "./init.js";
|
|
6
|
+
import { initProject, listStarters } from "./init.js";
|
|
8
7
|
import { toNames } from "./names.js";
|
|
8
|
+
import { renderTemplates } from "./render.js";
|
|
9
9
|
import { CliError, format } from "./system.js";
|
|
10
|
-
import { REGISTRY } from "./templates/project.js";
|
|
11
10
|
const USAGE = `Usage: brisk <command> [options]
|
|
12
11
|
|
|
13
12
|
Commands:
|
|
14
|
-
init
|
|
15
|
-
--
|
|
16
|
-
--auth JWT bearer auth: authenticate and requireRole middlewares
|
|
17
|
-
--docker Dockerfile, compose.yaml and .dockerignore
|
|
18
|
-
--ci GitHub Actions workflow: typecheck and tests
|
|
19
|
-
--web CORS, rate limiting, static files and pretty dev logs
|
|
13
|
+
init Start a project here from a starter; never overwrites files
|
|
14
|
+
--starter <name> Which starter (default: minimal); \`brisk init --starter list\` shows them
|
|
20
15
|
--pm <pnpm|npm|yarn> Package manager (default: detected)
|
|
21
|
-
--
|
|
22
|
-
|
|
23
|
-
g feature <name> Feature folder (schema, repository, service, controller) and test; registers it
|
|
24
|
-
g middleware <name> Typed middleware in src/middlewares
|
|
16
|
+
--no-install Print the install command instead of running it
|
|
17
|
+
g <kind> <name> Render the project's templates/<kind>/ for <name>, such as \`g feature notes\`
|
|
25
18
|
client --out <file> Write the route manifest for a frontend's typed client
|
|
26
19
|
openapi --out <file> Write the OpenAPI 3.1 document built from the routes' schemas
|
|
27
20
|
--app <file> Module exporting the app, for client and openapi (default src/app.ts)
|
|
28
21
|
agents Add or refresh the brisk guide for AI coding agents (AGENTS.md, CLAUDE.md)
|
|
29
22
|
help, --version
|
|
30
23
|
|
|
31
|
-
Run from the app's root
|
|
32
|
-
|
|
24
|
+
Run from the app's root. A starter brings its own choices (database, auth, tooling) and the templates that
|
|
25
|
+
\`brisk g\` renders; the templates are files in your project, yours to edit.`;
|
|
26
|
+
/** Entry point of the \`brisk\` binary; resolves with the exit code. */
|
|
33
27
|
export async function runCli(argv, root, io = console) {
|
|
34
28
|
try {
|
|
35
29
|
const { values, positionals } = parseArgs({
|
|
@@ -37,13 +31,8 @@ export async function runCli(argv, root, io = console) {
|
|
|
37
31
|
allowPositionals: true,
|
|
38
32
|
allowNegative: true,
|
|
39
33
|
options: {
|
|
40
|
-
|
|
41
|
-
auth: { type: "boolean" },
|
|
42
|
-
docker: { type: "boolean" },
|
|
43
|
-
ci: { type: "boolean" },
|
|
44
|
-
web: { type: "boolean" },
|
|
34
|
+
starter: { type: "string", default: "minimal" },
|
|
45
35
|
pm: { type: "string" },
|
|
46
|
-
yes: { type: "boolean", short: "y", default: false },
|
|
47
36
|
install: { type: "boolean", default: true },
|
|
48
37
|
out: { type: "string" },
|
|
49
38
|
app: { type: "string", default: "src/app.ts" },
|
|
@@ -61,7 +50,11 @@ export async function runCli(argv, root, io = console) {
|
|
|
61
50
|
return command === undefined && !values.help ? 1 : 0;
|
|
62
51
|
}
|
|
63
52
|
if (command === "init") {
|
|
64
|
-
|
|
53
|
+
if (values.starter === "list") {
|
|
54
|
+
io.log(`Starters: ${listStarters().join(", ")}`);
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
for (const line of initProject(root, values, io))
|
|
65
58
|
io.log(line);
|
|
66
59
|
return 0;
|
|
67
60
|
}
|
|
@@ -78,21 +71,14 @@ export async function runCli(argv, root, io = console) {
|
|
|
78
71
|
io.log(line);
|
|
79
72
|
return 0;
|
|
80
73
|
}
|
|
81
|
-
if ((command !== "g" && command !== "generate") || !name)
|
|
74
|
+
if ((command !== "g" && command !== "generate") || !kind || !name)
|
|
82
75
|
throw new CliError(USAGE);
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
? generateFeature(root, names)
|
|
86
|
-
: kind === "middleware"
|
|
87
|
-
? generateMiddleware(root, names)
|
|
88
|
-
: null;
|
|
89
|
-
if (!files)
|
|
90
|
-
throw new CliError(USAGE);
|
|
91
|
-
for (const file of files)
|
|
76
|
+
const rendered = renderTemplates(root, kind, toNames(name));
|
|
77
|
+
for (const file of rendered.created)
|
|
92
78
|
io.log(`created ${relative(root, file)}`);
|
|
93
|
-
|
|
94
|
-
io.log(`updated ${
|
|
95
|
-
const formatted = format(root,
|
|
79
|
+
for (const file of rendered.updated)
|
|
80
|
+
io.log(`updated ${relative(root, file)}`);
|
|
81
|
+
const formatted = format(root, [...rendered.created, ...rendered.updated]);
|
|
96
82
|
if (formatted)
|
|
97
83
|
io.log(formatted);
|
|
98
84
|
return 0;
|
package/dist/src/cli/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/cli/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/cli/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/src/cli/init.d.ts
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import { type CliIo } from "./system.ts";
|
|
2
|
-
/** `brisk init` flags
|
|
2
|
+
/** `brisk init` flags. */
|
|
3
3
|
export interface InitFlags {
|
|
4
|
-
|
|
5
|
-
auth?: boolean | undefined;
|
|
6
|
-
docker?: boolean | undefined;
|
|
7
|
-
ci?: boolean | undefined;
|
|
8
|
-
web?: boolean | undefined;
|
|
4
|
+
starter: string;
|
|
9
5
|
pm?: string | undefined;
|
|
10
|
-
yes: boolean;
|
|
11
6
|
install: boolean;
|
|
12
7
|
}
|
|
13
8
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
9
|
+
* Starts a project from a starter: a complete, tested app that brings its own choices (database, auth,
|
|
10
|
+
* tooling) and the templates `brisk g` generates from. Files that already exist are kept; `package.json` gains
|
|
11
|
+
* what it lacks. Then the packages are installed and the agent guide is written.
|
|
17
12
|
*/
|
|
18
|
-
export declare function initProject(root: string, flags: InitFlags, io: CliIo):
|
|
13
|
+
export declare function initProject(root: string, flags: InitFlags, io: CliIo): string[];
|
|
14
|
+
/** The starters shipped with this version of brisk. */
|
|
15
|
+
export declare function listStarters(): string[];
|
|
19
16
|
//# sourceMappingURL=init.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/init.ts"],"names":[],"mappings":"AAIA,OAAO,EAQL,KAAK,KAAK,EAEX,MAAM,aAAa,CAAC;AAErB,0BAA0B;AAC1B,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;CAClB;AAMD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,GAAG,MAAM,EAAE,CAgC/E;AAED,uDAAuD;AACvD,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAKvC"}
|
package/dist/src/cli/init.js
CHANGED
|
@@ -1,124 +1,148 @@
|
|
|
1
|
-
import { existsSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
1
|
+
import { cpSync, existsSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, join, relative } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
3
4
|
import { writeAgentGuides } from "./agents.js";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
5
|
+
import { CliError, detectPackageManager, format, PACKAGE, PackageJson, readPackageJson, run, } from "./system.js";
|
|
6
|
+
/** Never copied out of a starter: installs, local data, secrets, and the guides `brisk agents` writes. */
|
|
7
|
+
const SKIPPED = new Set(["node_modules", "dist", "coverage", ".env", "AGENTS.md", "CLAUDE.md"]);
|
|
8
|
+
const SKIPPED_SUFFIXES = [".db", ".db-wal", ".db-shm", ".log"];
|
|
8
9
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Starts a project from a starter: a complete, tested app that brings its own choices (database, auth,
|
|
11
|
+
* tooling) and the templates `brisk g` generates from. Files that already exist are kept; `package.json` gains
|
|
12
|
+
* what it lacks. Then the packages are installed and the agent guide is written.
|
|
12
13
|
*/
|
|
13
|
-
export
|
|
14
|
-
const
|
|
15
|
-
const
|
|
14
|
+
export function initProject(root, flags, io) {
|
|
15
|
+
const starter = findStarter(flags.starter);
|
|
16
|
+
const pm = flags.pm ?? detectPackageManager(root);
|
|
17
|
+
if (!isPackageManager(pm))
|
|
18
|
+
throw new CliError(`Unknown package manager "${pm}": use pnpm, npm or yarn.`);
|
|
16
19
|
const lines = [];
|
|
17
|
-
for (const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
lines.push(`kept ${path}`);
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
write(target, content);
|
|
24
|
-
lines.push(`created ${path}`);
|
|
20
|
+
for (const entry of readdirSync(starter)) {
|
|
21
|
+
if (!skipped(entry) && entry !== "package.json")
|
|
22
|
+
copy(join(starter, entry), join(root, published(entry)), root, lines);
|
|
25
23
|
}
|
|
26
|
-
|
|
27
|
-
const added = Object.entries(plan.scripts).filter(([name]) => {
|
|
28
|
-
const existing = pkg.scripts?.[name];
|
|
29
|
-
return existing === undefined || existing.includes(NPM_TEST_STUB);
|
|
30
|
-
});
|
|
31
|
-
writeFileSync(join(root, "package.json"), `${JSON.stringify({ ...pkg, type: pkg.type ?? "module", scripts: { ...pkg.scripts, ...Object.fromEntries(added) } }, null, 2)}\n`);
|
|
32
|
-
lines.push(`updated package.json${added.length > 0 ? ` (scripts: ${added.map(([name]) => name).join(", ")})` : ""}`);
|
|
33
|
-
const installed = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
34
|
-
const missing = (names) => [...new Set(names)].filter((name) => installed[name] === undefined);
|
|
35
|
-
const commands = [
|
|
36
|
-
...(missing(plan.dependencies).length > 0
|
|
37
|
-
? [addCommand(options.pm, missing(plan.dependencies), false)]
|
|
38
|
-
: []),
|
|
39
|
-
...(missing(plan.devDependencies).length > 0
|
|
40
|
-
? [addCommand(options.pm, missing(plan.devDependencies), true)]
|
|
41
|
-
: []),
|
|
42
|
-
];
|
|
43
|
-
lines.push(...writeAgentGuides(root));
|
|
24
|
+
lines.push(mergePackageJson(starter, root), ...writeAgentGuides(root));
|
|
44
25
|
for (const line of lines)
|
|
45
26
|
io.log(line);
|
|
46
|
-
const
|
|
27
|
+
const install = [pm, "install"];
|
|
47
28
|
if (!flags.install)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
29
|
+
return [`install: ${install.join(" ")}`, "", ...nextSteps(pm)];
|
|
30
|
+
io.log(`$ ${install.join(" ")}`);
|
|
31
|
+
try {
|
|
32
|
+
run(install, root);
|
|
33
|
+
const formatted = format(root, ["package.json", "AGENTS.md", "CLAUDE.md"].map((file) => join(root, file)));
|
|
34
|
+
if (formatted)
|
|
35
|
+
io.log(formatted);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
51
38
|
throw new CliError([
|
|
52
|
-
|
|
53
|
-
...
|
|
54
|
-
...(options.pm === "pnpm"
|
|
55
|
-
? ["If pnpm blocked build scripts, review them with: pnpm approve-builds"]
|
|
56
|
-
: []),
|
|
39
|
+
`The project files are in place, but \`${install.join(" ")}\` failed. Fix the cause above and run it again.`,
|
|
40
|
+
...(pm === "pnpm" ? ["If pnpm blocked build scripts, review them with: pnpm approve-builds"] : []),
|
|
57
41
|
].join("\n"));
|
|
58
42
|
}
|
|
59
|
-
return ["", ...nextSteps(
|
|
43
|
+
return ["", ...nextSteps(pm)];
|
|
60
44
|
}
|
|
61
|
-
/**
|
|
62
|
-
function
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
});
|
|
45
|
+
/** The starters shipped with this version of brisk. */
|
|
46
|
+
export function listStarters() {
|
|
47
|
+
const dir = startersDir();
|
|
48
|
+
return readdirSync(dir)
|
|
49
|
+
.filter((name) => statSync(join(dir, name)).isDirectory())
|
|
50
|
+
.toSorted();
|
|
73
51
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
52
|
+
/** Finds `starters/` above this file: the repository root in development, the package root once published. */
|
|
53
|
+
function startersDir() {
|
|
54
|
+
for (let dir = dirname(fileURLToPath(import.meta.url));; dir = dirname(dir)) {
|
|
55
|
+
if (existsSync(join(dir, "starters")))
|
|
56
|
+
return join(dir, "starters");
|
|
57
|
+
if (dirname(dir) === dir)
|
|
58
|
+
throw new CliError("No starters found next to this brisk installation.");
|
|
79
59
|
}
|
|
80
|
-
const pm = flags.pm ?? detectPackageManager(root);
|
|
81
|
-
if (!isPackageManager(pm))
|
|
82
|
-
throw new CliError(`Unknown package manager "${pm}": use pnpm, npm or yarn.`);
|
|
83
|
-
const confirm = async (flag, question) => flag ?? (ask ? await yesNo(ask, question) : false);
|
|
84
|
-
return {
|
|
85
|
-
db,
|
|
86
|
-
auth: await confirm(flags.auth, "JWT bearer auth (authenticate and requireRole middlewares)?"),
|
|
87
|
-
docker: await confirm(flags.docker, "Dockerfile and compose.yaml?"),
|
|
88
|
-
ci: await confirm(flags.ci, "GitHub Actions CI (typecheck and tests)?"),
|
|
89
|
-
web: await confirm(flags.web, "Web extras (CORS, rate limiting, static files, pretty dev logs)?"),
|
|
90
|
-
pm,
|
|
91
|
-
};
|
|
92
60
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
.trim()
|
|
98
|
-
.toLowerCase();
|
|
99
|
-
if (answer === "")
|
|
100
|
-
return choices[0] ?? "";
|
|
101
|
-
if (choices.includes(answer))
|
|
102
|
-
return answer;
|
|
61
|
+
function findStarter(name) {
|
|
62
|
+
const path = join(startersDir(), name);
|
|
63
|
+
if (!/^[\w-]+$/.test(name) || !existsSync(path)) {
|
|
64
|
+
throw new CliError(`Unknown starter "${name}". Starters: ${listStarters().join(", ")}.`);
|
|
103
65
|
}
|
|
66
|
+
return path;
|
|
104
67
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
68
|
+
/**
|
|
69
|
+
* npm drops every `.gitignore` from a published package, so starters keep theirs as `_gitignore` and the
|
|
70
|
+
* project gets it back under its real name.
|
|
71
|
+
*/
|
|
72
|
+
function published(name) {
|
|
73
|
+
return name === "_gitignore" ? ".gitignore" : name;
|
|
74
|
+
}
|
|
75
|
+
function skipped(name) {
|
|
76
|
+
return SKIPPED.has(name) || SKIPPED_SUFFIXES.some((suffix) => name.endsWith(suffix));
|
|
77
|
+
}
|
|
78
|
+
/** Copies a starter's file or folder into the project, keeping every file that is already there. */
|
|
79
|
+
function copy(source, target, root, lines) {
|
|
80
|
+
if (statSync(source).isDirectory()) {
|
|
81
|
+
for (const entry of readdirSync(source)) {
|
|
82
|
+
if (!skipped(entry))
|
|
83
|
+
copy(join(source, entry), join(target, entry), root, lines);
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const path = relative(root, target);
|
|
88
|
+
if (existsSync(target)) {
|
|
89
|
+
lines.push(`kept ${path}`);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
cpSync(source, target);
|
|
93
|
+
lines.push(`created ${path}`);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Gives the project's `package.json` what the starter's has and it lacks: `type`, `engines`, scripts and
|
|
97
|
+
* dependencies.
|
|
98
|
+
* The starter depends on brisk through the workspace; the project gets the version that is running.
|
|
99
|
+
*/
|
|
100
|
+
function mergePackageJson(starter, root) {
|
|
101
|
+
const template = PackageJson.parse(JSON.parse(readFileSync(join(starter, "package.json"), "utf8")));
|
|
102
|
+
const project = readPackageJson(root);
|
|
103
|
+
const running = version();
|
|
104
|
+
const brisk = running === undefined ? "latest" : `^${running}`;
|
|
105
|
+
const pin = (deps) => Object.fromEntries(Object.entries(deps ?? {}).map(([name, range]) => [name, name === PACKAGE ? brisk : range]));
|
|
106
|
+
const merged = {
|
|
107
|
+
...project,
|
|
108
|
+
name: typeof project["name"] === "string" ? project["name"] : basename(root),
|
|
109
|
+
type: "module",
|
|
110
|
+
engines: project["engines"] ?? template["engines"],
|
|
111
|
+
scripts: { ...template.scripts, ...withoutNpmStub(project.scripts) },
|
|
112
|
+
dependencies: { ...pin(template.dependencies), ...project.dependencies },
|
|
113
|
+
devDependencies: { ...pin(template.devDependencies), ...project.devDependencies },
|
|
114
|
+
};
|
|
115
|
+
writeFileSync(join(root, "package.json"), `${JSON.stringify(merged, null, 2)}\n`);
|
|
116
|
+
return project.type !== undefined && project.type !== "module"
|
|
117
|
+
? `updated package.json ("type" is now "module": brisk apps are ES modules)`
|
|
118
|
+
: "updated package.json";
|
|
119
|
+
}
|
|
120
|
+
/** `npm init` writes a `test` script that only fails; the starter's replaces it. */
|
|
121
|
+
function withoutNpmStub(scripts) {
|
|
122
|
+
return Object.fromEntries(Object.entries(scripts ?? {}).filter(([, command]) => !command.includes("Error: no test specified")));
|
|
123
|
+
}
|
|
124
|
+
/** The running brisk's version: the nearest `package.json` named `@raiyyan/brisk` above this file. */
|
|
125
|
+
function version() {
|
|
126
|
+
for (let dir = dirname(fileURLToPath(import.meta.url));; dir = dirname(dir)) {
|
|
127
|
+
const path = join(dir, "package.json");
|
|
128
|
+
if (existsSync(path)) {
|
|
129
|
+
const pkg = PackageJson.parse(JSON.parse(readFileSync(path, "utf8")));
|
|
130
|
+
if (pkg["name"] === PACKAGE && typeof pkg["version"] === "string")
|
|
131
|
+
return pkg["version"];
|
|
132
|
+
}
|
|
133
|
+
if (dirname(dir) === dir)
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
108
136
|
}
|
|
109
137
|
function isPackageManager(value) {
|
|
110
138
|
return value === "pnpm" || value === "npm" || value === "yarn";
|
|
111
139
|
}
|
|
112
|
-
function nextSteps(
|
|
140
|
+
function nextSteps(pm) {
|
|
113
141
|
const exec = pm === "npm" ? "npx" : pm;
|
|
114
142
|
return [
|
|
115
143
|
"Next:",
|
|
116
144
|
" cp .env.example .env",
|
|
117
|
-
|
|
118
|
-
...(db === "postgres"
|
|
119
|
-
? [` ${pm} run db:generate && ${pm} run db:migrate # after defining tables`]
|
|
120
|
-
: []),
|
|
121
|
-
` ${exec} brisk g feature users`,
|
|
145
|
+
` ${exec} brisk g feature tasks # renders templates/feature, which you own and can edit`,
|
|
122
146
|
` ${pm} run dev`,
|
|
123
147
|
];
|
|
124
148
|
}
|
package/dist/src/cli/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Names } from "./names.ts";
|
|
2
|
+
/** What `brisk g` did: files it created, and existing files it added to. */
|
|
3
|
+
export interface Rendered {
|
|
4
|
+
created: string[];
|
|
5
|
+
updated: string[];
|
|
6
|
+
}
|
|
7
|
+
/** What rendering a template folder produces, before anything is written. */
|
|
8
|
+
export interface TemplatePlan {
|
|
9
|
+
/** New files, by path relative to the project root. */
|
|
10
|
+
files: Map<string, string>;
|
|
11
|
+
/** Text to add to existing files: target path relative to the root, the marker, and the text. */
|
|
12
|
+
inserts: {
|
|
13
|
+
target: string;
|
|
14
|
+
marker: string;
|
|
15
|
+
text: string;
|
|
16
|
+
}[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Renders the project's own `templates/<kind>/` for `names`. Every file is copied with its path and contents
|
|
20
|
+
* rendered; `{{kebab}}`, `{{camel}}`, `{{pascal}}`, `{{snake}}`, `{{entity}}` and `{{entityCamel}}` are the
|
|
21
|
+
* tokens. A file named `<target>.<marker>.insert` is not copied: its text goes into the existing `<target>`,
|
|
22
|
+
* right before the line that holds `@brisk:<marker>`.
|
|
23
|
+
*
|
|
24
|
+
* Everything is checked before anything is written: an unknown token, a file that already exists, or a
|
|
25
|
+
* missing marker stops the run with nothing changed.
|
|
26
|
+
*/
|
|
27
|
+
export declare function renderTemplates(root: string, kind: string, names: Names): Rendered;
|
|
28
|
+
/** Renders a template folder in memory: the files it creates and the text it adds, nothing written. */
|
|
29
|
+
export declare function planTemplates(dir: string, names: Names, root: string): TemplatePlan;
|
|
30
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/cli/render.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC,4EAA4E;AAC5E,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAKD,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,iGAAiG;IACjG,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,QAAQ,CAoBlF;AAED,uGAAuG;AACvG,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAqBnF"}
|