diff --git a/.changeset/tricky-spoons-pay.md b/.changeset/tricky-spoons-pay.md new file mode 100644 index 000000000..3cfbc18dc --- /dev/null +++ b/.changeset/tricky-spoons-pay.md @@ -0,0 +1,7 @@ +--- +"@logto/js": minor +--- + +add `buildAngularAuthConfig()` to build `angular-auth-oidc-client` config in a Logto way + +Also add a new type `LogtoAngularConfig`. diff --git a/.gitignore b/.gitignore index 20fd7deb1..877706d51 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,9 @@ node_modules /packages/*/dist /packages/*/lib /packages/*/build +/packages/*/tmp +/packages/*/out-tsc +/packages/*/bazel-out # logs logs @@ -22,13 +25,16 @@ yarn-error.log* .pnpm-debug.log* # misc +.angular/cache +.sass-cache/ cache .*cache .DS_Store +Thumbs.db *.env .idea/ *.pem .history .vercel .next -*.local \ No newline at end of file +*.local diff --git a/packages/angular-sample/README.md b/packages/angular-sample/README.md new file mode 100644 index 000000000..48750a5f9 --- /dev/null +++ b/packages/angular-sample/README.md @@ -0,0 +1,35 @@ +# Logto Angular sample + +A sample Angular application that demonstrates how to integrate Logto with `angular-auth-oidc-client`. + +**Configuration**: See [app.config.ts](src/app/app.config.ts). +**Usage**: See [app.component.ts](src/app/app.component.ts). + +For more information about `angular-auth-oidc-client`, see its [repository](https://github.com/damienbod/angular-auth-oidc-client) and official [documentation](https://angular-auth-oidc-client.com/). + +> *[!Note] +> This project is excluded from the workspace. To run the sample, you need to manually install project dependencies. + +--- + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.2.0. + +## Development server + +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. + +## Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. diff --git a/packages/angular-sample/angular.json b/packages/angular-sample/angular.json new file mode 100644 index 000000000..f3cf9e5f8 --- /dev/null +++ b/packages/angular-sample/angular.json @@ -0,0 +1,106 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "@logto/angular-sample": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:application", + "options": { + "outputPath": "dist/logto/angular-sample", + "index": "src/index.html", + "browser": "src/main.ts", + "polyfills": [ + "zone.js" + ], + "tsConfig": "tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.scss" + ], + "scripts": [], + "server": "src/main.server.ts", + "prerender": true, + "ssr": { + "entry": "server.ts" + } + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "@logto/angular-sample:build:production" + }, + "development": { + "buildTarget": "@logto/angular-sample:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "@logto/angular-sample:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "polyfills": [ + "zone.js", + "zone.js/testing" + ], + "tsConfig": "tsconfig.spec.json", + "inlineStyleLanguage": "scss", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.scss" + ], + "scripts": [] + } + } + } + } + } +} diff --git a/packages/angular-sample/package.json b/packages/angular-sample/package.json new file mode 100644 index 000000000..686ac041d --- /dev/null +++ b/packages/angular-sample/package.json @@ -0,0 +1,46 @@ +{ + "name": "@logto/angular-sample", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "watch": "ng build --watch --configuration development", + "test": "ng test", + "serve:ssr:@logto/angular-sample": "node dist/logto/angular-sample/server/server.mjs" + }, + "private": true, + "dependencies": { + "@angular/animations": "^17.2.0", + "@angular/common": "^17.2.0", + "@angular/compiler": "^17.2.0", + "@angular/core": "^17.2.0", + "@angular/forms": "^17.2.0", + "@angular/platform-browser": "^17.2.0", + "@angular/platform-browser-dynamic": "^17.2.0", + "@angular/platform-server": "^17.2.0", + "@angular/router": "^17.2.0", + "@angular/ssr": "^17.2.0", + "@logto/js": "workspace:^", + "angular-auth-oidc-client": "^17.0.0", + "express": "^4.18.2", + "rxjs": "~7.8.0", + "tslib": "^2.3.0", + "zone.js": "~0.14.3" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^17.2.0", + "@angular/cli": "^17.2.0", + "@angular/compiler-cli": "^17.2.0", + "@types/express": "^4.17.17", + "@types/jasmine": "~5.1.0", + "@types/node": "^18.18.0", + "jasmine-core": "~5.1.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.2.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.1.0", + "typescript": "~5.3.2" + } +} \ No newline at end of file diff --git a/packages/angular-sample/server.ts b/packages/angular-sample/server.ts new file mode 100644 index 000000000..7083b14fe --- /dev/null +++ b/packages/angular-sample/server.ts @@ -0,0 +1,56 @@ +import { APP_BASE_HREF } from '@angular/common'; +import { CommonEngine } from '@angular/ssr'; +import express from 'express'; +import { fileURLToPath } from 'node:url'; +import { dirname, join, resolve } from 'node:path'; +import bootstrap from './src/main.server'; + +// The Express app is exported so that it can be used by serverless Functions. +export function app(): express.Express { + const server = express(); + const serverDistFolder = dirname(fileURLToPath(import.meta.url)); + const browserDistFolder = resolve(serverDistFolder, '../browser'); + const indexHtml = join(serverDistFolder, 'index.server.html'); + + const commonEngine = new CommonEngine(); + + server.set('view engine', 'html'); + server.set('views', browserDistFolder); + + // Example Express Rest API endpoints + // server.get('/api/**', (req, res) => { }); + // Serve static files from /browser + server.get('*.*', express.static(browserDistFolder, { + maxAge: '1y' + })); + + // All regular routes use the Angular engine + server.get('*', (req, res, next) => { + const { protocol, originalUrl, baseUrl, headers } = req; + + commonEngine + .render({ + bootstrap, + documentFilePath: indexHtml, + url: `${protocol}://${headers.host}${originalUrl}`, + publicPath: browserDistFolder, + providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }], + }) + .then((html) => res.send(html)) + .catch((err) => next(err)); + }); + + return server; +} + +function run(): void { + const port = process.env['PORT'] || 4000; + + // Start up the Node server + const server = app(); + server.listen(port, () => { + console.log(`Node Express server listening on http://localhost:${port}`); + }); +} + +run(); diff --git a/packages/angular-sample/src/app/app.component.html b/packages/angular-sample/src/app/app.component.html new file mode 100644 index 000000000..f32ed256e --- /dev/null +++ b/packages/angular-sample/src/app/app.component.html @@ -0,0 +1,9 @@ +

