@forinda/kickjs-cli 4.1.0 → 5.0.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/dist/cli.mjs +214 -321
- package/dist/index.d.mts +2 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +145 -159
- package/dist/index.mjs.map +1 -1
- package/dist/{typegen-C-H8pg-y.mjs → typegen-B13guHZF.mjs} +44 -6
- package/dist/typegen-B13guHZF.mjs.map +1 -0
- package/package.json +2 -8
- package/dist/typegen-C-H8pg-y.mjs.map +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -19,7 +19,7 @@ interface KickCommandDefinition {
|
|
|
19
19
|
aliases?: string[];
|
|
20
20
|
}
|
|
21
21
|
/** Project pattern — controls what generators produce and which deps are installed */
|
|
22
|
-
type ProjectPattern = 'rest' | '
|
|
22
|
+
type ProjectPattern = 'rest' | 'ddd' | 'cqrs' | 'minimal';
|
|
23
23
|
/** Package manager used for `kick add` and other dep-installing commands */
|
|
24
24
|
type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';
|
|
25
25
|
/** Built-in repository types with first-class code generation support */
|
|
@@ -143,7 +143,6 @@ interface KickConfig {
|
|
|
143
143
|
/**
|
|
144
144
|
* Project pattern — controls default generator behavior.
|
|
145
145
|
* - 'rest' — Express + Swagger (default)
|
|
146
|
-
* - 'graphql' — GraphQL + GraphiQL
|
|
147
146
|
* - 'ddd' — Full DDD modules with use cases, entities, value objects
|
|
148
147
|
* - 'cqrs' — CQRS with commands, queries, events, WebSocket + queue
|
|
149
148
|
* - 'minimal' — Bare Express with no scaffolding
|
|
@@ -287,7 +286,6 @@ interface GenerateModuleOptions {
|
|
|
287
286
|
* Patterns:
|
|
288
287
|
* rest — flat folder: controller + service + DTOs + repo
|
|
289
288
|
* ddd — nested DDD: presentation/ application/ domain/ infrastructure/
|
|
290
|
-
* graphql — flat folder: resolver + service + DTOs + repo (future)
|
|
291
289
|
* cqrs — commands, queries, events with WS/queue integration
|
|
292
290
|
* minimal — just controller + module index
|
|
293
291
|
*/
|
|
@@ -367,7 +365,7 @@ interface GenerateDtoOptions {
|
|
|
367
365
|
declare function generateDto(options: GenerateDtoOptions): Promise<string[]>;
|
|
368
366
|
//#endregion
|
|
369
367
|
//#region src/generators/project.d.ts
|
|
370
|
-
type ProjectTemplate = 'rest' | '
|
|
368
|
+
type ProjectTemplate = 'rest' | 'ddd' | 'cqrs' | 'minimal';
|
|
371
369
|
interface InitProjectOptions {
|
|
372
370
|
name: string;
|
|
373
371
|
directory: string;
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/config.ts","../src/generators/module.ts","../src/generators/adapter.ts","../src/generators/middleware.ts","../src/generators/guard.ts","../src/generators/service.ts","../src/generators/controller.ts","../src/generators/dto.ts","../src/generators/project.ts","../src/generator-extension/define.ts","../src/generator-extension/discover.ts","../src/generator-extension/context.ts","../src/utils/naming.ts"],"mappings":";;;UAKiB,qBAAA;EAAqB;EAEpC,IAAA;EAFoC;EAIpC,WAAA;EAAA;;;;;AAeF;;;EANE,KAAA;EAMwB;EAJxB,OAAA;AAAA;;KAIU,cAAA;;KAGA,cAAA;;KAKA,iBAAA;AAKZ;AAAA,UAAiB,cAAA;EACf,IAAA;AAAA;;KAIU,cAAA,GAAiB,iBAAA,GAAkB,cAAA;;;;;AAS/C;;;KAAY,eAAA;;AAOZ;;;;UAAiB,aAAA;EAcf;;;;AAUF;;EAjBE,GAAA;EAwCiC;;;;;;EAjCjC,IAAA;EA2CO;AAIT;;;;EAzCE,IAAA;AAAA;;UAIe,aAAA;EA6Df;;;;EAxDA,MAAA;EAsEyB;;;;EAjEzB,MAAA;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/config.ts","../src/generators/module.ts","../src/generators/adapter.ts","../src/generators/middleware.ts","../src/generators/guard.ts","../src/generators/service.ts","../src/generators/controller.ts","../src/generators/dto.ts","../src/generators/project.ts","../src/generator-extension/define.ts","../src/generator-extension/discover.ts","../src/generator-extension/context.ts","../src/utils/naming.ts"],"mappings":";;;UAKiB,qBAAA;EAAqB;EAEpC,IAAA;EAFoC;EAIpC,WAAA;EAAA;;;;;AAeF;;;EANE,KAAA;EAMwB;EAJxB,OAAA;AAAA;;KAIU,cAAA;;KAGA,cAAA;;KAKA,iBAAA;AAKZ;AAAA,UAAiB,cAAA;EACf,IAAA;AAAA;;KAIU,cAAA,GAAiB,iBAAA,GAAkB,cAAA;;;;;AAS/C;;;KAAY,eAAA;;AAOZ;;;;UAAiB,aAAA;EAcf;;;;AAUF;;EAjBE,GAAA;EAwCiC;;;;;;EAjCjC,IAAA;EA2CO;AAIT;;;;EAzCE,IAAA;AAAA;;UAIe,aAAA;EA6Df;;;;EAxDA,MAAA;EAsEyB;;;;EAjEzB,MAAA;EAoHW;;;;;;;;;;;;EAvGX,eAAA,GAAkB,eAAA;EAuGlB;;;;;;;;;EA7FA,OAAA;AAAA;;UAIe,YAAA;EAmJf;EAjJA,GAAA;EAmJE;;;;;AAOJ;;;;;;;;EA5IE,IAAA,GAAO,cAAA;EAyKa;EAvKpB,SAAA;;;;;;EAMA,SAAA;EAiKmE;;;;ACjSrE;;;;;ED0IE,gBAAA;AAAA;;UAIe,UAAA;EC7IqB;AAOrC;;;;;;ED8IC,OAAA,GAAU,cAAA;ECxIV;;;;;;;;;;;EDoJA,OAAA,GAAU,YAAA;EC/HU;;;;;;;;;;;;;;;ED+IpB,cAAA,GAAiB,cAAA;EE3LX;AAcR;;;;;;;;;;;;EF4LE,QAAA,GAAW,KAAA;IAAiB,GAAA;IAAa,IAAA;EAAA;EGzMzC;;;;;;;;;AAQF;;EH6ME,KAAA;IG7MmF;;;;;;IHoNjF,MAAA;EAAA;;AI/N2C;;;;;;;;;;;;;AAW/C;;;;;;;EJ2OE,QAAA,GAAW,MAAA,SAAe,aAAA;EI3O+C;;;;ACX5B;;;;;;;ELkQ7C,OAAA,GAAU,aAAA;EK3PV;EL6PA,QAAA,GAAW,qBAAA;EK5PX;EL8PA,KAAA;IACE,UAAA;IACA,MAAA;IACA,aAAA;IACA,MAAA;EAAA;AAAA;;iBAKY,YAAA,CAAa,MAAA,EAAQ,UAAA,GAAa,UAAA;;iBA6B5B,cAAA,CAAe,GAAA,WAAc,OAAA,CAAQ,UAAA;;;KCjS/C,eAAA;AAAA,KACA,QAAA,GAAW,eAAA;AAAA,UASb,qBAAA;EACR,IAAA;EACA,UAAA;EACA,QAAA;EACA,OAAA;EACA,IAAA,GAAO,QAAA;EACP,OAAA;EACA,KAAA;EACA,OAAA,GAAU,cAAA;EACV,MAAA;EDVwB;ECYxB,SAAA;EDTwB;ECWxB,gBAAA;AAAA;;ADNF;;;;;AAKA;;;iBCasB,cAAA,CAAe,OAAA,EAAS,qBAAA,GAAwB,OAAA;;;UC9C5D,sBAAA;EACR,IAAA;EACA,MAAA;AAAA;;;;;;;;AFkBF;;;;iBEJsB,eAAA,CAAgB,OAAA,EAAS,sBAAA,GAAyB,OAAA;;;UCd9D,yBAAA;EACR,IAAA;EACA,MAAA;EACA,UAAA;EACA,UAAA;EACA,OAAA,GAAU,cAAA;EACV,SAAA;AAAA;AAAA,iBAGoB,kBAAA,CAAmB,OAAA,EAAS,yBAAA,GAA4B,OAAA;;;UCTpE,oBAAA;EACR,IAAA;EACA,MAAA;EACA,UAAA;EACA,UAAA;EACA,OAAA,GAAU,cAAA;EACV,SAAA;AAAA;AAAA,iBAGoB,aAAA,CAAc,OAAA,EAAS,oBAAA,GAAuB,OAAA;;;UCT1D,sBAAA;EACR,IAAA;EACA,MAAA;EACA,UAAA;EACA,UAAA;EACA,OAAA,GAAU,cAAA;EACV,SAAA;AAAA;AAAA,iBAGoB,eAAA,CAAgB,OAAA,EAAS,sBAAA,GAAyB,OAAA;;;UCT9D,yBAAA;EACR,IAAA;EACA,MAAA;EACA,UAAA;EACA,UAAA;EACA,OAAA,GAAU,cAAA;EACV,SAAA;AAAA;AAAA,iBAGoB,kBAAA,CAAmB,OAAA,EAAS,yBAAA,GAA4B,OAAA;;;UCTpE,kBAAA;EACR,IAAA;EACA,MAAA;EACA,UAAA;EACA,UAAA;EACA,OAAA,GAAU,cAAA;EACV,SAAA;AAAA;AAAA,iBAGoB,WAAA,CAAY,OAAA,EAAS,kBAAA,GAAqB,OAAA;;;KCsB3D,eAAA;AAAA,UAEK,kBAAA;EACR,IAAA;EACA,SAAA;EACA,cAAA;EACA,OAAA;EACA,WAAA;EACA,QAAA,GAAW,eAAA;EACX,WAAA;EACA,QAAA;AAAA;ARvBF;AAAA,iBQ2BsB,WAAA,CAAY,OAAA,EAAS,kBAAA,GAAqB,OAAA;;;;AR9ChE;;;;;;;;;;AAmBA;;;;;AAGA;;;;;AAKA;;;;;AAKA;;;;;AAKA;;;;;AASA;;;;;AAOA;;USdiB,gBAAA;ETca;ESZ5B,IAAA;ET0BA;ESxBA,MAAA;ET8BI;ES5BJ,KAAA;ETgCe;ES9Bf,KAAA;;EAEA,KAAA;ETiCA;ES/BA,YAAA;ETiDA;ES/CA,WAAA;ETyDA;ESvDA,WAAA;ETuDO;ESrDP,UAAA;ETyD2B;ESvD3B,GAAA;ETuEqB;ESrErB,IAAA;ETqEA;ESnEA,KAAA,EAAO,MAAA;AAAA;;UAIQ,aAAA;ETiFC;;AAIlB;;EShFE,IAAA;ETwFU;EStFV,OAAA;AAAA;;UAIe,YAAA;EACf,IAAA;EACA,QAAA;EACA,WAAA;AAAA;;UAIe,aAAA;EACf,IAAA;EACA,KAAA;EACA,WAAA;EACA,UAAA;AAAA;;;;;UAOe,aAAA;ET8Hb;;;;ESzHF,IAAA;ET4JU;ES1JV,WAAA;ET4JW;ES1JX,IAAA,YAAgB,YAAA;ET6Jd;ES3JF,KAAA,YAAiB,aAAA;ET6Jf;ES3JF,KAAA,CAAM,GAAA,EAAK,gBAAA,GAAmB,aAAA,KAAkB,OAAA,CAAQ,aAAA;AAAA;;ATiK1D;;;;;;;;;AA6BA;;;;;;;;;;;;ACjSA;iBQ6HgB,eAAA,CAAgB,IAAA,EAAM,aAAA,GAAgB,aAAA;;;ATvItD;;;;;AAAA,UUOiB,mBAAA;EACf,MAAA;EACA,IAAA,EAAM,aAAA;AAAA;;AVUR;;;;UUFiB,eAAA;EACf,UAAA,EAAY,mBAAA;EVIY;EUFxB,MAAA;EVEwB;;AAK1B;;EUFE,MAAA,EAAQ,KAAA;IAAQ,MAAA;IAAgB,MAAA;EAAA;AAAA;;;AVzBlC;;;;;;AAAA,iBWWgB,qBAAA,CAAsB,KAAA;EACpC,IAAA;EACA,IAAA;EACA,KAAA,GAAQ,MAAA;EACR,UAAA;EACA,GAAA;EACA,SAAA;AAAA,IACE,gBAAA;;;;iBCpBY,YAAA,CAAa,IAAA;;iBAOb,WAAA,CAAY,IAAA;;iBAMZ,WAAA,CAAY,IAAA;;;;;;iBAYZ,SAAA,CAAU,IAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli
|
|
2
|
+
* @forinda/kickjs-cli v5.0.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -1588,54 +1588,9 @@ export class Prisma${pascal}Repository implements I${pascal}Repository {
|
|
|
1588
1588
|
*/
|
|
1589
1589
|
function generateEntryFile(name, template, version, packages = []) {
|
|
1590
1590
|
switch (template) {
|
|
1591
|
-
case "graphql": {
|
|
1592
|
-
const gqlImports = [];
|
|
1593
|
-
const gqlAdapters = [];
|
|
1594
|
-
if (packages.includes("devtools")) {
|
|
1595
|
-
gqlImports.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`);
|
|
1596
|
-
gqlAdapters.push(` DevToolsAdapter(),`);
|
|
1597
|
-
}
|
|
1598
|
-
if (packages.includes("otel")) {
|
|
1599
|
-
gqlImports.push(`import { OtelAdapter } from '@forinda/kickjs-otel'`);
|
|
1600
|
-
gqlAdapters.push(` OtelAdapter({ serviceName: '${name}' }),`);
|
|
1601
|
-
}
|
|
1602
|
-
if (packages.includes("swagger")) {
|
|
1603
|
-
gqlImports.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`);
|
|
1604
|
-
gqlAdapters.push(` SwaggerAdapter({ info: { title: '${name}', version: '${version}' } }),`);
|
|
1605
|
-
}
|
|
1606
|
-
return `import 'reflect-metadata'
|
|
1607
|
-
// Side-effect import — registers the extended env schema with kickjs
|
|
1608
|
-
// **before** any controller / service / @Value gets resolved. Without
|
|
1609
|
-
// this line ConfigService.get('YOUR_KEY') returns undefined because the
|
|
1610
|
-
// cached schema would still be the base shape. See guide/configuration.
|
|
1611
|
-
import './config'
|
|
1612
|
-
import { bootstrap } from '@forinda/kickjs'
|
|
1613
|
-
import { GraphQLAdapter } from '@forinda/kickjs-graphql'
|
|
1614
|
-
${gqlImports.length ? gqlImports.join("\n") + "\n" : ""}import { modules } from './modules'
|
|
1615
|
-
|
|
1616
|
-
// Import your resolvers here
|
|
1617
|
-
// import { UserResolver } from './resolvers/user.resolver'
|
|
1618
|
-
|
|
1619
|
-
// Export the app for the Vite plugin (dev mode)
|
|
1620
|
-
export const app = await bootstrap({
|
|
1621
|
-
modules,
|
|
1622
|
-
adapters: [
|
|
1623
|
-
${gqlAdapters.length ? gqlAdapters.join("\n") + "\n" : ""} new GraphQLAdapter({
|
|
1624
|
-
resolvers: [/* UserResolver */],
|
|
1625
|
-
// Add custom type definitions here:
|
|
1626
|
-
// typeDefs: userTypeDefs,
|
|
1627
|
-
}),
|
|
1628
|
-
],
|
|
1629
|
-
})
|
|
1630
|
-
`;
|
|
1631
|
-
}
|
|
1632
1591
|
case "cqrs": {
|
|
1633
1592
|
const cqrsImports = [];
|
|
1634
1593
|
const cqrsAdapters = [];
|
|
1635
|
-
if (packages.includes("otel")) {
|
|
1636
|
-
cqrsImports.push(`import { OtelAdapter } from '@forinda/kickjs-otel'`);
|
|
1637
|
-
cqrsAdapters.push(` OtelAdapter({ serviceName: '${name}' }),`);
|
|
1638
|
-
}
|
|
1639
1594
|
if (packages.includes("devtools")) {
|
|
1640
1595
|
cqrsImports.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`);
|
|
1641
1596
|
cqrsAdapters.push(` DevToolsAdapter(),`);
|
|
@@ -1644,10 +1599,6 @@ ${gqlAdapters.length ? gqlAdapters.join("\n") + "\n" : ""} new GraphQLAdapter
|
|
|
1644
1599
|
cqrsImports.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`);
|
|
1645
1600
|
cqrsAdapters.push(` SwaggerAdapter({\n info: { title: '${name}', version: '${version}' },\n }),`);
|
|
1646
1601
|
}
|
|
1647
|
-
if (packages.includes("graphql")) {
|
|
1648
|
-
cqrsImports.push(`import { GraphQLAdapter } from '@forinda/kickjs-graphql'`);
|
|
1649
|
-
cqrsAdapters.push(` new GraphQLAdapter({ resolvers: [] }),`);
|
|
1650
|
-
}
|
|
1651
1602
|
return `import 'reflect-metadata'
|
|
1652
1603
|
// Side-effect import — registers the extended env schema with kickjs
|
|
1653
1604
|
// **before** any controller / service / @Value gets resolved. Without
|
|
@@ -1676,14 +1627,6 @@ export const app = await bootstrap({
|
|
|
1676
1627
|
imports.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`);
|
|
1677
1628
|
adapters.push(` DevToolsAdapter(),`);
|
|
1678
1629
|
}
|
|
1679
|
-
if (packages.includes("otel")) {
|
|
1680
|
-
imports.push(`import { OtelAdapter } from '@forinda/kickjs-otel'`);
|
|
1681
|
-
adapters.push(` OtelAdapter({ serviceName: '${name}' }),`);
|
|
1682
|
-
}
|
|
1683
|
-
if (packages.includes("graphql")) {
|
|
1684
|
-
imports.push(`import { GraphQLAdapter } from '@forinda/kickjs-graphql'`);
|
|
1685
|
-
adapters.push(` new GraphQLAdapter({ resolvers: [] }),`);
|
|
1686
|
-
}
|
|
1687
1630
|
return `import 'reflect-metadata'
|
|
1688
1631
|
// Side-effect import — registers the extended env schema with kickjs
|
|
1689
1632
|
// **before** any controller / service / @Value gets resolved. Without
|
|
@@ -1708,10 +1651,6 @@ export const app = await bootstrap({ modules${adapters.length ? `,\n adapters:
|
|
|
1708
1651
|
restImports.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`);
|
|
1709
1652
|
restAdapters.push(` SwaggerAdapter({\n info: { title: '${name}', version: '${version}' },\n }),`);
|
|
1710
1653
|
}
|
|
1711
|
-
if (packages.includes("otel")) {
|
|
1712
|
-
restImports.push(`import { OtelAdapter } from '@forinda/kickjs-otel'`);
|
|
1713
|
-
restAdapters.push(` OtelAdapter({ serviceName: '${name}' }),`);
|
|
1714
|
-
}
|
|
1715
1654
|
return `import 'reflect-metadata'
|
|
1716
1655
|
// Side-effect import — registers the extended env schema with kickjs
|
|
1717
1656
|
// **before** any controller / service / @Value gets resolved. Without
|
|
@@ -2265,7 +2204,6 @@ async function generateDddFiles(ctx) {
|
|
|
2265
2204
|
* Patterns:
|
|
2266
2205
|
* rest — flat folder: controller + service + DTOs + repo
|
|
2267
2206
|
* ddd — nested DDD: presentation/ application/ domain/ infrastructure/
|
|
2268
|
-
* graphql — flat folder: resolver + service + DTOs + repo (future)
|
|
2269
2207
|
* cqrs — commands, queries, events with WS/queue integration
|
|
2270
2208
|
* minimal — just controller + module index
|
|
2271
2209
|
*/
|
|
@@ -2378,7 +2316,13 @@ async function generateAdapter(options) {
|
|
|
2378
2316
|
const pascal = toPascalCase(name);
|
|
2379
2317
|
const files = [];
|
|
2380
2318
|
const filePath = join(outDir, `${kebab}.adapter.ts`);
|
|
2381
|
-
await writeFileSafe(filePath, `import {
|
|
2319
|
+
await writeFileSafe(filePath, `import {
|
|
2320
|
+
defineAdapter,
|
|
2321
|
+
type AdapterContext,
|
|
2322
|
+
type AdapterMiddleware,
|
|
2323
|
+
type ContributorRegistrations,
|
|
2324
|
+
type Constructor,
|
|
2325
|
+
} from '@forinda/kickjs'
|
|
2382
2326
|
|
|
2383
2327
|
/**
|
|
2384
2328
|
* Configuration for the ${pascal} adapter.
|
|
@@ -2399,7 +2343,12 @@ export interface ${pascal}AdapterConfig {
|
|
|
2399
2343
|
* factory's call / \`.scoped()\` / \`.async()\` surfaces for free.
|
|
2400
2344
|
*
|
|
2401
2345
|
* Hooks into the Application lifecycle to add middleware, routes,
|
|
2402
|
-
* or external service connections.
|
|
2346
|
+
* Context Contributors, or external service connections.
|
|
2347
|
+
*
|
|
2348
|
+
* Every lifecycle hook below is OPTIONAL. The scaffold emits all of
|
|
2349
|
+
* them so adopters can browse what's available and delete what they
|
|
2350
|
+
* don't need — \`build()\` returning \`{}\` is also valid for an adapter
|
|
2351
|
+
* that only contributes config defaults.
|
|
2403
2352
|
*
|
|
2404
2353
|
* @example
|
|
2405
2354
|
* \`\`\`ts
|
|
@@ -2415,59 +2364,126 @@ export interface ${pascal}AdapterConfig {
|
|
|
2415
2364
|
export const ${pascal}Adapter = defineAdapter<${pascal}AdapterConfig>({
|
|
2416
2365
|
name: '${pascal}Adapter',
|
|
2417
2366
|
defaults: {
|
|
2418
|
-
// Default config values go here
|
|
2367
|
+
// Default config values go here. The adopter's overrides shallow-merge
|
|
2368
|
+
// on top of these before \`build()\` runs.
|
|
2419
2369
|
},
|
|
2420
|
-
build: (_config, { name: _name }) =>
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
* 'beforeGlobal' | 'afterGlobal' | 'beforeRoutes' | 'afterRoutes'.
|
|
2425
|
-
*/
|
|
2426
|
-
middleware(): AdapterMiddleware[] {
|
|
2427
|
-
return [
|
|
2428
|
-
// Example: add a custom header to all responses
|
|
2429
|
-
// {
|
|
2430
|
-
// phase: 'beforeGlobal',
|
|
2431
|
-
// handler: (_req, res, next) => {
|
|
2432
|
-
// res.setHeader('X-${pascal}', 'true')
|
|
2433
|
-
// next()
|
|
2434
|
-
// },
|
|
2435
|
-
// },
|
|
2436
|
-
]
|
|
2437
|
-
},
|
|
2438
|
-
|
|
2439
|
-
/**
|
|
2440
|
-
* Called before global middleware. Use this to mount routes that
|
|
2441
|
-
* bypass the middleware stack (health checks, docs UI, static
|
|
2442
|
-
* assets).
|
|
2443
|
-
*/
|
|
2444
|
-
beforeMount(_ctx: AdapterContext): void {
|
|
2445
|
-
// Example:
|
|
2446
|
-
// _ctx.app.get('/${kebab}/status', (_req, res) => res.json({ status: 'ok' }))
|
|
2447
|
-
},
|
|
2448
|
-
|
|
2449
|
-
/**
|
|
2450
|
-
* Called after modules and routes are registered, before the
|
|
2451
|
-
* server starts. Use this for late-stage DI registrations or
|
|
2452
|
-
* config validation.
|
|
2453
|
-
*/
|
|
2454
|
-
beforeStart(_ctx: AdapterContext): void {
|
|
2455
|
-
// Example: _ctx.container.bindToken(MY_TOKEN, new MyService(_config))
|
|
2456
|
-
},
|
|
2457
|
-
|
|
2458
|
-
/**
|
|
2459
|
-
* Called after the HTTP server is listening. Use this to attach
|
|
2460
|
-
* to the raw http.Server (Socket.IO, gRPC, etc).
|
|
2461
|
-
*/
|
|
2462
|
-
afterStart(_ctx: AdapterContext): void {
|
|
2463
|
-
// Example: const io = new Server(_ctx.server)
|
|
2464
|
-
},
|
|
2370
|
+
build: (_config, { name: _name }) => {
|
|
2371
|
+
// Closures inside \`build()\` are how each adapter instance owns its
|
|
2372
|
+
// own state (database client, Map, timer handle, …). The same
|
|
2373
|
+
// \`_config\` is visible to every hook below.
|
|
2465
2374
|
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2375
|
+
return {
|
|
2376
|
+
/**
|
|
2377
|
+
* Express middleware entries the Application mounts at named phases.
|
|
2378
|
+
*
|
|
2379
|
+
* \`phase\` controls where each handler sits in the pipeline:
|
|
2380
|
+
* 'beforeGlobal' | 'afterGlobal' | 'beforeRoutes' | 'afterRoutes'.
|
|
2381
|
+
*
|
|
2382
|
+
* \`path\` (optional) scopes the entry to a path prefix.
|
|
2383
|
+
*
|
|
2384
|
+
* Delete this hook entirely if you don't add middleware.
|
|
2385
|
+
*/
|
|
2386
|
+
middleware(): AdapterMiddleware[] {
|
|
2387
|
+
return [
|
|
2388
|
+
// Example: add a custom header to all responses
|
|
2389
|
+
// {
|
|
2390
|
+
// phase: 'beforeGlobal',
|
|
2391
|
+
// handler: (_req, res, next) => {
|
|
2392
|
+
// res.setHeader('X-${pascal}', 'true')
|
|
2393
|
+
// next()
|
|
2394
|
+
// },
|
|
2395
|
+
// },
|
|
2396
|
+
// Example: scope a rate limiter to one path prefix
|
|
2397
|
+
// {
|
|
2398
|
+
// phase: 'beforeRoutes',
|
|
2399
|
+
// path: '/api/v1/auth',
|
|
2400
|
+
// handler: rateLimit({ max: 10 }),
|
|
2401
|
+
// },
|
|
2402
|
+
]
|
|
2403
|
+
},
|
|
2404
|
+
|
|
2405
|
+
/**
|
|
2406
|
+
* Runs BEFORE global middleware. Mount routes that should bypass the
|
|
2407
|
+
* middleware stack — health checks, docs UI, static assets, OAuth
|
|
2408
|
+
* callbacks. Anything you want reachable even if a global middleware
|
|
2409
|
+
* later in the chain rejects requests.
|
|
2410
|
+
*
|
|
2411
|
+
* Delete this hook if you have no early routes.
|
|
2412
|
+
*/
|
|
2413
|
+
beforeMount(_ctx: AdapterContext): void {
|
|
2414
|
+
// Example:
|
|
2415
|
+
// _ctx.app.get('/${kebab}/status', (_req, res) => res.json({ status: 'ok' }))
|
|
2416
|
+
},
|
|
2417
|
+
|
|
2418
|
+
/**
|
|
2419
|
+
* Fires once per controller class as the router mounts. Use this to
|
|
2420
|
+
* collect route metadata for OpenAPI specs, dependency graphs, route
|
|
2421
|
+
* inventories, devtools dashboards.
|
|
2422
|
+
*
|
|
2423
|
+
* Delete this hook unless your adapter introspects the route registry.
|
|
2424
|
+
*/
|
|
2425
|
+
onRouteMount(_controllerClass: Constructor, _mountPath: string): void {
|
|
2426
|
+
// Example (Swagger-style): collect routes for the spec.
|
|
2427
|
+
// openApiSpec.addController(_controllerClass, _mountPath)
|
|
2428
|
+
},
|
|
2429
|
+
|
|
2430
|
+
/**
|
|
2431
|
+
* Runs AFTER modules + routes are wired, BEFORE the server starts.
|
|
2432
|
+
* Right place for late-stage DI registrations or final config validation.
|
|
2433
|
+
*
|
|
2434
|
+
* Delete this hook if there's nothing to wire post-modules.
|
|
2435
|
+
*/
|
|
2436
|
+
beforeStart(_ctx: AdapterContext): void {
|
|
2437
|
+
// Example: _ctx.container.registerInstance(MY_TOKEN, new MyService(_config))
|
|
2438
|
+
},
|
|
2439
|
+
|
|
2440
|
+
/**
|
|
2441
|
+
* Runs AFTER the HTTP server is listening. The raw \`http.Server\` is
|
|
2442
|
+
* available on \`ctx.server\` — attach upgrade handlers (Socket.IO,
|
|
2443
|
+
* gRPC, GraphQL subscriptions), warm caches, log a banner.
|
|
2444
|
+
*
|
|
2445
|
+
* Delete this hook if you don't need the running server reference.
|
|
2446
|
+
*/
|
|
2447
|
+
afterStart(_ctx: AdapterContext): void {
|
|
2448
|
+
// Example: const io = new Server(_ctx.server)
|
|
2449
|
+
},
|
|
2450
|
+
|
|
2451
|
+
/**
|
|
2452
|
+
* Returns Context Contributors to merge into every route's pipeline
|
|
2453
|
+
* at the \`'adapter'\` precedence level. Per-route handlers can
|
|
2454
|
+
* override the value at the method / class / module level.
|
|
2455
|
+
*
|
|
2456
|
+
* Delete this hook unless your adapter ships typed per-request values
|
|
2457
|
+
* (auth user, tenant, locale, feature flags, geo, etc).
|
|
2458
|
+
*/
|
|
2459
|
+
contributors(): ContributorRegistrations {
|
|
2460
|
+
return [
|
|
2461
|
+
// Example:
|
|
2462
|
+
// import { defineHttpContextDecorator } from '@forinda/kickjs'
|
|
2463
|
+
// declare module '@forinda/kickjs' { interface ContextMeta { ${kebab}: { id: string } } }
|
|
2464
|
+
// const Load${pascal} = defineHttpContextDecorator({
|
|
2465
|
+
// key: '${kebab}',
|
|
2466
|
+
// resolve: (ctx) => ({ id: ctx.req.headers['x-${kebab}-id'] as string }),
|
|
2467
|
+
// })
|
|
2468
|
+
// return [Load${pascal}.registration]
|
|
2469
|
+
]
|
|
2470
|
+
},
|
|
2471
|
+
|
|
2472
|
+
/**
|
|
2473
|
+
* Runs on graceful shutdown (SIGINT/SIGTERM). Clean up long-lived
|
|
2474
|
+
* resources the adapter owns: close connections, flush buffers,
|
|
2475
|
+
* cancel timers. The framework runs every adapter's \`shutdown\`
|
|
2476
|
+
* concurrently via \`Promise.allSettled\` — one failure won't block
|
|
2477
|
+
* sibling adapters.
|
|
2478
|
+
*
|
|
2479
|
+
* Delete this hook if your adapter holds no resources.
|
|
2480
|
+
*/
|
|
2481
|
+
async shutdown(): Promise<void> {
|
|
2482
|
+
// Example: await this.pool.end()
|
|
2483
|
+
// Example: clearInterval(this.heartbeatTimer)
|
|
2484
|
+
},
|
|
2485
|
+
}
|
|
2486
|
+
},
|
|
2471
2487
|
})
|
|
2472
2488
|
`);
|
|
2473
2489
|
files.push(filePath);
|
|
@@ -2741,15 +2757,9 @@ export type ${pascal}DTO = z.infer<typeof ${camel}Schema>
|
|
|
2741
2757
|
const PACKAGE_DEPS = {
|
|
2742
2758
|
auth: "@forinda/kickjs-auth",
|
|
2743
2759
|
swagger: "@forinda/kickjs-swagger",
|
|
2744
|
-
otel: "@forinda/kickjs-otel",
|
|
2745
2760
|
ws: "@forinda/kickjs-ws",
|
|
2746
2761
|
queue: "@forinda/kickjs-queue",
|
|
2747
|
-
|
|
2748
|
-
mailer: "@forinda/kickjs-mailer",
|
|
2749
|
-
graphql: "@forinda/kickjs-graphql",
|
|
2750
|
-
devtools: "@forinda/kickjs-devtools",
|
|
2751
|
-
notifications: "@forinda/kickjs-notifications",
|
|
2752
|
-
"multi-tenant": "@forinda/kickjs-multi-tenant"
|
|
2762
|
+
devtools: "@forinda/kickjs-devtools"
|
|
2753
2763
|
};
|
|
2754
2764
|
/** Generate package.json with template-aware dependencies */
|
|
2755
2765
|
function generatePackageJson(name, template, kickjsVersion, packages = []) {
|
|
@@ -2762,15 +2772,10 @@ function generatePackageJson(name, template, kickjsVersion, packages = []) {
|
|
|
2762
2772
|
pino: "^10.3.1",
|
|
2763
2773
|
"pino-pretty": "^13.1.3"
|
|
2764
2774
|
};
|
|
2765
|
-
if (template === "graphql") {
|
|
2766
|
-
baseDeps["@forinda/kickjs-graphql"] = kickjsVersion;
|
|
2767
|
-
baseDeps["graphql"] = "^16.11.0";
|
|
2768
|
-
}
|
|
2769
2775
|
for (const pkg of packages) {
|
|
2770
2776
|
const dep = PACKAGE_DEPS[pkg];
|
|
2771
2777
|
if (dep && !baseDeps[dep]) baseDeps[dep] = kickjsVersion;
|
|
2772
2778
|
}
|
|
2773
|
-
if (packages.includes("graphql") && !baseDeps["graphql"]) baseDeps["graphql"] = "^16.11.0";
|
|
2774
2779
|
return JSON.stringify({
|
|
2775
2780
|
name,
|
|
2776
2781
|
version: kickjsVersion.replace("^", ""),
|
|
@@ -2970,15 +2975,13 @@ export default defineConfig({
|
|
|
2970
2975
|
function generateReadme(name, template, pm) {
|
|
2971
2976
|
const templateLabels = {
|
|
2972
2977
|
rest: "REST API",
|
|
2973
|
-
graphql: "GraphQL API",
|
|
2974
2978
|
ddd: "Domain-Driven Design",
|
|
2975
2979
|
cqrs: "CQRS + Event-Driven",
|
|
2976
2980
|
minimal: "Minimal"
|
|
2977
2981
|
};
|
|
2978
2982
|
const packages = ["@forinda/kickjs", "@forinda/kickjs-vite"];
|
|
2979
2983
|
if (template !== "minimal") packages.push("@forinda/kickjs-swagger", "@forinda/kickjs-devtools");
|
|
2980
|
-
if (template === "
|
|
2981
|
-
if (template === "cqrs") packages.push("@forinda/kickjs-queue", "@forinda/kickjs-ws", "@forinda/kickjs-otel");
|
|
2984
|
+
if (template === "cqrs") packages.push("@forinda/kickjs-queue", "@forinda/kickjs-ws");
|
|
2982
2985
|
return `# ${name}
|
|
2983
2986
|
|
|
2984
2987
|
A **${templateLabels[template] ?? "REST API"}** built with [KickJS](https://forinda.github.io/kick-js/) — a decorator-driven Node.js framework on Express 5 and TypeScript.
|
|
@@ -3023,11 +3026,11 @@ kick add auth # Authentication (JWT, API key, OAuth)
|
|
|
3023
3026
|
kick add swagger # OpenAPI documentation
|
|
3024
3027
|
kick add ws # WebSocket support
|
|
3025
3028
|
kick add queue # Background job processing
|
|
3026
|
-
kick add mailer # Email sending
|
|
3027
|
-
kick add cron # Scheduled tasks
|
|
3028
3029
|
kick add --list # Show all available packages
|
|
3029
3030
|
\`\`\`
|
|
3030
3031
|
|
|
3032
|
+
For email, scheduled tasks, multi-tenancy, OpenTelemetry, GraphQL, and notifications use the BYO recipes in the [KickJS guides](https://forinda.github.io/kick-js/guide/) — they wire the upstream library through \`defineAdapter()\` / \`definePlugin()\` directly, so you keep control of the integration.
|
|
3033
|
+
|
|
3031
3034
|
## Environment Variables
|
|
3032
3035
|
|
|
3033
3036
|
Copy \`.env.example\` to \`.env\` and configure:
|
|
@@ -3202,8 +3205,8 @@ mistakes:
|
|
|
3202
3205
|
property assignment (\`ctx.tenant = …\`) sticks to the contributor
|
|
3203
3206
|
instance only — the handler instance never sees it.
|
|
3204
3207
|
- **Read across instances via \`ctx.set\` / \`ctx.get\`** (or
|
|
3205
|
-
\`
|
|
3206
|
-
|
|
3208
|
+
\`getRequestValue(key)\` from a service that has no \`ctx\` reference
|
|
3209
|
+
— typed via \`MetaValue<K>\`). \`ctx.req\` works because the underlying
|
|
3207
3210
|
Express request is shared; bespoke property assignments don't.
|
|
3208
3211
|
|
|
3209
3212
|
- **Test isolation** — default to \`Container.create()\` for fresh DI state.
|
|
@@ -3271,7 +3274,7 @@ package additions, env access patterns, troubleshooting) is detailed below.
|
|
|
3271
3274
|
| Module registry | \`src/modules/index.ts\` |
|
|
3272
3275
|
| Feature modules | \`src/modules/<module-name>/\` |
|
|
3273
3276
|
| **Module entry file** | \`src/modules/<name>/<name>.module.ts\` (filename suffix is required — see Vite HMR contract below) |
|
|
3274
|
-
|
|
3277
|
+
| Env values | \`.env\` |
|
|
3275
3278
|
| Env schema (Zod) | \`src/config/index.ts\` |
|
|
3276
3279
|
| TypeScript config | \`tsconfig.json\` |
|
|
3277
3280
|
| Vite config (HMR) | \`vite.config.ts\` |
|
|
@@ -3308,12 +3311,6 @@ ${template === "ddd" ? `\`\`\`
|
|
|
3308
3311
|
├── <name>.repository.ts # Data access
|
|
3309
3312
|
└── <name>.module.ts # Module definition (implements AppModule)
|
|
3310
3313
|
\`\`\`
|
|
3311
|
-
` : template === "graphql" ? `\`\`\`
|
|
3312
|
-
resolvers/
|
|
3313
|
-
├── <name>.resolver.ts # @Resolver, @Query, @Mutation
|
|
3314
|
-
├── <name>.types.ts # GraphQL type definitions
|
|
3315
|
-
└── <name>.service.ts # Business logic
|
|
3316
|
-
\`\`\`
|
|
3317
3314
|
` : template === "rest" ? `\`\`\`
|
|
3318
3315
|
<name>/
|
|
3319
3316
|
├── <name>.controller.ts # HTTP routes (@Controller)
|
|
@@ -3586,15 +3583,7 @@ fast). The \`onError\` hook is async-permitted.
|
|
|
3586
3583
|
|
|
3587
3584
|
Full guide: <https://forinda.github.io/kick-js/guide/context-decorators>.
|
|
3588
3585
|
|
|
3589
|
-
${template === "
|
|
3590
|
-
| Decorator | Purpose |
|
|
3591
|
-
|-----------|---------|
|
|
3592
|
-
| \`@Resolver()\` | GraphQL resolver class |
|
|
3593
|
-
| \`@Query()\` | Query handler |
|
|
3594
|
-
| \`@Mutation()\` | Mutation handler |
|
|
3595
|
-
| \`@Arg('name')\` | Resolver argument |
|
|
3596
|
-
|
|
3597
|
-
` : ""}${template === "cqrs" ? `### Background Jobs
|
|
3586
|
+
${template === "cqrs" ? `### Background Jobs
|
|
3598
3587
|
| Decorator | Purpose |
|
|
3599
3588
|
|-----------|---------|
|
|
3600
3589
|
| \`@Job('name')\` | Queue job handler |
|
|
@@ -3852,10 +3841,11 @@ Precedence high → low: **method > class > module > adapter > global**.
|
|
|
3852
3841
|
Cycles or unmet \`dependsOn\` keys throw \`MissingContributorError\` at boot.
|
|
3853
3842
|
|
|
3854
3843
|
**Critical rules — all stem from the same shared-via-ALS instance model**:
|
|
3855
|
-
- Every per-request stage (middleware → contributors → handler) gets its OWN \`RequestContext\` instance, but they all read/write the SAME \`AsyncLocalStorage\`-backed
|
|
3844
|
+
- Every per-request stage (middleware → contributors → handler) gets its OWN \`RequestContext\` instance, but they all read/write the SAME \`AsyncLocalStorage\`-backed bag.
|
|
3856
3845
|
- **\`resolve\` and \`onError\` must RETURN the value** — the runner writes it via \`ctx.set(key, value)\`. Direct property assignment (\`ctx.tenant = …\`) sticks to one instance only and the handler instance never sees it.
|
|
3857
3846
|
- \`ctx.set('tenant', x)\` then \`ctx.get('tenant')\` works across instances. \`ctx.req.headers[...]\` works (the underlying Express request is shared).
|
|
3858
|
-
- Services
|
|
3847
|
+
- Services with no \`ctx\` reference: \`getRequestValue('tenant')\` returns \`MetaValue<'tenant'> | undefined\` (typed via the augmented \`ContextMeta\`). For \`requestId\` use \`getRequestStore()\`.
|
|
3848
|
+
- **No \`setRequestValue\` — writes flow through \`ctx.set\` or a contributor's return value.** Avoids "spooky action at a distance" where any service can pollute the per-request bag.
|
|
3859
3849
|
|
|
3860
3850
|
**Don't use this for**: response short-circuit, stream mutation, or
|
|
3861
3851
|
pre-route-matching work — keep \`@Middleware()\` for those.
|
|
@@ -3928,7 +3918,6 @@ async function initProject(options) {
|
|
|
3928
3918
|
await writeFileSafe(join(dir, "src/modules/hello/hello.service.ts"), generateHelloService());
|
|
3929
3919
|
await writeFileSafe(join(dir, "src/modules/hello/hello.controller.ts"), generateHelloController());
|
|
3930
3920
|
await writeFileSafe(join(dir, "src/modules/hello/hello.module.ts"), generateHelloModule());
|
|
3931
|
-
if (template === "graphql") await writeFileSafe(join(dir, "src/resolvers/.gitkeep"), "");
|
|
3932
3921
|
await writeFileSafe(join(dir, "kick.config.ts"), generateKickConfig(template, defaultRepo, packageManager));
|
|
3933
3922
|
await writeFileSafe(join(dir, "vitest.config.ts"), generateVitestConfig());
|
|
3934
3923
|
await writeFileSafe(join(dir, "README.md"), generateReadme(name, template, packageManager));
|
|
@@ -3948,7 +3937,7 @@ async function initProject(options) {
|
|
|
3948
3937
|
}
|
|
3949
3938
|
}
|
|
3950
3939
|
try {
|
|
3951
|
-
const { runTypegen } = await import("./typegen-
|
|
3940
|
+
const { runTypegen } = await import("./typegen-B13guHZF.mjs");
|
|
3952
3941
|
await runTypegen({
|
|
3953
3942
|
cwd: dir,
|
|
3954
3943
|
allowDuplicates: true,
|
|
@@ -3984,7 +3973,6 @@ async function initProject(options) {
|
|
|
3984
3973
|
if (!options.installDeps) log(` ${packageManager} install`);
|
|
3985
3974
|
const genHint = {
|
|
3986
3975
|
rest: "kick g module user",
|
|
3987
|
-
graphql: "kick g resolver user",
|
|
3988
3976
|
ddd: "kick g module user --repo drizzle",
|
|
3989
3977
|
cqrs: "kick g module user --pattern cqrs",
|
|
3990
3978
|
minimal: "# add your routes to src/index.ts"
|
|
@@ -4006,7 +3994,6 @@ async function initProject(options) {
|
|
|
4006
3994
|
log(" kick g guard <name> Route guard (auth, roles, etc.)");
|
|
4007
3995
|
log(" kick g adapter <name> AppAdapter with lifecycle hooks");
|
|
4008
3996
|
log(" kick g dto <name> Zod DTO schema");
|
|
4009
|
-
if (template === "graphql") log(" kick g resolver <name> GraphQL resolver");
|
|
4010
3997
|
if (template === "cqrs") log(" kick g job <name> Queue job processor");
|
|
4011
3998
|
log(" kick g config Generate kick.config.ts");
|
|
4012
3999
|
log("");
|
|
@@ -4014,8 +4001,7 @@ async function initProject(options) {
|
|
|
4014
4001
|
log(" kick add <pkg> Install a KickJS package + peers");
|
|
4015
4002
|
log(" kick add --list Show all available packages");
|
|
4016
4003
|
log("");
|
|
4017
|
-
log("Available: auth, swagger,
|
|
4018
|
-
log(" queue, mailer, otel, devtools, multi-tenant, notifications, mcp, testing");
|
|
4004
|
+
log("Available: auth, swagger, drizzle, prisma, ws, queue, devtools, mcp, testing");
|
|
4019
4005
|
log("");
|
|
4020
4006
|
}
|
|
4021
4007
|
//#endregion
|