@abgov/nx-adsp 13.7.4 → 13.9.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/README.md +13 -1
- package/package.json +1 -1
- package/src/generators/angular-app/angular-app.js +12 -8
- package/src/generators/angular-app/angular-app.js.map +1 -1
- package/src/generators/angular-app/angular-app.spec.ts +5 -0
- package/src/generators/express-service/express-service.js +16 -45
- package/src/generators/express-service/express-service.js.map +1 -1
- package/src/generators/express-service/express-service.spec.ts +39 -0
- package/src/generators/express-service/files/AGENTS.md__tmpl__ +31 -0
- package/src/generators/express-service/files/src/main.ts__tmpl__ +23 -0
- package/src/generators/express-service/files/src/openapi.ts__tmpl__ +19 -0
- package/src/generators/express-service/files/src/routes/example.ts__tmpl__ +73 -0
- package/src/generators/mean/mean.spec.ts +5 -0
- package/src/generators/mern/mern.spec.ts +5 -0
- package/src/generators/mevn/mevn.spec.ts +5 -0
- package/src/generators/pean/pean.spec.ts +5 -0
- package/src/generators/pern/pern.spec.ts +5 -0
- package/src/generators/pevn/pevn.spec.ts +5 -0
- package/src/generators/react-app/react-app.js +12 -8
- package/src/generators/react-app/react-app.js.map +1 -1
- package/src/generators/react-app/react-app.spec.ts +5 -0
- package/src/generators/react-dotnet/react-dotnet.spec.ts +5 -0
- package/src/generators/vue-app/vue-app.js +11 -7
- package/src/generators/vue-app/vue-app.js.map +1 -1
- package/src/generators/vue-app/vue-app.spec.ts +12 -0
package/README.md
CHANGED
|
@@ -107,6 +107,12 @@ npx nx g @abgov/nx-adsp:express-service my-service --env dev --tenant my-tenant
|
|
|
107
107
|
| `tenantRealm` | `-tr` | No | Keycloak realm UUID; overrides the realm resolved from `--tenant` |
|
|
108
108
|
| `accessToken` | `-at` | No | Access token for non-interactive retrieval of ADSP configuration |
|
|
109
109
|
|
|
110
|
+
OpenAPI docs are generated from the same Zod schemas already used for request validation
|
|
111
|
+
(`@asteasolutions/zod-to-openapi`) and served at `/swagger/docs/v1` — no separate spec to
|
|
112
|
+
hand-maintain. The root `/` endpoint's `_links.docs` points at it, which is what ADSP's directory
|
|
113
|
+
service polls to aggregate the service's API docs into `https://api.adsp.alberta.ca/{tenant}` (once
|
|
114
|
+
the service has a directory entry — a one-time setup step outside this generator).
|
|
115
|
+
|
|
110
116
|
---
|
|
111
117
|
|
|
112
118
|
### `react-app`
|
|
@@ -224,7 +230,13 @@ Generator flags that steer which tenant/token is used:
|
|
|
224
230
|
| `--tenantRealm <uuid>` | Use the realm UUID directly; combine with `--tenant` to override the resolved realm |
|
|
225
231
|
| `--accessToken <token>` | Supply a pre-obtained token directly (CI/CD), bypassing the CLI |
|
|
226
232
|
|
|
227
|
-
With none of these, the generator lets `adsp login`'s interactive picker resolve the tenant.
|
|
233
|
+
With none of these, the generator lets `adsp login`'s interactive picker resolve the tenant. Don't
|
|
234
|
+
have a tenant yet? That picker also offers a **+ Create a new tenant** choice — available in
|
|
235
|
+
`dev`/`test` (never `prod`), for an account whose core-realm roles include `beta-tester` or
|
|
236
|
+
`tenant-service-admin`, and (unless `tenant-service-admin`) that doesn't already own a tenant (one
|
|
237
|
+
per admin email). Picking it prompts for a name and waits for the new realm to finish provisioning
|
|
238
|
+
before continuing the login as that tenant. Requires `@abgov/adsp-cli` ^1.4.0+ (this plugin pins
|
|
239
|
+
^1.5.2 or later).
|
|
228
240
|
|
|
229
241
|
## Agent consultation
|
|
230
242
|
|
package/package.json
CHANGED
|
@@ -57,7 +57,7 @@ function addFiles(host, options) {
|
|
|
57
57
|
}
|
|
58
58
|
function default_1(host, options) {
|
|
59
59
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
60
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
60
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
61
61
|
// Checked before normalizeOptions, which resolves ADSP auth and can trigger
|
|
62
62
|
// an interactive login — a missing peer shouldn't surface only after that.
|
|
63
63
|
const { applicationGenerator: initAngular } = yield Promise.resolve().then(() => require('@nx/angular/generators')).catch(() => {
|
|
@@ -122,11 +122,15 @@ function default_1(host, options) {
|
|
|
122
122
|
// Add the webpack dev server proxy if there is proxy configuration.
|
|
123
123
|
config.targets.serve.options = Object.assign(Object.assign({}, config.targets.serve.options), { proxyConfig: `${normalizedOptions.projectRoot}/proxy.conf.json` });
|
|
124
124
|
}
|
|
125
|
+
config.tags = [
|
|
126
|
+
...((_d = config.tags) !== null && _d !== void 0 ? _d : []),
|
|
127
|
+
...(0, nx_oc_1.adspProjectTags)(normalizedOptions.env, normalizedOptions.adsp.tenant).filter((tag) => { var _a; return !((_a = config.tags) !== null && _a !== void 0 ? _a : []).includes(tag); }),
|
|
128
|
+
];
|
|
125
129
|
(0, devkit_1.updateProjectConfiguration)(host, options.name, config);
|
|
126
130
|
(0, quality_1.addSemgrepTarget)(host, options.name);
|
|
127
131
|
yield (0, devkit_1.formatFiles)(host);
|
|
128
132
|
if (normalizedOptions.adsp) {
|
|
129
|
-
const accessToken = (
|
|
133
|
+
const accessToken = (_e = normalizedOptions.adsp.accessToken) !== null && _e !== void 0 ? _e : options.accessToken;
|
|
130
134
|
const clientId = `urn:ads:${normalizedOptions.adsp.tenant}:${normalizedOptions.projectName}`;
|
|
131
135
|
yield (0, keycloak_admin_1.ensurePublicClient)(normalizedOptions.adsp.accessServiceUrl, normalizedOptions.adsp.tenantRealm, clientId, accessToken);
|
|
132
136
|
if (options.serviceClientId) {
|
|
@@ -135,12 +139,12 @@ function default_1(host, options) {
|
|
|
135
139
|
}
|
|
136
140
|
}
|
|
137
141
|
if (normalizedOptions.adsp && !options.skipAgent) {
|
|
138
|
-
const accessToken = (
|
|
139
|
-
const appComponentTs = (
|
|
140
|
-
const appComponentHtml = (
|
|
141
|
-
const appConfigTs = (
|
|
142
|
-
const appRoutesTs = (
|
|
143
|
-
const environmentTs = (
|
|
142
|
+
const accessToken = (_f = normalizedOptions.adsp.accessToken) !== null && _f !== void 0 ? _f : options.accessToken;
|
|
143
|
+
const appComponentTs = (_h = (_g = host.read(`${normalizedOptions.projectRoot}/src/app/app.component.ts`)) === null || _g === void 0 ? void 0 : _g.toString()) !== null && _h !== void 0 ? _h : '';
|
|
144
|
+
const appComponentHtml = (_k = (_j = host.read(`${normalizedOptions.projectRoot}/src/app/app.component.html`)) === null || _j === void 0 ? void 0 : _j.toString()) !== null && _k !== void 0 ? _k : '';
|
|
145
|
+
const appConfigTs = (_m = (_l = host.read(`${normalizedOptions.projectRoot}/src/app/app.config.ts`)) === null || _l === void 0 ? void 0 : _l.toString()) !== null && _m !== void 0 ? _m : '';
|
|
146
|
+
const appRoutesTs = (_p = (_o = host.read(`${normalizedOptions.projectRoot}/src/app/app.routes.ts`)) === null || _o === void 0 ? void 0 : _o.toString()) !== null && _p !== void 0 ? _p : '';
|
|
147
|
+
const environmentTs = (_r = (_q = host.read(`${normalizedOptions.projectRoot}/src/environments/environment.ts`)) === null || _q === void 0 ? void 0 : _q.toString()) !== null && _r !== void 0 ? _r : '';
|
|
144
148
|
yield (0, agent_1.confirmAfterAgentInterrupt)(yield (0, agent_1.consultAgent)(normalizedOptions.adsp.directoryServiceUrl, accessToken, {
|
|
145
149
|
projectName: normalizedOptions.projectName,
|
|
146
150
|
projectType: 'angular-app',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-app.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/angular-app/angular-app.ts"],"names":[],"mappings":";;AAmGA,
|
|
1
|
+
{"version":3,"file":"angular-app.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/angular-app/angular-app.ts"],"names":[],"mappings":";;AAmGA,4BA0KC;;AA7QD,wCAA0F;AAC1F,6CAA6E;AAC7E,+DAA6G;AAC7G,+DAA4D;AAC5D,iDAA2H;AAC3H,uCAYoB;AACpB,6BAA6B;AAG7B,SAAe,gBAAgB,CAC7B,IAAU,EACV,OAAkC;;QAElC,MAAM,WAAW,GAAG,IAAA,cAAK,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC;QACjD,MAAM,WAAW,GAAG,GAAG,IAAA,2BAAkB,EAAC,IAAI,CAAC,CAAC,OAAO,IAAI,WAAW,EAAE,CAAC;QACzE,MAAM,kBAAkB,GAAG,cAAc,WAAW,EAAE,CAAC;QAEvD,MAAM,IAAI,GAAG,MAAM,IAAA,4BAAoB,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAEvD,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;YAC/C,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;YACpB,CAAC,CAAC,OAAO,CAAC,KAAK;gBACf,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;gBACjB,CAAC,CAAC,EAAE,CAAC;QAEP,uCACK,OAAO,KACV,WAAW;YACX,WAAW;YACX,kBAAkB;YAClB,IAAI;YACJ,YAAY,IACZ;IACJ,CAAC;CAAA;AAED,SAAS,QAAQ,CAAC,IAAU,EAAE,OAAyB;;IACrD,MAAM,eAAe,+DAChB,OAAO,GACP,OAAO,CAAC,IAAI,GACZ,IAAA,cAAK,EAAC,OAAO,CAAC,IAAI,CAAC,KACtB,cAAc,EAAE,IAAA,uBAAc,EAAC,OAAO,CAAC,WAAW,CAAC,EACnD,aAAa,EAAE,MAAA,OAAO,CAAC,aAAa,mCAAI,IAAI,EAC5C,IAAI,EAAE,EAAE,GACT,CAAC;IACF,IAAA,sBAAa,EACX,IAAI,EACJ,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,WAAW,EACnB,eAAe,CAChB,CAAC;IACF,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;IACrD,IAAI,YAAY,EAAE,CAAC;QACjB,mDAAmD;QACnD,6CAA6C;QAC7C,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,CAC9C,CAAC,SAAS,EAAE,UAAU,EAAE,EAAE;YACxB,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YAElD,MAAM,KAAK,GAAG;gBACZ,MAAM,EAAE,GAAG,WAAW,CAAC,QAAQ,cAC7B,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAC9C,EAAE;gBACF,MAAM,EAAE,WAAW,CAAC,QAAQ,KAAK,QAAQ;gBACzC,YAAY,EAAE,KAAK;gBACnB,WAAW,EAAE,EAAE;aAChB,CAAC;YAEF,8DAA8D;YAC9D,IAAI,WAAW,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpC,KAAK,CAAC,WAAW,GAAG;oBAClB,CAAC,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC,EAAE,WAAW,CAAC,QAAQ;iBAClD,CAAC;YACJ,CAAC;YAED,uCACK,SAAS,KACZ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,KAAK,IAC5B;QACJ,CAAC,EACD,EAAE,CACH,CAAC;QACF,IAAA,kBAAS,EAAC,IAAI,EAAE,GAAG,OAAO,CAAC,WAAW,kBAAkB,EAAE,YAAY,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAGD,mBAA+B,IAAU,EAAE,OAAkC;;;QAC3E,4EAA4E;QAC5E,2EAA2E;QAC3E,MAAM,EAAE,oBAAoB,EAAE,WAAW,EAAE,GAAG,MAAM,qCAClD,wBAAwB,GACxB,KAAK,CAAC,GAAG,EAAE;YACX,MAAM,IAAI,KAAK,CACb,+GAA+G,CAChH,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,iBAAiB,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAEhE,MAAM,WAAW,CAAC,IAAI,EAAE;YACtB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,MAAM,EAAE,iBAAiB,CAAC,WAAW;YACrC,MAAM,EAAE,MAAM;YACd,aAAa,EAAE,YAAY;YAC3B,SAAS,EAAE,iBAAiB,CAAC,WAAW;YACxC,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;QAEH,6EAA6E;QAC7E,0EAA0E;QAC1E,IAAA,kCAAwB,EAAC,IAAI,EAAE,GAAG,iBAAiB,CAAC,WAAW,MAAM,CAAC,CAAC;QAEvE,IAAA,qCAA4B,EAC1B,IAAI,EACJ;YACE,2BAA2B,EAAE,OAAO;YACpC,sBAAsB,EAAE,OAAO;YAC/B,4EAA4E;YAC5E,yEAAyE;YACzE,yEAAyE;YACzE,oCAAoC;YACpC,6BAA6B,EAAE,OAAO;YACtC,uBAAuB,EAAE,OAAO;YAChC,kBAAkB,EAAE,SAAS;YAC7B,aAAa,EAAE,SAAS;YACxB,SAAS,EAAE,SAAS;SACrB,EACD,EAAE,CACH,CAAC;QAEF,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC;QAErD,IAAA,+BAAqB,EAAC,IAAI,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;QAC3D,IAAA,2BAAiB,EAAC,IAAI,CAAC,CAAC;QAExB,gFAAgF;QAChF,8DAA8D;QAC9D,KAAK,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,CAAC,EAAE,CAAC;YACrF,IAAI,CAAC,MAAM,CAAC,GAAG,iBAAiB,CAAC,WAAW,YAAY,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC;QAED,MAAM,MAAM,GAAG,IAAA,iCAAwB,EAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAE5D,+EAA+E;QAC/E,0DAA0D;QAC1D,IAAI,MAAA,MAAA,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,cAAc,0CAAE,UAAU,0CAAE,gBAAgB,EAAE,CAAC;YACtE,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,gBAAgB,CAAC;QACzE,CAAC;QAED,mFAAmF;QACnF,IAAI,MAAA,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,cAAc,0CAAE,UAAU,EAAE,CAAC;YACpD,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,OAAO,GAAG;gBACvD,EAAE,IAAI,EAAE,SAAS,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE;gBAC/D,EAAE,IAAI,EAAE,mBAAmB,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE;aAC3E,CAAC;QACJ,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,mCACvB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,KAC/B,SAAS,EAAE,CAAC,SAAS,CAAC,EACtB,MAAM,EAAE;gBACN,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM;gBACtC,GAAG,iBAAiB,CAAC,WAAW,4BAA4B;gBAC5D;oBACE,IAAI,EAAE,YAAY;oBAClB,KAAK,EAAE,iBAAiB,CAAC,WAAW;oBACpC,MAAM,EAAE,IAAI;iBACb;aACF,GACF,CAAC;QAEF,IAAI,UAAU,EAAE,CAAC;YACf,oEAAoE;YACpE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,mCACvB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,KAC/B,WAAW,EAAE,GAAG,iBAAiB,CAAC,WAAW,kBAAkB,GAChE,CAAC;QACJ,CAAC;QAED,MAAM,CAAC,IAAI,GAAG;YACZ,GAAG,CAAC,MAAA,MAAM,CAAC,IAAI,mCAAI,EAAE,CAAC;YACtB,GAAG,IAAA,uBAAe,EAAC,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAC7E,CAAC,GAAG,EAAE,EAAE,WAAC,OAAA,CAAC,CAAC,MAAA,MAAM,CAAC,IAAI,mCAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA,EAAA,CAC5C;SACF,CAAC;QAEF,IAAA,mCAA0B,EAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAEvD,IAAA,0BAAgB,EAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;QAExB,IAAI,iBAAiB,CAAC,IAAI,EAAE,CAAC;YAC3B,MAAM,WAAW,GAAG,MAAA,iBAAiB,CAAC,IAAI,CAAC,WAAW,mCAAI,OAAO,CAAC,WAAW,CAAC;YAC9E,MAAM,QAAQ,GAAG,WAAW,iBAAiB,CAAC,IAAI,CAAC,MAAM,IAAI,iBAAiB,CAAC,WAAW,EAAE,CAAC;YAC7F,MAAM,IAAA,mCAAkB,EACtB,iBAAiB,CAAC,IAAI,CAAC,gBAAgB,EACvC,iBAAiB,CAAC,IAAI,CAAC,WAAW,EAClC,QAAQ,EACR,WAAW,CACZ,CAAC;YACF,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;gBAC5B,MAAM,IAAA,qCAAoB,EACxB,iBAAiB,CAAC,IAAI,CAAC,gBAAgB,EACvC,iBAAiB,CAAC,IAAI,CAAC,WAAW,EAClC,QAAQ,EACR,OAAO,CAAC,eAAe,EACvB,WAAW,CACZ,CAAC;gBACF,MAAM,IAAA,sCAAqB,EACzB,iBAAiB,CAAC,IAAI,CAAC,gBAAgB,EACvC,iBAAiB,CAAC,IAAI,CAAC,WAAW,EAClC,QAAQ,EACR,OAAO,CAAC,eAAe,EACvB,cAAc,EACd,WAAW,CACZ,CAAC;YACJ,CAAC;QACH,CAAC;QAED,IAAI,iBAAiB,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;YACjD,MAAM,WAAW,GAAG,MAAA,iBAAiB,CAAC,IAAI,CAAC,WAAW,mCAAI,OAAO,CAAC,WAAW,CAAC;YAC9E,MAAM,cAAc,GAAG,MAAA,MAAA,IAAI,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,WAAW,2BAA2B,CAAC,0CAAE,QAAQ,EAAE,mCAAI,EAAE,CAAC;YAChH,MAAM,gBAAgB,GAAG,MAAA,MAAA,IAAI,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,WAAW,6BAA6B,CAAC,0CAAE,QAAQ,EAAE,mCAAI,EAAE,CAAC;YACpH,MAAM,WAAW,GAAG,MAAA,MAAA,IAAI,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,WAAW,wBAAwB,CAAC,0CAAE,QAAQ,EAAE,mCAAI,EAAE,CAAC;YAC1G,MAAM,WAAW,GAAG,MAAA,MAAA,IAAI,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,WAAW,wBAAwB,CAAC,0CAAE,QAAQ,EAAE,mCAAI,EAAE,CAAC;YAC1G,MAAM,aAAa,GAAG,MAAA,MAAA,IAAI,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,WAAW,kCAAkC,CAAC,0CAAE,QAAQ,EAAE,mCAAI,EAAE,CAAC;YACtH,MAAM,IAAA,kCAA0B,EAAC,MAAM,IAAA,oBAAY,EACjD,iBAAiB,CAAC,IAAI,CAAC,mBAAmB,EAC1C,WAAW,EACX;gBACE,WAAW,EAAE,iBAAiB,CAAC,WAAW;gBAC1C,WAAW,EAAE,aAAa;gBAC1B,MAAM,EAAE,iBAAiB,CAAC,IAAI,CAAC,MAAM;gBACrC,aAAa,EAAE,+BAAc;gBAC7B,aAAa,EAAE;oBACb,0BAA0B,EAAE,cAAc;oBAC1C,4BAA4B,EAAE,gBAAgB;oBAC9C,uBAAuB,EAAE,WAAW;oBACpC,uBAAuB,EAAE,WAAW;oBACpC,iCAAiC,EAAE,aAAa;iBACjD;aACF,EACD,IAAI,EACJ,iBAAiB,CAAC,WAAW,CAC9B,CAAC,CAAC;QACL,CAAC;QAED,MAAM,IAAA,2BAAmB,EAAC,IAAI,kCACzB,iBAAiB,KACpB,OAAO,EAAE,UAAU,EACnB,OAAO,EAAE,iBAAiB,CAAC,WAAW,IACtC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,IAAA,4BAAmB,EAAC,IAAI,CAAC,CAAC;QAC5B,CAAC,CAAC;IACJ,CAAC;CAAA"}
|
|
@@ -19,6 +19,11 @@ utilsMock.getAdspConfiguration.mockResolvedValue({
|
|
|
19
19
|
accessServiceUrl: environments.test.accessServiceUrl,
|
|
20
20
|
directoryServiceUrl: environments.test.directoryServiceUrl,
|
|
21
21
|
});
|
|
22
|
+
// jest.mock('@abgov/nx-oc') automocks adspProjectTags too — restore the real
|
|
23
|
+
// (pure, no I/O) implementation so tag-writing behavior is actually exercised.
|
|
24
|
+
utilsMock.adspProjectTags.mockImplementation(
|
|
25
|
+
jest.requireActual('@abgov/nx-oc').adspProjectTags
|
|
26
|
+
);
|
|
22
27
|
|
|
23
28
|
describe('angular app generator', () => {
|
|
24
29
|
let appTree: Tree;
|
|
@@ -12,43 +12,13 @@ const plugin_version_1 = require("../../utils/plugin-version");
|
|
|
12
12
|
const quality_1 = require("../../utils/quality");
|
|
13
13
|
function normalizeOptions(host, options) {
|
|
14
14
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
15
|
-
var _a
|
|
15
|
+
var _a;
|
|
16
16
|
const projectName = (0, devkit_1.names)(options.name).fileName;
|
|
17
17
|
const projectRoot = `${(0, devkit_1.getWorkspaceLayout)(host).appsDir}/${projectName}`;
|
|
18
|
-
|
|
19
|
-
if (options.tenant) {
|
|
20
|
-
// Resolve realm from tenant name via the public tenant service API (no auth required),
|
|
21
|
-
// then obtain a token for that realm via @abgov/adsp-cli.
|
|
22
|
-
const env = nx_oc_1.environments[(_a = options.env) !== null && _a !== void 0 ? _a : 'prod'];
|
|
23
|
-
const tenantServiceUrl = (yield (0, nx_oc_1.getServiceUrls)(env.directoryServiceUrl))['urn:ads:platform:tenant-service'];
|
|
24
|
-
const { default: axios } = yield Promise.resolve().then(() => require('axios'));
|
|
25
|
-
const { data } = yield axios.get(new URL('/api/tenant/v2/tenants', tenantServiceUrl).href, { params: { name: options.tenant } });
|
|
26
|
-
const tenantInfo = (_b = data === null || data === void 0 ? void 0 : data.results) === null || _b === void 0 ? void 0 : _b[0];
|
|
27
|
-
if (!tenantInfo) {
|
|
28
|
-
throw new Error(`Tenant "${options.tenant}" not found in ${env.directoryServiceUrl}.`);
|
|
29
|
-
}
|
|
30
|
-
const tenantRealm = (_c = options.tenantRealm) !== null && _c !== void 0 ? _c : tenantInfo.realm;
|
|
31
|
-
if (!options.accessToken) {
|
|
32
|
-
options = Object.assign(Object.assign({}, options), { accessToken: yield (0, nx_oc_1.ensureAdspToken)({
|
|
33
|
-
env: (_d = options.env) !== null && _d !== void 0 ? _d : 'prod',
|
|
34
|
-
realm: tenantRealm,
|
|
35
|
-
tenant: options.tenant,
|
|
36
|
-
scopes: [nx_oc_1.ADSP_ADMIN_SCOPE],
|
|
37
|
-
}).catch(() => undefined) });
|
|
38
|
-
}
|
|
39
|
-
adsp = {
|
|
40
|
-
tenant: tenantInfo.name,
|
|
41
|
-
tenantRealm,
|
|
42
|
-
accessServiceUrl: env.accessServiceUrl,
|
|
43
|
-
directoryServiceUrl: env.directoryServiceUrl,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
adsp = yield (0, nx_oc_1.getAdspConfiguration)(host, options);
|
|
48
|
-
}
|
|
18
|
+
const adsp = yield (0, nx_oc_1.getAdspConfiguration)(host, options);
|
|
49
19
|
return Object.assign(Object.assign({}, options), { projectName,
|
|
50
20
|
projectRoot,
|
|
51
|
-
adsp, database: (
|
|
21
|
+
adsp, database: (_a = options.database) !== null && _a !== void 0 ? _a : 'none' });
|
|
52
22
|
});
|
|
53
23
|
}
|
|
54
24
|
function addFiles(host, options) {
|
|
@@ -61,7 +31,7 @@ function addFiles(host, options) {
|
|
|
61
31
|
}
|
|
62
32
|
function default_1(host, options) {
|
|
63
33
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
64
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p
|
|
34
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
65
35
|
// Checked before normalizeOptions, which resolves ADSP auth and can trigger
|
|
66
36
|
// an interactive login — a missing peer shouldn't surface only after that.
|
|
67
37
|
const { applicationGenerator: initExpress } = yield Promise.resolve().then(() => require('@nx/express')).catch(() => {
|
|
@@ -69,7 +39,7 @@ function default_1(host, options) {
|
|
|
69
39
|
});
|
|
70
40
|
const normalizedOptions = yield normalizeOptions(host, options);
|
|
71
41
|
yield initExpress(host, Object.assign(Object.assign({}, options), { skipFormat: true, skipPackageJson: false, linter: eslint_1.Linter.EsLint, unitTestRunner: 'jest', js: false, directory: normalizedOptions.projectRoot }));
|
|
72
|
-
(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' ? { 'drizzle-orm': '^0.44.0', pg: '^8.11.0' } : {})), (normalizedOptions.database === 'mongo' ? { mongoose: '^8.0.0' } : {})), Object.assign(Object.assign({ '@types/compression': '^1.7.5', '@types/cors': '^2.8.17', '@types/passport': '^1.0.16', '@types/passport-anonymous': '^1.0.3', supertest: '^7.0.0', '@types/supertest': '^6.0.0' }, (normalizedOptions.database === 'postgres' ? { 'drizzle-kit': '^0.31.0', '@types/pg': '^8.11.0' } : {})), { 'eslint-plugin-security': '^3.0.0', 'eslint-plugin-no-secrets': '^2.0.0', 'eslint-plugin-jest': '^28.0.0' }));
|
|
42
|
+
(0, devkit_1.addDependenciesToPackageJson)(host, Object.assign(Object.assign({ '@abgov/adsp-service-sdk': '^2.23.0', '@asteasolutions/zod-to-openapi': '^7.3.4', 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' ? { 'drizzle-orm': '^0.44.0', pg: '^8.11.0' } : {})), (normalizedOptions.database === 'mongo' ? { mongoose: '^8.0.0' } : {})), Object.assign(Object.assign({ '@types/compression': '^1.7.5', '@types/cors': '^2.8.17', '@types/passport': '^1.0.16', '@types/passport-anonymous': '^1.0.3', supertest: '^7.0.0', '@types/supertest': '^6.0.0' }, (normalizedOptions.database === 'postgres' ? { 'drizzle-kit': '^0.31.0', '@types/pg': '^8.11.0' } : {})), { 'eslint-plugin-security': '^3.0.0', 'eslint-plugin-no-secrets': '^2.0.0', 'eslint-plugin-jest': '^28.0.0' }));
|
|
73
43
|
addFiles(host, normalizedOptions);
|
|
74
44
|
(0, quality_1.addEslintQualityRules)(host, normalizedOptions.projectRoot, ['**/*.spec.ts', '**/*.test.ts']);
|
|
75
45
|
(0, quality_1.addJestCoverageConfig)(host, normalizedOptions.projectRoot);
|
|
@@ -124,17 +94,18 @@ function default_1(host, options) {
|
|
|
124
94
|
// Record the database as a project tag so the nx-oc sandbox generator can
|
|
125
95
|
// wire DATABASE_URL + the migrate init container without a --database flag.
|
|
126
96
|
const dbTag = `adsp:database:${normalizedOptions.database}`;
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
97
|
+
const newTags = [
|
|
98
|
+
...(normalizedOptions.database !== 'none' ? [dbTag] : []),
|
|
99
|
+
...(0, nx_oc_1.adspProjectTags)(normalizedOptions.env, normalizedOptions.adsp.tenant),
|
|
100
|
+
].filter((tag) => { var _a; return !((_a = projectConfig.tags) !== null && _a !== void 0 ? _a : []).includes(tag); });
|
|
101
|
+
const tags = [...((_d = projectConfig.tags) !== null && _d !== void 0 ? _d : []), ...newTags];
|
|
131
102
|
(0, devkit_1.updateProjectConfiguration)(host, normalizedOptions.projectName, Object.assign(Object.assign({}, projectConfig), { targets,
|
|
132
103
|
tags }));
|
|
133
104
|
(0, quality_1.addSemgrepTarget)(host, normalizedOptions.projectName);
|
|
134
105
|
yield (0, devkit_1.formatFiles)(host);
|
|
135
106
|
if (normalizedOptions.adsp) {
|
|
136
107
|
const clientId = `urn:ads:${normalizedOptions.adsp.tenant}:${normalizedOptions.projectName}`;
|
|
137
|
-
const accessToken = (
|
|
108
|
+
const accessToken = (_e = normalizedOptions.accessToken) !== null && _e !== void 0 ? _e : normalizedOptions.adsp.accessToken;
|
|
138
109
|
const clientSecret = yield (0, keycloak_admin_1.ensureServiceClient)(normalizedOptions.adsp.accessServiceUrl, normalizedOptions.adsp.tenantRealm, clientId, accessToken);
|
|
139
110
|
if (clientSecret) {
|
|
140
111
|
// .env.local, not .env: CLIENT_SECRET is a generated, local-only value — the
|
|
@@ -159,12 +130,12 @@ function default_1(host, options) {
|
|
|
159
130
|
if (normalizedOptions.adsp && !options.skipAgent) {
|
|
160
131
|
// Both normalizeOptions paths resolve a tenant-realm token via @abgov/adsp-cli,
|
|
161
132
|
// so it's already on normalizedOptions.accessToken (--tenant) or adsp.accessToken.
|
|
162
|
-
const accessToken = (
|
|
163
|
-
const mainTs = (
|
|
164
|
-
const environmentTs = (
|
|
165
|
-
const eventsTs = (
|
|
133
|
+
const accessToken = (_f = normalizedOptions.accessToken) !== null && _f !== void 0 ? _f : normalizedOptions.adsp.accessToken;
|
|
134
|
+
const mainTs = (_h = (_g = host.read(`${normalizedOptions.projectRoot}/src/main.ts`)) === null || _g === void 0 ? void 0 : _g.toString()) !== null && _h !== void 0 ? _h : '';
|
|
135
|
+
const environmentTs = (_k = (_j = host.read(`${normalizedOptions.projectRoot}/src/environment.ts`)) === null || _j === void 0 ? void 0 : _j.toString()) !== null && _k !== void 0 ? _k : '';
|
|
136
|
+
const eventsTs = (_m = (_l = host.read(`${normalizedOptions.projectRoot}/src/events.ts`)) === null || _l === void 0 ? void 0 : _l.toString()) !== null && _m !== void 0 ? _m : '';
|
|
166
137
|
const databaseTs = normalizedOptions.database !== 'none'
|
|
167
|
-
? (
|
|
138
|
+
? (_p = (_o = host.read(`${normalizedOptions.projectRoot}/src/database.ts`)) === null || _o === void 0 ? void 0 : _o.toString()) !== null && _p !== void 0 ? _p : ''
|
|
168
139
|
: undefined;
|
|
169
140
|
const agentResult = yield (0, agent_1.consultAgent)(normalizedOptions.adsp.directoryServiceUrl, accessToken, {
|
|
170
141
|
projectName: normalizedOptions.projectName,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express-service.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/express-service/express-service.ts"],"names":[],"mappings":";;
|
|
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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"}
|
|
@@ -15,6 +15,11 @@ utilsMock.getAdspConfiguration.mockResolvedValue({
|
|
|
15
15
|
accessServiceUrl: environments.test.accessServiceUrl,
|
|
16
16
|
directoryServiceUrl: environments.test.directoryServiceUrl,
|
|
17
17
|
});
|
|
18
|
+
// jest.mock('@abgov/nx-oc') automocks adspProjectTags too — restore the real
|
|
19
|
+
// (pure, no I/O) implementation so tag-writing behavior is actually exercised.
|
|
20
|
+
utilsMock.adspProjectTags.mockImplementation(
|
|
21
|
+
jest.requireActual('@abgov/nx-oc').adspProjectTags
|
|
22
|
+
);
|
|
18
23
|
utilsMock.deploymentGenerator.mockResolvedValue(undefined);
|
|
19
24
|
utilsMock.ensureAdspToken.mockResolvedValue('test-token');
|
|
20
25
|
|
|
@@ -39,6 +44,40 @@ describe('Express Service Generator', () => {
|
|
|
39
44
|
expect(host.exists('apps/test/src/environments/environment.ts')).toBeFalsy();
|
|
40
45
|
}, 60000);
|
|
41
46
|
|
|
47
|
+
it('serves generated OpenAPI docs, discoverable via the root _links convention', async () => {
|
|
48
|
+
const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
49
|
+
await generator(host, options);
|
|
50
|
+
|
|
51
|
+
// Shared registry module: extends Zod once, exports the registry every
|
|
52
|
+
// router registers its paths into.
|
|
53
|
+
expect(host.exists('apps/test/src/openapi.ts')).toBeTruthy();
|
|
54
|
+
const openapiTs = host.read('apps/test/src/openapi.ts').toString();
|
|
55
|
+
expect(openapiTs).toContain('extendZodWithOpenApi');
|
|
56
|
+
expect(openapiTs).toContain('export const registry');
|
|
57
|
+
|
|
58
|
+
// main.ts builds the doc from the registry once at startup and serves it
|
|
59
|
+
// at the conventional path; the root endpoint's _links gains a docs entry
|
|
60
|
+
// pointing at it — this is what ADSP's directory service polls for.
|
|
61
|
+
const mainTs = host.read('apps/test/src/main.ts').toString();
|
|
62
|
+
expect(mainTs).toContain('OpenApiGeneratorV3');
|
|
63
|
+
expect(mainTs).toContain('/swagger/docs/v1');
|
|
64
|
+
expect(mainTs).toContain("docs: { href: new URL('/swagger/docs/v1', rootUrl).href }");
|
|
65
|
+
// Document-level default security — without it, routes with no explicit
|
|
66
|
+
// `security` override (e.g. /private) would inherit nothing at all,
|
|
67
|
+
// rather than the accessToken requirement they actually enforce.
|
|
68
|
+
expect(mainTs).toContain('security: [{ accessToken: [] }]');
|
|
69
|
+
|
|
70
|
+
// The shipped example router documents its own routes, reusing the same
|
|
71
|
+
// schema already passed to createValidationHandler (no separate spec).
|
|
72
|
+
const routerTs = host.read('apps/test/src/routes/example.ts').toString();
|
|
73
|
+
expect(routerTs).toContain('registry.registerPath');
|
|
74
|
+
expect(routerTs).toContain("import { registry } from '../openapi'");
|
|
75
|
+
|
|
76
|
+
// Runtime dependency (built at app startup), not a devDependency.
|
|
77
|
+
const pkgJson = readJson(host, 'package.json');
|
|
78
|
+
expect(pkgJson.dependencies['@asteasolutions/zod-to-openapi']).toBeTruthy();
|
|
79
|
+
}, 60000);
|
|
80
|
+
|
|
42
81
|
it('wires the ADSP SDK MCP server into the workspace .mcp.json', async () => {
|
|
43
82
|
const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
44
83
|
await generator(host, options);
|
|
@@ -156,8 +156,28 @@ import { Router } from 'express';
|
|
|
156
156
|
import { authorize, createValidationHandler } from '@abgov/adsp-service-sdk';
|
|
157
157
|
import { z } from 'zod';
|
|
158
158
|
import * as items from '../services/items';
|
|
159
|
+
import { registry } from '../openapi';
|
|
159
160
|
|
|
160
161
|
const CreateItem = z.object({ name: z.string().trim().min(1) });
|
|
162
|
+
const BASE = '/<%= projectName %>/v1/items';
|
|
163
|
+
|
|
164
|
+
// Reuses CreateItem — the same schema passed to createValidationHandler below
|
|
165
|
+
// — so the served OpenAPI doc can't drift from what's actually validated. See
|
|
166
|
+
// "Why this matters for ADSP" below.
|
|
167
|
+
registry.registerPath({
|
|
168
|
+
method: 'get',
|
|
169
|
+
path: BASE,
|
|
170
|
+
summary: 'List items.',
|
|
171
|
+
security: [], // anonymous is allowed on the /v1 prefix — see the router below
|
|
172
|
+
responses: { 200: { description: 'The items.', content: { 'application/json': { schema: z.array(CreateItem) } } } },
|
|
173
|
+
});
|
|
174
|
+
registry.registerPath({
|
|
175
|
+
method: 'post',
|
|
176
|
+
path: BASE,
|
|
177
|
+
summary: 'Create an item.',
|
|
178
|
+
request: { body: { content: { 'application/json': { schema: CreateItem } } } },
|
|
179
|
+
responses: { 201: { description: 'The created item.', content: { 'application/json': { schema: CreateItem } } } },
|
|
180
|
+
});
|
|
161
181
|
|
|
162
182
|
export function itemsRouter(): Router {
|
|
163
183
|
const router = Router();
|
|
@@ -212,6 +232,17 @@ app.use('/<%= projectName %>/v1/items', itemsRouter());
|
|
|
212
232
|
z.infer<typeof Schema>`) — that's the raw, unparsed body, not the validated
|
|
213
233
|
one; parse it again with the same schema instead, as above.
|
|
214
234
|
|
|
235
|
+
### Why this matters for ADSP
|
|
236
|
+
|
|
237
|
+
`main.ts`'s root `/` handler returns a `docs` link pointing at `/swagger/docs/v1`, which serves an
|
|
238
|
+
OpenAPI document built at startup from every `registry.registerPath()` call across all mounted
|
|
239
|
+
routers (see `src/openapi.ts`). ADSP's directory service polls each registered service's root
|
|
240
|
+
endpoint and, when it finds that `docs` link, aggregates the spec into
|
|
241
|
+
`https://api.adsp.alberta.ca/{tenant}` — so every route added here (following the pattern above)
|
|
242
|
+
becomes part of the platform's aggregated API docs automatically, with no separate file to update.
|
|
243
|
+
This requires the service to already have a directory entry — a one-time setup step outside this
|
|
244
|
+
generator, done via the Tenant Management Webapp's directory admin UI.
|
|
245
|
+
|
|
215
246
|
## Recipe: add a resource end to end
|
|
216
247
|
|
|
217
248
|
Build a feature the conventional way — persistence, a service, a router, wiring,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AdspId, createErrorHandler, initializeService } from '@abgov/adsp-service-sdk';
|
|
2
|
+
import { OpenApiGeneratorV3 } from '@asteasolutions/zod-to-openapi';
|
|
2
3
|
import compression from 'compression';
|
|
3
4
|
import cors from 'cors';
|
|
4
5
|
import express from 'express';
|
|
@@ -12,6 +13,7 @@ import { connectDatabase, disconnectDatabase } from './database';
|
|
|
12
13
|
<% } %>
|
|
13
14
|
import { environment } from './environment';
|
|
14
15
|
import { exampleEventDefinition } from './events';
|
|
16
|
+
import { registry } from './openapi';
|
|
15
17
|
import { exampleRouter } from './routes/example';
|
|
16
18
|
|
|
17
19
|
async function initializeApp() {
|
|
@@ -57,6 +59,26 @@ async function initializeApp() {
|
|
|
57
59
|
res.json({ ...platform });
|
|
58
60
|
});
|
|
59
61
|
|
|
62
|
+
// Generated once from the routers' registry.registerPath() calls (see
|
|
63
|
+
// routes/example.ts) — every router imported above has already registered
|
|
64
|
+
// its paths by the time this runs. Served statically; ADSP's directory
|
|
65
|
+
// service polls the `docs` link below to aggregate this into
|
|
66
|
+
// https://api.adsp.alberta.ca/{tenant} (see AGENTS.md's "Why this matters
|
|
67
|
+
// for ADSP" — requires the service to have a directory entry, set up
|
|
68
|
+
// separately from this generator).
|
|
69
|
+
const openApiDoc = new OpenApiGeneratorV3(registry.definitions).generateDocument({
|
|
70
|
+
openapi: '3.0.0',
|
|
71
|
+
info: { title: '<%= projectName %>', version: '0.0.0' },
|
|
72
|
+
// Document-level default — an operation with no security override (e.g.
|
|
73
|
+
// /private, /example in routes/example.ts) inherits this; a route that's
|
|
74
|
+
// actually anonymous-accessible must set `security: []` explicitly, as
|
|
75
|
+
// the shipped example's index and /public routes do.
|
|
76
|
+
security: [{ accessToken: [] }],
|
|
77
|
+
});
|
|
78
|
+
app.get('/swagger/docs/v1', (_req, res) => {
|
|
79
|
+
res.json(openApiDoc);
|
|
80
|
+
});
|
|
81
|
+
|
|
60
82
|
app.get('/', (req, res) => {
|
|
61
83
|
const rootUrl = new URL(`${req.protocol}://${req.get('host')}`);
|
|
62
84
|
res.json({
|
|
@@ -64,6 +86,7 @@ async function initializeApp() {
|
|
|
64
86
|
self: { href: new URL(req.originalUrl, rootUrl).href },
|
|
65
87
|
health: { href: new URL('/health', rootUrl).href },
|
|
66
88
|
api: { href: new URL('/<%= projectName %>/v1', rootUrl).href },
|
|
89
|
+
docs: { href: new URL('/swagger/docs/v1', rootUrl).href },
|
|
67
90
|
},
|
|
68
91
|
});
|
|
69
92
|
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { extendZodWithOpenApi, OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
// Extends Zod schemas with a .openapi() method — must run before any schema
|
|
5
|
+
// calls it, which route modules importing `registry` from here already
|
|
6
|
+
// guarantee (Node evaluates this module's body once, on first import).
|
|
7
|
+
extendZodWithOpenApi(z);
|
|
8
|
+
|
|
9
|
+
// Shared across every route module: each router registers its own paths here,
|
|
10
|
+
// re-using the same Zod schemas already passed to createValidationHandler —
|
|
11
|
+
// one source of truth for validation and API docs, no separate spec to
|
|
12
|
+
// hand-maintain. main.ts generates the served document from this registry.
|
|
13
|
+
export const registry = new OpenAPIRegistry();
|
|
14
|
+
|
|
15
|
+
registry.registerComponent('securitySchemes', 'accessToken', {
|
|
16
|
+
type: 'http',
|
|
17
|
+
scheme: 'bearer',
|
|
18
|
+
bearerFormat: 'JWT',
|
|
19
|
+
});
|
|
@@ -3,11 +3,84 @@ import { Router } from 'express';
|
|
|
3
3
|
import passport from 'passport';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { createExampleEvent } from '../events';
|
|
6
|
+
import { registry } from '../openapi';
|
|
6
7
|
|
|
7
8
|
const ExampleRequestSchema = z.object({
|
|
8
9
|
id: z.string().min(1),
|
|
9
10
|
});
|
|
10
11
|
|
|
12
|
+
const IndexResponseSchema = z.object({
|
|
13
|
+
_links: z.object({
|
|
14
|
+
self: z.object({ href: z.string() }),
|
|
15
|
+
public: z.object({ href: z.string() }),
|
|
16
|
+
private: z.object({ href: z.string() }),
|
|
17
|
+
}),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const MessageResponseSchema = z.object({ message: z.string() });
|
|
21
|
+
|
|
22
|
+
const BASE = '/<%= projectName %>/v1';
|
|
23
|
+
|
|
24
|
+
// One registry.registerPath() per route, reusing the same schemas passed to
|
|
25
|
+
// createValidationHandler below — this keeps the served OpenAPI doc (see
|
|
26
|
+
// AGENTS.md's "Why this matters for ADSP") in sync with actual validation
|
|
27
|
+
// automatically. The mount in main.ts applies tenant-or-anonymous auth to
|
|
28
|
+
// every route here; /private and /example additionally require a real
|
|
29
|
+
// tenant user, so only the index and /public get an explicit `security: []`
|
|
30
|
+
// override.
|
|
31
|
+
registry.registerPath({
|
|
32
|
+
method: 'get',
|
|
33
|
+
path: BASE,
|
|
34
|
+
summary: 'Resource index for the example API.',
|
|
35
|
+
security: [],
|
|
36
|
+
responses: {
|
|
37
|
+
200: {
|
|
38
|
+
description: 'Hypermedia links to this resource\'s routes.',
|
|
39
|
+
content: { 'application/json': { schema: IndexResponseSchema } },
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
registry.registerPath({
|
|
45
|
+
method: 'get',
|
|
46
|
+
path: `${BASE}/public`,
|
|
47
|
+
summary: 'Public endpoint — no authentication required.',
|
|
48
|
+
security: [],
|
|
49
|
+
responses: {
|
|
50
|
+
200: {
|
|
51
|
+
description: 'A greeting message.',
|
|
52
|
+
content: { 'application/json': { schema: MessageResponseSchema } },
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
registry.registerPath({
|
|
58
|
+
method: 'get',
|
|
59
|
+
path: `${BASE}/private`,
|
|
60
|
+
summary: 'Private endpoint — requires an authenticated tenant user.',
|
|
61
|
+
responses: {
|
|
62
|
+
200: {
|
|
63
|
+
description: 'A greeting message with the caller\'s name.',
|
|
64
|
+
content: { 'application/json': { schema: MessageResponseSchema } },
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
registry.registerPath({
|
|
70
|
+
method: 'post',
|
|
71
|
+
path: `${BASE}/example`,
|
|
72
|
+
summary: 'Protected route demonstrating authorize, validation, and a domain event.',
|
|
73
|
+
request: {
|
|
74
|
+
body: { content: { 'application/json': { schema: ExampleRequestSchema } } },
|
|
75
|
+
},
|
|
76
|
+
responses: {
|
|
77
|
+
200: {
|
|
78
|
+
description: 'The submitted id, echoed back.',
|
|
79
|
+
content: { 'application/json': { schema: ExampleRequestSchema } },
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
11
84
|
// Thin HTTP handlers for the example resource, grouped in an express.Router().
|
|
12
85
|
// Capabilities from initializeService() are passed in (not imported) so the router
|
|
13
86
|
// stays testable — mount it with supertest and pass a mock eventService (see the
|
|
@@ -18,6 +18,11 @@ utilsMock.getAdspConfiguration.mockResolvedValue({
|
|
|
18
18
|
accessServiceUrl: environments.test.accessServiceUrl,
|
|
19
19
|
directoryServiceUrl: environments.test.directoryServiceUrl,
|
|
20
20
|
});
|
|
21
|
+
// jest.mock('@abgov/nx-oc') automocks adspProjectTags too — restore the real
|
|
22
|
+
// (pure, no I/O) implementation so tag-writing behavior is actually exercised.
|
|
23
|
+
utilsMock.adspProjectTags.mockImplementation(
|
|
24
|
+
jest.requireActual('@abgov/nx-oc').adspProjectTags
|
|
25
|
+
);
|
|
21
26
|
utilsMock.deploymentGenerator.mockResolvedValue(undefined);
|
|
22
27
|
utilsMock.ensureAdspToken.mockResolvedValue('test-token');
|
|
23
28
|
|
|
@@ -19,6 +19,11 @@ utilsMock.getAdspConfiguration.mockResolvedValue({
|
|
|
19
19
|
accessServiceUrl: environments.test.accessServiceUrl,
|
|
20
20
|
directoryServiceUrl: environments.test.directoryServiceUrl,
|
|
21
21
|
});
|
|
22
|
+
// jest.mock('@abgov/nx-oc') automocks adspProjectTags too — restore the real
|
|
23
|
+
// (pure, no I/O) implementation so tag-writing behavior is actually exercised.
|
|
24
|
+
utilsMock.adspProjectTags.mockImplementation(
|
|
25
|
+
jest.requireActual('@abgov/nx-oc').adspProjectTags
|
|
26
|
+
);
|
|
22
27
|
utilsMock.ensureAdspToken.mockResolvedValue('test-token');
|
|
23
28
|
|
|
24
29
|
describe('MERN Generator', () => {
|
|
@@ -19,6 +19,11 @@ utilsMock.getAdspConfiguration.mockResolvedValue({
|
|
|
19
19
|
accessServiceUrl: environments.test.accessServiceUrl,
|
|
20
20
|
directoryServiceUrl: environments.test.directoryServiceUrl,
|
|
21
21
|
});
|
|
22
|
+
// jest.mock('@abgov/nx-oc') automocks adspProjectTags too — restore the real
|
|
23
|
+
// (pure, no I/O) implementation so tag-writing behavior is actually exercised.
|
|
24
|
+
utilsMock.adspProjectTags.mockImplementation(
|
|
25
|
+
jest.requireActual('@abgov/nx-oc').adspProjectTags
|
|
26
|
+
);
|
|
22
27
|
utilsMock.ensureAdspToken.mockResolvedValue('test-token');
|
|
23
28
|
|
|
24
29
|
describe('MEVN Generator', () => {
|
|
@@ -19,6 +19,11 @@ utilsMock.getAdspConfiguration.mockResolvedValue({
|
|
|
19
19
|
accessServiceUrl: environments.test.accessServiceUrl,
|
|
20
20
|
directoryServiceUrl: environments.test.directoryServiceUrl,
|
|
21
21
|
});
|
|
22
|
+
// jest.mock('@abgov/nx-oc') automocks adspProjectTags too — restore the real
|
|
23
|
+
// (pure, no I/O) implementation so tag-writing behavior is actually exercised.
|
|
24
|
+
utilsMock.adspProjectTags.mockImplementation(
|
|
25
|
+
jest.requireActual('@abgov/nx-oc').adspProjectTags
|
|
26
|
+
);
|
|
22
27
|
utilsMock.ensureAdspToken.mockResolvedValue('test-token');
|
|
23
28
|
|
|
24
29
|
describe('PEAN Generator', () => {
|
|
@@ -19,6 +19,11 @@ utilsMock.getAdspConfiguration.mockResolvedValue({
|
|
|
19
19
|
accessServiceUrl: environments.test.accessServiceUrl,
|
|
20
20
|
directoryServiceUrl: environments.test.directoryServiceUrl,
|
|
21
21
|
});
|
|
22
|
+
// jest.mock('@abgov/nx-oc') automocks adspProjectTags too — restore the real
|
|
23
|
+
// (pure, no I/O) implementation so tag-writing behavior is actually exercised.
|
|
24
|
+
utilsMock.adspProjectTags.mockImplementation(
|
|
25
|
+
jest.requireActual('@abgov/nx-oc').adspProjectTags
|
|
26
|
+
);
|
|
22
27
|
utilsMock.ensureAdspToken.mockResolvedValue('test-token');
|
|
23
28
|
|
|
24
29
|
describe('PERN Generator', () => {
|
|
@@ -19,6 +19,11 @@ utilsMock.getAdspConfiguration.mockResolvedValue({
|
|
|
19
19
|
accessServiceUrl: environments.test.accessServiceUrl,
|
|
20
20
|
directoryServiceUrl: environments.test.directoryServiceUrl,
|
|
21
21
|
});
|
|
22
|
+
// jest.mock('@abgov/nx-oc') automocks adspProjectTags too — restore the real
|
|
23
|
+
// (pure, no I/O) implementation so tag-writing behavior is actually exercised.
|
|
24
|
+
utilsMock.adspProjectTags.mockImplementation(
|
|
25
|
+
jest.requireActual('@abgov/nx-oc').adspProjectTags
|
|
26
|
+
);
|
|
22
27
|
utilsMock.ensureAdspToken.mockResolvedValue('test-token');
|
|
23
28
|
|
|
24
29
|
describe('PEVN Generator', () => {
|
|
@@ -63,7 +63,7 @@ function removeFiles(host, options) {
|
|
|
63
63
|
}
|
|
64
64
|
function default_1(host, options) {
|
|
65
65
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
66
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
66
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
67
67
|
// Checked before normalizeOptions, which resolves ADSP auth and can trigger
|
|
68
68
|
// an interactive login — a missing peer shouldn't surface only after that.
|
|
69
69
|
const { applicationGenerator: initReact } = yield Promise.resolve().then(() => require('@nx/react')).catch(() => {
|
|
@@ -124,11 +124,15 @@ function default_1(host, options) {
|
|
|
124
124
|
// Add the webpack dev server proxy if there is proxy configuration.
|
|
125
125
|
config.targets.serve.options = Object.assign(Object.assign({}, config.targets.serve.options), { proxyConfig: `${normalizedOptions.projectRoot}/proxy.conf.json` });
|
|
126
126
|
}
|
|
127
|
+
config.tags = [
|
|
128
|
+
...((_c = config.tags) !== null && _c !== void 0 ? _c : []),
|
|
129
|
+
...(0, nx_oc_1.adspProjectTags)(normalizedOptions.env, normalizedOptions.adsp.tenant).filter((tag) => { var _a; return !((_a = config.tags) !== null && _a !== void 0 ? _a : []).includes(tag); }),
|
|
130
|
+
];
|
|
127
131
|
(0, devkit_1.updateProjectConfiguration)(host, options.name, config);
|
|
128
132
|
(0, quality_1.addSemgrepTarget)(host, options.name);
|
|
129
133
|
yield (0, devkit_1.formatFiles)(host);
|
|
130
134
|
if (normalizedOptions.adsp) {
|
|
131
|
-
const accessToken = (
|
|
135
|
+
const accessToken = (_d = normalizedOptions.adsp.accessToken) !== null && _d !== void 0 ? _d : options.accessToken;
|
|
132
136
|
const clientId = `urn:ads:${normalizedOptions.adsp.tenant}:${normalizedOptions.projectName}`;
|
|
133
137
|
yield (0, keycloak_admin_1.ensurePublicClient)(normalizedOptions.adsp.accessServiceUrl, normalizedOptions.adsp.tenantRealm, clientId, accessToken);
|
|
134
138
|
if (options.serviceClientId) {
|
|
@@ -137,12 +141,12 @@ function default_1(host, options) {
|
|
|
137
141
|
}
|
|
138
142
|
}
|
|
139
143
|
if (normalizedOptions.adsp && !options.skipAgent) {
|
|
140
|
-
const accessToken = (
|
|
141
|
-
const appTs = (
|
|
142
|
-
const storeTs = (
|
|
143
|
-
const environmentTs = (
|
|
144
|
-
const configSliceTs = (
|
|
145
|
-
const intakeSliceTs = (
|
|
144
|
+
const accessToken = (_e = normalizedOptions.adsp.accessToken) !== null && _e !== void 0 ? _e : options.accessToken;
|
|
145
|
+
const appTs = (_g = (_f = host.read(`${normalizedOptions.projectRoot}/src/app/app.tsx`)) === null || _f === void 0 ? void 0 : _f.toString()) !== null && _g !== void 0 ? _g : '';
|
|
146
|
+
const storeTs = (_j = (_h = host.read(`${normalizedOptions.projectRoot}/src/store.ts`)) === null || _h === void 0 ? void 0 : _h.toString()) !== null && _j !== void 0 ? _j : '';
|
|
147
|
+
const environmentTs = (_l = (_k = host.read(`${normalizedOptions.projectRoot}/src/environments/environment.ts`)) === null || _k === void 0 ? void 0 : _k.toString()) !== null && _l !== void 0 ? _l : '';
|
|
148
|
+
const configSliceTs = (_o = (_m = host.read(`${normalizedOptions.projectRoot}/src/app/config.slice.ts`)) === null || _m === void 0 ? void 0 : _m.toString()) !== null && _o !== void 0 ? _o : '';
|
|
149
|
+
const intakeSliceTs = (_q = (_p = host.read(`${normalizedOptions.projectRoot}/src/app/intake.slice.ts`)) === null || _p === void 0 ? void 0 : _p.toString()) !== null && _q !== void 0 ? _q : '';
|
|
146
150
|
yield (0, agent_1.confirmAfterAgentInterrupt)(yield (0, agent_1.consultAgent)(normalizedOptions.adsp.directoryServiceUrl, accessToken, {
|
|
147
151
|
projectName: normalizedOptions.projectName,
|
|
148
152
|
projectType: 'react-app',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-app.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/react-app/react-app.ts"],"names":[],"mappings":";;AAwGA,
|
|
1
|
+
{"version":3,"file":"react-app.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/react-app/react-app.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,11 @@ utilsMock.getAdspConfiguration.mockResolvedValue({
|
|
|
14
14
|
accessServiceUrl: environments.test.accessServiceUrl,
|
|
15
15
|
directoryServiceUrl: environments.test.directoryServiceUrl,
|
|
16
16
|
});
|
|
17
|
+
// jest.mock('@abgov/nx-oc') automocks adspProjectTags too — restore the real
|
|
18
|
+
// (pure, no I/O) implementation so tag-writing behavior is actually exercised.
|
|
19
|
+
utilsMock.adspProjectTags.mockImplementation(
|
|
20
|
+
jest.requireActual('@abgov/nx-oc').adspProjectTags
|
|
21
|
+
);
|
|
17
22
|
|
|
18
23
|
describe('React App Generator', () => {
|
|
19
24
|
const options: Schema = {
|
|
@@ -15,6 +15,11 @@ utilsMock.getAdspConfiguration.mockResolvedValue({
|
|
|
15
15
|
accessServiceUrl: environments.test.accessServiceUrl,
|
|
16
16
|
directoryServiceUrl: environments.test.directoryServiceUrl,
|
|
17
17
|
});
|
|
18
|
+
// jest.mock('@abgov/nx-oc') automocks adspProjectTags too — restore the real
|
|
19
|
+
// (pure, no I/O) implementation so tag-writing behavior is actually exercised.
|
|
20
|
+
utilsMock.adspProjectTags.mockImplementation(
|
|
21
|
+
jest.requireActual('@abgov/nx-oc').adspProjectTags
|
|
22
|
+
);
|
|
18
23
|
|
|
19
24
|
jest.mock('../dotnet-service/dotnet-service');
|
|
20
25
|
const serviceGeneratorMock = serviceGenerator as jest.Mocked<
|
|
@@ -51,7 +51,7 @@ function addFiles(host, options) {
|
|
|
51
51
|
}
|
|
52
52
|
function default_1(host, options) {
|
|
53
53
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
54
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
54
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
55
55
|
// Checked before normalizeOptions, which resolves ADSP auth and can trigger
|
|
56
56
|
// an interactive login — a missing peer shouldn't surface only after that.
|
|
57
57
|
const { applicationGenerator: initVue } = yield Promise.resolve().then(() => require('@nx/vue')).catch(() => {
|
|
@@ -146,11 +146,15 @@ function default_1(host, options) {
|
|
|
146
146
|
`adsp:proxy-service:${pairedService}:${port}`,
|
|
147
147
|
];
|
|
148
148
|
}
|
|
149
|
+
config.tags = [
|
|
150
|
+
...((_d = config.tags) !== null && _d !== void 0 ? _d : []),
|
|
151
|
+
...(0, nx_oc_1.adspProjectTags)(normalizedOptions.env, normalizedOptions.adsp.tenant).filter((tag) => { var _a; return !((_a = config.tags) !== null && _a !== void 0 ? _a : []).includes(tag); }),
|
|
152
|
+
];
|
|
149
153
|
(0, devkit_1.updateProjectConfiguration)(host, options.name, config);
|
|
150
154
|
(0, quality_1.addSemgrepTarget)(host, options.name);
|
|
151
155
|
yield (0, devkit_1.formatFiles)(host);
|
|
152
156
|
if (normalizedOptions.adsp) {
|
|
153
|
-
const accessToken = (
|
|
157
|
+
const accessToken = (_e = normalizedOptions.adsp.accessToken) !== null && _e !== void 0 ? _e : options.accessToken;
|
|
154
158
|
const clientId = `urn:ads:${normalizedOptions.adsp.tenant}:${normalizedOptions.projectName}`;
|
|
155
159
|
yield (0, keycloak_admin_1.ensurePublicClient)(normalizedOptions.adsp.accessServiceUrl, normalizedOptions.adsp.tenantRealm, clientId, accessToken);
|
|
156
160
|
if (options.serviceClientId) {
|
|
@@ -159,11 +163,11 @@ function default_1(host, options) {
|
|
|
159
163
|
}
|
|
160
164
|
}
|
|
161
165
|
if (normalizedOptions.adsp && !options.skipAgent) {
|
|
162
|
-
const accessToken = (
|
|
163
|
-
const appVue = (
|
|
164
|
-
const mainTs = (
|
|
165
|
-
const routerTs = (
|
|
166
|
-
const environmentTs = (
|
|
166
|
+
const accessToken = (_f = normalizedOptions.adsp.accessToken) !== null && _f !== void 0 ? _f : options.accessToken;
|
|
167
|
+
const appVue = (_h = (_g = host.read(`${normalizedOptions.projectRoot}/src/App.vue`)) === null || _g === void 0 ? void 0 : _g.toString()) !== null && _h !== void 0 ? _h : '';
|
|
168
|
+
const mainTs = (_k = (_j = host.read(`${normalizedOptions.projectRoot}/src/main.ts`)) === null || _j === void 0 ? void 0 : _j.toString()) !== null && _k !== void 0 ? _k : '';
|
|
169
|
+
const routerTs = (_m = (_l = host.read(`${normalizedOptions.projectRoot}/src/router/index.ts`)) === null || _l === void 0 ? void 0 : _l.toString()) !== null && _m !== void 0 ? _m : '';
|
|
170
|
+
const environmentTs = (_p = (_o = host.read(`${normalizedOptions.projectRoot}/src/environments/environment.ts`)) === null || _o === void 0 ? void 0 : _o.toString()) !== null && _p !== void 0 ? _p : '';
|
|
167
171
|
yield (0, agent_1.confirmAfterAgentInterrupt)(yield (0, agent_1.consultAgent)(normalizedOptions.adsp.directoryServiceUrl, accessToken, {
|
|
168
172
|
projectName: normalizedOptions.projectName,
|
|
169
173
|
projectType: 'vue-app',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vue-app.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/vue-app/vue-app.ts"],"names":[],"mappings":";;AAmEA,
|
|
1
|
+
{"version":3,"file":"vue-app.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/vue-app/vue-app.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,6 +23,11 @@ utilsMock.getAdspConfiguration.mockResolvedValue({
|
|
|
23
23
|
accessServiceUrl: environments.test.accessServiceUrl,
|
|
24
24
|
directoryServiceUrl: environments.test.directoryServiceUrl,
|
|
25
25
|
});
|
|
26
|
+
// jest.mock('@abgov/nx-oc') automocks adspProjectTags too — restore the real
|
|
27
|
+
// (pure, no I/O) implementation so tag-writing behavior is actually exercised.
|
|
28
|
+
utilsMock.adspProjectTags.mockImplementation(
|
|
29
|
+
jest.requireActual('@abgov/nx-oc').adspProjectTags
|
|
30
|
+
);
|
|
26
31
|
|
|
27
32
|
describe('Vue App Generator', () => {
|
|
28
33
|
let host: Tree;
|
|
@@ -49,6 +54,13 @@ describe('Vue App Generator', () => {
|
|
|
49
54
|
expect(config.targets.build.options.outputPath).toBe('dist/apps/test');
|
|
50
55
|
}, 30000);
|
|
51
56
|
|
|
57
|
+
it('records the resolved env/tenant as project tags for the sandbox generator', async () => {
|
|
58
|
+
await generator(host, options);
|
|
59
|
+
const config = readProjectConfiguration(host, 'test');
|
|
60
|
+
expect(config.tags).toContain('adsp:scaffold-env:dev');
|
|
61
|
+
expect(config.tags).toContain('adsp:scaffold-tenant:test');
|
|
62
|
+
}, 30000);
|
|
63
|
+
|
|
52
64
|
it('scaffolds a Playwright e2e project (consistent across frontends)', async () => {
|
|
53
65
|
await generator(host, options);
|
|
54
66
|
expect(host.exists('apps/test-e2e/project.json')).toBeTruthy();
|