@abgov/nx-adsp 12.11.0 → 12.12.1
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/package.json +1 -1
- package/src/generators/express-service/express-service.js +7 -6
- package/src/generators/express-service/express-service.js.map +1 -1
- package/src/generators/express-service/express-service.spec.ts +12 -0
- package/src/generators/express-service/files/AGENTS.md__tmpl__ +33 -5
- package/src/generators/express-service/files/src/environment.ts__tmpl__ +1 -1
- package/src/generators/express-service/files/src/events.ts__tmpl__ +0 -2
- package/src/generators/express-service/files/src/main.ts__tmpl__ +25 -2
package/package.json
CHANGED
|
@@ -53,11 +53,11 @@ function addFiles(host, options) {
|
|
|
53
53
|
}
|
|
54
54
|
function default_1(host, options) {
|
|
55
55
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
56
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
56
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
57
57
|
const normalizedOptions = yield normalizeOptions(host, options);
|
|
58
58
|
const { applicationGenerator: initExpress } = yield Promise.resolve().then(() => require('@nx/express'));
|
|
59
59
|
yield initExpress(host, Object.assign(Object.assign({}, options), { skipFormat: true, skipPackageJson: false, linter: eslint_1.Linter.EsLint, unitTestRunner: 'jest', js: false, directory: `apps/${options.name}` }));
|
|
60
|
-
(0, devkit_1.addDependenciesToPackageJson)(host, Object.assign(Object.assign({ '@abgov/adsp-service-sdk': '^2.
|
|
60
|
+
(0, devkit_1.addDependenciesToPackageJson)(host, Object.assign(Object.assign({ '@abgov/adsp-service-sdk': '^2.23.0', compression: '^1.8.1', cors: '^2.8.5', dotenv: '^16.4.7', envalid: '^8.0.0', helmet: '^8.0.0', passport: '^0.7.0', 'passport-anonymous': '^1.0.1', zod: '^3.0.0' }, (normalizedOptions.database === 'postgres' ? { '@prisma/client': '^6.0.0' } : {})), (normalizedOptions.database === 'mongo' ? { mongoose: '^8.0.0' } : {})), Object.assign({ '@types/compression': '^1.7.5', '@types/cors': '^2.8.17', '@types/passport': '^1.0.16', '@types/passport-anonymous': '^1.0.3' }, (normalizedOptions.database === 'postgres' ? { prisma: '^6.0.0' } : {})));
|
|
61
61
|
addFiles(host, normalizedOptions);
|
|
62
62
|
if (normalizedOptions.database !== 'none') {
|
|
63
63
|
const projectConfig = (0, devkit_1.readProjectConfiguration)(host, normalizedOptions.projectName);
|
|
@@ -124,15 +124,16 @@ function default_1(host, options) {
|
|
|
124
124
|
}));
|
|
125
125
|
const mainTs = (_e = (_d = host.read(`${normalizedOptions.projectRoot}/src/main.ts`)) === null || _d === void 0 ? void 0 : _d.toString()) !== null && _e !== void 0 ? _e : '';
|
|
126
126
|
const environmentTs = (_g = (_f = host.read(`${normalizedOptions.projectRoot}/src/environment.ts`)) === null || _f === void 0 ? void 0 : _f.toString()) !== null && _g !== void 0 ? _g : '';
|
|
127
|
+
const eventsTs = (_j = (_h = host.read(`${normalizedOptions.projectRoot}/src/events.ts`)) === null || _h === void 0 ? void 0 : _h.toString()) !== null && _j !== void 0 ? _j : '';
|
|
128
|
+
const databaseTs = normalizedOptions.database !== 'none'
|
|
129
|
+
? (_l = (_k = host.read(`${normalizedOptions.projectRoot}/src/database.ts`)) === null || _k === void 0 ? void 0 : _k.toString()) !== null && _l !== void 0 ? _l : ''
|
|
130
|
+
: undefined;
|
|
127
131
|
const agentResult = yield (0, agent_1.consultAgent)(normalizedOptions.adsp.directoryServiceUrl, accessToken, {
|
|
128
132
|
projectName: normalizedOptions.projectName,
|
|
129
133
|
projectType: 'express-service',
|
|
130
134
|
tenant: normalizedOptions.adsp.tenant,
|
|
131
135
|
pluginVersion: plugin_version_1.PLUGIN_VERSION,
|
|
132
|
-
existingFiles: {
|
|
133
|
-
'src/main.ts': mainTs,
|
|
134
|
-
'src/environment.ts': environmentTs,
|
|
135
|
-
},
|
|
136
|
+
existingFiles: Object.assign({ 'src/main.ts': mainTs, 'src/environment.ts': environmentTs, 'src/events.ts': eventsTs }, (databaseTs ? { 'src/database.ts': databaseTs } : {})),
|
|
136
137
|
}, host, normalizedOptions.projectRoot);
|
|
137
138
|
// When the agent interaction ended without generating files — whether the
|
|
138
139
|
// user was in a conversation or Ctrl+C'd before the agent responded —
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express-service.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/express-service/express-service.ts"],"names":[],"mappings":";;AA8FA,
|
|
1
|
+
{"version":3,"file":"express-service.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/express-service/express-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -35,6 +35,18 @@ describe('Express Service Generator', () => {
|
|
|
35
35
|
expect(host.exists('apps/test/src/environments/environment.ts')).toBeFalsy();
|
|
36
36
|
}, 60000);
|
|
37
37
|
|
|
38
|
+
it('includes authorize, createValidationHandler, and example route in main.ts', async () => {
|
|
39
|
+
const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
40
|
+
await generator(host, options);
|
|
41
|
+
|
|
42
|
+
const mainTs = host.read('apps/test/src/main.ts').toString();
|
|
43
|
+
expect(mainTs).toContain('authorize');
|
|
44
|
+
expect(mainTs).toContain('createValidationHandler');
|
|
45
|
+
expect(mainTs).toContain('createErrorHandler');
|
|
46
|
+
expect(mainTs).toContain('/v1/example');
|
|
47
|
+
expect(mainTs).toContain('eventService.send');
|
|
48
|
+
}, 60000);
|
|
49
|
+
|
|
38
50
|
it('scaffolds postgres database files and targets', async () => {
|
|
39
51
|
const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
40
52
|
await generator(host, { ...options, database: 'postgres' });
|
|
@@ -53,18 +53,46 @@ const token = await tokenProvider.getAccessToken();
|
|
|
53
53
|
|
|
54
54
|
## Adding routes
|
|
55
55
|
|
|
56
|
-
Add route handlers in `main.ts` under the `/<%= projectName %>/v1` path prefix
|
|
56
|
+
Add route handlers in `main.ts` under the `/<%= projectName %>/v1` path prefix.
|
|
57
|
+
`passport.authenticate(['tenant', 'anonymous'])` is applied to the entire prefix —
|
|
58
|
+
`req.user` is null for anonymous requests and populated for authenticated ones.
|
|
57
59
|
|
|
60
|
+
**Public route:**
|
|
58
61
|
```typescript
|
|
59
62
|
app.get('/<%= projectName %>/v1/my-resource', (req, res) => {
|
|
60
|
-
const user = req.user; // null for anonymous, populated for authenticated
|
|
61
63
|
res.json({ ... });
|
|
62
64
|
});
|
|
63
65
|
```
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
**Protected route** (requires a role, validates input, publishes an event):
|
|
68
|
+
```typescript
|
|
69
|
+
import { authorize, createValidationHandler } from '@abgov/adsp-service-sdk';
|
|
70
|
+
import { z } from 'zod';
|
|
71
|
+
|
|
72
|
+
const MySchema = z.object({ name: z.string().min(1) });
|
|
73
|
+
|
|
74
|
+
app.post(
|
|
75
|
+
'/<%= projectName %>/v1/my-resource',
|
|
76
|
+
authorize('my-role'), // 403 if authenticated user lacks role
|
|
77
|
+
createValidationHandler(MySchema), // 400 if body fails schema
|
|
78
|
+
async (req, res, next) => {
|
|
79
|
+
try {
|
|
80
|
+
const { name } = req.body as z.infer<typeof MySchema>;
|
|
81
|
+
eventService.send(createMyEvent(name));
|
|
82
|
+
res.json({ name });
|
|
83
|
+
} catch (err) {
|
|
84
|
+
next(err); // createErrorHandler maps to 500
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Both `authorize` and `createValidationHandler` pass errors to `next()` —
|
|
91
|
+
`createErrorHandler(logger)` at the bottom of `main.ts` translates them to
|
|
92
|
+
structured HTTP responses (401/403 and 400 respectively).
|
|
93
|
+
|
|
94
|
+
See the `ExampleRequestSchema` and example route already in `main.ts` as a
|
|
95
|
+
starting point — replace or remove it once you have real business logic.
|
|
68
96
|
<% if (database === 'postgres') { %>
|
|
69
97
|
|
|
70
98
|
## Local database
|
|
@@ -21,7 +21,7 @@ export const environment = cleanEnv(process.env, {
|
|
|
21
21
|
CLIENT_SECRET: str({ default: '' }),
|
|
22
22
|
TRUSTED_PROXY: str({ default: 'uniquelocal' }),
|
|
23
23
|
LOG_LEVEL: str({ default: 'debug' }),
|
|
24
|
-
PORT: num({ default:
|
|
24
|
+
PORT: num({ default: 3333 }),
|
|
25
25
|
<% if (database === 'postgres') { %>
|
|
26
26
|
DATABASE_URL: str(),
|
|
27
27
|
<% } else if (database === 'mongo') { %>
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
import { AdspId, createErrorHandler, initializeService } from '@abgov/adsp-service-sdk';
|
|
1
|
+
import { AdspId, authorize, createErrorHandler, createValidationHandler, initializeService } from '@abgov/adsp-service-sdk';
|
|
2
2
|
import compression from 'compression';
|
|
3
3
|
import cors from 'cors';
|
|
4
4
|
import express from 'express';
|
|
5
5
|
import helmet from 'helmet';
|
|
6
6
|
import passport from 'passport';
|
|
7
7
|
import { Strategy as AnonymousStrategy } from 'passport-anonymous';
|
|
8
|
+
import { z } from 'zod';
|
|
8
9
|
<% if (database === 'postgres') { %>
|
|
9
10
|
import { prisma } from './database';
|
|
10
11
|
<% } else if (database === 'mongo') { %>
|
|
11
12
|
import { connectDatabase, disconnectDatabase } from './database';
|
|
12
13
|
<% } %>
|
|
13
14
|
import { environment } from './environment';
|
|
14
|
-
import { exampleEventDefinition } from './events';
|
|
15
|
+
import { createExampleEvent, exampleEventDefinition } from './events';
|
|
16
|
+
|
|
17
|
+
const ExampleRequestSchema = z.object({
|
|
18
|
+
id: z.string().min(1),
|
|
19
|
+
});
|
|
15
20
|
|
|
16
21
|
async function initializeApp() {
|
|
17
22
|
const serviceId = AdspId.parse(environment.CLIENT_ID);
|
|
@@ -81,6 +86,24 @@ async function initializeApp() {
|
|
|
81
86
|
});
|
|
82
87
|
});
|
|
83
88
|
|
|
89
|
+
// Example: protected route demonstrating authorize, input validation, and a domain event.
|
|
90
|
+
// Require 'example-role' — replace with a role relevant to your service.
|
|
91
|
+
// Remove or replace this route once you have real business logic.
|
|
92
|
+
app.post(
|
|
93
|
+
'/<%= projectName %>/v1/example',
|
|
94
|
+
authorize('example-role'),
|
|
95
|
+
createValidationHandler(ExampleRequestSchema),
|
|
96
|
+
async (req, res, next) => {
|
|
97
|
+
try {
|
|
98
|
+
const { id } = req.body as z.infer<typeof ExampleRequestSchema>;
|
|
99
|
+
eventService.send(createExampleEvent(id));
|
|
100
|
+
res.json({ id });
|
|
101
|
+
} catch (err) {
|
|
102
|
+
next(err);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
|
|
84
107
|
// Mount error handler last — after all routes and middleware.
|
|
85
108
|
app.use(createErrorHandler(logger));
|
|
86
109
|
|