@abgov/nx-adsp 13.1.3 → 13.2.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/package.json +1 -1
- package/src/generators/express-service/express-service.js +2 -0
- package/src/generators/express-service/express-service.js.map +1 -1
- package/src/generators/express-service/express-service.spec.ts +35 -1
- package/src/generators/express-service/files/AGENTS.md__tmpl__ +19 -0
- package/src/generators/vue-app/files/AGENTS.md__tmpl__ +37 -15
- package/src/generators/vue-app/files/public/nginx.conf__tmpl__ +0 -4
- package/src/generators/vue-app/files/src/App.spec.ts__tmpl__ +24 -13
- package/src/generators/vue-app/files/src/App.vue__tmpl__ +13 -9
- package/src/generators/vue-app/files/src/main.ts__tmpl__ +15 -2
- package/src/generators/vue-app/files/src/router/index.ts__tmpl__ +6 -4
- package/src/generators/vue-app/files/src/views/HomeView.vue__tmpl__ +17 -7
- package/src/generators/vue-app/files/src/views/ProtectedView.vue__tmpl__ +7 -3
- package/src/generators/vue-app/vue-app.js +4 -3
- package/src/generators/vue-app/vue-app.js.map +1 -1
- package/src/generators/vue-app/vue-app.spec.ts +43 -2
- package/src/utils/quality.d.ts +10 -0
- package/src/utils/quality.js +27 -0
- package/src/utils/quality.js.map +1 -1
- package/src/generators/vue-app/files/public/silent-check-sso.html__tmpl__ +0 -5
package/package.json
CHANGED
|
@@ -67,6 +67,8 @@ function default_1(host, options) {
|
|
|
67
67
|
(0, quality_1.addEslintQualityRules)(host, normalizedOptions.projectRoot, ['**/*.spec.ts', '**/*.test.ts']);
|
|
68
68
|
(0, quality_1.addJestCoverageConfig)(host, normalizedOptions.projectRoot);
|
|
69
69
|
(0, quality_1.addVsCodeSettings)(host);
|
|
70
|
+
// Equip coding agents with grounded ADSP docs + Node SDK reference lookup.
|
|
71
|
+
(0, quality_1.addAdspMcpServer)(host);
|
|
70
72
|
const projectConfig = (0, devkit_1.readProjectConfiguration)(host, normalizedOptions.projectName);
|
|
71
73
|
const targets = Object.assign({}, projectConfig.targets);
|
|
72
74
|
if (normalizedOptions.database !== 'none') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express-service.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/express-service/express-service.ts"],"names":[],"mappings":";;AAiGA,
|
|
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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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readProjectConfiguration } from '@nx/devkit';
|
|
1
|
+
import { readJson, readProjectConfiguration, writeJson } from '@nx/devkit';
|
|
2
2
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
|
3
3
|
|
|
4
4
|
import * as utils from '@abgov/nx-oc';
|
|
@@ -35,6 +35,40 @@ describe('Express Service Generator', () => {
|
|
|
35
35
|
expect(host.exists('apps/test/src/environments/environment.ts')).toBeFalsy();
|
|
36
36
|
}, 60000);
|
|
37
37
|
|
|
38
|
+
it('wires the ADSP SDK MCP server into the workspace .mcp.json', async () => {
|
|
39
|
+
const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
40
|
+
await generator(host, options);
|
|
41
|
+
|
|
42
|
+
expect(host.exists('.mcp.json')).toBeTruthy();
|
|
43
|
+
const mcp = readJson(host, '.mcp.json');
|
|
44
|
+
expect(mcp.mcpServers['adsp-sdk']).toEqual({
|
|
45
|
+
command: 'npx',
|
|
46
|
+
args: ['-y', '@abgov/adsp-sdk-mcp-server'],
|
|
47
|
+
});
|
|
48
|
+
// Agents are pointed at the tools, not left to guess the SDK.
|
|
49
|
+
const agents = host.read('apps/test/AGENTS.md').toString();
|
|
50
|
+
expect(agents).toContain('@abgov/adsp-sdk-mcp-server');
|
|
51
|
+
expect(agents).toContain('get_platform_quickstart');
|
|
52
|
+
expect(agents).toContain('search_sdk_reference');
|
|
53
|
+
}, 60000);
|
|
54
|
+
|
|
55
|
+
it('merges .mcp.json without clobbering other servers or a customized entry', async () => {
|
|
56
|
+
const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
57
|
+
writeJson(host, '.mcp.json', {
|
|
58
|
+
mcpServers: {
|
|
59
|
+
other: { command: 'other-cmd', args: [] },
|
|
60
|
+
'adsp-sdk': { command: 'node', args: ['/local/build/main.js'] },
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
await generator(host, options);
|
|
64
|
+
|
|
65
|
+
const mcp = readJson(host, '.mcp.json');
|
|
66
|
+
// Unrelated server preserved.
|
|
67
|
+
expect(mcp.mcpServers.other).toEqual({ command: 'other-cmd', args: [] });
|
|
68
|
+
// A team's customized adsp-sdk entry is not overwritten.
|
|
69
|
+
expect(mcp.mcpServers['adsp-sdk']).toEqual({ command: 'node', args: ['/local/build/main.js'] });
|
|
70
|
+
}, 60000);
|
|
71
|
+
|
|
38
72
|
it('includes authorize, createValidationHandler, and example route in main.ts', async () => {
|
|
39
73
|
const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
40
74
|
await generator(host, options);
|
|
@@ -17,6 +17,25 @@ interactive prompt never blocks your session (`CI=true` in the env does the same
|
|
|
17
17
|
also skips the Nx Cloud prompt). This applies to `nx g` generators; `nx run <target>`
|
|
18
18
|
executors read options from `project.json` and do not prompt.
|
|
19
19
|
|
|
20
|
+
## ADSP knowledge (MCP)
|
|
21
|
+
|
|
22
|
+
This workspace is wired with the **`@abgov/adsp-sdk-mcp-server`** MCP server (see
|
|
23
|
+
`.mcp.json` at the workspace root). It gives grounded, sourced answers about ADSP
|
|
24
|
+
and the Node SDK. **Prefer these tools over recalling `@abgov/adsp-service-sdk`
|
|
25
|
+
APIs from memory** when integrating ADSP capabilities:
|
|
26
|
+
|
|
27
|
+
- `get_platform_quickstart` — the canonical `initializePlatform` usage pattern and
|
|
28
|
+
a capabilities summary. Start here for "how do I use ADSP from this service?".
|
|
29
|
+
- `search_sdk_reference` — look up `@abgov/adsp-service-sdk` by symbol, module, or
|
|
30
|
+
keyword; returns kind, description, option/return shape, example, deprecation.
|
|
31
|
+
- `search_adsp_docs` — keyword search across ADSP platform docs (getting started,
|
|
32
|
+
architecture, service concepts, tutorials).
|
|
33
|
+
- `read_adsp_doc` — read the full content of a doc page found via search.
|
|
34
|
+
|
|
35
|
+
If these tools aren't available, your MCP client hasn't loaded `.mcp.json` yet —
|
|
36
|
+
Claude Code prompts to approve project MCP servers on first use; other clients may
|
|
37
|
+
need project-scoped MCP enabled. The server runs via `npx` and needs no credentials.
|
|
38
|
+
|
|
20
39
|
## Stack
|
|
21
40
|
|
|
22
41
|
|
|
@@ -40,24 +40,47 @@ executors read options from `project.json` and do not prompt.
|
|
|
40
40
|
|
|
41
41
|
## Auth pattern
|
|
42
42
|
|
|
43
|
+
> ⚠️ **Never destructure `useKeycloak()`.** Unlike most Vue composables (which
|
|
44
|
+
> return `ref`s that survive destructuring), this wrapper returns a
|
|
45
|
+
> `readonly(reactive({...}))` whose fields are **plain values** — `authenticated`
|
|
46
|
+
> is a `boolean`, `keycloak` is the instance-or-`undefined`, etc. Every field is
|
|
47
|
+
> `false`/`undefined` at setup time and only populates **asynchronously** once
|
|
48
|
+
> Keycloak's init settles. `const { keycloak } = useKeycloak()` therefore captures
|
|
49
|
+
> a permanent `undefined`, so `keycloak?.login()` becomes a silent no-op and
|
|
50
|
+
> `authenticated` never flips — and it *looks* fine because the initial render is
|
|
51
|
+
> correct. Always keep the object (`const kc = useKeycloak()`) and read `kc.field`
|
|
52
|
+
> at call/render time. This is the single most common way to break auth here.
|
|
53
|
+
|
|
43
54
|
```typescript
|
|
44
55
|
import { useKeycloak } from '@dsb-norge/vue-keycloak-js';
|
|
45
56
|
|
|
46
|
-
// useKeycloak() returns a
|
|
47
|
-
|
|
57
|
+
// useKeycloak() returns a readonly(reactive(...)) instance. Keep the object and
|
|
58
|
+
// read fields off it — do NOT destructure. Destructuring snapshots each field at
|
|
59
|
+
// setup time, so `kc.keycloak` would freeze at `undefined` (login() a no-op) and
|
|
60
|
+
// `kc.authenticated` would never flip to true. All fields populate asynchronously
|
|
61
|
+
// once Keycloak's init settles.
|
|
62
|
+
const kc = useKeycloak();
|
|
48
63
|
|
|
49
|
-
authenticated
|
|
50
|
-
fullName
|
|
51
|
-
ready
|
|
52
|
-
token
|
|
64
|
+
kc.authenticated // boolean — true after sign-in
|
|
65
|
+
kc.fullName // string | undefined — display name from token
|
|
66
|
+
kc.ready // boolean — true once Keycloak init has settled
|
|
67
|
+
kc.token // string | undefined — current access token
|
|
53
68
|
|
|
54
69
|
// Call Keycloak actions via the underlying keycloak-js instance:
|
|
55
|
-
keycloak?.login()
|
|
56
|
-
keycloak?.logout({ redirectUri: window.location.origin })
|
|
70
|
+
kc.keycloak?.login()
|
|
71
|
+
kc.keycloak?.logout({ redirectUri: window.location.origin })
|
|
57
72
|
|
|
58
73
|
// Refresh token before an authenticated API call:
|
|
59
|
-
await keycloak?.updateToken(30);
|
|
60
|
-
const bearer = keycloak?.token;
|
|
74
|
+
await kc.keycloak?.updateToken(30);
|
|
75
|
+
const bearer = kc.keycloak?.token;
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
To run work when auth settles (it flips after mount, e.g. on return from the
|
|
79
|
+
login redirect), `watch` it rather than reading once:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { watch } from 'vue';
|
|
83
|
+
watch(() => kc.authenticated, (authed) => { if (authed) loadPrivateData(); }, { immediate: true });
|
|
61
84
|
```
|
|
62
85
|
|
|
63
86
|
Route guard (in `router/index.ts`):
|
|
@@ -65,10 +88,10 @@ Route guard (in `router/index.ts`):
|
|
|
65
88
|
```typescript
|
|
66
89
|
router.beforeEach((to) => {
|
|
67
90
|
if (to.meta.requiresAuth) {
|
|
68
|
-
const
|
|
69
|
-
if (!ready) return true; // let Keycloak init settle first
|
|
70
|
-
if (!authenticated) {
|
|
71
|
-
keycloak?.login({ redirectUri: window.location.origin + to.fullPath });
|
|
91
|
+
const kc = useKeycloak();
|
|
92
|
+
if (!kc.ready) return true; // let Keycloak init settle first
|
|
93
|
+
if (!kc.authenticated) {
|
|
94
|
+
kc.keycloak?.login({ redirectUri: window.location.origin + to.fullPath });
|
|
72
95
|
return false;
|
|
73
96
|
}
|
|
74
97
|
}
|
|
@@ -155,7 +178,6 @@ nx run <%= projectName %>:teardown-dev # remove from dev environment
|
|
|
155
178
|
|
|
156
179
|
- `src/main.ts` — Keycloak plugin is registered once here; do not call `new Keycloak()` elsewhere
|
|
157
180
|
- `environments/environment.ts` — access URL and realm are pre-configured for the ADSP tenant
|
|
158
|
-
- `silent-check-sso.html` — required for keycloak-js silent SSO; must be served from the app root
|
|
159
181
|
- `vite.config.ts` — the `isCustomElement` predicate must stay to suppress Vue warnings for `goa-*` elements
|
|
160
182
|
|
|
161
183
|
## Sandbox deployment (local build)
|
|
@@ -1,27 +1,38 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
|
-
import { ref } from 'vue';
|
|
3
2
|
import { describe, it, expect, vi } from 'vitest';
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
// Mirror the real wrapper: useKeycloak() returns a reactive() whose fields are
|
|
5
|
+
// plain values (NOT refs), with login/logout on the nested `keycloak` instance.
|
|
6
|
+
// Build the state inside the (hoisted) factory to dodge vi.mock hoisting issues.
|
|
7
|
+
vi.mock('@dsb-norge/vue-keycloak-js', async () => {
|
|
8
|
+
const { reactive } = await import('vue');
|
|
9
|
+
const kc = reactive({
|
|
10
|
+
authenticated: false,
|
|
11
|
+
fullName: '',
|
|
12
|
+
ready: true,
|
|
11
13
|
keycloak: { login: vi.fn(), logout: vi.fn() },
|
|
12
|
-
})
|
|
13
|
-
}
|
|
14
|
+
});
|
|
15
|
+
return { useKeycloak: () => kc };
|
|
16
|
+
});
|
|
14
17
|
|
|
18
|
+
import { useKeycloak } from '@dsb-norge/vue-keycloak-js';
|
|
15
19
|
import App from './App.vue';
|
|
16
20
|
|
|
17
21
|
describe('App shell header', () => {
|
|
18
|
-
it('shows Sign in when unauthenticated
|
|
22
|
+
it('shows Sign in when unauthenticated', () => {
|
|
19
23
|
const wrapper = mount(App, { global: { stubs: { RouterView: true } } });
|
|
20
|
-
|
|
21
|
-
// The sign-in affordance must not be gated on `ready`: if check-sso never
|
|
22
|
-
// resolves, the button would be hidden and the user could never log in.
|
|
23
24
|
const group = wrapper.find('goa-button-group');
|
|
24
25
|
expect(group.exists()).toBe(true);
|
|
25
26
|
expect(group.html()).toContain('Sign in');
|
|
26
27
|
});
|
|
28
|
+
|
|
29
|
+
it('Sign in click calls keycloak.login (guards against lost reactivity)', async () => {
|
|
30
|
+
// The bug: destructuring useKeycloak() froze `keycloak` at undefined, so
|
|
31
|
+
// login() was a permanent no-op. Reactive access must reach the instance.
|
|
32
|
+
const kc = useKeycloak();
|
|
33
|
+
const wrapper = mount(App, { global: { stubs: { RouterView: true } } });
|
|
34
|
+
const btn = wrapper.findAll('goa-button').find((b) => b.text().includes('Sign in'));
|
|
35
|
+
await btn?.trigger('_click');
|
|
36
|
+
expect(kc.keycloak?.login).toHaveBeenCalled();
|
|
37
|
+
});
|
|
27
38
|
});
|
|
@@ -2,24 +2,28 @@
|
|
|
2
2
|
import { useKeycloak } from '@dsb-norge/vue-keycloak-js';
|
|
3
3
|
import { RouterView } from 'vue-router';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// Keep the reactive instance — do NOT destructure. useKeycloak() returns a
|
|
6
|
+
// readonly(reactive()); destructuring snapshots each field at setup time, so
|
|
7
|
+
// `keycloak` would be frozen at its initial `undefined` (login() a no-op) and
|
|
8
|
+
// `authenticated` would never flip. Access fields on `kc` to stay reactive.
|
|
9
|
+
const kc = useKeycloak();
|
|
6
10
|
|
|
7
|
-
function login() { keycloak?.login(); }
|
|
8
|
-
function logout() { keycloak?.logout({ redirectUri: window.location.origin }); }
|
|
11
|
+
function login() { kc.keycloak?.login(); }
|
|
12
|
+
function logout() { kc.keycloak?.logout({ redirectUri: window.location.origin }); }
|
|
9
13
|
</script>
|
|
10
14
|
|
|
11
15
|
<template>
|
|
12
16
|
<goa-microsite-header type="alpha" />
|
|
13
17
|
<goa-app-header url="/" heading="<%= projectName %>">
|
|
14
18
|
<goa-button-group alignment="end">
|
|
15
|
-
<span v-if="authenticated && fullName">{{ fullName }}</span>
|
|
16
|
-
<!-- Gate on !authenticated only,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
<goa-button v-if="!authenticated" type="tertiary" @_click="login">
|
|
19
|
+
<span v-if="kc.authenticated && kc.fullName">{{ kc.fullName }}</span>
|
|
20
|
+
<!-- Gate on !authenticated only, never on `ready`: with no load-time SSO
|
|
21
|
+
check, `ready` flips true immediately but stays informational — the
|
|
22
|
+
sign-in affordance must always show until the user is authenticated. -->
|
|
23
|
+
<goa-button v-if="!kc.authenticated" type="tertiary" @_click="login">
|
|
20
24
|
Sign in
|
|
21
25
|
</goa-button>
|
|
22
|
-
<goa-button v-if="authenticated" type="tertiary" @_click="logout">
|
|
26
|
+
<goa-button v-if="kc.authenticated" type="tertiary" @_click="logout">
|
|
23
27
|
Sign out
|
|
24
28
|
</goa-button>
|
|
25
29
|
</goa-button-group>
|
|
@@ -18,10 +18,23 @@ app.use(keycloakPlugin, {
|
|
|
18
18
|
realm: environment.access.realm,
|
|
19
19
|
clientId: environment.access.client_id,
|
|
20
20
|
},
|
|
21
|
+
// No load-time SSO check and no hidden iframes. keycloak-js's silent-SSO
|
|
22
|
+
// (silentCheckSsoRedirectUri) and login-status (checkLoginIframe) iframes both
|
|
23
|
+
// wait on an untimed postMessage that never arrives when third-party cookies are
|
|
24
|
+
// blocked (common cross-origin, e.g. behind the ADSP gateway) — init() then
|
|
25
|
+
// hangs forever, the wrapper never populates its `keycloak` ref, and login()
|
|
26
|
+
// stays a permanent no-op. So we disable every iframe: checkLoginIframe:false
|
|
27
|
+
// drops the login-status iframe, omitting silentCheckSsoRedirectUri drops the
|
|
28
|
+
// silent iframe (that combination also skips the 3p-cookie probe iframe), and an
|
|
29
|
+
// empty onLoad skips the load-time check entirely — the wrapper requires onLoad
|
|
30
|
+
// to be a string, and keycloak-js treats a falsy onLoad as "no check". Result:
|
|
31
|
+
// init settles immediately as anonymous and Sign in redirects on demand. To
|
|
32
|
+
// auto-detect an existing session where the environment allows it, set
|
|
33
|
+
// onLoad: 'check-sso' (adds a prompt=none redirect round-trip on every load).
|
|
21
34
|
init: {
|
|
22
|
-
onLoad: '
|
|
35
|
+
onLoad: '',
|
|
23
36
|
pkceMethod: 'S256',
|
|
24
|
-
|
|
37
|
+
checkLoginIframe: false,
|
|
25
38
|
},
|
|
26
39
|
});
|
|
27
40
|
|
|
@@ -16,10 +16,12 @@ const router = createRouter({
|
|
|
16
16
|
|
|
17
17
|
router.beforeEach((to) => {
|
|
18
18
|
if (to.meta.requiresAuth) {
|
|
19
|
-
|
|
20
|
-
if
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
// Read fields off the reactive instance (don't destructure) — consistent with
|
|
20
|
+
// the views and safe if this ever moves out of the per-navigation callback.
|
|
21
|
+
const kc = useKeycloak();
|
|
22
|
+
if (!kc.ready) return true;
|
|
23
|
+
if (!kc.authenticated) {
|
|
24
|
+
kc.keycloak?.login({ redirectUri: window.location.origin + to.fullPath });
|
|
23
25
|
return false;
|
|
24
26
|
}
|
|
25
27
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, onMounted } from 'vue';
|
|
2
|
+
import { ref, onMounted, watch } from 'vue';
|
|
3
3
|
import { useKeycloak } from '@dsb-norge/vue-keycloak-js';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// Keep the reactive instance — do NOT destructure (see App.vue): a destructured
|
|
6
|
+
// `authenticated`/`keycloak` freezes at its setup-time value, so the private
|
|
7
|
+
// fetch below would never see the user sign in and the bearer token stays undefined.
|
|
8
|
+
const kc = useKeycloak();
|
|
6
9
|
const publicResource = ref('Not retrieved — is the backend service running?');
|
|
7
10
|
const privateResource = ref('Not retrieved — sign in first.');
|
|
8
11
|
|
|
@@ -14,20 +17,27 @@ onMounted(async () => {
|
|
|
14
17
|
} catch {
|
|
15
18
|
publicResource.value = 'Error loading public resource.';
|
|
16
19
|
}
|
|
20
|
+
});
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
// React to authentication (which settles asynchronously and may flip after mount,
|
|
23
|
+
// e.g. on return from the login redirect) rather than reading it once on mount.
|
|
24
|
+
watch(
|
|
25
|
+
() => kc.authenticated,
|
|
26
|
+
async (authenticated) => {
|
|
27
|
+
if (!authenticated) return;
|
|
19
28
|
try {
|
|
20
|
-
await keycloak?.updateToken(30);
|
|
29
|
+
await kc.keycloak?.updateToken(30);
|
|
21
30
|
const res = await fetch('/api/v1/private', {
|
|
22
|
-
headers: { Authorization: `Bearer ${keycloak?.token}` },
|
|
31
|
+
headers: { Authorization: `Bearer ${kc.keycloak?.token}` },
|
|
23
32
|
});
|
|
24
33
|
const data = await res.json();
|
|
25
34
|
privateResource.value = data.message;
|
|
26
35
|
} catch {
|
|
27
36
|
privateResource.value = 'Error loading private resource.';
|
|
28
37
|
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
38
|
+
},
|
|
39
|
+
{ immediate: true }
|
|
40
|
+
);
|
|
31
41
|
</script>
|
|
32
42
|
|
|
33
43
|
<template>
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue';
|
|
2
3
|
import { useKeycloak } from '@dsb-norge/vue-keycloak-js';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
// Keep the reactive instance — do NOT destructure (see App.vue): fullName and
|
|
6
|
+
// tokenParsed populate asynchronously once Keycloak settles, so a destructured
|
|
7
|
+
// snapshot would freeze them at undefined and the page would render blank.
|
|
8
|
+
const kc = useKeycloak();
|
|
9
|
+
const userEmail = computed(() => kc.tokenParsed?.email ?? '');
|
|
6
10
|
</script>
|
|
7
11
|
|
|
8
12
|
<template>
|
|
9
13
|
<section>
|
|
10
14
|
<h2>Protected page</h2>
|
|
11
|
-
<p>You are signed in as <strong>{{ fullName }}</strong> ({{ userEmail }}).</p>
|
|
15
|
+
<p>You are signed in as <strong>{{ kc.fullName }}</strong> ({{ userEmail }}).</p>
|
|
12
16
|
<router-link to="/">← Back to home</router-link>
|
|
13
17
|
</section>
|
|
14
18
|
</template>
|
|
@@ -66,8 +66,9 @@ function default_1(host, options) {
|
|
|
66
66
|
(0, devkit_1.addDependenciesToPackageJson)(host, {
|
|
67
67
|
'@abgov/design-tokens': '1.8.0',
|
|
68
68
|
'@abgov/web-components': '1.39.3',
|
|
69
|
+
// keycloak-js is a transitive dependency of @dsb-norge/vue-keycloak-js;
|
|
70
|
+
// don't pin it directly or the versions diverge into two copies.
|
|
69
71
|
'@dsb-norge/vue-keycloak-js': '^3.0.0',
|
|
70
|
-
'keycloak-js': '^23.0.7',
|
|
71
72
|
'pinia': '^2.0.0',
|
|
72
73
|
'vue-router': '^4.0.0',
|
|
73
74
|
}, {
|
|
@@ -101,8 +102,8 @@ function default_1(host, options) {
|
|
|
101
102
|
if (addedProxy && ((_a = config.targets.serve) === null || _a === void 0 ? void 0 : _a.options)) {
|
|
102
103
|
config.targets.serve.options = Object.assign(Object.assign({}, config.targets.serve.options), { proxyConfig: `${normalizedOptions.projectRoot}/vite.proxy.json` });
|
|
103
104
|
}
|
|
104
|
-
// nginx.conf
|
|
105
|
-
// (<projectRoot>/public) so
|
|
105
|
+
// nginx.conf lives in the Vite publicDir
|
|
106
|
+
// (<projectRoot>/public) so it's emitted to the build output root — the
|
|
106
107
|
// @nx/vite:build executor ignores webpack-style `assets`. Pin outputPath to
|
|
107
108
|
// the workspace-root dist so it matches the vite config's outDir and the
|
|
108
109
|
// generated Dockerfile's COPY path.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vue-app.js","sourceRoot":"","sources":["../../../../../../packages/nx-adsp/src/generators/vue-app/vue-app.ts"],"names":[],"mappings":";;AAgEA,
|
|
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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"}
|
|
@@ -36,9 +36,8 @@ describe('Vue App Generator', () => {
|
|
|
36
36
|
await generator(host, options);
|
|
37
37
|
const config = readProjectConfiguration(host, 'test');
|
|
38
38
|
expect(config.root).toBe('apps/test');
|
|
39
|
-
// nginx.conf
|
|
39
|
+
// nginx.conf lives in the Vite publicDir so it ends up in the build output.
|
|
40
40
|
expect(host.exists('apps/test/public/nginx.conf')).toBeTruthy();
|
|
41
|
-
expect(host.exists('apps/test/public/silent-check-sso.html')).toBeTruthy();
|
|
42
41
|
expect(host.exists('apps/test/src/main.ts')).toBeTruthy();
|
|
43
42
|
expect(host.exists('apps/test/src/App.vue')).toBeTruthy();
|
|
44
43
|
expect(host.exists('apps/test/src/router/index.ts')).toBeTruthy();
|
|
@@ -50,6 +49,48 @@ describe('Vue App Generator', () => {
|
|
|
50
49
|
expect(config.targets.build.options.outputPath).toBe('dist/apps/test');
|
|
51
50
|
}, 30000);
|
|
52
51
|
|
|
52
|
+
it('inits Keycloak with no hidden iframes so init never hangs', async () => {
|
|
53
|
+
await generator(host, options);
|
|
54
|
+
// Strip // comments — they legitimately reference the disabled iframe options
|
|
55
|
+
// to explain their absence; assert against the actual init code.
|
|
56
|
+
const code = host
|
|
57
|
+
.read('apps/test/src/main.ts')
|
|
58
|
+
.toString()
|
|
59
|
+
.split('\n')
|
|
60
|
+
.filter((l) => !l.trim().startsWith('//'))
|
|
61
|
+
.join('\n');
|
|
62
|
+
// keycloak-js's silent-SSO (silentCheckSsoRedirectUri) and login-status
|
|
63
|
+
// (checkLoginIframe) iframes both wait on an untimed postMessage that hangs
|
|
64
|
+
// when third-party cookies are blocked, leaving keycloak.login() a no-op. We
|
|
65
|
+
// disable both and skip the load-time check (empty onLoad) so init settles.
|
|
66
|
+
expect(code).not.toContain('silentCheckSsoRedirectUri');
|
|
67
|
+
expect(code).toContain('checkLoginIframe: false');
|
|
68
|
+
expect(code).toContain("onLoad: ''");
|
|
69
|
+
expect(code).toContain("pkceMethod: 'S256'");
|
|
70
|
+
// the now-unused silent-check-sso.html is no longer generated
|
|
71
|
+
expect(host.exists('apps/test/public/silent-check-sso.html')).toBeFalsy();
|
|
72
|
+
}, 30000);
|
|
73
|
+
|
|
74
|
+
it('reads Keycloak fields off the reactive instance without destructuring', async () => {
|
|
75
|
+
await generator(host, options);
|
|
76
|
+
// The Sign in no-op bug: destructuring useKeycloak() (a readonly(reactive()))
|
|
77
|
+
// froze `keycloak` at undefined so login() never fired. Every consumer must
|
|
78
|
+
// keep the instance and read fields off it.
|
|
79
|
+
for (const file of [
|
|
80
|
+
'apps/test/src/App.vue',
|
|
81
|
+
'apps/test/src/views/HomeView.vue',
|
|
82
|
+
'apps/test/src/views/ProtectedView.vue',
|
|
83
|
+
'apps/test/src/router/index.ts',
|
|
84
|
+
]) {
|
|
85
|
+
const code = host.read(file).toString();
|
|
86
|
+
expect(code).toContain('= useKeycloak()');
|
|
87
|
+
// no destructuring assignment off useKeycloak()
|
|
88
|
+
expect(code).not.toMatch(/const\s*\{[^}]*\}\s*=\s*useKeycloak\(\)/);
|
|
89
|
+
}
|
|
90
|
+
const app = host.read('apps/test/src/App.vue').toString();
|
|
91
|
+
expect(app).toContain('kc.keycloak?.login()');
|
|
92
|
+
}, 30000);
|
|
93
|
+
|
|
53
94
|
it('index.html is at the Vite entry root and its mount target matches main.ts', async () => {
|
|
54
95
|
await generator(host, options);
|
|
55
96
|
// Vite's entry is <projectRoot>/index.html, not src/index.html — a template
|
package/src/utils/quality.d.ts
CHANGED
|
@@ -21,3 +21,13 @@ export declare function addJestCoverageConfig(host: Tree, projectRoot: string):
|
|
|
21
21
|
*/
|
|
22
22
|
export declare function addSemgrepTarget(host: Tree, projectName: string): void;
|
|
23
23
|
export declare function addVsCodeSettings(host: Tree): void;
|
|
24
|
+
/**
|
|
25
|
+
* Registers the @abgov/adsp-sdk-mcp-server MCP server in the workspace-root
|
|
26
|
+
* `.mcp.json` so a coding agent (Claude Code and other MCP clients) can look up
|
|
27
|
+
* grounded ADSP docs and `@abgov/adsp-service-sdk` reference instead of guessing.
|
|
28
|
+
*
|
|
29
|
+
* It's a stdio knowledge server (no credentials, run via npx), so wiring is just
|
|
30
|
+
* config. Merges into an existing `.mcp.json` and never clobbers a user-customized
|
|
31
|
+
* `adsp-sdk` entry, so it's safe to re-run and to run for every generated service.
|
|
32
|
+
*/
|
|
33
|
+
export declare function addAdspMcpServer(host: Tree): void;
|
package/src/utils/quality.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.addEslintQualityRules = addEslintQualityRules;
|
|
|
4
4
|
exports.addJestCoverageConfig = addJestCoverageConfig;
|
|
5
5
|
exports.addSemgrepTarget = addSemgrepTarget;
|
|
6
6
|
exports.addVsCodeSettings = addVsCodeSettings;
|
|
7
|
+
exports.addAdspMcpServer = addAdspMcpServer;
|
|
7
8
|
const devkit_1 = require("@nx/devkit");
|
|
8
9
|
/**
|
|
9
10
|
* Rewrites the project-level eslint.config.mjs to add:
|
|
@@ -100,4 +101,30 @@ function addVsCodeSettings(host) {
|
|
|
100
101
|
(0, devkit_1.writeJson)(host, settingsPath, settings);
|
|
101
102
|
}
|
|
102
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Registers the @abgov/adsp-sdk-mcp-server MCP server in the workspace-root
|
|
106
|
+
* `.mcp.json` so a coding agent (Claude Code and other MCP clients) can look up
|
|
107
|
+
* grounded ADSP docs and `@abgov/adsp-service-sdk` reference instead of guessing.
|
|
108
|
+
*
|
|
109
|
+
* It's a stdio knowledge server (no credentials, run via npx), so wiring is just
|
|
110
|
+
* config. Merges into an existing `.mcp.json` and never clobbers a user-customized
|
|
111
|
+
* `adsp-sdk` entry, so it's safe to re-run and to run for every generated service.
|
|
112
|
+
*/
|
|
113
|
+
function addAdspMcpServer(host) {
|
|
114
|
+
const mcpPath = '.mcp.json';
|
|
115
|
+
const server = { command: 'npx', args: ['-y', '@abgov/adsp-sdk-mcp-server'] };
|
|
116
|
+
if (host.exists(mcpPath)) {
|
|
117
|
+
(0, devkit_1.updateJson)(host, mcpPath, (existing) => {
|
|
118
|
+
var _a, _b;
|
|
119
|
+
const mcpServers = Object.assign({}, ((_a = existing === null || existing === void 0 ? void 0 : existing.mcpServers) !== null && _a !== void 0 ? _a : {}));
|
|
120
|
+
// Preserve an existing entry (a team may have pinned a version or repointed
|
|
121
|
+
// it at a local build) — only add ours when it isn't already configured.
|
|
122
|
+
mcpServers['adsp-sdk'] = (_b = mcpServers['adsp-sdk']) !== null && _b !== void 0 ? _b : server;
|
|
123
|
+
return Object.assign(Object.assign({}, existing), { mcpServers });
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
(0, devkit_1.writeJson)(host, mcpPath, { mcpServers: { 'adsp-sdk': server } });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
103
130
|
//# sourceMappingURL=quality.js.map
|
package/src/utils/quality.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quality.js","sourceRoot":"","sources":["../../../../../packages/nx-adsp/src/utils/quality.ts"],"names":[],"mappings":";;AAUA,sDAoCC;AAOD,sDAgBC;AAOD,4CAeC;AAED,8CAeC;
|
|
1
|
+
{"version":3,"file":"quality.js","sourceRoot":"","sources":["../../../../../packages/nx-adsp/src/utils/quality.ts"],"names":[],"mappings":"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"}
|