go-duck-cli 1.3.2 → 1.3.5
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 +4 -1
- package/generators/ai_docs.js +14 -11
- package/generators/config.js +6 -1
- package/generators/devops.js +86 -17
- package/generators/docs.js +1 -1
- package/generators/mqtt-topics.js +54 -0
- package/generators/postman.js +24 -20
- package/generators/router.js +8 -1
- package/generators/swagger.js +26 -23
- package/index.js +10 -1
- package/package.json +22 -1
- package/templates/docs/pages/index.hbs +12 -2
- package/templates/docs/pages/integrations.hbs +6 -1
- package/templates/docs/pages/mosquitto.hbs +6 -0
- package/templates/go/router.go.hbs +467 -15
package/generators/swagger.js
CHANGED
|
@@ -6,6 +6,9 @@ export const generateSwaggerDocs = async (config, entities, outputDir, openEntit
|
|
|
6
6
|
const docsDir = path.join(outputDir, 'docs');
|
|
7
7
|
await fs.ensureDir(docsDir);
|
|
8
8
|
|
|
9
|
+
const apiPrefixRaw = config.server?.rest?.['api-path-prefix'] || '/api';
|
|
10
|
+
const apiPrefix = apiPrefixRaw.endsWith('/') ? apiPrefixRaw.slice(0, -1) : apiPrefixRaw;
|
|
11
|
+
|
|
9
12
|
const swagger = {
|
|
10
13
|
openapi: '3.0.0',
|
|
11
14
|
info: {
|
|
@@ -14,7 +17,7 @@ export const generateSwaggerDocs = async (config, entities, outputDir, openEntit
|
|
|
14
17
|
description: `Generated documentation for ${config.name} microservice`
|
|
15
18
|
},
|
|
16
19
|
servers: [
|
|
17
|
-
{ url:
|
|
20
|
+
{ url: "/", description: "Current Host" }
|
|
18
21
|
],
|
|
19
22
|
paths: {},
|
|
20
23
|
components: {
|
|
@@ -48,7 +51,7 @@ export const generateSwaggerDocs = async (config, entities, outputDir, openEntit
|
|
|
48
51
|
};
|
|
49
52
|
|
|
50
53
|
const commonHeaders = [
|
|
51
|
-
{ name: 'X-Tenant-ID', in: 'header', required:
|
|
54
|
+
{ name: 'X-Tenant-ID', in: 'header', required: false, schema: { type: 'string', default: 'default' }, description: 'Multi-tenancy context identifier' }
|
|
52
55
|
];
|
|
53
56
|
|
|
54
57
|
const isOpen = (entityName, action) => {
|
|
@@ -81,7 +84,7 @@ export const generateSwaggerDocs = async (config, entities, outputDir, openEntit
|
|
|
81
84
|
properties: {
|
|
82
85
|
id: { type: 'integer' },
|
|
83
86
|
...entity.fields.reduce((acc, field) => {
|
|
84
|
-
acc[field.name] =
|
|
87
|
+
acc[field.name] = getSwaggerFieldSchema(field.type);
|
|
85
88
|
return acc;
|
|
86
89
|
}, {}),
|
|
87
90
|
createdAt: { type: 'string', format: 'date-time' },
|
|
@@ -201,14 +204,14 @@ export const generateSwaggerDocs = async (config, entities, outputDir, openEntit
|
|
|
201
204
|
};
|
|
202
205
|
|
|
203
206
|
// 1a. Secured Paths
|
|
204
|
-
addEntityOperations(
|
|
207
|
+
addEntityOperations(apiPrefix, false);
|
|
205
208
|
|
|
206
209
|
// 1b. Public Paths (if marked as open)
|
|
207
|
-
addEntityOperations('/open
|
|
210
|
+
addEntityOperations('/open' + apiPrefix, true);
|
|
208
211
|
}
|
|
209
212
|
|
|
210
213
|
// 2. Add System Paths
|
|
211
|
-
swagger.paths[
|
|
214
|
+
swagger.paths[`${apiPrefix}/rpc/{table}`] = {
|
|
212
215
|
get: {
|
|
213
216
|
tags: ['Search Engine'],
|
|
214
217
|
summary: 'Generic PostgREST RPC Engine',
|
|
@@ -240,7 +243,7 @@ export const generateSwaggerDocs = async (config, entities, outputDir, openEntit
|
|
|
240
243
|
}
|
|
241
244
|
};
|
|
242
245
|
|
|
243
|
-
swagger.paths[
|
|
246
|
+
swagger.paths[`${apiPrefix}/admin/audit`] = {
|
|
244
247
|
get: {
|
|
245
248
|
tags: ['Observability'],
|
|
246
249
|
summary: 'Fetch Audit Trail',
|
|
@@ -270,7 +273,7 @@ export const generateSwaggerDocs = async (config, entities, outputDir, openEntit
|
|
|
270
273
|
}
|
|
271
274
|
},
|
|
272
275
|
parameters: [
|
|
273
|
-
{ name: 'X-Tenant-ID', in: 'header', required:
|
|
276
|
+
{ name: 'X-Tenant-ID', in: 'header', required: false, schema: { type: 'string', default: 'master_internal' }, description: 'SuperAdmin internal master bypass token' }
|
|
274
277
|
],
|
|
275
278
|
responses: {
|
|
276
279
|
200: { description: 'Success' },
|
|
@@ -281,7 +284,7 @@ export const generateSwaggerDocs = async (config, entities, outputDir, openEntit
|
|
|
281
284
|
};
|
|
282
285
|
|
|
283
286
|
if (config.elasticsearch?.enabled) {
|
|
284
|
-
swagger.paths[
|
|
287
|
+
swagger.paths[`${apiPrefix}/search/{entity}`] = {
|
|
285
288
|
get: {
|
|
286
289
|
tags: ['Search Engine'],
|
|
287
290
|
summary: 'Elasticsearch Global Search',
|
|
@@ -315,19 +318,19 @@ export const generateSwaggerDocs = async (config, entities, outputDir, openEntit
|
|
|
315
318
|
console.log(chalk.gray(' Generated Swagger Documentation: swagger.json'));
|
|
316
319
|
};
|
|
317
320
|
|
|
318
|
-
const
|
|
319
|
-
const
|
|
320
|
-
'String': 'string',
|
|
321
|
-
'Integer': 'integer',
|
|
322
|
-
'Float': 'number',
|
|
323
|
-
'Boolean': 'boolean',
|
|
324
|
-
'Long': 'integer',
|
|
325
|
-
'BigDecimal': 'number',
|
|
326
|
-
'LocalDate': 'string',
|
|
327
|
-
'Instant': 'string',
|
|
328
|
-
'JSON': 'object',
|
|
329
|
-
'JSONB': 'object',
|
|
330
|
-
'Text': 'string'
|
|
321
|
+
const getSwaggerFieldSchema = (type) => {
|
|
322
|
+
const schemas = {
|
|
323
|
+
'String': { type: 'string' },
|
|
324
|
+
'Integer': { type: 'integer', format: 'int32' },
|
|
325
|
+
'Float': { type: 'number', format: 'double' },
|
|
326
|
+
'Boolean': { type: 'boolean' },
|
|
327
|
+
'Long': { type: 'integer', format: 'int64' },
|
|
328
|
+
'BigDecimal': { type: 'number', format: 'double' },
|
|
329
|
+
'LocalDate': { type: 'string', format: 'date' },
|
|
330
|
+
'Instant': { type: 'string', format: 'date-time' },
|
|
331
|
+
'JSON': { type: 'object' },
|
|
332
|
+
'JSONB': { type: 'object' },
|
|
333
|
+
'Text': { type: 'string' }
|
|
331
334
|
};
|
|
332
|
-
return
|
|
335
|
+
return schemas[type] || { type: 'string' };
|
|
333
336
|
};
|
package/index.js
CHANGED
|
@@ -31,6 +31,7 @@ import { generateWebSocketCode } from './generators/websocket.js';
|
|
|
31
31
|
import { generateConfigLoader } from './generators/config.js';
|
|
32
32
|
import { generateLoggerCode } from './generators/logger.js';
|
|
33
33
|
import { generateMQTTCode } from './generators/mqtt.js';
|
|
34
|
+
import { generateMQTTTopicsJSON } from './generators/mqtt-topics.js';
|
|
34
35
|
import { generateCacheCode } from './generators/cache.js';
|
|
35
36
|
import { generateResilienceCode } from './generators/resilience.js';
|
|
36
37
|
import { generateTelemetryCode } from './generators/telemetry.js';
|
|
@@ -875,13 +876,21 @@ const generateYAMLConfigs = async (config, outputDir) => {
|
|
|
875
876
|
delete cleanConfig.datasource['multitenancy-databases'];
|
|
876
877
|
}
|
|
877
878
|
|
|
879
|
+
const toKebabCase = (str) => {
|
|
880
|
+
if (!str) return '';
|
|
881
|
+
return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
const rawApiPrefix = cleanConfig.server?.rest?.['api-path-prefix'] || `/${cleanConfig.name || 'api'}/api`;
|
|
885
|
+
const kebabApiPrefix = rawApiPrefix.split('/').map(segment => toKebabCase(segment)).join('/');
|
|
886
|
+
|
|
878
887
|
const extendedConfig = {
|
|
879
888
|
...cleanConfig,
|
|
880
889
|
server: {
|
|
881
890
|
rest: {
|
|
882
891
|
port: cleanConfig.server?.rest?.port || cleanConfig.server?.port || 8080,
|
|
883
892
|
protocol: cleanConfig.server?.rest?.protocol || 'json',
|
|
884
|
-
'api-path-prefix':
|
|
893
|
+
'api-path-prefix': kebabApiPrefix
|
|
885
894
|
},
|
|
886
895
|
'read-timeout': cleanConfig.server?.['read-timeout'] || '30s',
|
|
887
896
|
'write-timeout': cleanConfig.server?.['write-timeout'] || '30s',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "go-duck-cli",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.5",
|
|
4
4
|
"description": "The Ultimate Evolutionary Go Microservice Scaffolder.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
12
|
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=18.0.0"
|
|
15
|
+
},
|
|
13
16
|
"author": "heavenscode",
|
|
14
17
|
"license": "ISC",
|
|
15
18
|
"dependencies": {
|
|
@@ -21,5 +24,23 @@
|
|
|
21
24
|
"inquirer": "^8.2.7",
|
|
22
25
|
"js-yaml": "^4.1.1",
|
|
23
26
|
"open": "^11.0.0"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"go",
|
|
30
|
+
"golang",
|
|
31
|
+
"microservice",
|
|
32
|
+
"scaffold",
|
|
33
|
+
"cli",
|
|
34
|
+
"generator",
|
|
35
|
+
"go-duck"
|
|
36
|
+
],
|
|
37
|
+
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/heavenscode/go-duck.git"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://goduck.theheavenscode.com",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/heavenscode/go-duck/issues"
|
|
24
45
|
}
|
|
25
46
|
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
|
|
17
17
|
<span class="relative inline-flex rounded-full h-3 w-3 bg-emerald-500"></span>
|
|
18
18
|
</span>
|
|
19
|
-
<p class="text-[11px] font-black text-indigo-900 uppercase tracking-[0.25em]">The
|
|
19
|
+
<p class="text-[11px] font-black text-indigo-900 uppercase tracking-[0.25em]">The 420% Elite Milestone Surpassed</p>
|
|
20
20
|
</div>
|
|
21
21
|
|
|
22
22
|
<!-- Heroic Logo Anchor (Enhanced) -->
|
|
@@ -121,6 +121,16 @@
|
|
|
121
121
|
</div>
|
|
122
122
|
</div>
|
|
123
123
|
|
|
124
|
+
<div class="lg:col-span-12 bg-white p-10 rounded-[2.5rem] border border-amber-100 shadow-sm hover:shadow-2xl transition-all group relative overflow-hidden cursor-crosshair bg-gradient-to-br from-white to-amber-50/30">
|
|
125
|
+
<p class="text-[9px] font-bold text-amber-600 uppercase tracking-widest mb-4">Elite Extension (+10%)</p>
|
|
126
|
+
<h4 class="text-2xl font-black text-slate-900 mb-3 tracking-tight italic">API Gateway Standards & Swagger UI</h4>
|
|
127
|
+
<p class="text-slate-600 leading-relaxed mb-8">Natively exposes OpenAPI JSON at the JHipster-standard <code>/v3/api-docs</code> endpoint. Features a completely re-engineered, glassmorphism Swagger UI deeply integrated with Keycloak SSO and automatic token refreshing.</p>
|
|
128
|
+
<div class="flex gap-3">
|
|
129
|
+
<span class="px-4 py-1.5 bg-amber-100 text-amber-700 text-[9px] font-black rounded-lg">JHIPSTER COMPATIBLE</span>
|
|
130
|
+
<span class="px-4 py-1.5 bg-amber-100 text-amber-700 text-[9px] font-black rounded-lg">KEYCLOAK SSO UI</span>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
124
134
|
<div class="lg:col-span-12 bg-white p-10 rounded-[2.5rem] border border-fuchsia-100 shadow-sm hover:shadow-2xl transition-all group relative overflow-hidden cursor-crosshair bg-gradient-to-br from-white to-fuchsia-50/30">
|
|
125
135
|
<p class="text-[9px] font-bold text-fuchsia-600 uppercase tracking-widest mb-4">Elite Extension (+12%)</p>
|
|
126
136
|
<h4 class="text-2xl font-black text-slate-900 mb-3 tracking-tight italic">K8s Network Isolation & NodePorts</h4>
|
|
@@ -436,7 +446,7 @@
|
|
|
436
446
|
</div>
|
|
437
447
|
|
|
438
448
|
<div class="mt-24 text-slate-500 font-mono text-[10px] uppercase tracking-[0.6em] font-black relative z-10">
|
|
439
|
-
GO-DUCK • THE
|
|
449
|
+
GO-DUCK • THE 420% ELITE MILESTONE • SOVEREIGN CODE ORCHESTRATION
|
|
440
450
|
</div>
|
|
441
451
|
</div>
|
|
442
452
|
</section>
|
|
@@ -86,8 +86,13 @@ class ApiProvider {
|
|
|
86
86
|
<h2 class="text-2xl font-bold text-gray-800 mb-4 border-b pb-2">3. WSO2 API Manager Integration</h2>
|
|
87
87
|
<p class="mb-4">GO-DUCK generated APIs can automatically register themselves with a <strong>WSO2 API Manager</strong> instance on startup. This uses the WSO2 Publisher REST API to import your dynamically generated OpenAPI 3.0 specs.</p>
|
|
88
88
|
|
|
89
|
+
<div class="bg-indigo-50 border-l-4 border-indigo-500 p-4 mb-6 rounded-r">
|
|
90
|
+
<h4 class="font-bold text-indigo-900 mb-1">Standard API Gateway Discovery</h4>
|
|
91
|
+
<p class="text-sm text-indigo-800">For external gateways (Kong, Apigee) and ecosystems like <strong>JHipster</strong> and <strong>Spring Boot</strong>, your microservice natively exposes its OpenAPI JSON at the standard <code>/v3/api-docs</code> endpoint. Legacy systems can still use <code>/swagger.json</code>.</p>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
89
94
|
<div class="bg-blue-50 border-l-4 border-blue-500 p-4 mb-6 rounded-r">
|
|
90
|
-
<p class="text-blue-900"><strong>Configuration:</strong> Enable this by adding the <code>wso2</code> block to your <code>config.yaml</code>.</p>
|
|
95
|
+
<p class="text-blue-900"><strong>WSO2 Configuration:</strong> Enable this by adding the <code>wso2</code> block to your <code>config.yaml</code>.</p>
|
|
91
96
|
</div>
|
|
92
97
|
|
|
93
98
|
<pre><code class="language-yaml">go-duck:
|
|
@@ -29,6 +29,12 @@ messaging.Publish("events/users", event)</code></pre>
|
|
|
29
29
|
mosquitto_sub -h localhost -p {{mqttPort}} -t "audit/logs/#" -v</code></pre>
|
|
30
30
|
</section>
|
|
31
31
|
|
|
32
|
+
<section class="mb-10">
|
|
33
|
+
<h2 class="text-2xl font-bold text-gray-800 mb-4 border-b pb-2">Interactive Swagger Console</h2>
|
|
34
|
+
<p class="mb-4">GO-DUCK's automatically generated Swagger UI features a built-in <strong>Interactive MQTT Topics Dictionary</strong>. By connecting via WebSockets, it allows authenticated users to dynamically <strong>SUBSCRIBE</strong> to event streams or <strong>PUBLISH</strong> payloads directly from the documentation interface!</p>
|
|
35
|
+
<p class="mb-4 text-sm text-gray-600 italic">Note: Ensure your Mosquitto broker is configured to accept WebSocket connections (default port 9001) for this feature to work.</p>
|
|
36
|
+
</section>
|
|
37
|
+
|
|
32
38
|
<section class="mb-10">
|
|
33
39
|
<h2 class="text-2xl font-bold text-gray-800 mb-4 border-b pb-2">External Resources</h2>
|
|
34
40
|
<ul class="space-y-2">
|