@swovohq/fuel 0.2.2-alpha.91 → 0.2.2-alpha.93
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/README.md +107 -11
- package/dist/bin/fuel.js +61 -0
- package/dist/bin/fuel.js.map +1 -1
- package/dist/commands/generate-module.d.ts +7 -0
- package/dist/commands/generate-module.d.ts.map +1 -0
- package/dist/commands/generate-module.js +180 -0
- package/dist/commands/generate-module.js.map +1 -0
- package/dist/generators/module/index.d.ts +7 -0
- package/dist/generators/module/index.d.ts.map +1 -0
- package/dist/generators/module/index.js +86 -0
- package/dist/generators/module/index.js.map +1 -0
- package/dist/generators/module/register.d.ts +4 -0
- package/dist/generators/module/register.d.ts.map +1 -0
- package/dist/generators/module/register.js +124 -0
- package/dist/generators/module/register.js.map +1 -0
- package/dist/generators/module/render.d.ts +10 -0
- package/dist/generators/module/render.d.ts.map +1 -0
- package/dist/generators/module/render.js +19 -0
- package/dist/generators/module/render.js.map +1 -0
- package/dist/generators/module/skill.d.ts +3 -0
- package/dist/generators/module/skill.d.ts.map +1 -0
- package/dist/generators/module/skill.js +223 -0
- package/dist/generators/module/skill.js.map +1 -0
- package/dist/generators/module/templates/api.d.ts +14 -0
- package/dist/generators/module/templates/api.d.ts.map +1 -0
- package/dist/generators/module/templates/api.js +363 -0
- package/dist/generators/module/templates/api.js.map +1 -0
- package/dist/generators/module/templates/types-pkg.d.ts +7 -0
- package/dist/generators/module/templates/types-pkg.d.ts.map +1 -0
- package/dist/generators/module/templates/types-pkg.js +56 -0
- package/dist/generators/module/templates/types-pkg.js.map +1 -0
- package/dist/generators/module/templates/web.d.ts +16 -0
- package/dist/generators/module/templates/web.d.ts.map +1 -0
- package/dist/generators/module/templates/web.js +573 -0
- package/dist/generators/module/templates/web.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.registerInAppModule = registerInAppModule;
|
|
37
|
+
exports.registerWebTypesDependency = registerWebTypesDependency;
|
|
38
|
+
const fs = __importStar(require("fs-extra"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
async function registerInAppModule(projectRoot, vars, withAdmin) {
|
|
41
|
+
const appModulePath = path.join(projectRoot, 'apps', 'api', 'src', 'app.module.ts');
|
|
42
|
+
if (!(await fs.pathExists(appModulePath))) {
|
|
43
|
+
throw new Error(`app.module.ts not found at ${appModulePath}`);
|
|
44
|
+
}
|
|
45
|
+
let content = await fs.readFile(appModulePath, 'utf-8');
|
|
46
|
+
const moduleName = `${vars.pascal}Module`;
|
|
47
|
+
const adminModuleName = `Admin${vars.pascal}Module`;
|
|
48
|
+
const importPath = `./${vars.kebab}/${vars.kebab}.module`;
|
|
49
|
+
const adminImportPath = `./${vars.kebab}/admin-${vars.kebab}.module`;
|
|
50
|
+
const insertImport = (src, importLine) => {
|
|
51
|
+
const lastImportMatch = [...src.matchAll(/^import\s[\s\S]*?;$/gm)].pop();
|
|
52
|
+
if (!lastImportMatch || lastImportMatch.index === undefined)
|
|
53
|
+
return src + '\n' + importLine;
|
|
54
|
+
const insertAt = lastImportMatch.index + lastImportMatch[0].length;
|
|
55
|
+
return src.slice(0, insertAt) + '\n' + importLine + src.slice(insertAt);
|
|
56
|
+
};
|
|
57
|
+
const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
58
|
+
// Matches the name inside any brace-delimited import list from the given
|
|
59
|
+
// path, not just a standalone `{ Name }` import, so a pre-existing
|
|
60
|
+
// multi-name import (e.g. `{ FooModule, DashboardModule }`) isn't missed.
|
|
61
|
+
// Commented-out import lines are ignored, and aliased specifiers (`Foo as
|
|
62
|
+
// Bar`) don't count as importing `Foo` since the local binding differs.
|
|
63
|
+
const hasNamedImport = (src, name, fromPath) => {
|
|
64
|
+
const importRe = new RegExp(`import\\s*\\{([^}]*)\\}\\s*from\\s*['"]${escapeRegExp(fromPath)}['"]`, 'g');
|
|
65
|
+
let match;
|
|
66
|
+
while ((match = importRe.exec(src)) !== null) {
|
|
67
|
+
const lineStart = src.lastIndexOf('\n', match.index) + 1;
|
|
68
|
+
const linePrefix = src.slice(lineStart, match.index);
|
|
69
|
+
if (linePrefix.trimStart().startsWith('//'))
|
|
70
|
+
continue;
|
|
71
|
+
const specifiers = match[1].split(',').map((s) => s.trim()).filter(Boolean);
|
|
72
|
+
if (specifiers.includes(name))
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
};
|
|
77
|
+
if (!hasNamedImport(content, moduleName, importPath)) {
|
|
78
|
+
content = insertImport(content, `import { ${moduleName} } from '${importPath}';`);
|
|
79
|
+
}
|
|
80
|
+
if (withAdmin && !hasNamedImport(content, adminModuleName, adminImportPath)) {
|
|
81
|
+
content = insertImport(content, `import { ${adminModuleName} } from '${adminImportPath}';`);
|
|
82
|
+
}
|
|
83
|
+
// Insert into imports array before OptionalApiModulesModule.forRoot()
|
|
84
|
+
const anchor = 'OptionalApiModulesModule.forRoot()';
|
|
85
|
+
if (!content.includes(anchor)) {
|
|
86
|
+
throw new Error(`Could not find "${anchor}" in app.module.ts. Register ${moduleName}${withAdmin ? ` and ${adminModuleName}` : ''} in the imports array manually.`);
|
|
87
|
+
}
|
|
88
|
+
if (!content.includes(`${moduleName},`)) {
|
|
89
|
+
content = content.replace(anchor, `${moduleName},\n ${anchor}`);
|
|
90
|
+
}
|
|
91
|
+
if (withAdmin && !content.includes(`${adminModuleName},`)) {
|
|
92
|
+
content = content.replace(anchor, `${adminModuleName},\n ${anchor}`);
|
|
93
|
+
}
|
|
94
|
+
await fs.writeFile(appModulePath, content, 'utf-8');
|
|
95
|
+
}
|
|
96
|
+
function isPackageManifest(value) {
|
|
97
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
98
|
+
return false;
|
|
99
|
+
const deps = value.dependencies;
|
|
100
|
+
if (deps === undefined)
|
|
101
|
+
return true;
|
|
102
|
+
if (typeof deps !== 'object' || deps === null || Array.isArray(deps))
|
|
103
|
+
return false;
|
|
104
|
+
return Object.values(deps).every((v) => typeof v === 'string');
|
|
105
|
+
}
|
|
106
|
+
async function registerWebTypesDependency(projectRoot, vars) {
|
|
107
|
+
const webPackageJsonPath = path.join(projectRoot, 'apps', 'web', 'package.json');
|
|
108
|
+
if (!(await fs.pathExists(webPackageJsonPath))) {
|
|
109
|
+
throw new Error(`package.json not found at ${webPackageJsonPath}`);
|
|
110
|
+
}
|
|
111
|
+
const content = await fs.readFile(webPackageJsonPath, 'utf-8');
|
|
112
|
+
const depName = `@fuel/${vars.kebab}-types`;
|
|
113
|
+
const parsed = JSON.parse(content);
|
|
114
|
+
if (!isPackageManifest(parsed)) {
|
|
115
|
+
throw new Error(`Invalid package.json at ${webPackageJsonPath}: expected an object with a "dependencies" object of string values.`);
|
|
116
|
+
}
|
|
117
|
+
const pkg = parsed;
|
|
118
|
+
if (pkg.dependencies?.[depName]) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
pkg.dependencies = { ...pkg.dependencies, [depName]: '*' };
|
|
122
|
+
await fs.writeFile(webPackageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf-8');
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=register.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/generators/module/register.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface ModuleVars {
|
|
2
|
+
pascal: string;
|
|
3
|
+
camel: string;
|
|
4
|
+
kebab: string;
|
|
5
|
+
upper: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function render(template: string, vars: ModuleVars): string;
|
|
8
|
+
/** Expects an already-normalized kebab-case name (see `validateName` in generate-module.ts). */
|
|
9
|
+
export declare function toModuleVars(kebab: string): ModuleVars;
|
|
10
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/generators/module/render.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAMjE;AAED,gGAAgG;AAChG,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAKtD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.render = render;
|
|
4
|
+
exports.toModuleVars = toModuleVars;
|
|
5
|
+
function render(template, vars) {
|
|
6
|
+
return template
|
|
7
|
+
.replaceAll('__MODULE_PASCAL__', vars.pascal)
|
|
8
|
+
.replaceAll('__MODULE_CAMEL__', vars.camel)
|
|
9
|
+
.replaceAll('__MODULE_KEBAB__', vars.kebab)
|
|
10
|
+
.replaceAll('__MODULE_UPPER__', vars.upper);
|
|
11
|
+
}
|
|
12
|
+
/** Expects an already-normalized kebab-case name (see `validateName` in generate-module.ts). */
|
|
13
|
+
function toModuleVars(kebab) {
|
|
14
|
+
const camel = kebab.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
15
|
+
const pascal = camel.charAt(0).toUpperCase() + camel.slice(1);
|
|
16
|
+
const upper = kebab.replace(/-/g, '_').toUpperCase();
|
|
17
|
+
return { pascal, camel, kebab, upper };
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/generators/module/render.ts"],"names":[],"mappings":";;AAOA,wBAMC;AAGD,oCAKC;AAdD,SAAgB,MAAM,CAAC,QAAgB,EAAE,IAAgB;IACvD,OAAO,QAAQ;SACZ,UAAU,CAAC,mBAAmB,EAAE,IAAI,CAAC,MAAM,CAAC;SAC5C,UAAU,CAAC,kBAAkB,EAAE,IAAI,CAAC,KAAK,CAAC;SAC1C,UAAU,CAAC,kBAAkB,EAAE,IAAI,CAAC,KAAK,CAAC;SAC1C,UAAU,CAAC,kBAAkB,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;AAC/C,CAAC;AAED,gGAAgG;AAChG,SAAgB,YAAY,CAAC,KAAa;IACxC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA;IAC3E,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAA;IACpD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;AACxC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../../../src/generators/module/skill.ts"],"names":[],"mappings":"AAEA,OAAO,EAAU,KAAK,UAAU,EAAE,MAAM,UAAU,CAAA;AAuKlD,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,OAAO,GAClB,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.updateSkill = updateSkill;
|
|
37
|
+
const fs = __importStar(require("fs-extra"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const render_1 = require("./render");
|
|
40
|
+
const MODULES_END_MARKER = '<!-- FUEL_MODULES_END -->';
|
|
41
|
+
const moduleEntryTemplate = `### __MODULE_PASCAL__ (\`__MODULE_KEBAB__\`)
|
|
42
|
+
|
|
43
|
+
Generated by \`fuel generate:module __MODULE_KEBAB__\`.
|
|
44
|
+
|
|
45
|
+
**API Layer** (\`apps/api/src/__MODULE_KEBAB__/\`):
|
|
46
|
+
|
|
47
|
+
| File | Purpose |
|
|
48
|
+
|---|---|
|
|
49
|
+
| \`__MODULE_KEBAB__.module.ts\` | NestJS \`@Module\` — registers TypeORM entity, service, repository, controller |
|
|
50
|
+
| \`__MODULE_KEBAB__.controller.ts\` | REST endpoints: GET list, GET :id, POST, PUT :id, DELETE :id |
|
|
51
|
+
| \`__MODULE_KEBAB__.service.ts\` | Business logic — delegates to repository, throws typed exceptions |
|
|
52
|
+
| \`__MODULE_KEBAB__.repository.ts\` | TypeORM data access — wraps \`Repository<__MODULE_PASCAL__Item>\` |
|
|
53
|
+
| \`entities/__MODULE_KEBAB__-item.entity.ts\` | TypeORM entity: \`id\`, \`name\`, \`organizationId\`, timestamps |
|
|
54
|
+
| \`dto/create-__MODULE_KEBAB__.dto.ts\` | Create DTO with class-validator decorators |
|
|
55
|
+
| \`dto/update-__MODULE_KEBAB__.dto.ts\` | \`PartialType(Create__MODULE_PASCAL__Dto)\` |
|
|
56
|
+
| \`dto/__MODULE_KEBAB__-list-query.dto.ts\` | Pagination + search + sort query params |
|
|
57
|
+
| \`exceptions/__MODULE_KEBAB__-exceptions.ts\` | \`__MODULE_PASCAL__ItemNotFoundException extends NotFoundException\` |
|
|
58
|
+
|
|
59
|
+
**Web Layer** (\`apps/web/src/\`):
|
|
60
|
+
|
|
61
|
+
| File | Purpose |
|
|
62
|
+
|---|---|
|
|
63
|
+
| \`api/__MODULE_KEBAB__.ts\` | Typed fetch functions: Get/Create/Update/Delete endpoints |
|
|
64
|
+
| \`hooks/__MODULE_KEBAB__/use-__MODULE_KEBAB__-items.ts\` | \`useQuery\` list hook with pagination/search/sort |
|
|
65
|
+
| \`hooks/__MODULE_KEBAB__/use-create-__MODULE_KEBAB__-item.ts\` | \`useMutation\` create hook with cache invalidation |
|
|
66
|
+
| \`hooks/__MODULE_KEBAB__/use-delete-__MODULE_KEBAB__-item.ts\` | \`useMutation\` delete hook with cache invalidation |
|
|
67
|
+
| \`components/__MODULE_KEBAB__/__MODULE_KEBAB__-context.tsx\` | React context — TanStack Table + URL-synced state via nuqs |
|
|
68
|
+
| \`components/__MODULE_KEBAB__/__MODULE_KEBAB__-table.tsx\` | Client component consuming context |
|
|
69
|
+
| \`components/__MODULE_KEBAB__/create-__MODULE_KEBAB__-item-drawer.tsx\` | react-hook-form + zod create form |
|
|
70
|
+
| \`components/__MODULE_KEBAB__/index.ts\` | Barrel exports |
|
|
71
|
+
| \`app/(dashboard)/__MODULE_KEBAB__/page.tsx\` | Next.js server component page |
|
|
72
|
+
| \`app/(dashboard)/__MODULE_KEBAB__/layout.tsx\` | Layout wrapper |
|
|
73
|
+
| \`app/(dashboard)/__MODULE_KEBAB__/__MODULE_KEBAB__-client-layout.tsx\` | Client layout with \`ContextProvider\` |
|
|
74
|
+
|
|
75
|
+
**Types Package** (\`packages/types/__MODULE_KEBAB__/\`):
|
|
76
|
+
|
|
77
|
+
| File | Purpose |
|
|
78
|
+
|---|---|
|
|
79
|
+
| \`src/types.ts\` | \`__MODULE_PASCAL__Item\` interface, Create/Update input types |
|
|
80
|
+
| \`src/index.ts\` | Barrel export |
|
|
81
|
+
|
|
82
|
+
**NestJS Registration**: \`__MODULE_PASCAL__Module\` auto-registered in \`apps/api/src/app.module.ts\`.`;
|
|
83
|
+
const fullSkillTemplate = `# Fuel Module Skill
|
|
84
|
+
|
|
85
|
+
You are an expert in the Fuel full-stack monorepo module pattern. When a developer asks
|
|
86
|
+
you to work on, explain, or extend a generated Fuel module, use the architectural reference
|
|
87
|
+
below to guide your answers.
|
|
88
|
+
|
|
89
|
+
Always follow the exact file naming, import paths, and code patterns described here. Never
|
|
90
|
+
introduce patterns that don't match what is documented.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Generated Modules in This Project
|
|
95
|
+
|
|
96
|
+
${moduleEntryTemplate}
|
|
97
|
+
|
|
98
|
+
${MODULES_END_MARKER}
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Architectural Patterns
|
|
103
|
+
|
|
104
|
+
### API (NestJS) Patterns
|
|
105
|
+
|
|
106
|
+
**Endpoint decoration stack** (read operations):
|
|
107
|
+
\`\`\`typescript
|
|
108
|
+
@UseGuards(BetterAuthOrganizationRolesGuard)
|
|
109
|
+
@SecuredEndpoint(HttpStatus.OK)
|
|
110
|
+
@Get()
|
|
111
|
+
\`\`\`
|
|
112
|
+
|
|
113
|
+
**Endpoint decoration stack** (write operations — require org admin):
|
|
114
|
+
\`\`\`typescript
|
|
115
|
+
@UseGuards(BetterAuthOrganizationRolesGuard)
|
|
116
|
+
@RequireOrganizationAdmin()
|
|
117
|
+
@SecuredEndpoint(HttpStatus.OK)
|
|
118
|
+
@Put(':id')
|
|
119
|
+
\`\`\`
|
|
120
|
+
|
|
121
|
+
**Service pattern:** thin orchestration — delegates to repository, throws typed exceptions.
|
|
122
|
+
|
|
123
|
+
**Repository pattern:** wraps TypeORM \`Repository<T>\`, uses \`createQueryBuilder\` for
|
|
124
|
+
filtered queries, \`addPaginationToQuery\` + \`getPaginatedResult\` from
|
|
125
|
+
\`src/common/utils/pagination\` for pagination.
|
|
126
|
+
|
|
127
|
+
**DTO pattern:** \`class-validator\` decorators + \`@ApiProperty\` for Swagger.
|
|
128
|
+
Update DTOs use \`PartialType\` from \`@nestjs/swagger\`.
|
|
129
|
+
|
|
130
|
+
**Exception pattern:**
|
|
131
|
+
\`\`\`typescript
|
|
132
|
+
export class ItemNotFoundException extends NotFoundException {
|
|
133
|
+
constructor() { super('Item not found.') }
|
|
134
|
+
}
|
|
135
|
+
\`\`\`
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### Web (Next.js) Patterns
|
|
140
|
+
|
|
141
|
+
**API endpoint pattern** (\`apps/web/src/api/*.ts\`):
|
|
142
|
+
\`\`\`typescript
|
|
143
|
+
export const GetItemsEndpoint = async (
|
|
144
|
+
payload: { client: typeof fetch } & PaginationOptions
|
|
145
|
+
): Promise<PaginatedResponse<Item>> => {
|
|
146
|
+
// build URLSearchParams, call client(), return handleResponse()
|
|
147
|
+
}
|
|
148
|
+
\`\`\`
|
|
149
|
+
|
|
150
|
+
**Hook pattern** (\`apps/web/src/hooks/*/\`):
|
|
151
|
+
\`\`\`typescript
|
|
152
|
+
export const useItems = (opts) => {
|
|
153
|
+
const query = useQuery({ queryKey: ['key', opts], queryFn: ... })
|
|
154
|
+
return {
|
|
155
|
+
itemsState: { isLoading, isError, error, data },
|
|
156
|
+
refetchItems: query.refetch,
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
\`\`\`
|
|
160
|
+
|
|
161
|
+
**Context pattern** (\`apps/web/src/components/*/\`):
|
|
162
|
+
\`\`\`typescript
|
|
163
|
+
export const ContextProvider = ({ children }) => {
|
|
164
|
+
// useQueryState from nuqs for URL-synced page/limit/search/sort
|
|
165
|
+
// useReactTable from @tanstack/react-table
|
|
166
|
+
// expose via Context.Provider
|
|
167
|
+
}
|
|
168
|
+
export const useModuleContext = () => { /* guard + return */ }
|
|
169
|
+
\`\`\`
|
|
170
|
+
|
|
171
|
+
**Query key convention:** \`'{module-name}-items'\` (kebab-case, \`-items\` suffix).
|
|
172
|
+
|
|
173
|
+
**URL query param convention:** \`{moduleCamel}_page\`, \`{moduleCamel}_limit\`,
|
|
174
|
+
\`{moduleCamel}_q\`, \`{moduleCamel}_sort\`.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Common Extension Tasks
|
|
179
|
+
|
|
180
|
+
### Add a new field to the entity
|
|
181
|
+
1. Add \`@Column()\` to \`apps/api/src/{module}/entities/{module}-item.entity.ts\`
|
|
182
|
+
2. Add field to \`packages/types/{module}/src/types.ts\`
|
|
183
|
+
3. Add to \`dto/create-{module}.dto.ts\` (with validator) — update DTO inherits via \`PartialType\`
|
|
184
|
+
4. Generate a migration: \`yarn workspace api database:migration:generate\`
|
|
185
|
+
5. Run it: \`yarn workspace api database:migration:run\`
|
|
186
|
+
|
|
187
|
+
### Add a new API endpoint
|
|
188
|
+
1. Add method to \`apps/api/src/{module}/{module}.service.ts\`
|
|
189
|
+
2. Add route to \`apps/api/src/{module}/{module}.controller.ts\` using the decoration stack above
|
|
190
|
+
3. Add fetch function to \`apps/web/src/api/{module}.ts\`
|
|
191
|
+
4. Add React Query hook in \`apps/web/src/hooks/{module}/\`
|
|
192
|
+
|
|
193
|
+
### Add a table column
|
|
194
|
+
Add to the \`columns: ColumnDef<Item>[]\` array in
|
|
195
|
+
\`apps/web/src/components/{module}/{module}-context.tsx\`.
|
|
196
|
+
|
|
197
|
+
### Replace the placeholder form with the design system Drawer
|
|
198
|
+
Replace the plain HTML form in \`create-{module}-item-drawer.tsx\` with the \`Drawer\`
|
|
199
|
+
component from \`@fuel/design-system\`. Follow the pattern in
|
|
200
|
+
\`apps/web/src/components/teams/invitations/invite-member-drawer.tsx\`.
|
|
201
|
+
`;
|
|
202
|
+
async function updateSkill(projectRoot, vars, _withAdmin) {
|
|
203
|
+
const skillDir = path.join(projectRoot, '.claude', 'skills', 'fuel-module');
|
|
204
|
+
const skillPath = path.join(skillDir, 'SKILL.md');
|
|
205
|
+
if (!(await fs.pathExists(skillPath))) {
|
|
206
|
+
await fs.ensureDir(skillDir);
|
|
207
|
+
await fs.writeFile(skillPath, (0, render_1.render)(fullSkillTemplate, vars), 'utf-8');
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
let content = await fs.readFile(skillPath, 'utf-8');
|
|
211
|
+
// Skip if module section already present
|
|
212
|
+
if (content.includes(`\`${vars.kebab}\``))
|
|
213
|
+
return;
|
|
214
|
+
const newSection = (0, render_1.render)(moduleEntryTemplate, vars);
|
|
215
|
+
if (content.includes(MODULES_END_MARKER)) {
|
|
216
|
+
content = content.replace(MODULES_END_MARKER, `${newSection}\n\n${MODULES_END_MARKER}`);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
content += `\n\n${newSection}`;
|
|
220
|
+
}
|
|
221
|
+
await fs.writeFile(skillPath, content, 'utf-8');
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill.js","sourceRoot":"","sources":["../../../src/generators/module/skill.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyKA,kCA+BC;AAxMD,6CAA8B;AAC9B,2CAA4B;AAC5B,qCAAkD;AAElD,MAAM,kBAAkB,GAAG,2BAA2B,CAAA;AAEtD,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wGAyC4E,CAAA;AAExG,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;EAaxB,mBAAmB;;EAEnB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuGnB,CAAA;AAEM,KAAK,UAAU,WAAW,CAC/B,WAAmB,EACnB,IAAgB,EAChB,UAAmB;IAEnB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAA;IAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;IAEjD,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QACtC,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;QAC5B,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,IAAA,eAAM,EAAC,iBAAiB,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAA;QACvE,OAAM;IACR,CAAC;IAED,IAAI,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAEnD,yCAAyC;IACzC,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,KAAK,IAAI,CAAC;QAAE,OAAM;IAEjD,MAAM,UAAU,GAAG,IAAA,eAAM,EAAC,mBAAmB,EAAE,IAAI,CAAC,CAAA;IAEpD,IAAI,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACzC,OAAO,GAAG,OAAO,CAAC,OAAO,CACvB,kBAAkB,EAClB,GAAG,UAAU,OAAO,kBAAkB,EAAE,CACzC,CAAA;IACH,CAAC;SAAM,CAAC;QACN,OAAO,IAAI,OAAO,UAAU,EAAE,CAAA;IAChC,CAAC;IAED,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;AACjD,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const apiTemplates: {
|
|
2
|
+
module: string;
|
|
3
|
+
controller: string;
|
|
4
|
+
service: string;
|
|
5
|
+
repository: string;
|
|
6
|
+
entity: string;
|
|
7
|
+
dtoCreate: string;
|
|
8
|
+
dtoUpdate: string;
|
|
9
|
+
dtoListQuery: string;
|
|
10
|
+
exceptions: string;
|
|
11
|
+
adminController: string;
|
|
12
|
+
adminModule: string;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/generators/module/templates/api.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY;;;;;;;;;;;;CAgXxB,CAAA"}
|