Hello, {{ title }}

+

Congratulations! Your app is running. 🎉

+ + +
{{ userData | json }}
+

Access token: {{ accessToken }}

+ +
+ diff --git a/packages/angular-sample/src/app/app.component.scss b/packages/angular-sample/src/app/app.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/packages/angular-sample/src/app/app.component.spec.ts b/packages/angular-sample/src/app/app.component.spec.ts new file mode 100644 index 000000000..535e602b4 --- /dev/null +++ b/packages/angular-sample/src/app/app.component.spec.ts @@ -0,0 +1,29 @@ +import { TestBed } from '@angular/core/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AppComponent], + }).compileComponents(); + }); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.componentInstance; + expect(app).toBeTruthy(); + }); + + it(`should have the '@logto/angular-sample' title`, () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.componentInstance; + expect(app.title).toEqual('@logto/angular-sample'); + }); + + it('should render title', () => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.nativeElement as HTMLElement; + expect(compiled.querySelector('h1')?.textContent).toContain('Hello, @logto/angular-sample'); + }); +}); diff --git a/packages/angular-sample/src/app/app.component.ts b/packages/angular-sample/src/app/app.component.ts new file mode 100644 index 000000000..741d0ac69 --- /dev/null +++ b/packages/angular-sample/src/app/app.component.ts @@ -0,0 +1,43 @@ +import { Component, OnInit } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; +import { CommonModule } from '@angular/common'; +import { OidcSecurityService } from 'angular-auth-oidc-client'; +import type { UserInfoResponse } from '@logto/js'; + +@Component({ + selector: 'app-root', + standalone: true, + imports: [RouterOutlet, CommonModule], + templateUrl: './app.component.html', + styleUrl: './app.component.scss' +}) +export class AppComponent implements OnInit { + title = '@logto/angular-sample'; + isAuthenticated = false; + userData?: UserInfoResponse; + idToken?: string; + accessToken?: string; + + constructor(public oidcSecurityService: OidcSecurityService) { } + + ngOnInit() { + this.oidcSecurityService.checkAuth().subscribe(({ isAuthenticated, userData, idToken, accessToken }) => { + console.log('app authenticated', isAuthenticated, userData); + this.isAuthenticated = isAuthenticated; + this.userData = userData; + this.idToken = idToken; + this.accessToken = accessToken; + }); + } + + signIn() { + this.oidcSecurityService.authorize(); + } + + signOut() { + this.oidcSecurityService.logoff().subscribe((result) => { + console.log('app sign-out', result); + this.isAuthenticated = false; + }); + } +} diff --git a/packages/angular-sample/src/app/app.config.server.ts b/packages/angular-sample/src/app/app.config.server.ts new file mode 100644 index 000000000..b4d57c942 --- /dev/null +++ b/packages/angular-sample/src/app/app.config.server.ts @@ -0,0 +1,11 @@ +import { mergeApplicationConfig, ApplicationConfig } from '@angular/core'; +import { provideServerRendering } from '@angular/platform-server'; +import { appConfig } from './app.config'; + +const serverConfig: ApplicationConfig = { + providers: [ + provideServerRendering() + ] +}; + +export const config = mergeApplicationConfig(appConfig, serverConfig); diff --git a/packages/angular-sample/src/app/app.config.ts b/packages/angular-sample/src/app/app.config.ts new file mode 100644 index 000000000..bdaaf1b06 --- /dev/null +++ b/packages/angular-sample/src/app/app.config.ts @@ -0,0 +1,27 @@ +import { ApplicationConfig } from '@angular/core'; +import { provideRouter } from '@angular/router'; +import { provideAuth } from 'angular-auth-oidc-client'; + +import { routes } from './app.routes'; +import { provideClientHydration } from '@angular/platform-browser'; +import { provideHttpClient, withFetch } from '@angular/common/http'; +import { UserScope, buildAngularAuthConfig } from '@logto/js'; + +export const appConfig: ApplicationConfig = { + providers: [ + provideHttpClient(withFetch()), + provideAuth({ + config: buildAngularAuthConfig({ + endpoint: '', + appId: '', + scopes: [UserScope.Email], // Replace with your scopes + redirectUri: '', + postLogoutRedirectUri: '', + // See https://docs.logto.io/sdk/angular/ for more information + // resource: 'https://default.logto.app/api' + }) + }), + provideRouter(routes), + provideClientHydration() + ] +}; diff --git a/packages/angular-sample/src/app/app.routes.ts b/packages/angular-sample/src/app/app.routes.ts new file mode 100644 index 000000000..dc39edb5f --- /dev/null +++ b/packages/angular-sample/src/app/app.routes.ts @@ -0,0 +1,3 @@ +import { Routes } from '@angular/router'; + +export const routes: Routes = []; diff --git a/packages/angular-sample/src/assets/.gitkeep b/packages/angular-sample/src/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/angular-sample/src/favicon.ico b/packages/angular-sample/src/favicon.ico new file mode 100644 index 000000000..57614f9c9 Binary files /dev/null and b/packages/angular-sample/src/favicon.ico differ diff --git a/packages/angular-sample/src/index.html b/packages/angular-sample/src/index.html new file mode 100644 index 000000000..a95e5ca0a --- /dev/null +++ b/packages/angular-sample/src/index.html @@ -0,0 +1,13 @@ + + + + + @logto/angularSample + + + + + + + + diff --git a/packages/angular-sample/src/main.server.ts b/packages/angular-sample/src/main.server.ts new file mode 100644 index 000000000..4b9d4d154 --- /dev/null +++ b/packages/angular-sample/src/main.server.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { config } from './app/app.config.server'; + +const bootstrap = () => bootstrapApplication(AppComponent, config); + +export default bootstrap; diff --git a/packages/angular-sample/src/main.ts b/packages/angular-sample/src/main.ts new file mode 100644 index 000000000..35b00f346 --- /dev/null +++ b/packages/angular-sample/src/main.ts @@ -0,0 +1,6 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { appConfig } from './app/app.config'; +import { AppComponent } from './app/app.component'; + +bootstrapApplication(AppComponent, appConfig) + .catch((err) => console.error(err)); diff --git a/packages/angular-sample/src/styles.scss b/packages/angular-sample/src/styles.scss new file mode 100644 index 000000000..90d4ee007 --- /dev/null +++ b/packages/angular-sample/src/styles.scss @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/packages/angular-sample/tsconfig.app.json b/packages/angular-sample/tsconfig.app.json new file mode 100644 index 000000000..7dc7284f6 --- /dev/null +++ b/packages/angular-sample/tsconfig.app.json @@ -0,0 +1,18 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [ + "node" + ] + }, + "files": [ + "src/main.ts", + "src/main.server.ts", + "server.ts" + ], + "include": [ + "src/**/*.d.ts" + ] +} diff --git a/packages/angular-sample/tsconfig.json b/packages/angular-sample/tsconfig.json new file mode 100644 index 000000000..f37b67ff0 --- /dev/null +++ b/packages/angular-sample/tsconfig.json @@ -0,0 +1,33 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "compileOnSave": false, + "compilerOptions": { + "outDir": "./dist/out-tsc", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + "esModuleInterop": true, + "sourceMap": true, + "declaration": false, + "experimentalDecorators": true, + "moduleResolution": "node", + "importHelpers": true, + "target": "ES2022", + "module": "ES2022", + "useDefineForClassFields": false, + "lib": [ + "ES2022", + "dom" + ] + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/packages/angular-sample/tsconfig.spec.json b/packages/angular-sample/tsconfig.spec.json new file mode 100644 index 000000000..be7e9da76 --- /dev/null +++ b/packages/angular-sample/tsconfig.spec.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/packages/js/package.json b/packages/js/package.json index d1aa0dd79..0810a8cde 100644 --- a/packages/js/package.json +++ b/packages/js/package.json @@ -41,6 +41,7 @@ "@swc/jest": "^0.2.24", "@types/jest": "^29.5.1", "@types/node": "^20.11.19", + "angular-auth-oidc-client": "^17.0.0", "eslint": "^8.44.0", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0", diff --git a/packages/js/src/core/user-info.test.ts b/packages/js/src/core/user-info.test.ts index e08552759..4a2716dfc 100644 --- a/packages/js/src/core/user-info.test.ts +++ b/packages/js/src/core/user-info.test.ts @@ -3,7 +3,13 @@ import { fetchUserInfo } from './user-info.js'; describe('fetchUserInfo', () => { test('should return UserInfoResponse', async () => { - const userInfoResponse: UserInfoResponse = { sub: 'foo' }; + const userInfoResponse: UserInfoResponse = { + sub: 'foo', + iss: 'bar', + aud: 'baz', + iat: 123, + exp: 123, + }; const fetchFunction = jest.fn().mockResolvedValue(userInfoResponse); await expect( fetchUserInfo('https://example.com/oidc/me', 'access_token_value', fetchFunction) diff --git a/packages/js/src/core/user-info.ts b/packages/js/src/core/user-info.ts index cd4db7be4..100f0cf8f 100644 --- a/packages/js/src/core/user-info.ts +++ b/packages/js/src/core/user-info.ts @@ -1,5 +1,4 @@ -import type { Nullable } from '@silverhand/essentials'; - +import { type IdTokenClaims } from '../index.js'; import type { Requester } from '../types/index.js'; type Identity = { @@ -7,17 +6,9 @@ type Identity = { details?: Record; }; -export type UserInfoResponse = { - sub: string; - name?: Nullable; - username?: Nullable; - picture?: Nullable; - email?: Nullable; - email_verified?: boolean; - phone_number?: Nullable; - phone_number_verified?: boolean; - custom_data?: unknown; // Not null in DB. - identities?: Record; // Not null in DB. +export type UserInfoResponse = IdTokenClaims & { + custom_data?: unknown; + identities?: Record; }; export const fetchUserInfo = async ( diff --git a/packages/js/src/utils/angular.ts b/packages/js/src/utils/angular.ts new file mode 100644 index 000000000..c699c24a2 --- /dev/null +++ b/packages/js/src/utils/angular.ts @@ -0,0 +1,110 @@ +import { type OpenIdConfiguration } from 'angular-auth-oidc-client'; + +import { Prompt } from '../consts/index.js'; + +import { withDefaultScopes } from './scopes.js'; + +/** The Logto configuration object for Angular apps. */ +export type LogtoAngularConfig = { + /** + * The endpoint for the Logto server, you can get it from the integration guide + * or the team settings page of the Logto Console. + * + * @example https://foo.logto.app + */ + endpoint: string; + /** + * The client ID of your application, you can get it from the integration guide + * or the application details page of the Logto Console. + */ + appId: string; + /** + * The scopes (permissions) that your application needs to access. + * Scopes that will be added by default: `openid`, `offline_access` and `profile`. + */ + scopes?: string[]; + /** + * The API resource that your application needs to access. + * + * @see {@link https://docs.logto.io/docs/recipes/rbac/ | RBAC} to learn more about how to use + * role-based access control (RBAC) to protect API resources. + */ + resource?: string; + /** + * @param redirectUri The redirect URI that the user will be redirected to after the sign-in flow + * is completed. + */ + redirectUri: string; + /** + * @param postLogoutRedirectUri The URI that the user will be redirected to after the sign-out + * flow is completed. + */ + postLogoutRedirectUri?: string; + /** + * The prompt parameter to be used for the authorization request. + * + * @default Prompt.Consent + */ + prompt?: Prompt | Prompt[]; +}; + +/** + * A helper function to build the OpenID Connect configuration for `angular-auth-oidc-client` + * using a Logto-friendly way. + * + * @example + * ```ts + * // A minimal example + * import { buildAngularAuthConfig } from '@logto/js'; + * import { provideAuth } from 'angular-auth-oidc-client'; + * + * provideAuth({ + * config: buildAngularAuthConfig({ + * endpoint: '', + * appId: '', + * redirectUri: '', + * }), + * }); + * ``` + * + * @param logtoConfig The Logto configuration object for Angular apps. + * @returns The OpenID Connect configuration for `angular-auth-oidc-client`. + * @see {@link https://angular-auth-oidc-client.com/ | angular-auth-oidc-client} to learn more + * about how to use the library. + */ +export const buildAngularAuthConfig = (logtoConfig: LogtoAngularConfig): OpenIdConfiguration => { + const { + endpoint, + appId: clientId, + scopes, + resource, + redirectUri: redirectUrl, + postLogoutRedirectUri, + prompt = Prompt.Consent, + } = logtoConfig; + const scope = withDefaultScopes(scopes); + const customParameters = resource ? { resource } : undefined; + + return { + authority: new URL('/oidc', endpoint).href, + redirectUrl, + postLogoutRedirectUri, + clientId, + scope, + responseType: 'code', + autoUserInfo: !resource, + renewUserInfoAfterTokenRenew: !resource, + silentRenew: true, + useRefreshToken: true, + customParamsAuthRequest: { + prompt: Array.isArray(prompt) ? prompt.join(' ') : prompt, + ...customParameters, + }, + customParamsCodeRequest: { + ...customParameters, + }, + customParamsRefreshTokenRequest: { + ...customParameters, + }, + }; +}; diff --git a/packages/js/src/utils/index.ts b/packages/js/src/utils/index.ts index b62ee6930..67933b790 100644 --- a/packages/js/src/utils/index.ts +++ b/packages/js/src/utils/index.ts @@ -4,3 +4,4 @@ export * from './id-token.js'; export * from './access-token.js'; export * from './scopes.js'; export * from './arbitrary-object.js'; +export * from './angular.js'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cd538f11c..85b6b5179 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -411,6 +411,9 @@ importers: '@types/node': specifier: ^20.11.19 version: 20.11.19 + angular-auth-oidc-client: + specifier: ^17.0.0 + version: 17.0.0(@angular/common@17.2.1)(@angular/core@17.2.1)(@angular/router@17.2.1)(rxjs@7.8.1) eslint: specifier: ^8.44.0 version: 8.44.0 @@ -1123,6 +1126,62 @@ packages: dependencies: '@jridgewell/trace-mapping': 0.3.17 + /@angular/common@17.2.1(@angular/core@17.2.1)(rxjs@7.8.1): + resolution: {integrity: sha512-ZkQwvjJhnqKulJn3kwbnodYvQf8g8hy2FUMB2MRLXKgwLPv9iqF/KRgSwcNIZnq8hyvIr6FmAntMdyCOonykDQ==} + engines: {node: ^18.13.0 || >=20.9.0} + peerDependencies: + '@angular/core': 17.2.1 + rxjs: ^6.5.3 || ^7.4.0 + dependencies: + '@angular/core': 17.2.1(rxjs@7.8.1)(zone.js@0.14.4) + rxjs: 7.8.1 + tslib: 2.5.0 + dev: true + + /@angular/core@17.2.1(rxjs@7.8.1)(zone.js@0.14.4): + resolution: {integrity: sha512-gfWeskXA8RA0D3WOPBV5wT8RpqtqFhB8OCR8diGfLojqbMrmZXEvxALBHKAgfarWcR1rnRgmjCQKejWLWCLmmg==} + engines: {node: ^18.13.0 || >=20.9.0} + peerDependencies: + rxjs: ^6.5.3 || ^7.4.0 + zone.js: ~0.14.0 + dependencies: + rxjs: 7.8.1 + tslib: 2.5.0 + zone.js: 0.14.4 + dev: true + + /@angular/platform-browser@17.2.1(@angular/common@17.2.1)(@angular/core@17.2.1): + resolution: {integrity: sha512-on+fTZiDTBJmRQbQe6GOClqaUFe4GJdLS1EbmI+6/8Ntv4QW2PowWnaxajoqTj2Zrh22J9DSNy7RWcrQDdyU3g==} + engines: {node: ^18.13.0 || >=20.9.0} + peerDependencies: + '@angular/animations': 17.2.1 + '@angular/common': 17.2.1 + '@angular/core': 17.2.1 + peerDependenciesMeta: + '@angular/animations': + optional: true + dependencies: + '@angular/common': 17.2.1(@angular/core@17.2.1)(rxjs@7.8.1) + '@angular/core': 17.2.1(rxjs@7.8.1)(zone.js@0.14.4) + tslib: 2.5.0 + dev: true + + /@angular/router@17.2.1(@angular/common@17.2.1)(@angular/core@17.2.1)(@angular/platform-browser@17.2.1)(rxjs@7.8.1): + resolution: {integrity: sha512-sJFraoPTHV09jZQV3XcFHRJsY7EAuXcBn5k+7GGye60YgTXAjL3OC++Cuv4AScFYRp+IqbrE3I0tflsRtQzemw==} + engines: {node: ^18.13.0 || >=20.9.0} + peerDependencies: + '@angular/common': 17.2.1 + '@angular/core': 17.2.1 + '@angular/platform-browser': 17.2.1 + rxjs: ^6.5.3 || ^7.4.0 + dependencies: + '@angular/common': 17.2.1(@angular/core@17.2.1)(rxjs@7.8.1) + '@angular/core': 17.2.1(rxjs@7.8.1)(zone.js@0.14.4) + '@angular/platform-browser': 17.2.1(@angular/common@17.2.1)(@angular/core@17.2.1) + rxjs: 7.8.1 + tslib: 2.5.0 + dev: true + /@babel/code-frame@7.21.4: resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==} engines: {node: '>=6.9.0'} @@ -5306,6 +5365,22 @@ packages: uri-js: 4.4.1 dev: true + /angular-auth-oidc-client@17.0.0(@angular/common@17.2.1)(@angular/core@17.2.1)(@angular/router@17.2.1)(rxjs@7.8.1): + resolution: {integrity: sha512-WjQDwMJ+XpoCTht5wn8XgR1MFW+IykDvEOZNQCbpxzNzR1312hv6nPSStYQA9Jtpj3T6fZFFQsn06jfFwDE7WQ==} + peerDependencies: + '@angular/common': '>=15.0.0' + '@angular/core': '>=15.0.0' + '@angular/router': '>=15.0.0' + rxjs: ^6.5.3 || ^7.4.0 + dependencies: + '@angular/common': 17.2.1(@angular/core@17.2.1)(rxjs@7.8.1) + '@angular/core': 17.2.1(rxjs@7.8.1)(zone.js@0.14.4) + '@angular/router': 17.2.1(@angular/common@17.2.1)(@angular/core@17.2.1)(@angular/platform-browser@17.2.1)(rxjs@7.8.1) + rfc4648: 1.5.3 + rxjs: 7.8.1 + tslib: 2.5.0 + dev: true + /ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -11487,6 +11562,10 @@ packages: engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true + /rfc4648@1.5.3: + resolution: {integrity: sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==} + dev: true + /rfdc@1.3.0: resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} dev: true @@ -11547,6 +11626,12 @@ packages: queue-microtask: 1.2.3 dev: true + /rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + dependencies: + tslib: 2.5.0 + dev: true + /safe-array-concat@1.0.1: resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} engines: {node: '>=0.4'} @@ -13182,3 +13267,9 @@ packages: /zod@3.21.4: resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} + + /zone.js@0.14.4: + resolution: {integrity: sha512-NtTUvIlNELez7Q1DzKVIFZBzNb646boQMgpATo9z3Ftuu/gWvzxCW7jdjcUDoRGxRikrhVHB/zLXh1hxeJawvw==} + dependencies: + tslib: 2.5.0 + dev: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 18ec407ef..81a5d3c6a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,2 +1,3 @@ packages: - 'packages/*' + - '!packages/angular-sample' # Angular needs too many dependencies