diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index 9e1356873..a78465b23 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -60,10 +60,11 @@ services: thunder-setup: condition: service_completed_successfully ports: - - "8090:8090" + - "9090:8090" volumes: - thunder-db:/opt/thunder/repository/database - ./thunder-config/deployment.yaml:/opt/thunder/repository/conf/deployment.yaml:ro + - ./thunder-config/gate-config.js:/opt/thunder/apps/gate/config.js:ro healthcheck: test: ["CMD", "curl", "-k", "-f", "https://localhost:8090/health/readiness"] interval: 10s diff --git a/e2e/playwright-report-embedded/index.html b/e2e/playwright-report-embedded/index.html index 5a1660df4..5c7bc631f 100644 --- a/e2e/playwright-report-embedded/index.html +++ b/e2e/playwright-report-embedded/index.html @@ -82,4 +82,4 @@
- \ No newline at end of file + \ No newline at end of file diff --git a/e2e/setup/is/app-registration.ts b/e2e/setup/is/app-registration.ts index cb2bff02c..ed6cef641 100644 --- a/e2e/setup/is/app-registration.ts +++ b/e2e/setup/is/app-registration.ts @@ -137,7 +137,7 @@ export async function registerIsApp(): Promise<{clientId: string; clientSecret: }; // Remove read-only fields that can't be sent in PUT - delete updatedConfig.state; + delete (updatedConfig as Record).state; const oidcPutResponse = await fetch(oidcUrl, { method: 'PUT', diff --git a/e2e/setup/thunder/app-registration.ts b/e2e/setup/thunder/app-registration.ts index 0f6b0d15c..3926595d0 100644 --- a/e2e/setup/thunder/app-registration.ts +++ b/e2e/setup/thunder/app-registration.ts @@ -34,7 +34,7 @@ export async function getThunderAppClientId(): Promise<{clientId: string; applic let applicationId: string | undefined; try { - const result = thunderSqlite("SELECT APP_ID FROM SP_APP WHERE APP_NAME='React SDK Sample'"); + const result = thunderSqlite("SELECT APP_ID FROM APPLICATION WHERE APP_NAME='React SDK Sample'"); if (result) { applicationId = result; @@ -44,15 +44,13 @@ export async function getThunderAppClientId(): Promise<{clientId: string; applic console.warn('[E2E] Could not retrieve Thunder application ID from database'); } - // Patch the pre-configured app's OAuth config: - // 1. Add the callback URL to redirect_uris (bootstrap only has / and /dashboard) - // 2. Fix the token issuer to match the OIDC discovery issuer (baseUrl, not baseUrl/oauth2/token) + // Patch the pre-configured app's OAuth config to add the callback URL + // to redirect_uris (bootstrap only has / and /dashboard). const callbackUrl = `${SAMPLE_APP.url}${SAMPLE_APP.afterSignInPath}`; - const correctIssuer = THUNDER_CONFIG.baseUrl; try { const configJson = thunderSqlite( - `SELECT OAUTH_CONFIG_JSON FROM IDN_OAUTH_CONSUMER_APPS WHERE CONSUMER_KEY='${clientId}'`, + `SELECT OAUTH_CONFIG_JSON FROM APP_OAUTH_INBOUND_CONFIG WHERE CLIENT_ID='${clientId}'`, ); if (configJson) { @@ -68,25 +66,19 @@ export async function getThunderAppClientId(): Promise<{clientId: string; applic needsUpdate = true; } - // Fix token issuer to match OIDC discovery (required for ID token validation) - if (config.token?.issuer !== correctIssuer) { - config.token.issuer = correctIssuer; - needsUpdate = true; - } - if (needsUpdate) { const updatedJson = JSON.stringify(config); // Write JSON to a temp file inside the container to avoid shell escaping issues, // then use readfile() in the SQLite UPDATE. - execSync( - `docker exec -i ${CONTAINER} sh -c 'cat > /tmp/oauth_config.json'`, - {input: updatedJson, encoding: 'utf-8'}, - ); + execSync(`docker exec -i ${CONTAINER} sh -c 'cat > /tmp/oauth_config.json'`, { + input: updatedJson, + encoding: 'utf-8', + }); thunderSqlite( - `UPDATE IDN_OAUTH_CONSUMER_APPS SET OAUTH_CONFIG_JSON=readfile('/tmp/oauth_config.json') WHERE CONSUMER_KEY='${clientId}'`, + `UPDATE APP_OAUTH_INBOUND_CONFIG SET OAUTH_CONFIG_JSON=readfile('/tmp/oauth_config.json') WHERE CLIENT_ID='${clientId}'`, ); - console.log(`[E2E] Thunder app OAuth config updated (redirect_uris, token issuer)`); + console.log(`[E2E] Thunder app OAuth config updated (redirect_uris)`); } } } catch (err) { diff --git a/e2e/setup/thunder/constants.ts b/e2e/setup/thunder/constants.ts index df7acca67..93fe25af3 100644 --- a/e2e/setup/thunder/constants.ts +++ b/e2e/setup/thunder/constants.ts @@ -3,7 +3,7 @@ */ export const THUNDER_CONFIG = { - baseUrl: process.env.THUNDER_BASE_URL ?? 'https://localhost:8090', + baseUrl: process.env.THUNDER_BASE_URL ?? 'https://localhost:9090', healthCheckPath: '/health/readiness', adminUsername: 'admin', adminPassword: 'admin', diff --git a/e2e/thunder-bootstrap/02-sample-resources.sh b/e2e/thunder-bootstrap/02-sample-resources.sh index 28f4100fd..cbad4e8fa 100755 --- a/e2e/thunder-bootstrap/02-sample-resources.sh +++ b/e2e/thunder-bootstrap/02-sample-resources.sh @@ -188,7 +188,7 @@ RESPONSE=$(thunder_api_call POST "/applications" "{ \"registration_flow_graph_id\": \"${REG_FLOW_ID}\", \"is_registration_flow_enabled\": true, \"user_attributes\": [\"given_name\",\"family_name\",\"email\",\"groups\",\"name\"], - \"allowed_user_types\": [\"Customer\"], + \"allowed_user_types\": [\"Customer\",\"Person\"], \"inbound_auth_config\": [{ \"type\": \"oauth2\", \"config\": { @@ -201,7 +201,7 @@ RESPONSE=$(thunder_api_call POST "/applications" "{ \"pkce_required\": true, \"public_client\": true, \"token\": { - \"issuer\": \"${PUBLIC_URL}/oauth2/token\", + \"issuer\": \"${PUBLIC_URL}\", \"access_token\": { \"validity_period\": 3600, \"user_attributes\": [\"given_name\",\"family_name\",\"email\",\"groups\",\"name\"] diff --git a/e2e/thunder-config/deployment.yaml b/e2e/thunder-config/deployment.yaml index dfa5bf6b8..03c0b77a3 100644 --- a/e2e/thunder-config/deployment.yaml +++ b/e2e/thunder-config/deployment.yaml @@ -1,8 +1,14 @@ server: hostname: "0.0.0.0" - public_url: "https://localhost:8090" + public_url: "https://localhost:9090" port: 8090 +gate_client: + hostname: "localhost" + port: 9090 + scheme: "https" + path: "/gate" + tls: min_version: "1.3" cert_file: "repository/resources/security/server.cert" diff --git a/e2e/thunder-config/gate-config.js b/e2e/thunder-config/gate-config.js new file mode 100644 index 000000000..a710761e9 --- /dev/null +++ b/e2e/thunder-config/gate-config.js @@ -0,0 +1,18 @@ +/** + * Custom Gate runtime config for e2e tests. + * + * Points the Gate's API calls at the Docker Thunder container + * on port 9090 (mapped from 8090 to avoid conflicts with any + * local Thunder dev server). + */ + +/* eslint-disable no-underscore-dangle */ + +window.__THUNDER_RUNTIME_CONFIG__ = { + client: { + base: '/gate', + }, + server: { + public_url: 'https://localhost:9090', + }, +}; diff --git a/package.json b/package.json index b23a4ecb9..ac66f762c 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,13 @@ "undici": "^7.21.0" }, "pnpm": { + "packageExtensions": { + "@analogjs/vite-plugin-angular": { + "peerDependencies": { + "typescript": ">=5.5" + } + } + }, "overrides": { "pbkdf2": "3.1.3", "sha.js": "2.4.12", diff --git a/packages/angular/.eslintignore b/packages/angular/.eslintignore new file mode 100644 index 000000000..99b0b518a --- /dev/null +++ b/packages/angular/.eslintignore @@ -0,0 +1,4 @@ +/dist +/build +/node_modules +/coverage diff --git a/packages/angular/.eslintrc.cjs b/packages/angular/.eslintrc.cjs new file mode 100644 index 000000000..236d65fc8 --- /dev/null +++ b/packages/angular/.eslintrc.cjs @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const path = require('path'); + +module.exports = { + extends: ['plugin:@wso2/typescript', 'plugin:@wso2/strict', 'plugin:@wso2/internal', 'plugin:@wso2/prettier'], + parserOptions: { + project: [path.resolve(__dirname, 'tsconfig.json'), path.resolve(__dirname, 'tsconfig.eslint.json')], + }, + plugins: ['@wso2'], + rules: { + 'import/no-extraneous-dependencies': ['error', {devDependencies: true}], + 'no-underscore-dangle': ['off'], + }, +}; diff --git a/packages/angular/ng-package.json b/packages/angular/ng-package.json new file mode 100644 index 000000000..fe8d7e76e --- /dev/null +++ b/packages/angular/ng-package.json @@ -0,0 +1,8 @@ +{ + "$schema": "node_modules/ng-packagr/ng-package.schema.json", + "dest": "dist", + "allowedNonPeerDependencies": ["@asgardeo/browser", "@asgardeo/i18n", "tslib"], + "lib": { + "entryFile": "src/index.ts" + } +} diff --git a/packages/angular/package.json b/packages/angular/package.json new file mode 100644 index 000000000..12210bac5 --- /dev/null +++ b/packages/angular/package.json @@ -0,0 +1,77 @@ +{ + "name": "@asgardeo/angular", + "version": "0.1.0", + "description": "Angular implementation of Asgardeo JavaScript SDK.", + "keywords": [ + "asgardeo", + "angular", + "spa", + "authentication", + "oidc" + ], + "homepage": "https://github.com/asgardeo/javascript/tree/main/packages/angular#readme", + "bugs": { + "url": "https://github.com/asgardeo/javascript/issues" + }, + "author": "WSO2", + "license": "Apache-2.0", + "type": "module", + "module": "dist/fesm2022/asgardeo-angular.mjs", + "typings": "dist/types/asgardeo-angular.d.ts", + "exports": { + "./package.json": { + "default": "./package.json" + }, + ".": { + "types": "./dist/types/asgardeo-angular.d.ts", + "default": "./dist/fesm2022/asgardeo-angular.mjs" + } + }, + "files": [ + "dist", + "README.md", + "LICENSE" + ], + "sideEffects": false, + "repository": { + "type": "git", + "url": "https://github.com/asgardeo/javascript", + "directory": "packages/angular" + }, + "scripts": { + "build": "pnpm clean && ng-packagr -p ng-package.json", + "clean": "rimraf dist", + "fix:lint": "eslint . --ext .js,.ts,.cjs,.mjs", + "lint": "eslint . --ext .js,.ts,.cjs,.mjs", + "test": "vitest", + "typecheck": "tsc -p tsconfig.lib.json" + }, + "devDependencies": { + "@angular/compiler": "21.1.5", + "@angular/compiler-cli": "21.1.5", + "@types/node": "22.15.3", + "@wso2/eslint-plugin": "catalog:", + "@wso2/prettier-config": "catalog:", + "eslint": "8.57.0", + "jsdom": "26.1.0", + "ng-packagr": "21.1.0", + "prettier": "2.6.2", + "rimraf": "6.1.0", + "typescript": "5.9.3", + "vitest": "3.1.3" + }, + "peerDependencies": { + "@angular/common": ">=18.0.0", + "@angular/core": ">=18.0.0", + "@angular/router": ">=18.0.0", + "rxjs": ">=7.0.0" + }, + "dependencies": { + "@asgardeo/browser": "workspace:*", + "@asgardeo/i18n": "workspace:*", + "tslib": "2.8.1" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/angular/prettier.config.cjs b/packages/angular/prettier.config.cjs new file mode 100644 index 000000000..ce60a8c85 --- /dev/null +++ b/packages/angular/prettier.config.cjs @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +module.exports = require('@wso2/prettier-config'); diff --git a/packages/angular/src/AsgardeoAngularClient.ts b/packages/angular/src/AsgardeoAngularClient.ts new file mode 100644 index 000000000..1afa3f6d5 --- /dev/null +++ b/packages/angular/src/AsgardeoAngularClient.ts @@ -0,0 +1,381 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + AsgardeoBrowserClient, + AsgardeoSPAClient, + AsgardeoRuntimeError, + flattenUserSchema, + generateFlattenedUserProfile, + generateUserProfile, + extractUserClaimsFromIdToken, + deriveOrganizationHandleFromBaseUrl, + navigate, + getRedirectBasedSignUpUrl, + User, + UserProfile, + Organization, + IdToken, + TokenResponse, + HttpRequestConfig, + HttpResponse, + AllOrganizationsApiResponse, + TokenExchangeRequestConfig, + SignInOptions, + SignUpOptions, + Config, + Platform, +} from '@asgardeo/browser'; +import getAllOrganizations from './api/getAllOrganizations'; +import getMeOrganizations from './api/getMeOrganizations'; +import getSchemas from './api/getSchemas'; +import getScim2Me from './api/getScim2Me'; +import {AsgardeoAngularConfig} from './models/config'; + +/** + * Client for implementing Asgardeo in Angular applications. + * This class provides the core functionality for managing user authentication and sessions. + * It uses AsgardeoSPAClient directly without the __temp__/api.ts wrapper layer. + * + * @typeParam T - Configuration type that extends AsgardeoAngularConfig. + */ +class AsgardeoAngularClient extends AsgardeoBrowserClient { + private spaClient: AsgardeoSPAClient; + + private loadingState: boolean = false; + + private clientInstanceId: number; + + /** + * Creates a new AsgardeoAngularClient instance. + * @param instanceId - Optional instance ID for multi-auth context support. Defaults to 0. + */ + constructor(instanceId: number = 0) { + super(); + this.clientInstanceId = instanceId; + this.spaClient = AsgardeoSPAClient.getInstance(instanceId); + } + + /** + * Get the instance ID for this client. + * @returns The instance ID used for multi-auth context support. + */ + public getInstanceId(): number { + return this.clientInstanceId; + } + + private setLoading(loading: boolean): void { + this.loadingState = loading; + } + + private async withLoading(operation: () => Promise): Promise { + this.setLoading(true); + try { + const result: TResult = await operation(); + return result; + } finally { + this.setLoading(false); + } + } + + override initialize(config: AsgardeoAngularConfig): Promise { + let resolvedOrganizationHandle: string | undefined = config?.organizationHandle; + + if (!resolvedOrganizationHandle) { + resolvedOrganizationHandle = deriveOrganizationHandleFromBaseUrl(config?.baseUrl); + } + + return this.withLoading(async () => + this.spaClient.initialize({...config, organizationHandle: resolvedOrganizationHandle} as any), + ); + } + + override reInitialize(config: Partial): Promise { + return this.withLoading(async () => { + try { + await this.spaClient.reInitialize(config as any); + return true; + } catch (error) { + throw new AsgardeoRuntimeError( + `Failed to re-initialize the client: ${error instanceof Error ? error.message : String(error)}`, + 'AsgardeoAngularClient-reInitialize-RuntimeError-001', + 'angular', + 'An error occurred while re-initializing the client.', + ); + } + }); + } + + // eslint-disable-next-line class-methods-use-this + override async updateUserProfile(): Promise { + throw new AsgardeoRuntimeError( + 'updateUserProfile() is not supported in the Angular SDK. Use AsgardeoUserService.updateUser() instead.', + 'AsgardeoAngularClient-updateUserProfile-NotSupported', + 'angular', + 'Use AsgardeoUserService.updateUser() to update the user profile via the SCIM2 API.', + ); + } + + override async getUser(options?: any): Promise { + try { + let baseUrl: string = options?.baseUrl; + + if (!baseUrl) { + const configData: any = await this.spaClient.getConfigData(); + baseUrl = configData?.baseUrl; + } + + const profile: User = await getScim2Me({baseUrl}); + const schemas: any = await getSchemas({baseUrl}); + + return generateUserProfile(profile, flattenUserSchema(schemas)); + } catch (error) { + return extractUserClaimsFromIdToken(await this.getDecodedIdToken()); + } + } + + async getDecodedIdToken(sessionId?: string): Promise { + return (await this.spaClient.getDecodedIdToken(sessionId)) as IdToken; + } + + async getIdToken(): Promise { + return this.withLoading(async () => (await this.spaClient.getIdToken()) as string); + } + + async getUserProfile(options?: any): Promise { + return this.withLoading(async () => { + try { + let baseUrl: string = options?.baseUrl; + + if (!baseUrl) { + const configData: any = await this.spaClient.getConfigData(); + baseUrl = configData?.baseUrl; + } + + const profile: User = await getScim2Me({baseUrl, instanceId: this.getInstanceId()}); + const schemas: any = await getSchemas({baseUrl, instanceId: this.getInstanceId()}); + + const processedSchemas: any = flattenUserSchema(schemas); + + const output: UserProfile = { + flattenedProfile: generateFlattenedUserProfile(profile, processedSchemas), + profile, + schemas: processedSchemas, + }; + + return output; + } catch (error) { + return { + flattenedProfile: extractUserClaimsFromIdToken(await this.getDecodedIdToken()), + profile: extractUserClaimsFromIdToken(await this.getDecodedIdToken()), + schemas: [], + }; + } + }); + } + + override async getMyOrganizations(options?: any): Promise { + try { + let baseUrl: string = options?.baseUrl; + + if (!baseUrl) { + const configData: any = await this.spaClient.getConfigData(); + baseUrl = configData?.baseUrl; + } + + return await getMeOrganizations({baseUrl, instanceId: this.getInstanceId()}); + } catch (error) { + throw new AsgardeoRuntimeError( + `Failed to fetch the user's associated organizations: ${ + error instanceof Error ? error.message : String(error) + }`, + 'AsgardeoAngularClient-getMyOrganizations-RuntimeError-001', + 'angular', + 'An error occurred while fetching associated organizations of the signed-in user.', + ); + } + } + + override async getAllOrganizations(options?: any): Promise { + try { + let baseUrl: string = options?.baseUrl; + + if (!baseUrl) { + const configData: any = await this.spaClient.getConfigData(); + baseUrl = configData?.baseUrl; + } + + return await getAllOrganizations({baseUrl, instanceId: this.getInstanceId()}); + } catch (error) { + throw new AsgardeoRuntimeError( + `Failed to fetch all organizations: ${error instanceof Error ? error.message : String(error)}`, + 'AsgardeoAngularClient-getAllOrganizations-RuntimeError-001', + 'angular', + 'An error occurred while fetching all the organizations associated with the user.', + ); + } + } + + override async getCurrentOrganization(): Promise { + try { + return await this.withLoading(async () => { + const idToken: IdToken = await this.getDecodedIdToken(); + return { + id: idToken?.org_id || '', + name: idToken?.org_name || '', + orgHandle: idToken?.org_handle || '', + }; + }); + } catch (error) { + throw new AsgardeoRuntimeError( + `Failed to fetch the current organization: ${error instanceof Error ? error.message : String(error)}`, + 'AsgardeoAngularClient-getCurrentOrganization-RuntimeError-001', + 'angular', + 'An error occurred while fetching the current organization of the signed-in user.', + ); + } + } + + override async switchOrganization(organization: Organization): Promise { + return this.withLoading(async () => { + try { + if (!organization.id) { + throw new AsgardeoRuntimeError( + 'Organization ID is required for switching organizations', + 'angular-AsgardeoAngularClient-SwitchOrganizationError-001', + 'angular', + 'The organization object must contain a valid ID to perform the organization switch.', + ); + } + + const exchangeConfig: TokenExchangeRequestConfig = { + attachToken: false, + data: { + client_id: '{{clientId}}', + grant_type: 'organization_switch', + scope: '{{scopes}}', + switching_organization: organization.id, + token: '{{accessToken}}', + }, + id: 'organization-switch', + returnsSession: true, + signInRequired: true, + }; + + return (await this.spaClient.exchangeToken(exchangeConfig)) as TokenResponse | Response; + } catch (error) { + throw new AsgardeoRuntimeError( + `Failed to switch organization: ${error instanceof Error ? error.message : String(error)}`, + 'angular-AsgardeoAngularClient-SwitchOrganizationError-003', + 'angular', + 'An error occurred while switching to the specified organization. Please try again.', + ); + } + }); + } + + override isLoading(): boolean { + return this.loadingState; + } + + async isInitialized(): Promise { + return this.spaClient.isInitialized(); + } + + override async isSignedIn(): Promise { + return (await this.spaClient.isSignedIn()) ?? false; + } + + /** + * @deprecated This method returns a Promise at runtime despite its sync return type + * (inherited from the base class). Use {@link getConfigurationAsync} instead. + * + * Calling `getConfiguration().baseUrl` will return `undefined` because the + * return value is actually a Promise, not the config object. + */ + override getConfiguration(): T { + return this.spaClient.getConfigData() as unknown as T; + } + + /** + * Returns the resolved configuration data. + * Always use this instead of {@link getConfiguration} for correct behavior. + */ + async getConfigurationAsync(): Promise { + return (await this.spaClient.getConfigData()) as unknown as T; + } + + override async exchangeToken(config: TokenExchangeRequestConfig): Promise { + return this.withLoading(async () => this.spaClient.exchangeToken(config) as unknown as TokenResponse | Response); + } + + override async signIn(options?: SignInOptions): Promise { + return this.withLoading(async () => (await this.spaClient.signIn(options as any)) as unknown as Promise); + } + + override async signInSilently(options?: SignInOptions): Promise { + return (await this.spaClient.signInSilently(options as Record)) as User | boolean; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override async signOut(..._args: any[]): Promise { + const config: AsgardeoAngularConfig = (await this.spaClient.getConfigData()) as any; + + if (config.platform === Platform.AsgardeoV2) { + this.spaClient.clearSession(); + return Promise.resolve(config.afterSignOutUrl || ''); + } + + const response: boolean = await this.spaClient.signOut(); + return Promise.resolve(String(response)); + } + + override async signUp(options?: SignUpOptions): Promise; + override async signUp(payload: any): Promise; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + override async signUp(..._args: any[]): Promise { + const config: AsgardeoAngularConfig = (await this.spaClient.getConfigData()) as any; + navigate(getRedirectBasedSignUpUrl(config as Config)); + } + + async request(requestConfig: HttpRequestConfig): Promise> { + return (await this.spaClient.httpRequest(requestConfig)) as HttpResponse; + } + + async requestAll(requestConfigs: HttpRequestConfig[]): Promise[]> { + return (await this.spaClient.httpRequestAll(requestConfigs)) as HttpResponse[]; + } + + override async getAccessToken(sessionId?: string): Promise { + return this.spaClient.getAccessToken(sessionId); + } + + override clearSession(sessionId?: string): void { + this.spaClient.clearSession(sessionId); + } + + override async setSession(sessionData: Record, sessionId?: string): Promise { + return (await this.spaClient.getStorageManager()).setSessionData(sessionData, sessionId); + } + + override decodeJwtToken>(token: string): Promise { + return this.spaClient.decodeJwtToken(token) as Promise; + } +} + +export default AsgardeoAngularClient; diff --git a/packages/angular/src/__tests__/index.test.ts b/packages/angular/src/__tests__/index.test.ts new file mode 100644 index 000000000..38f1da67e --- /dev/null +++ b/packages/angular/src/__tests__/index.test.ts @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {describe, it, expect} from 'vitest'; + +describe('@asgardeo/angular', () => { + it('should export AsgardeoAuthService', async () => { + const {AsgardeoAuthService} = await import('../index'); + expect(AsgardeoAuthService).toBeDefined(); + }); + + it('should export AsgardeoUserService', async () => { + const {AsgardeoUserService} = await import('../index'); + expect(AsgardeoUserService).toBeDefined(); + }); + + it('should export AsgardeoOrganizationService', async () => { + const {AsgardeoOrganizationService} = await import('../index'); + expect(AsgardeoOrganizationService).toBeDefined(); + }); + + it('should export structural directives', async () => { + const {AsgardeoSignedInDirective, AsgardeoSignedOutDirective, AsgardeoLoadingDirective} = await import('../index'); + expect(AsgardeoSignedInDirective).toBeDefined(); + expect(AsgardeoSignedOutDirective).toBeDefined(); + expect(AsgardeoLoadingDirective).toBeDefined(); + }); + + it('should export organization components', async () => { + const { + AsgardeoOrganizationListComponent, + AsgardeoCreateOrganizationComponent, + AsgardeoOrganizationProfileComponent, + AsgardeoOrganizationSwitcherComponent, + } = await import('../index'); + expect(AsgardeoOrganizationListComponent).toBeDefined(); + expect(AsgardeoCreateOrganizationComponent).toBeDefined(); + expect(AsgardeoOrganizationProfileComponent).toBeDefined(); + expect(AsgardeoOrganizationSwitcherComponent).toBeDefined(); + }); + + it('should export AsgardeoUserProfileComponent', async () => { + const {AsgardeoUserProfileComponent} = await import('../index'); + expect(AsgardeoUserProfileComponent).toBeDefined(); + }); + + it('should export AsgardeoCallbackComponent', async () => { + const {AsgardeoCallbackComponent} = await import('../index'); + expect(AsgardeoCallbackComponent).toBeDefined(); + }); +}); diff --git a/packages/angular/src/__tests__/setup.ts b/packages/angular/src/__tests__/setup.ts new file mode 100644 index 000000000..1d407e3fa --- /dev/null +++ b/packages/angular/src/__tests__/setup.ts @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import '@angular/compiler'; diff --git a/packages/angular/src/api/createOrganization.ts b/packages/angular/src/api/createOrganization.ts new file mode 100644 index 000000000..53d4958ed --- /dev/null +++ b/packages/angular/src/api/createOrganization.ts @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + Organization, + createOrganization as baseCreateOrganization, + CreateOrganizationConfig as BaseCreateOrganizationConfig, +} from '@asgardeo/browser'; +import {createDefaultFetcher} from '../utils/fetcher'; + +/** + * Configuration for the createOrganization request (Angular-specific) + */ +export interface CreateOrganizationConfig extends Omit { + /** + * Optional custom fetcher function. If not provided, the Asgardeo SPA client's httpClient will be used + * which is a wrapper around axios http.request + */ + fetcher?: (url: string, config: RequestInit) => Promise; + /** + * Optional instance ID for multi-instance support. Defaults to 0. + */ + instanceId?: number; +} + +/** + * Creates a new organization. + * This function uses the Asgardeo SPA client's httpClient by default, but allows for custom fetchers. + * + * @param config - Configuration object containing baseUrl, payload and optional request config. + * @returns A promise that resolves with the created organization information. + * @example + * ```typescript + * // Using default Asgardeo SPA client httpClient + * try { + * const organization = await createOrganization({ + * baseUrl: "https://api.asgardeo.io/t/", + * payload: { + * description: "Share your screens", + * name: "Team Viewer", + * orgHandle: "team-viewer", + * parentId: "f4825104-4948-40d9-ab65-a960eee3e3d5", + * type: "TENANT" + * } + * }); + * console.log(organization); + * } catch (error) { + * if (error instanceof AsgardeoAPIError) { + * console.error('Failed to create organization:', error.message); + * } + * } + * ``` + * + * @example + * ```typescript + * // Using custom fetcher + * try { + * const organization = await createOrganization({ + * baseUrl: "https://api.asgardeo.io/t/", + * payload: { + * description: "Share your screens", + * name: "Team Viewer", + * orgHandle: "team-viewer", + * parentId: "f4825104-4948-40d9-ab65-a960eee3e3d5", + * type: "TENANT" + * }, + * fetcher: customFetchFunction + * }); + * console.log(organization); + * } catch (error) { + * if (error instanceof AsgardeoAPIError) { + * console.error('Failed to create organization:', error.message); + * } + * } + * ``` + */ +const createOrganization = async ({ + fetcher, + instanceId = 0, + ...requestConfig +}: CreateOrganizationConfig): Promise => + baseCreateOrganization({ + ...requestConfig, + fetcher: fetcher || createDefaultFetcher(instanceId), + }); + +export default createOrganization; diff --git a/packages/angular/src/api/getAllOrganizations.ts b/packages/angular/src/api/getAllOrganizations.ts new file mode 100644 index 000000000..203c1ea1f --- /dev/null +++ b/packages/angular/src/api/getAllOrganizations.ts @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + getAllOrganizations as baseGetAllOrganizations, + GetAllOrganizationsConfig as BaseGetAllOrganizationsConfig, + AllOrganizationsApiResponse, +} from '@asgardeo/browser'; +import {createDefaultFetcher} from '../utils/fetcher'; + +/** + * Configuration for the getAllOrganizations request (Angular-specific) + */ +export interface GetAllOrganizationsConfig extends Omit { + /** + * Optional custom fetcher function. If not provided, the Asgardeo SPA client's httpClient will be used + * which is a wrapper around axios http.request + */ + fetcher?: (url: string, config: RequestInit) => Promise; + /** + * Optional instance ID for multi-instance support. Defaults to 0. + */ + instanceId?: number; +} + +/** + * Retrieves all organizations with pagination support. + * This function uses the Asgardeo SPA client's httpClient by default, but allows for custom fetchers. + * + * @param config - Configuration object containing baseUrl, optional query parameters, and request config. + * @returns A promise that resolves with the paginated organizations information. + * @example + * ```typescript + * // Using default Asgardeo SPA client httpClient + * try { + * const response = await getAllOrganizations({ + * baseUrl: "https://api.asgardeo.io/t/", + * filter: "", + * limit: 10, + * recursive: false + * }); + * console.log(response.organizations); + * } catch (error) { + * if (error instanceof AsgardeoAPIError) { + * console.error('Failed to get organizations:', error.message); + * } + * } + * ``` + * + * @example + * ```typescript + * // Using custom fetcher + * try { + * const response = await getAllOrganizations({ + * baseUrl: "https://api.asgardeo.io/t/", + * filter: "", + * limit: 10, + * recursive: false, + * fetcher: customFetchFunction + * }); + * console.log(response.organizations); + * } catch (error) { + * if (error instanceof AsgardeoAPIError) { + * console.error('Failed to get organizations:', error.message); + * } + * } + * ``` + */ +const getAllOrganizations = async ({ + fetcher, + instanceId = 0, + ...requestConfig +}: GetAllOrganizationsConfig): Promise => + baseGetAllOrganizations({ + ...requestConfig, + fetcher: fetcher || createDefaultFetcher(instanceId), + }); + +export default getAllOrganizations; diff --git a/packages/angular/src/api/getMeOrganizations.ts b/packages/angular/src/api/getMeOrganizations.ts new file mode 100644 index 000000000..54e86c194 --- /dev/null +++ b/packages/angular/src/api/getMeOrganizations.ts @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + Organization, + getMeOrganizations as baseGetMeOrganizations, + GetMeOrganizationsConfig as BaseGetMeOrganizationsConfig, +} from '@asgardeo/browser'; +import {createDefaultFetcher} from '../utils/fetcher'; + +/** + * Configuration for the getMeOrganizations request (Angular-specific) + */ +export interface GetMeOrganizationsConfig extends Omit { + /** + * Optional custom fetcher function. If not provided, the Asgardeo SPA client's httpClient will be used + * which is a wrapper around axios http.request + */ + fetcher?: (url: string, config: RequestInit) => Promise; + /** + * Optional instance ID for multi-instance support. Defaults to 0. + */ + instanceId?: number; +} + +/** + * Retrieves the organizations associated with the current user. + * This function uses the Asgardeo SPA client's httpClient by default, but allows for custom fetchers. + * + * @param config - Configuration object containing baseUrl, optional query parameters, and request config. + * @returns A promise that resolves with the organizations information. + * @example + * ```typescript + * // Using default Asgardeo SPA client httpClient + * try { + * const organizations = await getMeOrganizations({ + * baseUrl: "https://api.asgardeo.io/t/", + * after: "", + * before: "", + * filter: "", + * limit: 10, + * recursive: false + * }); + * console.log(organizations); + * } catch (error) { + * if (error instanceof AsgardeoAPIError) { + * console.error('Failed to get organizations:', error.message); + * } + * } + * ``` + * + * @example + * ```typescript + * // Using custom fetcher + * try { + * const organizations = await getMeOrganizations({ + * baseUrl: "https://api.asgardeo.io/t/", + * after: "", + * before: "", + * filter: "", + * limit: 10, + * recursive: false, + * fetcher: customFetchFunction + * }); + * console.log(organizations); + * } catch (error) { + * if (error instanceof AsgardeoAPIError) { + * console.error('Failed to get organizations:', error.message); + * } + * } + * ``` + */ +const getMeOrganizations = async ({ + fetcher, + instanceId = 0, + ...requestConfig +}: GetMeOrganizationsConfig): Promise => + baseGetMeOrganizations({ + ...requestConfig, + fetcher: fetcher || createDefaultFetcher(instanceId), + }); + +export default getMeOrganizations; diff --git a/packages/angular/src/api/getOrganization.ts b/packages/angular/src/api/getOrganization.ts new file mode 100644 index 000000000..abb322a63 --- /dev/null +++ b/packages/angular/src/api/getOrganization.ts @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + getOrganization as baseGetOrganization, + GetOrganizationConfig as BaseGetOrganizationConfig, + OrganizationDetails, +} from '@asgardeo/browser'; +import {createDefaultFetcher} from '../utils/fetcher'; + +/** + * Configuration for the getOrganization request (Angular-specific) + */ +export interface GetOrganizationConfig extends Omit { + /** + * Optional custom fetcher function. If not provided, the Asgardeo SPA client's httpClient will be used + * which is a wrapper around axios http.request + */ + fetcher?: (url: string, config: RequestInit) => Promise; + /** + * Optional instance ID for multi-instance support. Defaults to 0. + */ + instanceId?: number; +} + +/** + * Retrieves detailed information for a specific organization. + * This function uses the Asgardeo SPA client's httpClient by default, but allows for custom fetchers. + * + * @param config - Configuration object containing baseUrl, organizationId, and request config. + * @returns A promise that resolves with the organization details. + * @example + * ```typescript + * // Using default Asgardeo SPA client httpClient + * try { + * const organization = await getOrganization({ + * baseUrl: "https://api.asgardeo.io/t/dxlab", + * organizationId: "0d5e071b-d3d3-475d-b3c6-1a20ee2fa9b1" + * }); + * console.log(organization); + * } catch (error) { + * if (error instanceof AsgardeoAPIError) { + * console.error('Failed to get organization:', error.message); + * } + * } + * ``` + * + * @example + * ```typescript + * // Using custom fetcher + * try { + * const organization = await getOrganization({ + * baseUrl: "https://api.asgardeo.io/t/dxlab", + * organizationId: "0d5e071b-d3d3-475d-b3c6-1a20ee2fa9b1", + * fetcher: customFetchFunction + * }); + * console.log(organization); + * } catch (error) { + * if (error instanceof AsgardeoAPIError) { + * console.error('Failed to get organization:', error.message); + * } + * } + * ``` + */ +const getOrganization = async ({ + fetcher, + instanceId = 0, + ...requestConfig +}: GetOrganizationConfig): Promise => + baseGetOrganization({ + ...requestConfig, + fetcher: fetcher || createDefaultFetcher(instanceId), + }); + +export default getOrganization; diff --git a/packages/angular/src/api/getSchemas.ts b/packages/angular/src/api/getSchemas.ts new file mode 100644 index 000000000..37ce3003e --- /dev/null +++ b/packages/angular/src/api/getSchemas.ts @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {Schema, getSchemas as baseGetSchemas, GetSchemasConfig as BaseGetSchemasConfig} from '@asgardeo/browser'; +import {createDefaultFetcher} from '../utils/fetcher'; + +/** + * Configuration for the getSchemas request (Angular-specific) + */ +export interface GetSchemasConfig extends Omit { + /** + * Optional custom fetcher function. If not provided, the Asgardeo SPA client's httpClient will be used + * which is a wrapper around axios http.request + */ + fetcher?: (url: string, config: RequestInit) => Promise; + /** + * Optional instance ID for multi-instance support. Defaults to 0. + */ + instanceId?: number; +} + +/** + * Retrieves the SCIM2 schemas from the specified endpoint. + * This function uses the Asgardeo SPA client's httpClient by default, but allows for custom fetchers. + * + * @param config - Request configuration object. + * @returns A promise that resolves with the SCIM2 schemas information. + * @example + * ```typescript + * // Using default Asgardeo SPA client httpClient + * try { + * const schemas = await getSchemas({ + * url: "https://api.asgardeo.io/t//scim2/Schemas", + * }); + * console.log(schemas); + * } catch (error) { + * if (error instanceof AsgardeoAPIError) { + * console.error('Failed to get schemas:', error.message); + * } + * } + * ``` + * + * @example + * ```typescript + * // Using custom fetcher + * try { + * const schemas = await getSchemas({ + * url: "https://api.asgardeo.io/t//scim2/Schemas", + * fetcher: customFetchFunction + * }); + * console.log(schemas); + * } catch (error) { + * if (error instanceof AsgardeoAPIError) { + * console.error('Failed to get schemas:', error.message); + * } + * } + * ``` + */ +const getSchemas = async ({fetcher, instanceId = 0, ...requestConfig}: GetSchemasConfig): Promise => + baseGetSchemas({ + ...requestConfig, + fetcher: fetcher || createDefaultFetcher(instanceId), + }); + +export default getSchemas; diff --git a/packages/angular/src/api/getScim2Me.ts b/packages/angular/src/api/getScim2Me.ts new file mode 100644 index 000000000..3f5e082bb --- /dev/null +++ b/packages/angular/src/api/getScim2Me.ts @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {User, getScim2Me as baseGetScim2Me, GetScim2MeConfig as BaseGetScim2MeConfig} from '@asgardeo/browser'; +import {createDefaultFetcher} from '../utils/fetcher'; + +/** + * Configuration for the getScim2Me request (Angular-specific) + */ +export interface GetScim2MeConfig extends Omit { + /** + * Optional custom fetcher function. If not provided, the Asgardeo SPA client's httpClient will be used + * which is a wrapper around axios http.request + */ + fetcher?: (url: string, config: RequestInit) => Promise; + /** + * Optional instance ID for multi-instance support. Defaults to 0. + */ + instanceId?: number; +} + +/** + * Retrieves the user profile information from the specified SCIM2 /Me endpoint. + * This function uses the Asgardeo SPA client's httpClient by default, but allows for custom fetchers. + * + * @param requestConfig - Request configuration object. + * @returns A promise that resolves with the user profile information. + * @example + * ```typescript + * // Using default Asgardeo SPA client httpClient + * try { + * const userProfile = await getScim2Me({ + * url: "https://api.asgardeo.io/t//scim2/Me", + * }); + * console.log(userProfile); + * } catch (error) { + * if (error instanceof AsgardeoAPIError) { + * console.error('Failed to get user profile:', error.message); + * } + * } + * ``` + * + * @example + * ```typescript + * // Using custom fetcher + * try { + * const userProfile = await getScim2Me({ + * url: "https://api.asgardeo.io/t//scim2/Me", + * fetcher: customFetchFunction + * }); + * console.log(userProfile); + * } catch (error) { + * if (error instanceof AsgardeoAPIError) { + * console.error('Failed to get user profile:', error.message); + * } + * } + * ``` + */ +const getScim2Me = async ({fetcher, instanceId = 0, ...requestConfig}: GetScim2MeConfig): Promise => + baseGetScim2Me({ + ...requestConfig, + fetcher: fetcher || createDefaultFetcher(instanceId), + }); + +export default getScim2Me; diff --git a/packages/angular/src/api/updateMeProfile.ts b/packages/angular/src/api/updateMeProfile.ts new file mode 100644 index 000000000..a5e75cbf4 --- /dev/null +++ b/packages/angular/src/api/updateMeProfile.ts @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + User, + updateMeProfile as baseUpdateMeProfile, + UpdateMeProfileConfig as BaseUpdateMeProfileConfig, +} from '@asgardeo/browser'; +import {createDefaultFetcher} from '../utils/fetcher'; + +/** + * Configuration for the updateMeProfile request (Angular-specific) + */ +export interface UpdateMeProfileConfig extends Omit { + /** + * Optional custom fetcher function. If not provided, the Asgardeo SPA client's httpClient will be used + * which is a wrapper around axios http.request + */ + fetcher?: (url: string, config: RequestInit) => Promise; + /** + * Optional instance ID for multi-instance support. Defaults to 0. + */ + instanceId?: number; +} + +/** + * Updates the user profile information at the specified SCIM2 Me endpoint. + * This function uses the Asgardeo SPA client's httpClient by default, but allows for custom fetchers. + * + * @param config - Configuration object with URL, payload and optional request config. + * @returns A promise that resolves with the updated user profile information. + * @example + * ```typescript + * // Using default Asgardeo SPA client httpClient + * await updateMeProfile({ + * url: "https://api.asgardeo.io/t//scim2/Me", + * payload: { "urn:scim:wso2:schema": { mobileNumbers: ["0777933830"] } } + * }); + * ``` + * + * @example + * ```typescript + * // Using custom fetcher + * await updateMeProfile({ + * url: "https://api.asgardeo.io/t//scim2/Me", + * payload: { "urn:scim:wso2:schema": { mobileNumbers: ["0777933830"] } }, + * fetcher: customFetchFunction + * }); + * ``` + */ +const updateMeProfile = async ({fetcher, instanceId = 0, ...requestConfig}: UpdateMeProfileConfig): Promise => + baseUpdateMeProfile({ + ...requestConfig, + fetcher: fetcher || createDefaultFetcher(instanceId), + }); + +export default updateMeProfile; diff --git a/packages/angular/src/api/updateOrganization.ts b/packages/angular/src/api/updateOrganization.ts new file mode 100644 index 000000000..e35150e45 --- /dev/null +++ b/packages/angular/src/api/updateOrganization.ts @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + updateOrganization as baseUpdateOrganization, + UpdateOrganizationConfig as BaseUpdateOrganizationConfig, + OrganizationDetails, + createPatchOperations, +} from '@asgardeo/browser'; +import {createDefaultFetcher} from '../utils/fetcher'; + +/** + * Configuration for the updateOrganization request (Angular-specific) + */ +export interface UpdateOrganizationConfig extends Omit { + /** + * Optional custom fetcher function. If not provided, the Asgardeo SPA client's httpClient will be used + * which is a wrapper around axios http.request + */ + fetcher?: (url: string, config: RequestInit) => Promise; + /** + * Optional instance ID for multi-instance support. Defaults to 0. + */ + instanceId?: number; +} + +/** + * Updates the organization information using the Organizations Management API. + * This function uses the Asgardeo SPA client's httpClient by default, but allows for custom fetchers. + * + * @param config - Configuration object with baseUrl, organizationId, operations and optional request config. + * @returns A promise that resolves with the updated organization information. + * @example + * ```typescript + * // Using the helper function to create operations automatically + * const operations = createPatchOperations({ + * name: "Updated Organization Name", // Will use REPLACE + * description: "", // Will use REMOVE (empty string) + * customField: "Some value" // Will use REPLACE + * }); + * + * await updateOrganization({ + * baseUrl: "https://api.asgardeo.io/t/", + * organizationId: "0d5e071b-d3d3-475d-b3c6-1a20ee2fa9b1", + * operations + * }); + * + * // Or manually specify operations + * await updateOrganization({ + * baseUrl: "https://api.asgardeo.io/t/", + * organizationId: "0d5e071b-d3d3-475d-b3c6-1a20ee2fa9b1", + * operations: [ + * { operation: "REPLACE", path: "/name", value: "Updated Organization Name" }, + * { operation: "REMOVE", path: "/description" } + * ] + * }); + * ``` + * + * @example + * ```typescript + * // Using custom fetcher + * await updateOrganization({ + * baseUrl: "https://api.asgardeo.io/t/", + * organizationId: "0d5e071b-d3d3-475d-b3c6-1a20ee2fa9b1", + * operations: [ + * { operation: "REPLACE", path: "/name", value: "Updated Organization Name" } + * ], + * fetcher: customFetchFunction + * }); + * ``` + */ +const updateOrganization = async ({ + fetcher, + instanceId = 0, + ...requestConfig +}: UpdateOrganizationConfig): Promise => + baseUpdateOrganization({ + ...requestConfig, + fetcher: fetcher || createDefaultFetcher(instanceId), + }); + +// Re-export the helper function +export {createPatchOperations}; + +export default updateOrganization; diff --git a/packages/angular/src/components/callback/callback.component.ts b/packages/angular/src/components/callback/callback.component.ts new file mode 100644 index 000000000..6ebd140d2 --- /dev/null +++ b/packages/angular/src/components/callback/callback.component.ts @@ -0,0 +1,154 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {Component, ChangeDetectionStrategy, OnInit, output, inject, OutputEmitterRef} from '@angular/core'; +import {Router} from '@angular/router'; +import {navigate as browserNavigate} from '@asgardeo/browser'; + +/** + * Headless component that handles OAuth callback parameter forwarding. + * + * This component extracts OAuth parameters (code, state, error) from the URL and forwards them + * to the original component that initiated the OAuth flow. + * + * Adapted from React's `` component. + * + * @example + * ```typescript + * // In your routes + * const routes: Routes = [ + * { path: 'callback', component: AsgardeoCallbackComponent }, + * ]; + * ``` + */ +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'asgardeo-callback', + standalone: true, + template: '', +}) +export class AsgardeoCallbackComponent implements OnInit { + private router: Router | null = inject(Router, {optional: true}); + + readonly error: OutputEmitterRef = output(); + + ngOnInit(): void { + this.processOAuthCallback(); + } + + private processOAuthCallback(): void { + let returnPath: string = '/'; + + try { + // 1. Extract OAuth parameters from URL + const urlParams: URLSearchParams = new URLSearchParams(window.location.search); + const code: string | null = urlParams.get('code'); + const state: string | null = urlParams.get('state'); + const nonce: string | null = urlParams.get('nonce'); + const oauthError: string | null = urlParams.get('error'); + const errorDescription: string | null = urlParams.get('error_description'); + + // 2. Validate and retrieve OAuth state from sessionStorage + if (!state) { + throw new Error('Missing OAuth state parameter - possible security issue'); + } + + const storedData: string | null = sessionStorage.getItem(`asgardeo_oauth_${state}`); + if (!storedData) { + if (oauthError) { + const errorMsg: string = errorDescription || oauthError || 'OAuth authentication failed'; + const err: Error = new Error(errorMsg); + this.error.emit(err); + + const params: URLSearchParams = new URLSearchParams(); + params.set('error', oauthError); + if (errorDescription) { + params.set('error_description', errorDescription); + } + + this.navigate(`/?${params.toString()}`); + return; + } + throw new Error('Invalid OAuth state - possible CSRF attack'); + } + + const {path, timestamp} = JSON.parse(storedData); + returnPath = path || '/'; + + // 3. Validate state freshness + const MAX_STATE_AGE: number = 600000; // 10 minutes + if (Date.now() - timestamp > MAX_STATE_AGE) { + sessionStorage.removeItem(`asgardeo_oauth_${state}`); + throw new Error('OAuth state expired - please try again'); + } + + // 4. Clean up state + sessionStorage.removeItem(`asgardeo_oauth_${state}`); + + // 5. Handle OAuth error response + if (oauthError) { + const errorMsg: string = errorDescription || oauthError || 'OAuth authentication failed'; + const err: Error = new Error(errorMsg); + this.error.emit(err); + + const params: URLSearchParams = new URLSearchParams(); + params.set('error', oauthError); + if (errorDescription) { + params.set('error_description', errorDescription); + } + + this.navigate(`${returnPath}?${params.toString()}`); + return; + } + + // 6. Validate required parameters + if (!code) { + throw new Error('Missing OAuth authorization code'); + } + + // 7. Forward OAuth code to original component + const params: URLSearchParams = new URLSearchParams(); + params.set('code', code); + if (nonce) { + params.set('nonce', nonce); + } + + this.navigate(`${returnPath}?${params.toString()}`); + } catch (err: unknown) { + const errorMessage: string = err instanceof Error ? err.message : 'OAuth callback processing failed'; + // eslint-disable-next-line no-console + console.error('OAuth callback error:', err); + + this.error.emit(err instanceof Error ? err : new Error(errorMessage)); + + const params: URLSearchParams = new URLSearchParams(); + params.set('error', 'callback_error'); + params.set('error_description', errorMessage); + + this.navigate(`${returnPath}?${params.toString()}`); + } + } + + private navigate(path: string): void { + if (this.router) { + this.router.navigateByUrl(path); + } else { + browserNavigate(path); + } + } +} diff --git a/packages/angular/src/components/create-organization/create-organization.component.ts b/packages/angular/src/components/create-organization/create-organization.component.ts new file mode 100644 index 000000000..78b044588 --- /dev/null +++ b/packages/angular/src/components/create-organization/create-organization.component.ts @@ -0,0 +1,641 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {NgTemplateOutlet} from '@angular/common'; +import { + Component, + ChangeDetectionStrategy, + inject, + input, + model, + output, + signal, + effect, + HostListener, + InputSignal, + ModelSignal, + OutputEmitterRef, + WritableSignal, +} from '@angular/core'; +import {Organization} from '@asgardeo/browser'; +import {AsgardeoAuthService} from '../../services/asgardeo-auth.service'; +import {AsgardeoOrganizationService} from '../../services/asgardeo-organization.service'; + +interface CreateOrganizationPayload { + description: string; + name: string; + orgHandle: string; + parentId: string; + type: 'TENANT'; +} + +/** + * Angular Create Organization component matching the React SDK's ``. + * + * Provides a form for creating new organizations with name, handle, and description fields. + * Supports both inline and popup (dialog) modes. + * + * @example + * ```html + * + * + * + * + * + * ``` + */ +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [NgTemplateOutlet], + selector: 'asgardeo-create-organization', + standalone: true, + styles: ` + :host { + /* Core palette */ + --asgardeo-color-primary: #4f46e5; + --asgardeo-color-primary-hover: #4338ca; + --asgardeo-color-primary-ring: rgba(99, 102, 241, 0.2); + + /* Text */ + --asgardeo-color-text: #111827; + --asgardeo-color-text-secondary: #6b7280; + --asgardeo-color-text-muted: #9ca3af; + + /* Surfaces & borders */ + --asgardeo-color-surface: #fff; + --asgardeo-color-border: #e5e7eb; + --asgardeo-color-input-border: #d1d5db; + --asgardeo-color-hover: rgba(0, 0, 0, 0.05); + + /* Secondary button */ + --asgardeo-color-secondary: #f3f4f6; + --asgardeo-color-secondary-hover: #e5e7eb; + --asgardeo-color-secondary-text: #374151; + + /* Alert / error */ + --asgardeo-color-error-bg: #fef2f2; + --asgardeo-color-error-border: #fecaca; + --asgardeo-color-error-title: #991b1b; + --asgardeo-color-error-text: #b91c1c; + + /* Overlay */ + --asgardeo-overlay-bg: rgba(0, 0, 0, 0.5); + + /* Border radius */ + --asgardeo-radius-sm: 4px; + --asgardeo-radius-md: 6px; + --asgardeo-radius-lg: 8px; + --asgardeo-radius-xl: 12px; + + /* Font sizes */ + --asgardeo-font-size-xs: 0.8125rem; + --asgardeo-font-size-sm: 0.875rem; + --asgardeo-font-size-md: 1.2rem; + } + + /* Dialog Overlay */ + .asgardeo-dialog__overlay { + position: fixed; + inset: 0; + background: var(--asgardeo-overlay-bg); + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; + } + + .asgardeo-dialog__content { + background: var(--asgardeo-color-surface); + border-radius: var(--asgardeo-radius-xl); + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15); + max-width: 500px; + width: 90vw; + max-height: 85vh; + display: flex; + flex-direction: column; + z-index: 10000; + } + + .asgardeo-dialog__header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 1rem 1.5rem; + border-bottom: 1px solid var(--asgardeo-color-border); + } + + .asgardeo-dialog__heading { + font-size: var(--asgardeo-font-size-md); + font-weight: 600; + color: var(--asgardeo-color-text); + margin: 0; + } + + .asgardeo-dialog__close { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + background: none; + border: none; + border-radius: var(--asgardeo-radius-md); + cursor: pointer; + color: var(--asgardeo-color-text-secondary); + + &:hover { + background: var(--asgardeo-color-hover); + color: var(--asgardeo-color-text); + } + } + + .asgardeo-create-organization__popup { + padding: 1.5rem; + overflow-y: auto; + } + + /* Alert */ + .asgardeo-alert { + padding: 12px 16px; + border-radius: var(--asgardeo-radius-lg); + margin-bottom: 16px; + } + + .asgardeo-alert--error { + background: var(--asgardeo-color-error-bg); + border: 1px solid var(--asgardeo-color-error-border); + } + + .asgardeo-alert__title { + font-size: var(--asgardeo-font-size-sm); + font-weight: 600; + color: var(--asgardeo-color-error-title); + } + + .asgardeo-alert__description { + font-size: var(--asgardeo-font-size-sm); + color: var(--asgardeo-color-error-text); + margin-top: 2px; + } + + /* Form */ + .asgardeo-form-group { + margin-bottom: 20px; + } + + .asgardeo-label { + display: block; + font-size: var(--asgardeo-font-size-sm); + font-weight: 500; + color: var(--asgardeo-color-text); + margin-bottom: 6px; + } + + .asgardeo-required { + color: var(--asgardeo-color-error-text); + } + + .asgardeo-text-field { + width: 100%; + padding: 8px 12px; + font-size: var(--asgardeo-font-size-sm); + border: 1px solid var(--asgardeo-color-input-border); + border-radius: var(--asgardeo-radius-md); + outline: none; + font-family: inherit; + box-sizing: border-box; + + &:focus { + border-color: var(--asgardeo-color-primary); + box-shadow: 0 0 0 2px var(--asgardeo-color-primary-ring); + } + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } + } + + .asgardeo-text-field--error { + border-color: var(--asgardeo-color-error-text); + } + + .asgardeo-textarea { + width: 100%; + padding: 8px 12px; + font-size: var(--asgardeo-font-size-sm); + border: 1px solid var(--asgardeo-color-input-border); + border-radius: var(--asgardeo-radius-md); + outline: none; + font-family: inherit; + resize: vertical; + box-sizing: border-box; + + &:focus { + border-color: var(--asgardeo-color-primary); + box-shadow: 0 0 0 2px var(--asgardeo-color-primary-ring); + } + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } + } + + .asgardeo-textarea--error { + border-color: var(--asgardeo-color-error-text); + } + + .asgardeo-form-hint { + display: block; + font-size: var(--asgardeo-font-size-xs); + color: var(--asgardeo-color-text-muted); + margin-top: 4px; + } + + .asgardeo-form-error { + display: block; + font-size: var(--asgardeo-font-size-xs); + color: var(--asgardeo-color-error-text); + margin-top: 4px; + } + + .asgardeo-form-actions { + display: flex; + justify-content: flex-end; + gap: 8px; + margin-top: 24px; + } + + /* Spinner */ + .asgardeo-spinner { + width: 32px; + height: 32px; + border: 3px solid var(--asgardeo-color-border); + border-top-color: var(--asgardeo-color-primary); + border-radius: 50%; + animation: asgardeo-spin 0.6s linear infinite; + } + + .asgardeo-spinner--sm { + width: 16px; + height: 16px; + border-width: 2px; + border-color: rgba(255, 255, 255, 0.3); + border-top-color: white; + margin-right: 6px; + } + + @keyframes asgardeo-spin { + to { transform: rotate(360deg); } + } + + /* Buttons */ + .asgardeo-btn { + display: inline-flex; + align-items: center; + justify-content: center; + border: none; + cursor: pointer; + font-family: inherit; + border-radius: var(--asgardeo-radius-md); + padding: 8px 16px; + font-size: var(--asgardeo-font-size-sm); + font-weight: 500; + transition: background-color 0.15s; + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } + } + + .asgardeo-btn--primary { + background: var(--asgardeo-color-primary); + color: white; + + &:hover:not(:disabled) { + background: var(--asgardeo-color-primary-hover); + } + } + + .asgardeo-btn--secondary { + background: var(--asgardeo-color-secondary); + color: var(--asgardeo-color-secondary-text); + + &:hover:not(:disabled) { + background: var(--asgardeo-color-secondary-hover); + } + } + `, + template: ` + +
+ @if (error()) { +
+
Error
+
{{ error() }}
+
+ } + +
+
+ + + @if (formErrors().name) { + {{ formErrors().name }} + } +
+ +
+ + + Only lowercase letters, numbers, and hyphens are allowed. + @if (formErrors().handle) { + {{ formErrors().handle }} + } +
+ +
+ + + @if (formErrors().description) { + {{ formErrors().description }} + } +
+ +
+ + +
+
+
+
+ + @if (mode() === 'popup') { + @if (open()) { +
+
+
+

{{ title() }}

+ +
+
+ +
+
+
+ } + } @else { + + } + `, +}) +export class AsgardeoCreateOrganizationComponent { + /** Display mode: inline (default) or popup dialog */ + readonly mode: InputSignal<'inline' | 'popup'> = input<'inline' | 'popup'>('inline'); + + /** Whether the popup dialog is open (popup mode only). Supports two-way binding via `[(open)]`. */ + readonly open: ModelSignal = model(false); + + /** Dialog title (popup mode only) */ + readonly title: InputSignal = input('Create Organization'); + + /** Default parent organization ID */ + readonly defaultParentId: InputSignal = input(''); + + /** Initial form values */ + readonly initialValues: InputSignal> = input< + Partial<{description: string; handle: string; name: string}> + >({}); + + /** Emits when the form is submitted (before API call) */ + readonly submitted: OutputEmitterRef = output(); + + /** Emits when the organization is successfully created */ + readonly created: OutputEmitterRef = output(); + + /** Emits when the cancel button is clicked */ + readonly cancelled: OutputEmitterRef = output(); + + private readonly authService: AsgardeoAuthService = inject(AsgardeoAuthService); + + private readonly orgService: AsgardeoOrganizationService = inject(AsgardeoOrganizationService); + + formName: WritableSignal = signal(''); + + formHandle: WritableSignal = signal(''); + + formDescription: WritableSignal = signal(''); + + isSubmitting: WritableSignal = signal(false); + + error: WritableSignal = signal(null); + + formErrors: WritableSignal<{description?: string; handle?: string; name?: string}> = signal<{ + description?: string; + handle?: string; + name?: string; + }>({}); + + private readonly handleManuallyEdited: WritableSignal = signal(false); + + constructor() { + // Reset form when popup closes + effect(() => { + if (!this.open()) { + this.resetForm(); + } + }); + + // Apply initial values + effect(() => { + const iv: Partial<{description: string; handle: string; name: string}> = this.initialValues(); + if (iv.name) this.formName.set(iv.name); + if (iv.handle) this.formHandle.set(iv.handle); + if (iv.description) this.formDescription.set(iv.description); + }); + } + + @HostListener('document:keydown.escape') + onEscapeKey(): void { + if (this.mode() === 'popup' && this.open()) { + this.close(); + } + } + + close(): void { + this.open.set(false); + } + + onOverlayClick(event: Event): void { + if (event.target === event.currentTarget) { + this.close(); + } + } + + onNameInput(value: string): void { + this.formName.set(value); + this.clearFieldError('name'); + if (!this.handleManuallyEdited()) { + this.formHandle.set(AsgardeoCreateOrganizationComponent.generateHandle(value)); + } + } + + onHandleInput(value: string): void { + this.formHandle.set(value); + this.handleManuallyEdited.set(true); + this.clearFieldError('handle'); + } + + onDescriptionInput(value: string): void { + this.formDescription.set(value); + this.clearFieldError('description'); + } + + static generateHandle(name: string): string { + return name + .toLowerCase() + .replace(/[^a-z0-9\s-]/g, '') + .replace(/\s+/g, '-') + .replace(/-+/g, '-') + .replace(/^-|-$/g, ''); + } + + validate(): boolean { + const errors: {description?: string; handle?: string; name?: string} = {}; + if (!this.formName().trim()) errors.name = 'Organization name is required'; + if (!this.formHandle().trim()) { + errors.handle = 'Organization handle is required'; + } else if (!/^[a-z0-9-]+$/.test(this.formHandle())) { + errors.handle = 'Handle can only contain lowercase letters, numbers, and hyphens'; + } + if (!this.formDescription().trim()) errors.description = 'Description is required'; + this.formErrors.set(errors); + return Object.keys(errors).length === 0; + } + + async onSubmit(): Promise { + if (!this.validate() || this.isSubmitting()) return; + + this.isSubmitting.set(true); + this.error.set(null); + + const payload: CreateOrganizationPayload = { + description: this.formDescription().trim(), + name: this.formName().trim(), + orgHandle: this.formHandle().trim(), + parentId: this.defaultParentId() || this.orgService.currentOrganization()?.id || '', + type: 'TENANT' as const, + }; + + this.submitted.emit(payload); + + try { + const baseUrl: string = this.authService.getBaseUrl(); + const instanceId: number = this.authService.getClient().getInstanceId(); + const org: Organization = await this.orgService.createOrganization({baseUrl, instanceId, payload}); + await this.orgService.revalidateMyOrganizations(); + this.created.emit(org); + if (this.mode() === 'popup') { + this.open.set(false); + } + } catch (err: any) { + this.error.set(err?.message || 'Failed to create organization'); + } finally { + this.isSubmitting.set(false); + } + } + + onCancel(): void { + this.cancelled.emit(); + if (this.mode() === 'popup') { + this.open.set(false); + } + } + + private resetForm(): void { + this.formName.set(''); + this.formHandle.set(''); + this.formDescription.set(''); + this.error.set(null); + this.formErrors.set({}); + this.handleManuallyEdited.set(false); + this.isSubmitting.set(false); + } + + private clearFieldError(field: string): void { + this.formErrors.update((v: {description?: string; handle?: string; name?: string}) => { + const copy: {description?: string; handle?: string; name?: string} = {...v}; + delete (copy as any)[field]; + return copy; + }); + } +} diff --git a/packages/angular/src/components/organization-list/organization-list.component.ts b/packages/angular/src/components/organization-list/organization-list.component.ts new file mode 100644 index 000000000..81993bb1e --- /dev/null +++ b/packages/angular/src/components/organization-list/organization-list.component.ts @@ -0,0 +1,569 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {NgTemplateOutlet} from '@angular/common'; +import { + Component, + ChangeDetectionStrategy, + inject, + input, + model, + output, + signal, + computed, + effect, + HostListener, + InputSignal, + ModelSignal, + OutputEmitterRef, + WritableSignal, + Signal, +} from '@angular/core'; +import {Organization, AllOrganizationsApiResponse} from '@asgardeo/browser'; +import {AsgardeoAuthService} from '../../services/asgardeo-auth.service'; +import {AsgardeoOrganizationService} from '../../services/asgardeo-organization.service'; +import {generateGradient, getInitials} from '../../utils/avatar'; + +/** + * Angular Organization List component matching the React SDK's ``. + * + * Displays a paginated list of organizations with "Switch" buttons and "Current" badges. + * Supports both inline and popup (dialog) modes. + * + * @example + * ```html + * + * + * + * + * + * ``` + */ +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [NgTemplateOutlet], + selector: 'asgardeo-organization-list', + standalone: true, + styles: ` + :host { + /* Core palette */ + --asgardeo-color-primary: #4f46e5; + --asgardeo-color-primary-hover: #4338ca; + --asgardeo-color-primary-ring: rgba(99, 102, 241, 0.2); + + /* Text */ + --asgardeo-color-text: #111827; + --asgardeo-color-text-secondary: #6b7280; + --asgardeo-color-text-muted: #9ca3af; + + /* Surfaces & borders */ + --asgardeo-color-surface: #fff; + --asgardeo-color-border: #e5e7eb; + --asgardeo-color-hover: rgba(0, 0, 0, 0.05); + + /* Secondary button */ + --asgardeo-color-secondary: #f3f4f6; + --asgardeo-color-secondary-hover: #e5e7eb; + --asgardeo-color-secondary-text: #374151; + + /* Alert / error */ + --asgardeo-color-error-bg: #fef2f2; + --asgardeo-color-error-border: #fecaca; + --asgardeo-color-error-title: #991b1b; + --asgardeo-color-error-text: #b91c1c; + + /* Status */ + --asgardeo-color-success: #059669; + --asgardeo-color-success-bg: #ecfdf5; + + /* Overlay */ + --asgardeo-overlay-bg: rgba(0, 0, 0, 0.5); + + /* Border radius */ + --asgardeo-radius-sm: 4px; + --asgardeo-radius-md: 6px; + --asgardeo-radius-lg: 8px; + --asgardeo-radius-xl: 12px; + + /* Font sizes */ + --asgardeo-font-size-xs: 0.8125rem; + --asgardeo-font-size-sm: 0.875rem; + --asgardeo-font-size-md: 1.2rem; + --asgardeo-font-size-lg: 1.5rem; + } + + /* Dialog Overlay */ + .asgardeo-dialog__overlay { + position: fixed; + inset: 0; + background: var(--asgardeo-overlay-bg); + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; + } + + .asgardeo-dialog__content { + background: var(--asgardeo-color-surface); + border-radius: var(--asgardeo-radius-xl); + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15); + max-width: 600px; + width: 90vw; + max-height: 85vh; + display: flex; + flex-direction: column; + z-index: 10000; + } + + .asgardeo-dialog__header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 1rem 1.5rem; + border-bottom: 1px solid var(--asgardeo-color-border); + } + + .asgardeo-dialog__heading { + font-size: var(--asgardeo-font-size-md); + font-weight: 600; + color: var(--asgardeo-color-text); + margin: 0; + } + + .asgardeo-dialog__close { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + background: none; + border: none; + border-radius: var(--asgardeo-radius-md); + cursor: pointer; + color: var(--asgardeo-color-text-secondary); + + &:hover { + background: var(--asgardeo-color-hover); + color: var(--asgardeo-color-text); + } + } + + .asgardeo-organization-list__popup { + padding: 1.5rem; + overflow-y: auto; + } + + /* Alert */ + .asgardeo-alert { + padding: 12px 16px; + border-radius: var(--asgardeo-radius-lg); + margin-bottom: 16px; + } + + .asgardeo-alert--error { + background: var(--asgardeo-color-error-bg); + border: 1px solid var(--asgardeo-color-error-border); + } + + .asgardeo-alert__title { + font-size: var(--asgardeo-font-size-sm); + font-weight: 600; + color: var(--asgardeo-color-error-title); + } + + .asgardeo-alert__description { + font-size: var(--asgardeo-font-size-sm); + color: var(--asgardeo-color-error-text); + margin-top: 2px; + } + + /* Loading */ + .asgardeo-organization-list__loading { + display: flex; + flex-direction: column; + align-items: center; + gap: 12px; + padding: 48px 0; + color: var(--asgardeo-color-text-secondary); + font-size: var(--asgardeo-font-size-sm); + } + + .asgardeo-spinner { + width: 32px; + height: 32px; + border: 3px solid var(--asgardeo-color-border); + border-top-color: var(--asgardeo-color-primary); + border-radius: 50%; + animation: asgardeo-spin 0.6s linear infinite; + } + + .asgardeo-spinner--sm { + width: 16px; + height: 16px; + border-width: 2px; + margin-right: 4px; + } + + @keyframes asgardeo-spin { + to { transform: rotate(360deg); } + } + + /* Empty state */ + .asgardeo-organization-list__empty { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + padding: 48px 0; + color: var(--asgardeo-color-text-muted); + font-size: var(--asgardeo-font-size-sm); + } + + .asgardeo-organization-list__empty-icon { + width: 48px; + height: 48px; + } + + /* Header */ + .asgardeo-organization-list__header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 12px; + } + + .asgardeo-organization-list__count { + font-size: var(--asgardeo-font-size-sm); + color: var(--asgardeo-color-text-secondary); + } + + /* List item */ + .asgardeo-organization-list__item { + display: flex; + align-items: center; + gap: 12px; + padding: 12px; + border-bottom: 1px solid var(--asgardeo-color-border); + + &:last-child { + border-bottom: none; + } + + &:hover { + background: var(--asgardeo-color-hover); + border-radius: var(--asgardeo-radius-lg); + } + } + + .asgardeo-organization-list__item-info { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + gap: 2px; + } + + .asgardeo-organization-list__item-name { + font-size: var(--asgardeo-font-size-sm); + font-weight: 500; + color: var(--asgardeo-color-text); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .asgardeo-organization-list__item-handle { + font-size: var(--asgardeo-font-size-xs); + color: var(--asgardeo-color-text-muted); + } + + .asgardeo-organization-list__item-actions { + flex-shrink: 0; + } + + /* Avatar */ + .asgardeo-avatar { + display: flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 500; + overflow: hidden; + flex-shrink: 0; + } + + .asgardeo-avatar--square { + width: 40px; + height: 40px; + border-radius: var(--asgardeo-radius-lg); + font-size: 14px; + } + + /* Badge */ + .asgardeo-badge { + display: inline-flex; + align-items: center; + padding: 2px 8px; + font-size: 0.75rem; + font-weight: 500; + border-radius: 9999px; + background: var(--asgardeo-color-secondary); + color: var(--asgardeo-color-secondary-text); + } + + .asgardeo-badge--current { + background: var(--asgardeo-color-success-bg); + color: var(--asgardeo-color-success); + } + + .asgardeo-badge--active { + background: var(--asgardeo-color-success-bg); + color: var(--asgardeo-color-success); + } + + /* Buttons */ + .asgardeo-btn { + display: inline-flex; + align-items: center; + justify-content: center; + border: none; + cursor: pointer; + font-family: inherit; + border-radius: var(--asgardeo-radius-md); + transition: background-color 0.15s; + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } + } + + .asgardeo-btn--sm { + padding: 4px 12px; + font-size: var(--asgardeo-font-size-xs); + font-weight: 500; + } + + .asgardeo-btn--primary { + background: var(--asgardeo-color-primary); + color: white; + + &:hover:not(:disabled) { + background: var(--asgardeo-color-primary-hover); + } + } + + .asgardeo-btn--secondary { + background: var(--asgardeo-color-secondary); + color: var(--asgardeo-color-secondary-text); + + &:hover:not(:disabled) { + background: var(--asgardeo-color-secondary-hover); + } + } + `, + template: ` + +
+ @if (error()) { +
+
Error
+
{{ error() }}
+
+ } + + @if (isLoadingAll() && organizationsWithAccess().length === 0) { +
+
+ Loading organizations... +
+ } @else if (!isLoadingAll() && organizationsWithAccess().length === 0 && !error()) { +
+ + + + No organizations found +
+ } @else { +
+ + {{ organizationsWithAccess().length }} organization{{ organizationsWithAccess().length === 1 ? '' : 's' }} + + +
+ + @for (org of organizationsWithAccess(); track org.id) { +
+
+ {{ getInitials(org.name || 'Org') }} +
+
+ {{ org.name || org.id }} + @if (org.orgHandle) { + @{{ org.orgHandle }} + } + @if (showStatus() && org.status) { + + {{ org.status }} + + } +
+
+ @if (org.isCurrent) { + Current + } @else if (org.canSwitch) { + + } +
+
+ } + } +
+
+ + @if (mode() === 'popup') { + @if (open()) { +
+
+
+

{{ title() }}

+ +
+
+ +
+
+
+ } + } @else { + + } + `, +}) +export class AsgardeoOrganizationListComponent { + /** Display mode: inline (default) or popup dialog */ + readonly mode: InputSignal<'inline' | 'popup'> = input<'inline' | 'popup'>('inline'); + + /** Whether the popup dialog is open (popup mode only). Supports two-way binding via `[(open)]`. */ + readonly open: ModelSignal = model(false); + + /** Dialog title (popup mode only) */ + readonly title: InputSignal = input('Organizations'); + + /** Whether to show organization status badges */ + readonly showStatus: InputSignal = input(false); + + /** Emits when an organization is selected for switching */ + readonly organizationSelect: OutputEmitterRef = output(); + + private authService: AsgardeoAuthService = inject(AsgardeoAuthService); + + private orgService: AsgardeoOrganizationService = inject(AsgardeoOrganizationService); + + isLoadingAll: WritableSignal = signal(false); + + error: WritableSignal = signal(null); + + private allOrganizations: WritableSignal = + signal(null); + + organizationsWithAccess: Signal<(Organization & {canSwitch: boolean; isCurrent: boolean})[]> = computed(() => { + const all: AllOrganizationsApiResponse | null = this.allOrganizations(); + const my: Organization[] = this.orgService.myOrganizations(); + const currentId: string | undefined = this.orgService.currentOrganization()?.id; + const myIds: Set = new Set(my.map((o: Organization) => o.id)); + + // If we have allOrganizations response, use it; otherwise fall back to myOrganizations + const orgList: Organization[] = all?.organizations || my; + + return orgList.map((org: Organization) => ({ + ...org, + canSwitch: myIds.has(org.id) && org.id !== currentId, + isCurrent: org.id === currentId, + })); + }); + + constructor() { + this.fetchOrganizations(); + + effect(() => { + if (!this.open()) { + this.error.set(null); + } + }); + } + + @HostListener('document:keydown.escape') + onEscapeKey(): void { + if (this.mode() === 'popup' && this.open()) { + this.close(); + } + } + + close(): void { + this.open.set(false); + } + + onOverlayClick(event: Event): void { + if (event.target === event.currentTarget) { + this.close(); + } + } + + async fetchOrganizations(): Promise { + this.isLoadingAll.set(true); + this.error.set(null); + try { + const result: AllOrganizationsApiResponse = await this.orgService.getAllOrganizations(); + this.allOrganizations.set(result); + } catch (err: any) { + this.error.set(err?.message || 'Failed to fetch organizations'); + } finally { + this.isLoadingAll.set(false); + } + } + + async refresh(): Promise { + await Promise.all([this.fetchOrganizations(), this.orgService.revalidateMyOrganizations()]); + } + + async onSwitch(org: Organization): Promise { + this.organizationSelect.emit(org); + await this.orgService.switchOrganization(org); + } + + readonly getInitials: (name: string) => string = getInitials; + + readonly generateGradient: (inputString: string) => string = generateGradient; +} diff --git a/packages/angular/src/components/organization-profile/organization-profile.component.ts b/packages/angular/src/components/organization-profile/organization-profile.component.ts new file mode 100644 index 000000000..75ed25dcf --- /dev/null +++ b/packages/angular/src/components/organization-profile/organization-profile.component.ts @@ -0,0 +1,687 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {NgTemplateOutlet} from '@angular/common'; +import { + Component, + ChangeDetectionStrategy, + inject, + input, + model, + output, + signal, + computed, + effect, + HostListener, + InputSignal, + ModelSignal, + OutputEmitterRef, + WritableSignal, + Signal, +} from '@angular/core'; +import {OrganizationDetails} from '@asgardeo/browser'; +import {AsgardeoOrganizationService} from '../../services/asgardeo-organization.service'; +import {generateGradient, getInitials} from '../../utils/avatar'; + +interface FieldConfig { + editable: boolean; + format?: (value: any) => string; + key: string; + label: string; +} + +function formatDate(dateString: any): string { + if (!dateString) return '-'; + try { + return new Date(dateString).toLocaleDateString('en-US', {day: 'numeric', month: 'long', year: 'numeric'}); + } catch { + return String(dateString); + } +} + +const DEFAULT_FIELDS: FieldConfig[] = [ + {editable: false, key: 'id', label: 'Organization ID'}, + {editable: true, key: 'name', label: 'Organization Name'}, + {editable: true, key: 'description', label: 'Description'}, + {editable: false, format: formatDate, key: 'created', label: 'Created Date'}, + {editable: false, format: formatDate, key: 'lastModified', label: 'Last Modified'}, +]; + +/** + * Angular Organization Profile component matching the React SDK's ``. + * + * Displays organization details with per-field inline editing. + * Supports both inline and popup (dialog) modes. + * + * @example + * ```html + * + * + * + * + * + * ``` + */ +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [NgTemplateOutlet], + selector: 'asgardeo-organization-profile', + standalone: true, + styles: ` + :host { + /* Core palette */ + --asgardeo-color-primary: #4f46e5; + --asgardeo-color-primary-hover: #4338ca; + --asgardeo-color-primary-ring: rgba(99, 102, 241, 0.2); + + /* Text */ + --asgardeo-color-text: #111827; + --asgardeo-color-text-secondary: #6b7280; + --asgardeo-color-text-muted: #9ca3af; + + /* Surfaces & borders */ + --asgardeo-color-surface: #fff; + --asgardeo-color-border: #e5e7eb; + --asgardeo-color-input-border: #d1d5db; + --asgardeo-color-hover: rgba(0, 0, 0, 0.05); + + /* Secondary button */ + --asgardeo-color-secondary: #f3f4f6; + --asgardeo-color-secondary-hover: #e5e7eb; + --asgardeo-color-secondary-text: #374151; + + /* Alert / error */ + --asgardeo-color-error-bg: #fef2f2; + --asgardeo-color-error-border: #fecaca; + --asgardeo-color-error-title: #991b1b; + --asgardeo-color-error-text: #b91c1c; + + /* Overlay */ + --asgardeo-overlay-bg: rgba(0, 0, 0, 0.5); + + /* Border radius */ + --asgardeo-radius-sm: 4px; + --asgardeo-radius-md: 6px; + --asgardeo-radius-lg: 8px; + --asgardeo-radius-xl: 12px; + + /* Font sizes */ + --asgardeo-font-size-xs: 0.8125rem; + --asgardeo-font-size-sm: 0.875rem; + --asgardeo-font-size-md: 1.2rem; + --asgardeo-font-size-lg: 1.5rem; + } + + /* Dialog Overlay */ + .asgardeo-dialog__overlay { + position: fixed; + inset: 0; + background: var(--asgardeo-overlay-bg); + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; + } + + .asgardeo-dialog__content { + background: var(--asgardeo-color-surface); + border-radius: var(--asgardeo-radius-xl); + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15); + max-width: 600px; + width: 90vw; + max-height: 85vh; + display: flex; + flex-direction: column; + z-index: 10000; + } + + .asgardeo-dialog__header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 1rem 1.5rem; + border-bottom: 1px solid var(--asgardeo-color-border); + } + + .asgardeo-dialog__heading { + font-size: var(--asgardeo-font-size-md); + font-weight: 600; + color: var(--asgardeo-color-text); + margin: 0; + } + + .asgardeo-dialog__close { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + background: none; + border: none; + border-radius: var(--asgardeo-radius-md); + cursor: pointer; + color: var(--asgardeo-color-text-secondary); + + &:hover { + background: var(--asgardeo-color-hover); + color: var(--asgardeo-color-text); + } + } + + .asgardeo-organization-profile__popup { + padding: 1.5rem; + overflow-y: auto; + } + + /* Loading */ + .asgardeo-organization-profile__loading { + display: flex; + flex-direction: column; + align-items: center; + gap: 12px; + padding: 48px 0; + color: var(--asgardeo-color-text-secondary); + font-size: var(--asgardeo-font-size-sm); + } + + .asgardeo-spinner { + width: 32px; + height: 32px; + border: 3px solid var(--asgardeo-color-border); + border-top-color: var(--asgardeo-color-primary); + border-radius: 50%; + animation: asgardeo-spin 0.6s linear infinite; + } + + @keyframes asgardeo-spin { + to { transform: rotate(360deg); } + } + + /* Empty state */ + .asgardeo-organization-profile__empty { + display: flex; + align-items: center; + justify-content: center; + padding: 48px 0; + color: var(--asgardeo-color-text-muted); + font-size: var(--asgardeo-font-size-sm); + } + + /* Alert */ + .asgardeo-alert { + padding: 12px 16px; + border-radius: var(--asgardeo-radius-lg); + margin-bottom: 16px; + } + + .asgardeo-alert--error { + background: var(--asgardeo-color-error-bg); + border: 1px solid var(--asgardeo-color-error-border); + } + + .asgardeo-alert__title { + font-size: var(--asgardeo-font-size-sm); + font-weight: 600; + color: var(--asgardeo-color-error-title); + } + + .asgardeo-alert__description { + font-size: var(--asgardeo-font-size-sm); + color: var(--asgardeo-color-error-text); + margin-top: 2px; + } + + /* Avatar */ + .asgardeo-avatar { + display: flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 500; + overflow: hidden; + flex-shrink: 0; + } + + .asgardeo-avatar--lg { + width: 70px; + height: 70px; + font-size: 24px; + } + + .asgardeo-avatar--square { + border-radius: var(--asgardeo-radius-lg); + } + + /* Profile Summary */ + .asgardeo-organization-profile__summary { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; + margin-bottom: 12px; + } + + .asgardeo-organization-profile__summary-name { + font-size: var(--asgardeo-font-size-lg); + font-weight: 600; + color: var(--asgardeo-color-text); + margin-top: 8px; + } + + .asgardeo-organization-profile__summary-handle { + font-size: var(--asgardeo-font-size-sm); + color: var(--asgardeo-color-text-secondary); + } + + /* Divider */ + .asgardeo-divider { + border-bottom: 1px solid var(--asgardeo-color-border); + } + + /* Field info row */ + .asgardeo-organization-profile__info { + padding: 12px 0; + border-bottom: 1px solid var(--asgardeo-color-border); + + &:last-child { + border-bottom: none; + } + } + + .asgardeo-organization-profile__field { + display: flex; + align-items: center; + padding: 4px 0; + min-height: 28px; + } + + .asgardeo-organization-profile__field-inner { + flex: 1; + display: flex; + align-items: center; + gap: 8px; + min-width: 0; + } + + .asgardeo-organization-profile__field-label { + width: 140px; + flex-shrink: 0; + font-size: var(--asgardeo-font-size-sm); + font-weight: 500; + color: var(--asgardeo-color-text-secondary); + line-height: 28px; + } + + .asgardeo-organization-profile__field-value { + flex: 1; + font-size: var(--asgardeo-font-size-sm); + color: var(--asgardeo-color-text); + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 350px; + line-height: 28px; + word-break: break-word; + } + + .asgardeo-organization-profile__field-placeholder { + font-style: italic; + opacity: 0.7; + cursor: pointer; + text-decoration: underline; + font-size: var(--asgardeo-font-size-sm); + } + + .asgardeo-organization-profile__field-actions { + display: flex; + align-items: center; + gap: 4px; + margin-left: 32px; + } + + /* Text Field */ + .asgardeo-text-field { + width: 100%; + max-width: 280px; + padding: 6px 10px; + font-size: var(--asgardeo-font-size-sm); + border: 1px solid var(--asgardeo-color-input-border); + border-radius: var(--asgardeo-radius-md); + outline: none; + font-family: inherit; + + &:focus { + border-color: var(--asgardeo-color-primary); + box-shadow: 0 0 0 2px var(--asgardeo-color-primary-ring); + } + } + + /* Buttons */ + .asgardeo-btn { + display: inline-flex; + align-items: center; + justify-content: center; + border: none; + cursor: pointer; + font-family: inherit; + border-radius: var(--asgardeo-radius-md); + transition: background-color 0.15s; + } + + .asgardeo-btn--sm { + padding: 4px 12px; + font-size: var(--asgardeo-font-size-xs); + font-weight: 500; + } + + .asgardeo-btn--primary { + background: var(--asgardeo-color-primary); + color: white; + + &:hover { + background: var(--asgardeo-color-primary-hover); + } + } + + .asgardeo-btn--secondary { + background: var(--asgardeo-color-secondary); + color: var(--asgardeo-color-secondary-text); + + &:hover { + background: var(--asgardeo-color-secondary-hover); + } + } + + .asgardeo-btn--icon { + width: 28px; + height: 28px; + padding: 0; + background: none; + color: var(--asgardeo-color-text-muted); + border-radius: var(--asgardeo-radius-sm); + + &:hover { + background: var(--asgardeo-color-hover); + color: var(--asgardeo-color-text-secondary); + } + } + `, + template: ` + +
+ @if (error()) { +
+
Error
+
{{ error() }}
+
+ } + + @if (isLoadingDetails()) { +
+
+ Loading organization... +
+ } @else if (resolvedOrganization(); as org) { + +
+
+ {{ orgInitials() }} +
+
{{ org.name }}
+ @if (org.orgHandle) { +
@{{ org.orgHandle }}
+ } +
+ +
+ + @for (field of fields; track field.key) { + @if (getFieldValue(org, field.key) !== undefined || (editable() && field.editable)) { +
+
+
+
{{ field.label }}
+
+ @if (isFieldEditing(field.key)) { + + } @else { + @if (getFieldValue(org, field.key) != null && getFieldValue(org, field.key) !== '') { + {{ field.format ? field.format(getFieldValue(org, field.key)) : getFieldValue(org, field.key) }} + } @else if (editable() && field.editable) { + + Add {{ field.label.toLowerCase() }} + + } @else { + - + } + } +
+
+ @if (editable() && field.editable) { +
+ @if (isFieldEditing(field.key)) { + + + } @else if (getFieldValue(org, field.key) != null && getFieldValue(org, field.key) !== '') { + + } +
+ } +
+
+ } + } + } @else if (!isLoadingDetails()) { +
No organization data available
+ } +
+
+ + @if (mode() === 'popup') { + @if (open()) { +
+
+
+

{{ title() }}

+ +
+
+ +
+
+
+ } + } @else { + + } + `, +}) +export class AsgardeoOrganizationProfileComponent { + /** Display mode: inline (default) or popup dialog */ + readonly mode: InputSignal<'inline' | 'popup'> = input<'inline' | 'popup'>('inline'); + + /** Whether the popup dialog is open (popup mode only). Supports two-way binding via `[(open)]`. */ + readonly open: ModelSignal = model(false); + + /** Dialog title (popup mode only) */ + readonly title: InputSignal = input('Organization Profile'); + + /** Whether fields can be edited */ + readonly editable: InputSignal = input(true); + + /** Organization ID to fetch details for */ + readonly organizationId: InputSignal = input(); + + /** Organization data to display directly (alternative to organizationId) */ + readonly organization: InputSignal = input(); + + /** Emits when the organization is updated */ + readonly updated: OutputEmitterRef = output(); + + private orgService: AsgardeoOrganizationService = inject(AsgardeoOrganizationService); + + private fetchedOrganization: WritableSignal = signal(null); + + private editingFields: WritableSignal> = signal>({}); + + private editedValues: WritableSignal> = signal>({}); + + error: WritableSignal = signal(null); + + isLoadingDetails: WritableSignal = signal(false); + + readonly fields: FieldConfig[] = DEFAULT_FIELDS; + + resolvedOrganization: Signal = computed( + () => this.organization() || this.fetchedOrganization(), + ); + + orgInitials: Signal = computed(() => { + const name: string | undefined = this.resolvedOrganization()?.name; + if (!name) return 'ORG'; + return getInitials(name); + }); + + avatarGradient: Signal = computed(() => { + const name: string = this.resolvedOrganization()?.name || 'Organization'; + return generateGradient(name); + }); + + constructor() { + // Fetch organization when organizationId changes + effect(() => { + const id: string | undefined = this.organizationId(); + if (id) { + this.fetchOrganization(id); + } + }); + + // Reset editing state when popup closes + effect(() => { + if (!this.open()) { + this.editingFields.set({}); + this.editedValues.set({}); + this.error.set(null); + } + }); + } + + @HostListener('document:keydown.escape') + onEscapeKey(): void { + if (this.mode() === 'popup' && this.open()) { + this.close(); + } + } + + close(): void { + this.open.set(false); + } + + onOverlayClick(event: Event): void { + if (event.target === event.currentTarget) { + this.close(); + } + } + + async fetchOrganization(id: string): Promise { + this.isLoadingDetails.set(true); + this.error.set(null); + try { + const result: OrganizationDetails = await this.orgService.getOrganization(id); + this.fetchedOrganization.set(result); + } catch (err: any) { + this.error.set(err?.message || 'Failed to load organization'); + } finally { + this.isLoadingDetails.set(false); + } + } + + // eslint-disable-next-line class-methods-use-this + getFieldValue(org: OrganizationDetails, key: string): any { + return (org as Record)[key]; + } + + isFieldEditing(fieldKey: string): boolean { + return this.editingFields()[fieldKey] || false; + } + + getEditedValue(fieldKey: string): any { + const edited: Record = this.editedValues(); + if (fieldKey in edited) return edited[fieldKey]; + const org: OrganizationDetails | null = this.resolvedOrganization(); + return org ? this.getFieldValue(org, fieldKey) : ''; + } + + toggleEdit(fieldKey: string): void { + this.editingFields.update((v: Record) => ({...v, [fieldKey]: !v[fieldKey]})); + } + + onFieldChange(fieldKey: string, value: any): void { + this.editedValues.update((v: Record) => ({...v, [fieldKey]: value})); + } + + cancelEdit(fieldKey: string): void { + this.editingFields.update((v: Record) => ({...v, [fieldKey]: false})); + this.editedValues.update((v: Record) => { + const copy: Record = {...v}; + delete copy[fieldKey]; + return copy; + }); + } + + async saveField(field: FieldConfig): Promise { + const org: OrganizationDetails | null = this.resolvedOrganization(); + if (!org) return; + + const value: any = this.getEditedValue(field.key); + this.error.set(null); + + try { + const updated: OrganizationDetails = await this.orgService.updateOrganization(org.id, {[field.key]: value}); + this.fetchedOrganization.set(updated); + this.editingFields.update((v: Record) => ({...v, [field.key]: false})); + this.editedValues.update((v: Record) => { + const copy: Record = {...v}; + delete copy[field.key]; + return copy; + }); + this.updated.emit(updated); + } catch (err: any) { + this.error.set(err?.message || 'Failed to update organization'); + } + } +} diff --git a/packages/angular/src/components/organization-switcher/organization-switcher.component.ts b/packages/angular/src/components/organization-switcher/organization-switcher.component.ts new file mode 100644 index 000000000..4629093f5 --- /dev/null +++ b/packages/angular/src/components/organization-switcher/organization-switcher.component.ts @@ -0,0 +1,411 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + ChangeDetectionStrategy, + Component, + HostListener, + InputSignal, + OutputEmitterRef, + Signal, + WritableSignal, + computed, + inject, + input, + output, + signal, +} from '@angular/core'; +import {Organization} from '@asgardeo/browser'; +import {AsgardeoOrganizationService} from '../../services/asgardeo-organization.service'; +import {generateGradient, getInitials} from '../../utils/avatar'; + +/** + * Angular Organization Switcher component matching the React SDK's ``. + * + * A trigger button with dropdown for switching between organizations. + * Uses CSS absolute positioning (no floating-ui dependency). + * + * @example + * ```html + * + * + * + * + * ``` + */ +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'asgardeo-organization-switcher', + standalone: true, + styles: ` + :host { + /* Core palette */ + --asgardeo-color-primary: #4f46e5; + --asgardeo-color-primary-hover: #4338ca; + + /* Text */ + --asgardeo-color-text: #111827; + --asgardeo-color-text-secondary: #6b7280; + --asgardeo-color-text-muted: #9ca3af; + + /* Surfaces & borders */ + --asgardeo-color-surface: #fff; + --asgardeo-color-border: #e5e7eb; + --asgardeo-color-hover: rgba(0, 0, 0, 0.05); + + /* Border radius */ + --asgardeo-radius-md: 6px; + --asgardeo-radius-lg: 8px; + --asgardeo-radius-xl: 12px; + + /* Font sizes */ + --asgardeo-font-size-xs: 0.8125rem; + --asgardeo-font-size-sm: 0.875rem; + + display: inline-block; + } + + .asgardeo-org-switcher { + position: relative; + display: inline-block; + } + + /* Trigger */ + .asgardeo-org-switcher__trigger { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 6px 10px; + background: none; + border: 1px solid var(--asgardeo-color-border); + border-radius: var(--asgardeo-radius-lg); + cursor: pointer; + font-family: inherit; + transition: background-color 0.15s; + + &:hover { + background-color: var(--asgardeo-color-hover); + } + + &:focus { + outline: 2px solid var(--asgardeo-color-primary); + outline-offset: 2px; + } + } + + .asgardeo-org-switcher__trigger-label { + font-size: var(--asgardeo-font-size-sm); + font-weight: 500; + color: var(--asgardeo-color-text); + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .asgardeo-org-switcher__trigger-icon { + color: var(--asgardeo-color-text-secondary); + } + + .asgardeo-org-switcher__chevron { + color: var(--asgardeo-color-text-muted); + transition: transform 0.2s; + flex-shrink: 0; + } + + .asgardeo-org-switcher__chevron--open { + transform: rotate(180deg); + } + + /* Dropdown content */ + .asgardeo-org-switcher__content { + position: absolute; + top: calc(100% + 5px); + right: 0; + min-width: 250px; + max-width: 350px; + background: var(--asgardeo-color-surface); + border-radius: var(--asgardeo-radius-xl); + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + border: 1px solid var(--asgardeo-color-border); + overflow: hidden; + z-index: 9999; + } + + /* Header */ + .asgardeo-org-switcher__header { + display: flex; + align-items: center; + gap: 10px; + padding: 12px 16px; + border-bottom: 1px solid var(--asgardeo-color-border); + } + + .asgardeo-org-switcher__header-info { + display: flex; + flex-direction: column; + gap: 1px; + flex: 1; + min-width: 0; + overflow: hidden; + } + + .asgardeo-org-switcher__header-name { + font-size: var(--asgardeo-font-size-sm); + font-weight: 600; + color: var(--asgardeo-color-text); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .asgardeo-org-switcher__header-handle { + font-size: var(--asgardeo-font-size-xs); + color: var(--asgardeo-color-text-muted); + } + + /* Section header */ + .asgardeo-org-switcher__section-header { + padding: 8px 16px 4px; + font-size: 0.75rem; + font-weight: 600; + color: var(--asgardeo-color-text-muted); + text-transform: uppercase; + letter-spacing: 0.05em; + } + + /* Menu items */ + .asgardeo-org-switcher__menu { + display: flex; + flex-direction: column; + padding: 4px 0; + } + + .asgardeo-org-switcher__menu-item { + display: flex; + align-items: center; + gap: 10px; + padding: 8px 16px; + width: 100%; + color: var(--asgardeo-color-text); + text-decoration: none; + border: none; + background: transparent; + cursor: pointer; + font-size: var(--asgardeo-font-size-sm); + text-align: start; + font-family: inherit; + + &:hover { + background-color: var(--asgardeo-color-hover); + } + } + + /* Empty state */ + .asgardeo-org-switcher__empty { + padding: 16px; + text-align: center; + font-size: var(--asgardeo-font-size-xs); + color: var(--asgardeo-color-text-muted); + } + + /* Avatar */ + .asgardeo-avatar { + display: flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 500; + overflow: hidden; + flex-shrink: 0; + } + + .asgardeo-avatar--square { + border-radius: var(--asgardeo-radius-md); + } + + .asgardeo-avatar--sm { + width: 24px; + height: 24px; + font-size: 10px; + } + `, + template: ` +
+ + + + + @if (isOpen()) { +
+ + @if (resolvedCurrentOrg(); as org) { +
+
+ {{ currentOrgInitials() }} +
+
+ {{ org.name || org.id }} + @if (org.orgHandle) { + @{{ org.orgHandle }} + } +
+
+ } + + + @if (switchableOrganizations().length > 0) { +
Switch organization
+
+ @for (org of switchableOrganizations(); track org.id) { + + } +
+ } @else { +
No other organizations available
+ } + + + +
+ } +
+ `, +}) +export class AsgardeoOrganizationSwitcherComponent { + /** Whether to show the organization name next to the avatar in the trigger */ + readonly showTriggerLabel: InputSignal = input(true); + + /** Avatar size in pixels */ + readonly avatarSize: InputSignal = input(24); + + /** Override the list of organizations (defaults to orgService.myOrganizations) */ + readonly organizations: InputSignal = input(); + + /** Override the current organization (defaults to orgService.currentOrganization) */ + readonly currentOrganization: InputSignal = input(); + + /** Emits when an organization is selected for switching */ + readonly organizationSwitch: OutputEmitterRef = output(); + + private orgService: AsgardeoOrganizationService = inject(AsgardeoOrganizationService); + + isOpen: WritableSignal = signal(false); + + resolvedCurrentOrg: Signal = computed( + () => this.currentOrganization() || this.orgService.currentOrganization() || undefined, + ); + + switchableOrganizations: Signal = computed(() => { + const orgs: Organization[] = this.organizations() || this.orgService.myOrganizations(); + const currentId: string | undefined = this.resolvedCurrentOrg()?.id; + return orgs.filter((o: Organization) => o.id !== currentId); + }); + + currentOrgInitials: Signal = computed(() => { + const name: string | undefined = this.resolvedCurrentOrg()?.name; + if (!name) return 'O'; + return getInitials(name); + }); + + currentOrgGradient: Signal = computed(() => { + const name: string = this.resolvedCurrentOrg()?.name || 'Organization'; + return generateGradient(name); + }); + + @HostListener('document:click') + onDocumentClick(): void { + if (this.isOpen()) { + this.isOpen.set(false); + } + } + + toggle(event: Event): void { + event.stopPropagation(); + this.isOpen.update((v: boolean) => !v); + } + + async switchTo(org: Organization): Promise { + this.isOpen.set(false); + this.organizationSwitch.emit(org); + await this.orgService.switchOrganization(org); + } + + readonly getInitials: (name: string) => string = getInitials; + + readonly generateGradient: (name: string) => string = generateGradient; +} diff --git a/packages/angular/src/components/user-profile/user-profile.component.ts b/packages/angular/src/components/user-profile/user-profile.component.ts new file mode 100644 index 000000000..32c927d01 --- /dev/null +++ b/packages/angular/src/components/user-profile/user-profile.component.ts @@ -0,0 +1,828 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {NgTemplateOutlet} from '@angular/common'; +import { + Component, + ChangeDetectionStrategy, + inject, + input, + model, + signal, + computed, + effect, + HostListener, + InputSignal, + ModelSignal, + WritableSignal, + Signal, +} from '@angular/core'; +import {AsgardeoAuthService} from '../../services/asgardeo-auth.service'; +import {AsgardeoUserService} from '../../services/asgardeo-user.service'; +import {generateGradient, getInitials} from '../../utils/avatar'; + +/** Fields that should never be displayed in the profile fields list. + * Matches React SDK's BaseUserProfile.fieldsToSkip. */ +const FIELDS_TO_SKIP: string[] = [ + 'roles.default', + 'active', + 'groups', + 'accountLocked', + 'accountDisabled', + 'oneTimePassword', + 'userSourceId', + 'idpType', + 'localCredentialExists', + 'ResourceType', + 'ExternalID', + 'MetaData', + 'verifiedMobileNumbers', + 'verifiedEmailAddresses', + 'phoneNumbers.mobile', + 'emailAddresses', + 'preferredMFAOption', +]; + +/** Fields that cannot be edited */ +const READONLY_FIELDS: string[] = ['username', 'userName', 'user_name']; + +/** Well-known SCIM2 schema IDs */ +const WELL_KNOWN_USER_SCHEMA: string = 'urn:ietf:params:scim:schemas:core:2.0:User'; + +interface SchemaField { + caseExact?: boolean; + description?: string; + displayName?: string; + displayOrder?: string; + multiValued?: boolean; + mutability?: string; + name?: string; + path?: string; + required?: boolean; + returned?: string; + schemaId?: string; + subAttributes?: SchemaField[]; + type?: string; + uniqueness?: string; + value?: any; +} + +/** + * Angular User Profile component matching the React SDK's ``. + * + * Supports both inline and popup (dialog) modes with SCIM schema-based + * field rendering and inline editing. + * + * @example + * ```html + * + * + * + * + * + * ``` + */ +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [NgTemplateOutlet], + selector: 'asgardeo-user-profile', + standalone: true, + styles: ` + /* ------------------------------------------------------------------ */ + /* Custom Properties — override these to theme the component. */ + /* */ + /* Usage: */ + /* asgardeo-user-profile { */ + /* --asgardeo-color-primary: #0ea5e9; */ + /* --asgardeo-color-primary-hover: #0284c7; */ + /* } */ + /* ------------------------------------------------------------------ */ + :host { + /* Core palette */ + --asgardeo-color-primary: #4f46e5; + --asgardeo-color-primary-hover: #4338ca; + --asgardeo-color-primary-ring: rgba(99, 102, 241, 0.2); + + /* Text */ + --asgardeo-color-text: #111827; + --asgardeo-color-text-secondary: #6b7280; + --asgardeo-color-text-muted: #9ca3af; + + /* Surfaces & borders */ + --asgardeo-color-surface: #fff; + --asgardeo-color-border: #e5e7eb; + --asgardeo-color-input-border: #d1d5db; + --asgardeo-color-hover: rgba(0, 0, 0, 0.05); + + /* Secondary button */ + --asgardeo-color-secondary: #f3f4f6; + --asgardeo-color-secondary-hover: #e5e7eb; + --asgardeo-color-secondary-text: #374151; + + /* Alert / error */ + --asgardeo-color-error-bg: #fef2f2; + --asgardeo-color-error-border: #fecaca; + --asgardeo-color-error-title: #991b1b; + --asgardeo-color-error-text: #b91c1c; + + /* Overlay */ + --asgardeo-overlay-bg: rgba(0, 0, 0, 0.5); + + /* Border radius */ + --asgardeo-radius-sm: 4px; + --asgardeo-radius-md: 6px; + --asgardeo-radius-lg: 8px; + --asgardeo-radius-xl: 12px; + + /* Font sizes */ + --asgardeo-font-size-xs: 0.8125rem; + --asgardeo-font-size-sm: 0.875rem; + --asgardeo-font-size-md: 1.2rem; + --asgardeo-font-size-lg: 1.5rem; + } + + /* Dialog Overlay */ + .asgardeo-dialog__overlay { + position: fixed; + inset: 0; + background: var(--asgardeo-overlay-bg); + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; + } + + .asgardeo-dialog__content { + background: var(--asgardeo-color-surface); + border-radius: var(--asgardeo-radius-xl); + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15); + max-width: 600px; + width: 90vw; + max-height: 85vh; + display: flex; + flex-direction: column; + z-index: 10000; + padding: 2rem; + } + + .asgardeo-dialog__header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 1rem 2rem; + border-bottom: 1px solid var(--asgardeo-color-border); + } + + .asgardeo-dialog__heading { + font-size: var(--asgardeo-font-size-md); + font-weight: 600; + color: var(--asgardeo-color-text); + margin: 0; + } + + .asgardeo-dialog__close { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + background: none; + border: none; + border-radius: var(--asgardeo-radius-md); + cursor: pointer; + color: var(--asgardeo-color-text-secondary); + + &:hover { + background: var(--asgardeo-color-hover); + color: var(--asgardeo-color-text); + } + } + + /* Profile Content */ + .asgardeo-user-profile__popup { + padding: 2rem; + overflow-y: auto; + } + + .asgardeo-user-profile { + min-width: 0; + } + + /* Alert */ + .asgardeo-alert { + padding: 12px 16px; + border-radius: var(--asgardeo-radius-lg); + margin-bottom: 24px; + } + + .asgardeo-alert--error { + background: var(--asgardeo-color-error-bg); + border: 1px solid var(--asgardeo-color-error-border); + } + + .asgardeo-alert__title { + font-size: var(--asgardeo-font-size-sm); + font-weight: 600; + color: var(--asgardeo-color-error-title); + } + + .asgardeo-alert__description { + font-size: var(--asgardeo-font-size-sm); + color: var(--asgardeo-color-error-text); + margin-top: 2px; + } + + /* Avatar */ + .asgardeo-avatar { + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 500; + overflow: hidden; + flex-shrink: 0; + } + + .asgardeo-avatar--lg { + width: 70px; + height: 70px; + font-size: 24px; + } + + .asgardeo-avatar img { + width: 100%; + height: 100%; + object-fit: cover; + } + + /* Profile Summary */ + .asgardeo-user-profile__summary { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; + margin-bottom: 12px; + } + + .asgardeo-user-profile__summary-name { + font-size: var(--asgardeo-font-size-lg); + font-weight: 600; + color: var(--asgardeo-color-text); + margin-top: 8px; + } + + .asgardeo-user-profile__summary-email { + font-size: var(--asgardeo-font-size-sm); + color: var(--asgardeo-color-text-secondary); + } + + /* Divider */ + .asgardeo-divider { + border-bottom: 1px solid var(--asgardeo-color-border); + } + + /* Field info row */ + .asgardeo-user-profile__info { + padding: 12px 0; + border-bottom: 1px solid var(--asgardeo-color-border); + + &:last-child { + border-bottom: none; + } + } + + /* Field */ + .asgardeo-user-profile__field { + display: flex; + align-items: center; + padding: 4px 0; + min-height: 28px; + } + + .asgardeo-user-profile__field-inner { + flex: 1; + display: flex; + align-items: center; + gap: 8px; + min-width: 0; + } + + .asgardeo-user-profile__field-label { + width: 120px; + flex-shrink: 0; + font-size: var(--asgardeo-font-size-sm); + font-weight: 500; + color: var(--asgardeo-color-text-secondary); + line-height: 28px; + } + + .asgardeo-user-profile__field-value { + flex: 1; + font-size: var(--asgardeo-font-size-sm); + color: var(--asgardeo-color-text); + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 350px; + line-height: 28px; + word-break: break-word; + } + + .asgardeo-user-profile__field-placeholder { + font-style: italic; + opacity: 0.7; + cursor: pointer; + text-decoration: underline; + font-size: var(--asgardeo-font-size-sm); + } + + .asgardeo-user-profile__field-actions { + display: flex; + align-items: center; + gap: 4px; + margin-left: 32px; + } + + /* Text Field */ + .asgardeo-text-field { + width: 100%; + max-width: 280px; + padding: 6px 10px; + font-size: var(--asgardeo-font-size-sm); + border: 1px solid var(--asgardeo-color-input-border); + border-radius: var(--asgardeo-radius-md); + outline: none; + font-family: inherit; + + &:focus { + border-color: var(--asgardeo-color-primary); + box-shadow: 0 0 0 2px var(--asgardeo-color-primary-ring); + } + } + + /* Checkbox */ + .asgardeo-checkbox { + display: flex; + align-items: center; + cursor: pointer; + } + + .asgardeo-checkbox input { + width: 16px; + height: 16px; + } + + /* Buttons */ + .asgardeo-btn { + display: inline-flex; + align-items: center; + justify-content: center; + border: none; + cursor: pointer; + font-family: inherit; + border-radius: var(--asgardeo-radius-md); + transition: background-color 0.15s; + } + + .asgardeo-btn--sm { + padding: 4px 12px; + font-size: var(--asgardeo-font-size-xs); + font-weight: 500; + } + + .asgardeo-btn--primary { + background: var(--asgardeo-color-primary); + color: white; + + &:hover { + background: var(--asgardeo-color-primary-hover); + } + } + + .asgardeo-btn--secondary { + background: var(--asgardeo-color-secondary); + color: var(--asgardeo-color-secondary-text); + + &:hover { + background: var(--asgardeo-color-secondary-hover); + } + } + + .asgardeo-btn--icon { + width: 28px; + height: 28px; + padding: 0; + background: none; + color: var(--asgardeo-color-text-muted); + border-radius: var(--asgardeo-radius-sm); + + &:hover { + background: var(--asgardeo-color-hover); + color: var(--asgardeo-color-text-secondary); + } + } + `, + template: ` + + + + + @if (mode() === 'popup') { + @if (open()) { +
+
+
+

{{ title() || 'Profile' }}

+ +
+ +
+
+ } + } @else { + + } + `, +}) +export class AsgardeoUserProfileComponent { + /** Display mode: inline (default) or popup dialog */ + readonly mode: InputSignal<'inline' | 'popup'> = input<'inline' | 'popup'>('inline'); + + /** Whether the popup dialog is open (popup mode only). Supports two-way binding via `[(open)]`. */ + readonly open: ModelSignal = model(false); + + /** Dialog title (popup mode only) */ + readonly title: InputSignal = input(''); + + /** Whether fields can be edited */ + readonly editable: InputSignal = input(true); + + /** Whitelist of field names to show (if set, only these are shown) */ + readonly showFields: InputSignal = input(); + + /** Blacklist of field names to hide */ + readonly hideFields: InputSignal = input(); + + private authService: AsgardeoAuthService = inject(AsgardeoAuthService); + + private userService: AsgardeoUserService = inject(AsgardeoUserService); + + private editingFields: WritableSignal> = signal>({}); + + private editedValues: WritableSignal> = signal>({}); + + constructor() { + // Reset editing state when the popup closes + effect(() => { + if (!this.open()) { + this.editingFields.set({}); + this.editedValues.set({}); + this.error.set(null); + } + }); + } + + error: WritableSignal = signal(null); + + schemasAvailable: Signal = computed(() => { + const up: Record | null = this.authService.userProfile(); + return up?.['schemas'] && up['schemas'].length > 0; + }); + + displayName: Signal = computed(() => { + const user: Record | null = this.authService.flattenedProfile() || this.authService.user(); + if (!user) return 'User'; + const u: Record = user as Record; + const firstName: string = u['name']?.['givenName'] || u['given_name'] || ''; + const lastName: string = u['name']?.['familyName'] || u['family_name'] || ''; + if (firstName && lastName) return `${firstName} ${lastName}`; + return u['userName'] || u['username'] || u['email'] || 'User'; + }); + + emailValue: Signal = computed(() => { + const user: Record | null = this.authService.flattenedProfile() || this.authService.user(); + if (!user) return ''; + const u: Record = user as Record; + const {emails}: {emails: any} = u as {emails: any}; + if (Array.isArray(emails)) return emails[0] || ''; + return u['email'] || ''; + }); + + profileImageUrl: Signal = computed(() => { + const user: Record | null = this.authService.flattenedProfile() || this.authService.user(); + if (!user) return null; + const u: Record = user as Record; + return u['profile'] || u['profileUrl'] || u['picture'] || u['URL'] || null; + }); + + initials: Signal = computed(() => getInitials(this.displayName())); + + avatarGradient: Signal = computed(() => { + const name: string = this.displayName(); + if (!name) return 'linear-gradient(135deg, #6366f1, #8b5cf6)'; + return generateGradient(name); + }); + + /** + * Flattened schema fields with current values, filtered and sorted. + * `userProfile().schemas` is already flattened by `flattenUserSchema()` — a flat + * array of field definitions (each with `name`, `type`, `schemaId`, `displayOrder`, etc.), + * NOT nested schema objects with `.attributes`. + */ + visibleFields: Signal = computed(() => { + const up: Record | null = this.authService.userProfile(); + if (!up?.['schemas'] || up['schemas'].length === 0) return []; + const flatProfile: Record = (this.authService.flattenedProfile() || {}) as Record; + + return (up['schemas'] as any[]) + .map((field: any) => ({...field, value: flatProfile[field.name]} as SchemaField)) + .filter((f: SchemaField) => { + if (!f.name) return false; + if (FIELDS_TO_SKIP.includes(f.name)) return false; + if (this.hideFields()?.includes(f.name)) return false; + const sf: string[] | undefined = this.showFields(); + if (sf && sf.length > 0 && !sf.includes(f.name)) return false; + if (!this.editable()) { + return f.value !== undefined && f.value !== '' && f.value !== null; + } + return true; + }) + .sort((a: SchemaField, b: SchemaField) => { + const orderA: number = a.displayOrder ? parseInt(a.displayOrder, 10) : 999; + const orderB: number = b.displayOrder ? parseInt(b.displayOrder, 10) : 999; + return orderA - orderB; + }); + }); + + /** Fallback flat profile key-value pairs when no schemas available */ + flatProfileEntries: Signal<{key: string; value: string}[]> = computed(() => { + const profile: Record = (this.authService.flattenedProfile() || this.authService.user()) as Record< + string, + any + >; + if (!profile) return []; + + const entries: {key: string; value: string}[] = []; + + const flatten = (obj: Record, prefix: string = ''): void => { + Object.entries(obj).forEach((entry: [string, any]) => { + const key: string = entry[0]; + const value: any = entry[1]; + const fullKey: string = prefix ? `${prefix}.${key}` : key; + if (FIELDS_TO_SKIP.includes(fullKey) || FIELDS_TO_SKIP.includes(key)) return; + if (this.hideFields()?.includes(fullKey)) return; + const sf: string[] | undefined = this.showFields(); + if (sf && sf.length > 0 && !sf.includes(fullKey)) return; + if (value === undefined || value === '' || value === null) return; + + if (Array.isArray(value)) { + const displayVal: string = value.filter((v: any) => v !== null && v !== undefined && v !== '').join(', '); + if (displayVal) entries.push({key: fullKey, value: displayVal}); + } else if (typeof value === 'object') { + flatten(value, fullKey); + } else { + entries.push({key: fullKey, value: String(value)}); + } + }); + }; + + flatten(profile); + return entries.sort((a: {key: string; value: string}, b: {key: string; value: string}) => + a.key.localeCompare(b.key), + ); + }); + + @HostListener('document:keydown.escape') + onEscapeKey(): void { + if (this.mode() === 'popup' && this.open()) { + this.close(); + } + } + + close(): void { + this.open.set(false); + } + + onOverlayClick(event: Event): void { + if (event.target === event.currentTarget) { + this.close(); + } + } + + isFieldEditing(fieldName: string): boolean { + return this.editingFields()[fieldName] || false; + } + + getEditedValue(fieldName: string): any { + const edited: Record = this.editedValues(); + if (fieldName in edited) return edited[fieldName]; + const profile: Record = (this.authService.flattenedProfile() || {}) as Record; + return profile[fieldName]; + } + + toggleEdit(fieldName: string): void { + const current: Record = this.editingFields(); + this.editingFields.set({...current, [fieldName]: !current[fieldName]}); + } + + onFieldChange(fieldName: string, value: any): void { + this.editedValues.update((v: Record) => ({...v, [fieldName]: value})); + } + + cancelEdit(fieldName: string): void { + this.editingFields.update((v: Record) => ({...v, [fieldName]: false})); + this.editedValues.update((v: Record) => { + const copy: Record = {...v}; + delete copy[fieldName]; + return copy; + }); + } + + async saveField(field: SchemaField): Promise { + if (!field.name) return; + + const fieldName: string = field.name; + let fieldValue: any = this.getEditedValue(fieldName) ?? ''; + + if (Array.isArray(fieldValue)) { + fieldValue = fieldValue.filter((v: any) => v !== undefined && v !== null && v !== ''); + } + + let payload: Record = {}; + if (field.schemaId && field.schemaId !== WELL_KNOWN_USER_SCHEMA) { + payload = {[field.schemaId]: {[fieldName]: fieldValue}}; + } else { + AsgardeoUserProfileComponent.setNestedValue(payload, fieldName, fieldValue); + } + + this.error.set(null); + try { + const baseUrl: string = this.authService.getBaseUrl(); + const instanceId: number = this.authService.getClient().getInstanceId(); + + await this.userService.updateUser({baseUrl, instanceId, payload}); + + this.editingFields.update((v: Record) => ({...v, [fieldName]: false})); + this.editedValues.update((v: Record) => { + const copy: Record = {...v}; + delete copy[fieldName]; + return copy; + }); + } catch (err: any) { + this.error.set(err?.message || 'Failed to update profile'); + } + } + + // eslint-disable-next-line class-methods-use-this + isReadonly(field: SchemaField): boolean { + if (field.mutability === 'READ_ONLY') return true; + if (field.name && READONLY_FIELDS.includes(field.name)) return true; + return false; + } + + // eslint-disable-next-line class-methods-use-this + hasFieldValue(field: SchemaField): boolean { + return field.value !== undefined && field.value !== '' && field.value !== null; + } + + // eslint-disable-next-line class-methods-use-this + formatFieldValue(field: SchemaField): string { + const val: any = field.value; + if (val === null || val === undefined) return ''; + if (typeof val === 'boolean') return val ? 'Yes' : 'No'; + if (typeof val === 'object') return JSON.stringify(val); + return String(val); + } + + // eslint-disable-next-line class-methods-use-this + formatLabel(key: string): string { + return key + .split(/(?=[A-Z])|_|\./) + .map((word: string) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) + .join(' '); + } + + private static setNestedValue(obj: Record, path: string, value: any): void { + const keys: string[] = path.split('.'); + let current: Record = obj; + for (let i: number = 0; i < keys.length; i += 1) { + if (i === keys.length - 1) { + current[keys[i]] = value; + } else { + if (!current[keys[i]] || typeof current[keys[i]] !== 'object') { + current[keys[i]] = {}; + } + current = current[keys[i]]; + } + } + } +} diff --git a/packages/angular/src/directives/loading.directive.ts b/packages/angular/src/directives/loading.directive.ts new file mode 100644 index 000000000..8e25fd288 --- /dev/null +++ b/packages/angular/src/directives/loading.directive.ts @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {Directive, TemplateRef, ViewContainerRef, effect, inject} from '@angular/core'; +import {AsgardeoAuthService} from '../services/asgardeo-auth.service'; + +/** + * Structural directive that renders its template only when the SDK is in a loading state. + * Angular equivalent of React's `` component. + * + * @example + * ```html + *
+ *

Loading...

+ *
+ * ``` + */ +@Directive({ + selector: '[asgardeoLoading]', + standalone: true, +}) +export class AsgardeoLoadingDirective { + private readonly authService: AsgardeoAuthService = inject(AsgardeoAuthService); + + private readonly templateRef: TemplateRef = inject(TemplateRef); + + private readonly viewContainer: ViewContainerRef = inject(ViewContainerRef); + + private hasView: boolean = false; + + constructor() { + effect(() => { + const loading: boolean = this.authService.isLoading(); + if (loading && !this.hasView) { + this.viewContainer.createEmbeddedView(this.templateRef); + this.hasView = true; + } else if (!loading && this.hasView) { + this.viewContainer.clear(); + this.hasView = false; + } + }); + } +} diff --git a/packages/angular/src/directives/signed-in.directive.ts b/packages/angular/src/directives/signed-in.directive.ts new file mode 100644 index 000000000..c277f265e --- /dev/null +++ b/packages/angular/src/directives/signed-in.directive.ts @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {Directive, TemplateRef, ViewContainerRef, effect, inject} from '@angular/core'; +import {AsgardeoAuthService} from '../services/asgardeo-auth.service'; + +/** + * Structural directive that renders its template only when the user is signed in. + * Angular equivalent of React's `` component. + * + * @example + * ```html + *
+ *

Welcome! You are signed in.

+ *
+ * ``` + */ +@Directive({ + selector: '[asgardeoSignedIn]', + standalone: true, +}) +export class AsgardeoSignedInDirective { + private readonly authService: AsgardeoAuthService = inject(AsgardeoAuthService); + + private readonly templateRef: TemplateRef = inject(TemplateRef); + + private readonly viewContainer: ViewContainerRef = inject(ViewContainerRef); + + private hasView: boolean = false; + + constructor() { + effect(() => { + const isSignedIn: boolean = this.authService.isSignedIn(); + if (isSignedIn && !this.hasView) { + this.viewContainer.createEmbeddedView(this.templateRef); + this.hasView = true; + } else if (!isSignedIn && this.hasView) { + this.viewContainer.clear(); + this.hasView = false; + } + }); + } +} diff --git a/packages/angular/src/directives/signed-out.directive.ts b/packages/angular/src/directives/signed-out.directive.ts new file mode 100644 index 000000000..cbfdfc18e --- /dev/null +++ b/packages/angular/src/directives/signed-out.directive.ts @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {Directive, TemplateRef, ViewContainerRef, effect, inject} from '@angular/core'; +import {AsgardeoAuthService} from '../services/asgardeo-auth.service'; + +/** + * Structural directive that renders its template only when the user is NOT signed in + * and the SDK is not in a loading state. + * Angular equivalent of React's `` component. + * + * @example + * ```html + *
+ * + *
+ * ``` + */ +@Directive({ + selector: '[asgardeoSignedOut]', + standalone: true, +}) +export class AsgardeoSignedOutDirective { + private readonly authService: AsgardeoAuthService = inject(AsgardeoAuthService); + + private readonly templateRef: TemplateRef = inject(TemplateRef); + + private readonly viewContainer: ViewContainerRef = inject(ViewContainerRef); + + private hasView: boolean = false; + + constructor() { + effect(() => { + const isSignedOut: boolean = !this.authService.isSignedIn() && !this.authService.isLoading(); + if (isSignedOut && !this.hasView) { + this.viewContainer.createEmbeddedView(this.templateRef); + this.hasView = true; + } else if (!isSignedOut && this.hasView) { + this.viewContainer.clear(); + this.hasView = false; + } + }); + } +} diff --git a/packages/angular/src/guards/asgardeo.guard.ts b/packages/angular/src/guards/asgardeo.guard.ts new file mode 100644 index 000000000..b2a0cd59d --- /dev/null +++ b/packages/angular/src/guards/asgardeo.guard.ts @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {inject} from '@angular/core'; +import {ActivatedRouteSnapshot, CanActivateFn, Router, RouterStateSnapshot, UrlTree} from '@angular/router'; +import {AsgardeoAuthService} from '../services/asgardeo-auth.service'; + +/** + * Functional route guard that protects routes requiring authentication. + * + * If the user is signed in, the route is activated. If not, the guard either: + * - Triggers the signIn() flow (redirect to Asgardeo), or + * - Redirects to a configured `signInUrl` from route data. + * + * @example + * ```typescript + * const routes: Routes = [ + * { + * path: 'dashboard', + * component: DashboardComponent, + * canActivate: [asgardeoGuard], + * }, + * { + * path: 'admin', + * component: AdminComponent, + * canActivate: [asgardeoGuard], + * data: { signInUrl: '/login' }, + * }, + * ]; + * ``` + */ +export const asgardeoGuard: CanActivateFn = async ( + route: ActivatedRouteSnapshot, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _state: RouterStateSnapshot, +): Promise => { + const authService: AsgardeoAuthService = inject(AsgardeoAuthService); + const router: Router = inject(Router); + + // Wait for initialization to complete if still loading + if (authService.isLoading()) { + await new Promise((resolve: () => void) => { + const check: ReturnType = setInterval(() => { + if (!authService.isLoading()) { + clearInterval(check); + resolve(); + } + }, 50); + }); + } + + if (authService.isSignedIn()) { + return true; + } + + // Check if a custom sign-in URL is provided via route data + const signInUrl: string | undefined = route.data?.['signInUrl'] as string | undefined; + + if (signInUrl) { + return router.createUrlTree([signInUrl]); + } + + // Trigger the redirect-based sign-in flow + await authService.signIn(); + return false; +}; diff --git a/packages/angular/src/index.ts b/packages/angular/src/index.ts new file mode 100644 index 000000000..5b9799060 --- /dev/null +++ b/packages/angular/src/index.ts @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// --- Config --- +export type {AsgardeoAngularConfig} from './models/config'; + +// --- Providers --- +export {provideAsgardeo} from './providers/provide-asgardeo'; +export {AsgardeoModule} from './providers/asgardeo.module'; +export {ASGARDEO_CONFIG} from './providers/asgardeo-config.token'; + +// --- Services --- +export {AsgardeoAuthService} from './services/asgardeo-auth.service'; +export {AsgardeoUserService} from './services/asgardeo-user.service'; +export {AsgardeoOrganizationService} from './services/asgardeo-organization.service'; + +// --- Guard --- +export {asgardeoGuard} from './guards/asgardeo.guard'; + +// --- Interceptor --- +export {asgardeoInterceptor} from './interceptors/asgardeo.interceptor'; + +// --- Directives --- +export {AsgardeoSignedInDirective} from './directives/signed-in.directive'; +export {AsgardeoSignedOutDirective} from './directives/signed-out.directive'; +export {AsgardeoLoadingDirective} from './directives/loading.directive'; + +// --- Components --- +export {AsgardeoCallbackComponent} from './components/callback/callback.component'; +export {AsgardeoUserProfileComponent} from './components/user-profile/user-profile.component'; +export {AsgardeoOrganizationListComponent} from './components/organization-list/organization-list.component'; +export {AsgardeoCreateOrganizationComponent} from './components/create-organization/create-organization.component'; +export {AsgardeoOrganizationProfileComponent} from './components/organization-profile/organization-profile.component'; +export {AsgardeoOrganizationSwitcherComponent} from './components/organization-switcher/organization-switcher.component'; + +// --- API --- +export {default as getAllOrganizations, GetAllOrganizationsConfig} from './api/getAllOrganizations'; +export {default as createOrganization, CreateOrganizationConfig} from './api/createOrganization'; +export {default as getMeOrganizations, GetMeOrganizationsConfig} from './api/getMeOrganizations'; +export {default as getOrganization, GetOrganizationConfig} from './api/getOrganization'; +export {default as updateOrganization, createPatchOperations, UpdateOrganizationConfig} from './api/updateOrganization'; +export {default as getSchemas, GetSchemasConfig} from './api/getSchemas'; +export {default as updateMeProfile, UpdateMeProfileConfig} from './api/updateMeProfile'; +export {default as getMeProfile} from './api/getScim2Me'; +export * from './api/getScim2Me'; + +// --- Re-exports from @asgardeo/browser --- +export { + AsgardeoRuntimeError, + http, + navigate, + type User, + type UserProfile, + type Organization, + type OrganizationDetails, + type IdToken, + type TokenResponse, + type HttpRequestConfig, + type HttpResponse, + type AllOrganizationsApiResponse, + type TokenExchangeRequestConfig, + type SignInOptions, + type SignOutOptions, + type SignUpOptions, + type Config, + Platform, +} from '@asgardeo/browser'; diff --git a/packages/angular/src/interceptors/asgardeo.interceptor.ts b/packages/angular/src/interceptors/asgardeo.interceptor.ts new file mode 100644 index 000000000..f428d7f3d --- /dev/null +++ b/packages/angular/src/interceptors/asgardeo.interceptor.ts @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {HttpInterceptorFn, HttpHandlerFn, HttpRequest} from '@angular/common/http'; +import {inject} from '@angular/core'; +import {from, switchMap} from 'rxjs'; +import {AsgardeoAuthService} from '../services/asgardeo-auth.service'; + +/** + * Checks whether the request URL belongs to the same origin as the configured base URL. + * Only attaches tokens to requests targeting the Asgardeo/IS server to prevent leaking + * credentials to third-party APIs. + */ +function isAllowedUrl(requestUrl: string, baseUrl: string): boolean { + if (!baseUrl) { + return false; + } + + try { + const reqOrigin: string = new URL(requestUrl).origin; + const baseOrigin: string = new URL(baseUrl).origin; + return reqOrigin === baseOrigin; + } catch { + return false; + } +} + +/** + * Functional HTTP interceptor that automatically attaches the access token + * to outgoing HTTP requests as a Bearer token in the Authorization header. + * + * Skips token attachment if: + * - The request already has an Authorization header + * - The user is not signed in + * - The request URL does not match the configured base URL origin + * + * @example + * ```typescript + * // app.config.ts + * import { provideHttpClient, withInterceptors } from '@angular/common/http'; + * import { asgardeoInterceptor } from '@asgardeo/angular'; + * + * export const appConfig = { + * providers: [ + * provideHttpClient(withInterceptors([asgardeoInterceptor])), + * provideAsgardeo({ ... }), + * ], + * }; + * ``` + */ +export const asgardeoInterceptor: HttpInterceptorFn = (req: HttpRequest, next: HttpHandlerFn) => { + const authService: AsgardeoAuthService = inject(AsgardeoAuthService); + + // Skip if the request already has an Authorization header + if (req.headers.has('Authorization')) { + return next(req); + } + + // Skip token attachment if the user is not signed in + if (!authService.isSignedIn()) { + return next(req); + } + + // Only attach token to requests targeting the configured base URL origin + const baseUrl: string = authService.getBaseUrl(); + if (!isAllowedUrl(req.url, baseUrl)) { + return next(req); + } + + return from(authService.getAccessToken()).pipe( + switchMap((token: string) => { + if (token) { + const authReq: HttpRequest = req.clone({ + setHeaders: { + Authorization: `Bearer ${token}`, + }, + }); + return next(authReq); + } + return next(req); + }), + ); +}; diff --git a/packages/angular/src/models/config.ts b/packages/angular/src/models/config.ts new file mode 100644 index 000000000..3c0c89807 --- /dev/null +++ b/packages/angular/src/models/config.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {AsgardeoBrowserConfig} from '@asgardeo/browser'; + +export type AsgardeoAngularConfig = AsgardeoBrowserConfig; diff --git a/packages/angular/src/providers/asgardeo-config.token.ts b/packages/angular/src/providers/asgardeo-config.token.ts new file mode 100644 index 000000000..764bf66f1 --- /dev/null +++ b/packages/angular/src/providers/asgardeo-config.token.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {InjectionToken} from '@angular/core'; +import {AsgardeoAngularConfig} from '../models/config'; + +/** + * Injection token for providing the Asgardeo configuration to Angular services. + */ +export const ASGARDEO_CONFIG: InjectionToken = new InjectionToken( + 'AsgardeoAngularConfig', +); diff --git a/packages/angular/src/providers/asgardeo.module.ts b/packages/angular/src/providers/asgardeo.module.ts new file mode 100644 index 000000000..795e5efcb --- /dev/null +++ b/packages/angular/src/providers/asgardeo.module.ts @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {NgModule, ModuleWithProviders, APP_INITIALIZER} from '@angular/core'; +import {ASGARDEO_CONFIG} from './asgardeo-config.token'; +import {AsgardeoCallbackComponent} from '../components/callback/callback.component'; +import {AsgardeoCreateOrganizationComponent} from '../components/create-organization/create-organization.component'; +import {AsgardeoOrganizationListComponent} from '../components/organization-list/organization-list.component'; +import {AsgardeoOrganizationProfileComponent} from '../components/organization-profile/organization-profile.component'; +import {AsgardeoOrganizationSwitcherComponent} from '../components/organization-switcher/organization-switcher.component'; +import {AsgardeoUserProfileComponent} from '../components/user-profile/user-profile.component'; +import {AsgardeoLoadingDirective} from '../directives/loading.directive'; +import {AsgardeoSignedInDirective} from '../directives/signed-in.directive'; +import {AsgardeoSignedOutDirective} from '../directives/signed-out.directive'; +import {AsgardeoAngularConfig} from '../models/config'; +import {AsgardeoAuthService} from '../services/asgardeo-auth.service'; +import {AsgardeoOrganizationService} from '../services/asgardeo-organization.service'; +import {AsgardeoUserService} from '../services/asgardeo-user.service'; + +/** + * NgModule for Asgardeo authentication in module-based Angular applications. + * Use `AsgardeoModule.forRoot(config)` in your root module. + * + * For standalone Angular 17+ apps, prefer `provideAsgardeo()` instead. + * + * @example + * ```typescript + * @NgModule({ + * imports: [ + * AsgardeoModule.forRoot({ + * baseUrl: 'https://api.asgardeo.io/t/myorg', + * clientId: 'my-client-id', + * afterSignInUrl: window.location.origin, + * }), + * ], + * }) + * export class AppModule {} + * ``` + */ +@NgModule({ + exports: [ + AsgardeoSignedInDirective, + AsgardeoSignedOutDirective, + AsgardeoLoadingDirective, + AsgardeoCallbackComponent, + AsgardeoUserProfileComponent, + AsgardeoOrganizationListComponent, + AsgardeoCreateOrganizationComponent, + AsgardeoOrganizationProfileComponent, + AsgardeoOrganizationSwitcherComponent, + ], + imports: [ + AsgardeoSignedInDirective, + AsgardeoSignedOutDirective, + AsgardeoLoadingDirective, + AsgardeoCallbackComponent, + AsgardeoUserProfileComponent, + AsgardeoOrganizationListComponent, + AsgardeoCreateOrganizationComponent, + AsgardeoOrganizationProfileComponent, + AsgardeoOrganizationSwitcherComponent, + ], +}) +export class AsgardeoModule { + static forRoot(config: AsgardeoAngularConfig): ModuleWithProviders { + return { + ngModule: AsgardeoModule, + providers: [ + {provide: ASGARDEO_CONFIG, useValue: config}, + AsgardeoAuthService, + AsgardeoUserService, + AsgardeoOrganizationService, + { + deps: [AsgardeoAuthService], + multi: true, + provide: APP_INITIALIZER, + useFactory: (authService: AsgardeoAuthService) => () => authService.initialize(), + }, + ], + }; + } +} diff --git a/packages/angular/src/providers/provide-asgardeo.ts b/packages/angular/src/providers/provide-asgardeo.ts new file mode 100644 index 000000000..ed9db0eb1 --- /dev/null +++ b/packages/angular/src/providers/provide-asgardeo.ts @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {EnvironmentProviders, makeEnvironmentProviders, APP_INITIALIZER} from '@angular/core'; +import {ASGARDEO_CONFIG} from './asgardeo-config.token'; +import {AsgardeoAngularConfig} from '../models/config'; +import {AsgardeoAuthService} from '../services/asgardeo-auth.service'; +import {AsgardeoOrganizationService} from '../services/asgardeo-organization.service'; +import {AsgardeoUserService} from '../services/asgardeo-user.service'; + +/** + * Provides Asgardeo authentication services for standalone Angular applications (Angular 17+). + * + * @param config - The Asgardeo configuration object. + * @returns EnvironmentProviders to be used in the app's providers array. + * + * @example + * ```typescript + * // app.config.ts + * import { provideAsgardeo } from '@asgardeo/angular'; + * + * export const appConfig = { + * providers: [ + * provideAsgardeo({ + * baseUrl: 'https://api.asgardeo.io/t/myorg', + * clientId: 'my-client-id', + * afterSignInUrl: window.location.origin, + * afterSignOutUrl: window.location.origin, + * scopes: ['openid', 'profile', 'email'], + * }), + * ], + * }; + * ``` + */ +export function provideAsgardeo(config: AsgardeoAngularConfig): EnvironmentProviders { + return makeEnvironmentProviders([ + {provide: ASGARDEO_CONFIG, useValue: config}, + AsgardeoAuthService, + AsgardeoUserService, + AsgardeoOrganizationService, + { + deps: [AsgardeoAuthService], + multi: true, + provide: APP_INITIALIZER, + useFactory: (authService: AsgardeoAuthService) => () => authService.initialize(), + }, + ]); +} diff --git a/packages/angular/src/services/asgardeo-auth.service.ts b/packages/angular/src/services/asgardeo-auth.service.ts new file mode 100644 index 000000000..75b4d6382 --- /dev/null +++ b/packages/angular/src/services/asgardeo-auth.service.ts @@ -0,0 +1,537 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {Injectable, Injector, inject, signal, computed, OnDestroy, Signal, WritableSignal} from '@angular/core'; +import {toObservable} from '@angular/core/rxjs-interop'; +import { + AsgardeoRuntimeError, + AsgardeoSPAClient, + User, + UserProfile, + Organization, + IdToken, + TokenResponse, + SignInOptions, + SignOutOptions, + HttpRequestConfig, + HttpResponse, + TokenExchangeRequestConfig, + Hooks, + hasAuthParamsInUrl, + hasCalledForThisInstanceInUrl, + Platform, + extractUserClaimsFromIdToken, + generateFlattenedUserProfile, +} from '@asgardeo/browser'; +import {Observable} from 'rxjs'; +import AsgardeoAngularClient from '../AsgardeoAngularClient'; +import {AsgardeoAngularConfig} from '../models/config'; +import {ASGARDEO_CONFIG} from '../providers/asgardeo-config.token'; + +/** + * Core authentication service for Asgardeo Angular SDK. + * + * This service manages the authentication lifecycle and provides reactive state + * via Angular Signals (primary) with RxJS Observable accessors derived via `toObservable()`. + * + * It is the Angular equivalent of React's `AsgardeoProvider` + `useAsgardeo()` hook. + */ +@Injectable() +export class AsgardeoAuthService implements OnDestroy { + // --- Angular Signals (primary reactive state) --- + private readonly _isLoading: WritableSignal = signal(true); + + private readonly _isSignedIn: WritableSignal = signal(false); + + private readonly _isInitialized: WritableSignal = signal(false); + + private readonly _user: WritableSignal = signal(null); + + private readonly _currentOrganization: WritableSignal = signal(null); + + private readonly _userProfile: WritableSignal = signal(null); + + private readonly _myOrganizations: WritableSignal = signal([]); + + private readonly _baseUrl: WritableSignal = signal(''); + + // --- Read-only public signals --- + readonly isLoading: Signal = this._isLoading.asReadonly(); + + readonly isSignedIn: Signal = this._isSignedIn.asReadonly(); + + readonly isInitialized: Signal = this._isInitialized.asReadonly(); + + readonly user: Signal = this._user.asReadonly(); + + readonly currentOrganization: Signal = this._currentOrganization.asReadonly(); + + readonly userProfile: Signal = this._userProfile.asReadonly(); + + readonly myOrganizations: Signal = this._myOrganizations.asReadonly(); + + // --- Computed signals --- + readonly flattenedProfile: Signal = computed(() => this._userProfile()?.flattenedProfile ?? null); + + readonly profile: Signal = computed(() => this._userProfile()?.profile ?? null); + + // --- RxJS Observables (lazily derived from signals via toObservable) --- + // These are lazy because toObservable() requires ChangeDetectionScheduler, + // which is not available during APP_INITIALIZER when this service is constructed. + private _isLoading$: Observable | null = null; + + private _isSignedIn$: Observable | null = null; + + private _isInitialized$: Observable | null = null; + + private _user$: Observable | null = null; + + get isLoading$(): Observable { + if (!this._isLoading$) this._isLoading$ = toObservable(this.isLoading, {injector: this.injector}); + return this._isLoading$; + } + + get isSignedIn$(): Observable { + if (!this._isSignedIn$) this._isSignedIn$ = toObservable(this.isSignedIn, {injector: this.injector}); + return this._isSignedIn$; + } + + get isInitialized$(): Observable { + if (!this._isInitialized$) this._isInitialized$ = toObservable(this.isInitialized, {injector: this.injector}); + return this._isInitialized$; + } + + get user$(): Observable { + if (!this._user$) this._user$ = toObservable(this.user, {injector: this.injector}); + return this._user$; + } + + // --- Internal state --- + private readonly injector: Injector = inject(Injector); + + private config: AsgardeoAngularConfig = {...inject(ASGARDEO_CONFIG)}; + + private client: AsgardeoAngularClient = new AsgardeoAngularClient(this.config.instanceId ?? 0); + + private signInHookRegistered: boolean = false; + + private loadingCheckInterval: ReturnType | null = null; + + private isUpdatingSession: boolean = false; + + constructor() { + this._baseUrl.set(this.config.baseUrl || ''); + } + + /** + * Initialize the Asgardeo client. This is called automatically via APP_INITIALIZER. + * It mirrors the initialization logic from AsgardeoProvider's useEffect. + */ + async initialize(): Promise { + try { + await this.client.initialize(this.config); + const initializedConfig: AsgardeoAngularConfig = await this.client.getConfigurationAsync(); + this.config = initializedConfig; + + if (initializedConfig?.platform) { + sessionStorage.setItem('asgardeo_platform', initializedConfig.platform); + } + if (initializedConfig?.baseUrl) { + sessionStorage.setItem('asgardeo_base_url', initializedConfig.baseUrl); + this._baseUrl.set(initializedConfig.baseUrl); + } + + this.setInitializedState(true); + + // Check if user is already signed in + const isAlreadySignedIn: boolean = await this.client.isSignedIn(); + + if (isAlreadySignedIn) { + await this.updateSession(); + this.startSignInPolling(); + return; + } + + // Check for auth params in URL (OAuth callback handling) + const currentUrl: URL = new URL(window.location.href); + const afterSignInUrl: string = this.config.afterSignInUrl || window.location.origin; + const instanceId: number = this.config.instanceId ?? 0; + + const hasParams: boolean = + hasAuthParamsInUrl() && + new URL(currentUrl.origin + currentUrl.pathname).toString() === new URL(afterSignInUrl).toString(); + const isForThisInstance: boolean = hasCalledForThisInstanceInUrl(instanceId, currentUrl.search); + + if (hasParams && isForThisInstance) { + try { + this.isUpdatingSession = true; + this.setLoadingState(true); + + await this.client.signIn({callOnlyOnRedirect: true} as any); + + if (await this.client.isSignedIn()) { + await this.updateSession(); + } + } catch (error) { + throw new AsgardeoRuntimeError( + `Sign in failed: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`, + 'asgardeo-signIn-Error', + 'angular', + 'An error occurred while trying to sign in.', + ); + } finally { + this.isUpdatingSession = false; + this.setLoadingState(this.client.isLoading()); + } + } else { + this.setLoadingState(false); + } + + this.startSignInPolling(); + this.startLoadingStateTracking(); + } catch (error) { + this.setLoadingState(false); + throw error; + } + } + + // --- Auth Methods --- + + async signIn(options?: SignInOptions): Promise { + try { + this.isUpdatingSession = true; + this.setLoadingState(true); + + const response: User = await this.client.signIn(options); + + if (await this.client.isSignedIn()) { + await this.updateSession(); + } + + return response; + } catch (error) { + throw new AsgardeoRuntimeError( + `Sign in failed: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`, + 'asgardeo-signIn-Error', + 'angular', + 'An error occurred while trying to sign in.', + ); + } finally { + this.isUpdatingSession = false; + this.setLoadingState(this.client.isLoading()); + } + } + + async signInSilently(options?: SignInOptions): Promise { + try { + this.isUpdatingSession = true; + this.setLoadingState(true); + const response: User | boolean = await this.client.signInSilently(options); + + if (await this.client.isSignedIn()) { + await this.updateSession(); + } + + return response; + } catch (error) { + throw new AsgardeoRuntimeError( + `Error while signing in silently: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`, + 'asgardeo-signInSilently-Error', + 'angular', + 'An error occurred while trying to sign in silently.', + ); + } finally { + this.isUpdatingSession = false; + this.setLoadingState(this.client.isLoading()); + } + } + + async signOut(options?: SignOutOptions): Promise { + return this.client.signOut(options); + } + + async signUp(): Promise { + return this.client.signUp(); + } + + async switchOrganization(organization: Organization): Promise { + try { + this.isUpdatingSession = true; + this.setLoadingState(true); + const response: TokenResponse | Response = await this.client.switchOrganization(organization); + + if (await this.client.isSignedIn()) { + await this.updateSession(); + } + + return response; + } catch (error) { + throw new AsgardeoRuntimeError( + `Failed to switch organization: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`, + 'asgardeo-switchOrganization-Error', + 'angular', + 'An error occurred while switching to the specified organization.', + ); + } finally { + this.isUpdatingSession = false; + this.setLoadingState(this.client.isLoading()); + } + } + + // --- Token Methods --- + + async getAccessToken(sessionId?: string): Promise { + return this.client.getAccessToken(sessionId); + } + + async getIdToken(): Promise { + return this.client.getIdToken(); + } + + async getDecodedIdToken(sessionId?: string): Promise { + return this.client.getDecodedIdToken(sessionId); + } + + async exchangeToken(config: TokenExchangeRequestConfig): Promise { + return this.client.exchangeToken(config); + } + + async decodeJwtToken(token: string): Promise { + return this.client.decodeJwtToken(token); + } + + // --- HTTP --- + + async request(requestConfig: HttpRequestConfig): Promise> { + return this.client.request(requestConfig); + } + + async requestAll(requestConfigs: HttpRequestConfig[]): Promise[]> { + return this.client.requestAll(requestConfigs); + } + + // --- Session --- + + clearSession(sessionId?: string): void { + this.client.clearSession(sessionId); + } + + async setSession(data: Record, sessionId?: string): Promise { + return this.client.setSession(data, sessionId); + } + + // --- Configuration --- + + getConfiguration(): AsgardeoAngularConfig { + return this.config; + } + + /** + * Returns the resolved base URL, including the `/o` suffix for organization logins. + */ + getBaseUrl(): string { + return this._baseUrl(); + } + + async reInitialize(config: Partial): Promise { + return this.client.reInitialize(config); + } + + // --- Session Refresh --- + + /** + * Re-fetches user, profile, and organization data from the server. + * Use this to refresh the cached session state without re-initializing the client. + */ + async refreshSession(): Promise { + return this.updateSession(); + } + + // --- State Mutations (for secondary services) --- + + /** + * Updates the cached user and user profile after a successful SCIM2 PATCH. + * + * @param updatedUser - The updated user object returned from the SCIM2 API. + */ + handleProfileUpdate(updatedUser: User): void { + this._user.set(updatedUser); + + const currentProfile: UserProfile | null = this._userProfile(); + this._userProfile.set({ + ...currentProfile, + flattenedProfile: generateFlattenedUserProfile(updatedUser, currentProfile?.schemas ?? []), + profile: updatedUser, + } as UserProfile); + } + + /** + * Updates the cached list of the user's organizations. + * + * @param organizations - The updated list of organizations. + */ + setMyOrganizations(organizations: Organization[]): void { + this._myOrganizations.set(organizations); + } + + // --- Internal: Expose client for secondary services --- + + /** @internal */ + getClient(): AsgardeoAngularClient { + return this.client; + } + + // --- Private Methods --- + + /** + * Fetches user, user profile, and organization data after sign-in. + * Mirrors AsgardeoProvider's updateSession() function. + */ + private async updateSession(): Promise { + try { + this.isUpdatingSession = true; + this.setLoadingState(true); + let resolvedBaseUrl: string = this._baseUrl(); + + const decodedToken: IdToken = await this.client.getDecodedIdToken(); + + // If there's a `user_org` claim, treat this as an organization login + if (decodedToken?.['user_org']) { + resolvedBaseUrl = `${(await this.client.getConfigurationAsync()).baseUrl}/o`; + this._baseUrl.set(resolvedBaseUrl); + } + + if (this.config.platform === Platform.AsgardeoV2) { + const claims: Record = extractUserClaimsFromIdToken(decodedToken); + this._user.set(claims as User); + this._userProfile.set({ + flattenedProfile: claims as User, + profile: claims as User, + schemas: [], + }); + } else { + try { + const fetchedUser: User = await this.client.getUser({baseUrl: resolvedBaseUrl}); + this._user.set(fetchedUser); + } catch { + // Silently handle user fetch failure + } + + try { + const fetchedUserProfile: UserProfile = await this.client.getUserProfile({baseUrl: resolvedBaseUrl}); + this._userProfile.set(fetchedUserProfile); + } catch { + // Silently handle profile fetch failure + } + + try { + const fetchedOrganization: Organization | null = await this.client.getCurrentOrganization(); + this._currentOrganization.set(fetchedOrganization); + } catch { + // Silently handle organization fetch failure + } + + try { + const fetchedMyOrganizations: Organization[] = await this.client.getMyOrganizations(); + this._myOrganizations.set(fetchedMyOrganizations); + } catch { + // Silently handle organizations list fetch failure + } + } + + // Update sign-in status BEFORE setting loading to false + const currentSignInStatus: boolean = await this.client.isSignedIn(); + this.setSignedInState(currentSignInStatus); + } catch { + // Silently handle session update failure + } finally { + this.isUpdatingSession = false; + this.setLoadingState(this.client.isLoading()); + } + } + + /** + * Registers a hook to be notified when sign-in completes, + * instead of polling with setInterval. + */ + private startSignInPolling(): void { + if (this.signInHookRegistered) { + return; + } + + this.client.isSignedIn().then((status: boolean) => { + this.setSignedInState(status); + + if (!status) { + this.signInHookRegistered = true; + AsgardeoSPAClient.getInstance(this.config.instanceId ?? 0).on(Hooks.SignIn, () => { + this.setSignedInState(true); + }); + } + }); + } + + /** + * Tracks loading state changes from the client. + * Caches the afterSignInUrl path to avoid repeated URL parsing on every tick. + */ + private startLoadingStateTracking(): void { + const afterSignInUrl: string = this.config.afterSignInUrl || window.location.origin; + let cachedAfterSignInPath: string; + try { + const parsed: URL = new URL(afterSignInUrl); + cachedAfterSignInPath = new URL(parsed.origin + parsed.pathname).toString(); + } catch { + cachedAfterSignInPath = afterSignInUrl; + } + + this.loadingCheckInterval = setInterval(() => { + if (this.isUpdatingSession) { + return; + } + + if (!this._isSignedIn() && hasAuthParamsInUrl()) { + const currentPathUrl: string = window.location.origin + window.location.pathname; + if (currentPathUrl === cachedAfterSignInPath) { + return; + } + } + + this.setLoadingState(this.client.isLoading()); + }, 100); + } + + private setLoadingState(value: boolean): void { + this._isLoading.set(value); + } + + private setSignedInState(value: boolean): void { + this._isSignedIn.set(value); + } + + private setInitializedState(value: boolean): void { + this._isInitialized.set(value); + } + + ngOnDestroy(): void { + if (this.loadingCheckInterval) { + clearInterval(this.loadingCheckInterval); + this.loadingCheckInterval = null; + } + } +} diff --git a/packages/angular/src/services/asgardeo-organization.service.ts b/packages/angular/src/services/asgardeo-organization.service.ts new file mode 100644 index 000000000..346f0f7ef --- /dev/null +++ b/packages/angular/src/services/asgardeo-organization.service.ts @@ -0,0 +1,151 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {Injectable, Signal, WritableSignal, inject, signal} from '@angular/core'; +import {Organization, AllOrganizationsApiResponse, TokenResponse, OrganizationDetails} from '@asgardeo/browser'; +import {AsgardeoAuthService} from './asgardeo-auth.service'; +import createOrganization, {CreateOrganizationConfig} from '../api/createOrganization'; +import getOrganizationApi from '../api/getOrganization'; +import updateOrganizationApi, {createPatchOperations} from '../api/updateOrganization'; + +/** + * Service for managing organizations. + * Angular equivalent of React's `OrganizationProvider` + `useOrganization()` hook. + */ +@Injectable() +export class AsgardeoOrganizationService { + private readonly _isLoading: WritableSignal = signal(false); + + private readonly _error: WritableSignal = signal(null); + + readonly isLoading: Signal = this._isLoading.asReadonly(); + + readonly error: Signal = this._error.asReadonly(); + + /** Delegates to AsgardeoAuthService signals. */ + readonly myOrganizations: Signal; + + readonly currentOrganization: Signal; + + private readonly authService: AsgardeoAuthService = inject(AsgardeoAuthService); + + constructor() { + this.myOrganizations = this.authService.myOrganizations; + this.currentOrganization = this.authService.currentOrganization; + } + + /** + * Fetches all organizations with pagination support. + */ + async getAllOrganizations(): Promise { + this._isLoading.set(true); + this._error.set(null); + + try { + return await this.authService.getClient().getAllOrganizations(); + } catch (error) { + this._error.set(error instanceof Error ? error : new Error('Failed to fetch organizations')); + throw error; + } finally { + this._isLoading.set(false); + } + } + + /** + * Switches to the specified organization. + */ + async switchOrganization(organization: Organization): Promise { + return this.authService.switchOrganization(organization); + } + + /** + * Re-fetches the user's organizations from the server and updates the cached state. + */ + async revalidateMyOrganizations(): Promise { + this._isLoading.set(true); + this._error.set(null); + + try { + const organizations: Organization[] = await this.authService.getClient().getMyOrganizations(); + this.authService.setMyOrganizations(organizations); + return organizations; + } catch (error) { + this._error.set(error instanceof Error ? error : new Error('Failed to fetch organizations')); + throw error; + } finally { + this._isLoading.set(false); + } + } + + /** + * Creates a new organization. + */ + async createOrganization(config: CreateOrganizationConfig): Promise { + this._isLoading.set(true); + this._error.set(null); + + try { + return await createOrganization(config); + } catch (error) { + this._error.set(error instanceof Error ? error : new Error('Failed to create organization')); + throw error; + } finally { + this._isLoading.set(false); + } + } + + /** + * Fetches detailed information for a specific organization. + */ + async getOrganization(organizationId: string): Promise { + this._isLoading.set(true); + this._error.set(null); + + try { + const baseUrl: string = this.authService.getBaseUrl(); + const instanceId: number = this.authService.getClient().getInstanceId(); + return await getOrganizationApi({baseUrl, instanceId, organizationId}); + } catch (error) { + this._error.set(error instanceof Error ? error : new Error('Failed to fetch organization')); + throw error; + } finally { + this._isLoading.set(false); + } + } + + /** + * Updates an organization using PATCH operations. + */ + async updateOrganization(organizationId: string, data: Record): Promise { + this._isLoading.set(true); + this._error.set(null); + + try { + const baseUrl: string = this.authService.getBaseUrl(); + const instanceId: number = this.authService.getClient().getInstanceId(); + const operations: Array<{operation: 'REPLACE' | 'REMOVE'; path: string; value?: any}> = + createPatchOperations(data); + return await updateOrganizationApi({baseUrl, instanceId, operations, organizationId}); + } catch (error) { + this._error.set(error instanceof Error ? error : new Error('Failed to update organization')); + throw error; + } finally { + this._isLoading.set(false); + } + } +} diff --git a/packages/angular/src/services/asgardeo-user.service.ts b/packages/angular/src/services/asgardeo-user.service.ts new file mode 100644 index 000000000..1167f9719 --- /dev/null +++ b/packages/angular/src/services/asgardeo-user.service.ts @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {Injectable, Signal, WritableSignal, computed, inject, signal} from '@angular/core'; +import {User, UserProfile} from '@asgardeo/browser'; +import {AsgardeoAuthService} from './asgardeo-auth.service'; +import updateMeProfile, {UpdateMeProfileConfig} from '../api/updateMeProfile'; + +/** + * Service for managing user profile data. + * Angular equivalent of React's `UserProvider` + `useUser()` hook. + */ +@Injectable() +export class AsgardeoUserService { + private readonly _isLoading: WritableSignal = signal(false); + + private readonly _error: WritableSignal = signal(null); + + readonly isLoading: Signal = this._isLoading.asReadonly(); + + readonly error: Signal = this._error.asReadonly(); + + /** The full user profile (profile, flattenedProfile, schemas). Delegates to AsgardeoAuthService. */ + readonly userProfile: Signal; + + readonly flattenedProfile: Signal; + + readonly profile: Signal; + + readonly schemas: Signal; + + private readonly authService: AsgardeoAuthService = inject(AsgardeoAuthService); + + constructor() { + this.userProfile = this.authService.userProfile; + this.flattenedProfile = this.authService.flattenedProfile; + this.profile = this.authService.profile; + this.schemas = computed(() => this.authService.userProfile()?.schemas ?? []); + } + + /** + * Refreshes the user profile by re-fetching from the server. + */ + async refreshUser(): Promise { + this._isLoading.set(true); + this._error.set(null); + + try { + await this.authService.refreshSession(); + } catch (error) { + this._error.set(error instanceof Error ? error : new Error('Failed to refresh user profile')); + } finally { + this._isLoading.set(false); + } + } + + /** + * Updates the user profile via the SCIM2 API and updates the cached state. + * + * @param config - The update configuration containing operations and baseUrl. + * @returns The updated user profile data. + */ + async updateUser(config: UpdateMeProfileConfig): Promise { + this._isLoading.set(true); + this._error.set(null); + + try { + const result: User = await updateMeProfile(config); + this.authService.handleProfileUpdate(result); + return result; + } catch (error) { + this._error.set(error instanceof Error ? error : new Error('Failed to update user profile')); + throw error; + } finally { + this._isLoading.set(false); + } + } +} diff --git a/packages/angular/src/utils/avatar.ts b/packages/angular/src/utils/avatar.ts new file mode 100644 index 000000000..0c39e3f96 --- /dev/null +++ b/packages/angular/src/utils/avatar.ts @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Generates a deterministic gradient background CSS value from a string (e.g. a name). + * Uses the same algorithm as the React SDK's Avatar component. + */ +export function generateGradient(inputString: string): string { + const hash: number = inputString.split('').reduce((acc: number, char: string) => { + const charCode: number = char.charCodeAt(0); + // eslint-disable-next-line no-bitwise + return ((acc << 5) - acc + charCode) & 0xffffffff; + }, 0); + const seed: number = Math.abs(hash); + const hue1: number = (seed + seed) % 360; + const hue2: number = (hue1 + 60 + (seed % 120)) % 360; + const saturation: number = 70 + (seed % 20); + const lightness1: number = 55 + (seed % 15); + const lightness2: number = 60 + ((seed + seed) % 15); + const angle: number = 45 + (seed % 91); + return `linear-gradient(${angle}deg, hsl(${hue1}, ${saturation}%, ${lightness1}%), hsl(${hue2}, ${saturation}%, ${lightness2}%))`; +} + +/** + * Extracts initials from a name string (up to 2 characters). + */ +export function getInitials(name: string): string { + return name + .split(' ') + .map((w: string) => w[0]) + .slice(0, 2) + .join('') + .toUpperCase(); +} diff --git a/packages/angular/src/utils/fetcher.ts b/packages/angular/src/utils/fetcher.ts new file mode 100644 index 000000000..8bad61adc --- /dev/null +++ b/packages/angular/src/utils/fetcher.ts @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {HttpResponse, AsgardeoSPAClient, HttpRequestConfig} from '@asgardeo/browser'; + +/** + * Creates a default fetcher function that bridges the Fetch API interface expected + * by `@asgardeo/browser` API functions with the Axios-based AsgardeoSPAClient HTTP layer. + * + * @param instanceId - The Asgardeo client instance ID (for multi-instance support). + * @returns A Fetch API-compatible function. + */ +export function createDefaultFetcher(instanceId: number): (url: string, config: RequestInit) => Promise { + return async (url: string, config: RequestInit): Promise => { + const client: AsgardeoSPAClient = AsgardeoSPAClient.getInstance(instanceId); + const response: HttpResponse = (await client.httpRequest({ + data: config.body ? JSON.parse(config.body as string) : undefined, + headers: config.headers as Record, + method: (config.method as string) || 'GET', + url, + } as HttpRequestConfig)) as HttpResponse; + + return { + json: () => Promise.resolve(response.data), + ok: response.status >= 200 && response.status < 300, + status: response.status, + statusText: response.statusText || '', + text: () => Promise.resolve(typeof response.data === 'string' ? response.data : JSON.stringify(response.data)), + } as Response; + }; +} diff --git a/packages/angular/tsconfig.eslint.json b/packages/angular/tsconfig.eslint.json new file mode 100644 index 000000000..d5eefbbbb --- /dev/null +++ b/packages/angular/tsconfig.eslint.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "include": ["**/.*.js", "**/.*.cjs", "**/.*.ts", "**/*.js", "**/*.cjs", "**/*.ts"] +} diff --git a/packages/angular/tsconfig.json b/packages/angular/tsconfig.json new file mode 100644 index 000000000..1fec4399e --- /dev/null +++ b/packages/angular/tsconfig.json @@ -0,0 +1,33 @@ +{ + "extends": "../../tsconfig.json", + "compileOnSave": false, + "compilerOptions": { + "declaration": false, + "esModuleInterop": true, + "importHelpers": true, + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "sourceMap": true, + "target": "ESNext", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "exclude": ["node_modules", "tmp", "dist"], + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/angular/tsconfig.lib.json b/packages/angular/tsconfig.lib.json new file mode 100644 index 000000000..639af85aa --- /dev/null +++ b/packages/angular/tsconfig.lib.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declaration": true, + "outDir": "dist", + "declarationDir": "dist", + "types": ["node"] + }, + "angularCompilerOptions": { + "compilationMode": "partial" + }, + "exclude": [ + "**/*.spec.ts", + "**/*.test.ts" + ], + "include": ["src/**/*.ts"] +} diff --git a/packages/angular/tsconfig.spec.json b/packages/angular/tsconfig.spec.json new file mode 100644 index 000000000..66ed73f27 --- /dev/null +++ b/packages/angular/tsconfig.spec.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "types": ["node"] + }, + "include": [ + "**/*.test.ts", + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/packages/angular/vitest.config.ts b/packages/angular/vitest.config.ts new file mode 100644 index 000000000..1b3ce2a34 --- /dev/null +++ b/packages/angular/vitest.config.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// eslint-disable-next-line import/no-extraneous-dependencies +import {defineConfig} from 'vitest/config'; + +export default defineConfig({ + test: { + environment: 'jsdom', + setupFiles: ['./src/__tests__/setup.ts'], + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dae95cfc2..2a2b188b2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,6 +46,8 @@ overrides: '@wso2/eslint-plugin>@typescript-eslint/type-utils': 6.21.0 '@wso2/eslint-plugin>@typescript-eslint/utils': 6.21.0 +packageExtensionsChecksum: sha256-EMtoZD9TYQcjWtR0A05GjB9G1mp66W1Smh7cSozHxjs= + importers: .: @@ -84,6 +86,67 @@ importers: specifier: ^7.21.0 version: 7.21.0 + packages/angular: + dependencies: + '@angular/common': + specifier: '>=18.0.0' + version: 21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2) + '@angular/core': + specifier: '>=18.0.0' + version: 21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1) + '@angular/router': + specifier: '>=18.0.0' + version: 21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1)))(rxjs@7.8.2) + '@asgardeo/browser': + specifier: workspace:* + version: link:../browser + '@asgardeo/i18n': + specifier: workspace:* + version: link:../i18n + rxjs: + specifier: '>=7.0.0' + version: 7.8.2 + tslib: + specifier: 2.8.1 + version: 2.8.1 + devDependencies: + '@angular/compiler': + specifier: 21.1.5 + version: 21.1.5 + '@angular/compiler-cli': + specifier: 21.1.5 + version: 21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3) + '@types/node': + specifier: 22.15.3 + version: 22.15.3 + '@wso2/eslint-plugin': + specifier: 'catalog:' + version: https://codeload.github.com/brionmario/wso2-ui-configs/tar.gz/d3041825a4f8f235c8f9fa36b55cf29d54e791c8#path:packages/eslint-plugin(eslint@8.57.0)(typescript@5.9.3) + '@wso2/prettier-config': + specifier: 'catalog:' + version: https://codeload.github.com/brionmario/wso2-ui-configs/tar.gz/d3041825a4f8f235c8f9fa36b55cf29d54e791c8#path:packages/prettier-config(prettier@2.6.2)(typescript@5.9.3) + eslint: + specifier: 8.57.0 + version: 8.57.0 + jsdom: + specifier: 26.1.0 + version: 26.1.0 + ng-packagr: + specifier: 21.1.0 + version: 21.1.0(@angular/compiler-cli@21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3))(tailwindcss@4.1.8)(tslib@2.8.1)(typescript@5.9.3) + prettier: + specifier: 2.6.2 + version: 2.6.2 + rimraf: + specifier: 6.1.0 + version: 6.1.0 + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: 3.1.3 + version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@26.1.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + packages/browser: dependencies: '@asgardeo/javascript': @@ -134,7 +197,7 @@ importers: version: 22.15.3 '@vitest/browser': specifier: 3.1.3 - version: 3.1.3(playwright@1.55.1)(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3) + version: 3.1.3(playwright@1.55.1)(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3) '@wso2/eslint-plugin': specifier: 'catalog:' version: https://codeload.github.com/brionmario/wso2-ui-configs/tar.gz/d3041825a4f8f235c8f9fa36b55cf29d54e791c8#path:packages/eslint-plugin(eslint@8.57.0)(typescript@5.7.2) @@ -170,7 +233,7 @@ importers: version: 5.7.2 vitest: specifier: 3.1.3 - version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) packages/express: dependencies: @@ -210,7 +273,7 @@ importers: version: 5.7.2 vitest: specifier: 3.1.3 - version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) packages/i18n: dependencies: @@ -244,7 +307,7 @@ importers: version: 5.7.2 vitest: specifier: 3.1.3 - version: 3.1.3(@types/node@22.15.30)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + version: 3.1.3(@types/node@22.15.30)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) packages/javascript: dependencies: @@ -281,7 +344,7 @@ importers: version: 5.7.2 vitest: specifier: 3.1.3 - version: 3.1.3(@types/node@22.15.30)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + version: 3.1.3(@types/node@22.15.30)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) packages/nextjs: dependencies: @@ -321,7 +384,7 @@ importers: version: 8.57.0 next: specifier: 15.5.12 - version: 15.5.12(@babel/core@7.27.1)(@playwright/test@1.58.2)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)(sass@1.92.1) + version: 15.5.12(@playwright/test@1.58.2)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)(sass@1.97.1) prettier: specifier: 2.6.2 version: 2.6.2 @@ -336,7 +399,7 @@ importers: version: 5.7.2 vitest: specifier: 3.1.3 - version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) packages/node: dependencies: @@ -394,7 +457,7 @@ importers: version: 5.7.2 vitest: specifier: 3.1.3 - version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) packages/react: dependencies: @@ -464,7 +527,7 @@ importers: version: 5.7.2 vitest: specifier: 3.1.3 - version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@26.1.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@26.1.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) packages/react-router: dependencies: @@ -513,7 +576,7 @@ importers: version: 5.7.2 vitest: specifier: 3.1.3 - version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) packages/tanstack-router: dependencies: @@ -565,7 +628,7 @@ importers: version: 5.7.2 vitest: specifier: 3.1.3 - version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + version: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) packages/vue: dependencies: @@ -577,7 +640,7 @@ importers: version: 0.1.3 '@vitejs/plugin-vue': specifier: 5.2.4 - version: 5.2.4(vite@7.1.12(@types/node@20.12.7)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vue@3.5.13(typescript@5.1.6)) + version: 5.2.4(vite@7.1.12(@types/node@20.12.7)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vue@3.5.13(typescript@5.1.6)) base64url: specifier: 3.0.1 version: 3.0.1 @@ -617,10 +680,10 @@ importers: version: 20.12.7 '@vitest/coverage-v8': specifier: 3.0.8 - version: 3.0.8(vitest@3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + version: 3.0.8(vitest@3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) '@vitest/web-worker': specifier: 3.0.8 - version: 3.0.8(vitest@3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + version: 3.0.8(vitest@3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) '@vue/eslint-config-prettier': specifier: 8.0.0 version: 8.0.0(eslint@8.57.0)(prettier@2.6.2) @@ -671,10 +734,10 @@ importers: version: 5.1.6 vite: specifier: 7.1.12 - version: 7.1.12(@types/node@20.12.7)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + version: 7.1.12(@types/node@20.12.7)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) vitest: specifier: 3.0.8 - version: 3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + version: 3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) vue-tsc: specifier: 2.2.2 version: 2.2.2(typescript@5.1.6) @@ -708,10 +771,10 @@ importers: version: 19.1.5(@types/react@19.1.5) '@vitejs/plugin-basic-ssl': specifier: 2.0.0 - version: 2.0.0(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + version: 2.0.0(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) '@vitejs/plugin-react': specifier: 4.4.1 - version: 4.4.1(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + version: 4.4.1(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) eslint: specifier: 9.25.0 version: 9.25.0(jiti@2.6.0) @@ -732,7 +795,68 @@ importers: version: 8.30.1(eslint@9.25.0(jiti@2.6.0))(typescript@5.8.3) vite: specifier: 6.4.1 - version: 6.4.1(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + version: 6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + + samples/teamspace-angular: + dependencies: + '@angular/common': + specifier: 21.1.5 + version: 21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1) + '@angular/core': + specifier: 21.1.5 + version: 21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1) + '@angular/forms': + specifier: 21.1.5 + version: 21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)))(rxjs@7.8.1) + '@angular/platform-browser': + specifier: 21.1.5 + version: 21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)) + '@angular/platform-browser-dynamic': + specifier: 21.1.5 + version: 21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/compiler@21.1.5)(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))) + '@angular/router': + specifier: 21.1.5 + version: 21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)))(rxjs@7.8.1) + '@asgardeo/angular': + specifier: workspace:* + version: link:../../packages/angular + rxjs: + specifier: 7.8.1 + version: 7.8.1 + tslib: + specifier: 2.8.1 + version: 2.8.1 + zone.js: + specifier: 0.16.1 + version: 0.16.1 + devDependencies: + '@analogjs/vite-plugin-angular': + specifier: 2.2.3 + version: 2.2.3(@angular/build@21.1.4(@angular/compiler-cli@21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3))(@angular/compiler@21.1.5)(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)))(@types/node@24.0.3)(chokidar@5.0.0)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(ng-packagr@21.1.0(@angular/compiler-cli@21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3))(tailwindcss@4.1.8)(tslib@2.8.1)(typescript@5.9.3))(postcss@8.5.6)(sass-embedded@1.92.1)(tailwindcss@4.1.8)(terser@5.39.2)(tslib@2.8.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.0))(typescript@5.9.3) + '@angular/build': + specifier: 21.1.4 + version: 21.1.4(@angular/compiler-cli@21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3))(@angular/compiler@21.1.5)(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)))(@types/node@24.0.3)(chokidar@5.0.0)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(ng-packagr@21.1.0(@angular/compiler-cli@21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3))(tailwindcss@4.1.8)(tslib@2.8.1)(typescript@5.9.3))(postcss@8.5.6)(sass-embedded@1.92.1)(tailwindcss@4.1.8)(terser@5.39.2)(tslib@2.8.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.0) + '@angular/compiler': + specifier: 21.1.5 + version: 21.1.5 + '@angular/compiler-cli': + specifier: 21.1.5 + version: 21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3) + '@tailwindcss/vite': + specifier: 4.1.8 + version: 4.1.8(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + '@vitejs/plugin-basic-ssl': + specifier: 2.0.0 + version: 2.0.0(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + tailwindcss: + specifier: 4.1.8 + version: 4.1.8 + typescript: + specifier: 5.9.3 + version: 5.9.3 + vite: + specifier: 6.4.1 + version: 6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) samples/teamspace-react: dependencies: @@ -784,7 +908,7 @@ importers: version: 9.25.0 '@tailwindcss/vite': specifier: 4.1.8 - version: 4.1.8(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + version: 4.1.8(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) '@types/react': specifier: 19.1.5 version: 19.1.5 @@ -793,10 +917,10 @@ importers: version: 19.1.5(@types/react@19.1.5) '@vitejs/plugin-basic-ssl': specifier: 2.0.0 - version: 2.0.0(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + version: 2.0.0(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) '@vitejs/plugin-react': specifier: 4.4.1 - version: 4.4.1(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + version: 4.4.1(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) autoprefixer: specifier: 10.4.16 version: 10.4.16(postcss@8.4.31) @@ -829,7 +953,7 @@ importers: version: 8.30.1(eslint@9.25.0(jiti@2.6.0))(typescript@5.8.3) vite: specifier: 6.4.1 - version: 6.4.1(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + version: 6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) packages: @@ -840,6 +964,151 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@analogjs/vite-plugin-angular@2.2.3': + resolution: {integrity: sha512-OqVfiJsaHdHMxzvK0heVvp8MenSXh+xib6/p+v3d44kJ3J7ooD4gRx/jKC350zkgRKwcZc3a0ybGUnG6LEF7mg==} + peerDependencies: + '@angular-devkit/build-angular': ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 + '@angular/build': ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 + typescript: '>=5.5' + peerDependenciesMeta: + '@angular-devkit/build-angular': + optional: true + '@angular/build': + optional: true + + '@angular-devkit/architect@0.2101.4': + resolution: {integrity: sha512-3yyebORk+ovtO+LfDjIGbGCZhCMDAsyn9vkCljARj3sSshS4blOQBar0g+V3kYAweLT5Gf+rTKbN5jneOkBAFQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + hasBin: true + + '@angular-devkit/core@21.1.4': + resolution: {integrity: sha512-ObPTI5gYCB1jGxTRhcqZ6oQVUBFVJ8GH4LksVuAiz0nFX7xxpzARWvlhq943EtnlovVlUd9I8fM3RQqjfGVVAQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + chokidar: ^5.0.0 + peerDependenciesMeta: + chokidar: + optional: true + + '@angular/build@21.1.4': + resolution: {integrity: sha512-7CAAQPWFMMqod40ox5MOVB/CnoBXFDehyQhs0hls6lu7bOy/M0EDy0v6bERkyNGRz1mihWWBiCV8XzEinrlq1A==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + '@angular/compiler': ^21.0.0 + '@angular/compiler-cli': ^21.0.0 + '@angular/core': ^21.0.0 + '@angular/localize': ^21.0.0 + '@angular/platform-browser': ^21.0.0 + '@angular/platform-server': ^21.0.0 + '@angular/service-worker': ^21.0.0 + '@angular/ssr': ^21.1.4 + karma: ^6.4.0 + less: ^4.2.0 + ng-packagr: ^21.0.0 + postcss: ^8.4.0 + tailwindcss: ^2.0.0 || ^3.0.0 || ^4.0.0 + tslib: ^2.3.0 + typescript: '>=5.9 <6.0' + vitest: ^4.0.8 + peerDependenciesMeta: + '@angular/core': + optional: true + '@angular/localize': + optional: true + '@angular/platform-browser': + optional: true + '@angular/platform-server': + optional: true + '@angular/service-worker': + optional: true + '@angular/ssr': + optional: true + karma: + optional: true + less: + optional: true + ng-packagr: + optional: true + postcss: + optional: true + tailwindcss: + optional: true + vitest: + optional: true + + '@angular/common@21.1.5': + resolution: {integrity: sha512-olO2F0b+H8YBfsuQFEwo9Hjf+B714xGcttDW37+4jnY2IRS2uYeMu2RGIpY7ps+0uZ017c4iK3CCgSPBgmbTcA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@angular/core': 21.1.5 + rxjs: ^6.5.3 || ^7.4.0 + + '@angular/compiler-cli@21.1.5': + resolution: {integrity: sha512-i2r2bQuWdjjFGTd2TA7FtCWNx5yJ3BMoyTGUC9lzSfmxWAfcH/NWR+6OdaEVwv6Zap3IXYYxs8S+REkx954EwA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@angular/compiler': 21.1.5 + typescript: '>=5.9 <6.0' + peerDependenciesMeta: + typescript: + optional: true + + '@angular/compiler@21.1.5': + resolution: {integrity: sha512-yRUdWlL+AWcTL4d7zD0jkNqsjvxXpWEihvOfD2gc65DO0+E80DsWIpHq9A8yWeLukbfLcmBGI2QbfW9+SXAlvg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@angular/core@21.1.5': + resolution: {integrity: sha512-m61YHiyE+SIvS8UXcFLjYCucv6ShJJCwz9xxEk7ysYW9wOtHdfIf9tgyOsucZDAvrvpSyQLRj5jGBCGm1VIvXA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@angular/compiler': 21.1.5 + rxjs: ^6.5.3 || ^7.4.0 + zone.js: ~0.15.0 || ~0.16.0 + peerDependenciesMeta: + '@angular/compiler': + optional: true + zone.js: + optional: true + + '@angular/forms@21.1.5': + resolution: {integrity: sha512-Z8Vcgz5KYlCobRxLjyGGUBv0mA4nusuiD36GqYRn3sR780TLDcPFVwTCwVEWLdwID64oiHXG+x9jjU/Z3HzR6A==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@angular/common': 21.1.5 + '@angular/core': 21.1.5 + '@angular/platform-browser': 21.1.5 + rxjs: ^6.5.3 || ^7.4.0 + + '@angular/platform-browser-dynamic@21.1.5': + resolution: {integrity: sha512-Pd8nPbJSIONnze1WS9wLBAtaFw4TYIH+ZGjKHS9G1E9l09tDWtHWyB7dY82Sc//Nc8iR4V7dcsbUmFjOJHThww==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@angular/common': 21.1.5 + '@angular/compiler': 21.1.5 + '@angular/core': 21.1.5 + '@angular/platform-browser': 21.1.5 + + '@angular/platform-browser@21.1.5': + resolution: {integrity: sha512-rAN0cu05Pg7HHe9JMRd3g5JyyVCeFW8QiB/jG6klUrOTF4QzyCbmwlm7MX0uTx3CWAZraWCGbdahUkLyYtuqFA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@angular/animations': 21.1.5 + '@angular/common': 21.1.5 + '@angular/core': 21.1.5 + peerDependenciesMeta: + '@angular/animations': + optional: true + + '@angular/router@21.1.5': + resolution: {integrity: sha512-OjFn6Nw51CU712CMbl2U9TxlCkzOmjMLYPAfnV4+RdG7o+/eOS2nV0oapJ88RNCw7Yl04PA1amc3ql3agDFd4A==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@angular/common': 21.1.5 + '@angular/core': 21.1.5 + '@angular/platform-browser': 21.1.5 + rxjs: ^6.5.3 || ^7.4.0 + '@asamuzakjp/css-color@3.2.0': resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} @@ -865,6 +1134,10 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + '@babel/compat-data@7.27.2': resolution: {integrity: sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==} engines: {node: '>=6.9.0'} @@ -873,6 +1146,10 @@ packages: resolution: {integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==} engines: {node: '>=6.9.0'} + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + engines: {node: '>=6.9.0'} + '@babel/eslint-parser@7.28.5': resolution: {integrity: sha512-fcdRcWahONYo+JRnJg1/AekOacGvKx12Gu0qXJXFi2WBqQA1i7+O5PaxRB7kxE/Op94dExnCiiar6T09pvdHpA==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} @@ -884,24 +1161,50 @@ packages: resolution: {integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==} engines: {node: '>=6.9.0'} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.27.2': resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.27.1': resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-transforms@7.27.1': resolution: {integrity: sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-plugin-utils@7.27.1': resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} engines: {node: '>=6.9.0'} + '@babel/helper-split-export-declaration@7.24.7': + resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} + engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} @@ -910,6 +1213,10 @@ packages: resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} @@ -918,11 +1225,20 @@ packages: resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==} engines: {node: '>=6.9.0'} + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + engines: {node: '>=6.9.0'} + '@babel/parser@7.27.2': resolution: {integrity: sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==} engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-transform-react-jsx-self@7.27.1': resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} engines: {node: '>=6.9.0'} @@ -943,14 +1259,26 @@ packages: resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + '@babel/traverse@7.27.1': resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + '@babel/types@7.27.1': resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@1.0.2': resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} @@ -1077,6 +1405,9 @@ packages: '@emnapi/core@1.4.3': resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==} + '@emnapi/core@1.8.1': + resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} + '@emnapi/runtime@1.4.3': resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} @@ -1086,6 +1417,9 @@ packages: '@emnapi/wasi-threads@1.0.2': resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==} + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@emotion/babel-plugin@11.13.5': resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} @@ -1122,6 +1456,12 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.27.2': + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.27.3': resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} engines: {node: '>=18'} @@ -1134,6 +1474,12 @@ packages: cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.27.2': + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.27.3': resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} engines: {node: '>=18'} @@ -1146,6 +1492,12 @@ packages: cpu: [arm] os: [android] + '@esbuild/android-arm@0.27.2': + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.27.3': resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} engines: {node: '>=18'} @@ -1158,6 +1510,12 @@ packages: cpu: [x64] os: [android] + '@esbuild/android-x64@0.27.2': + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.27.3': resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} engines: {node: '>=18'} @@ -1170,6 +1528,12 @@ packages: cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.27.2': + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.27.3': resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} engines: {node: '>=18'} @@ -1182,6 +1546,12 @@ packages: cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.27.2': + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.27.3': resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} engines: {node: '>=18'} @@ -1194,6 +1564,12 @@ packages: cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.27.2': + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.27.3': resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} engines: {node: '>=18'} @@ -1206,6 +1582,12 @@ packages: cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.27.2': + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.27.3': resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} engines: {node: '>=18'} @@ -1218,6 +1600,12 @@ packages: cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.27.2': + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.27.3': resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} engines: {node: '>=18'} @@ -1230,6 +1618,12 @@ packages: cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.27.2': + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.27.3': resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} engines: {node: '>=18'} @@ -1242,6 +1636,12 @@ packages: cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.27.2': + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.27.3': resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} engines: {node: '>=18'} @@ -1254,6 +1654,12 @@ packages: cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.27.2': + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.27.3': resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} engines: {node: '>=18'} @@ -1266,6 +1672,12 @@ packages: cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.27.2': + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.27.3': resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} engines: {node: '>=18'} @@ -1278,6 +1690,12 @@ packages: cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.27.2': + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.27.3': resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} engines: {node: '>=18'} @@ -1290,6 +1708,12 @@ packages: cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.27.2': + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.27.3': resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} engines: {node: '>=18'} @@ -1302,6 +1726,12 @@ packages: cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.27.2': + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.27.3': resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} engines: {node: '>=18'} @@ -1314,6 +1744,12 @@ packages: cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.27.2': + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.27.3': resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} engines: {node: '>=18'} @@ -1326,6 +1762,12 @@ packages: cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.27.2': + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-arm64@0.27.3': resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} engines: {node: '>=18'} @@ -1338,6 +1780,12 @@ packages: cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.27.2': + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.27.3': resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} engines: {node: '>=18'} @@ -1350,6 +1798,12 @@ packages: cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.27.2': + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-arm64@0.27.3': resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} engines: {node: '>=18'} @@ -1362,6 +1816,12 @@ packages: cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.27.2': + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.27.3': resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} engines: {node: '>=18'} @@ -1374,6 +1834,12 @@ packages: cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.27.2': + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/openharmony-arm64@0.27.3': resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} engines: {node: '>=18'} @@ -1386,6 +1852,12 @@ packages: cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.27.2': + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.27.3': resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} engines: {node: '>=18'} @@ -1398,6 +1870,12 @@ packages: cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.27.2': + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.27.3': resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} engines: {node: '>=18'} @@ -1410,6 +1888,12 @@ packages: cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.27.2': + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.27.3': resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} engines: {node: '>=18'} @@ -1422,6 +1906,12 @@ packages: cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.27.2': + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.27.3': resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} engines: {node: '>=18'} @@ -1690,8 +2180,12 @@ packages: cpu: [x64] os: [win32] - '@inquirer/external-editor@1.0.3': - resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} + '@inquirer/ansi@1.0.2': + resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} + engines: {node: '>=18'} + + '@inquirer/confirm@5.1.21': + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -1699,10 +2193,41 @@ packages: '@types/node': optional: true - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - + '@inquirer/core@10.3.2': + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/external-editor@1.0.3': + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/figures@1.0.15': + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} + engines: {node: '>=18'} + + '@inquirer/type@3.0.10': + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + '@isaacs/brace-expansion@5.0.1': resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==} engines: {node: 20 || >=22} @@ -1730,6 +2255,9 @@ packages: resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} engines: {node: '>=6.0.0'} + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -1756,6 +2284,41 @@ packages: '@jspm/core@2.1.0': resolution: {integrity: sha512-3sRl+pkyFY/kLmHl0cgHiFp2xEqErA8N3ECjMs7serSUBmoJ70lBa0PG5t0IM6WJgdZNyyI0R8YFfi5wM8+mzg==} + '@lmdb/lmdb-darwin-arm64@3.4.4': + resolution: {integrity: sha512-XaKL705gDWd6XVls3ATDj13ZdML/LqSIxwgnYpG8xTzH2ifArx8fMMDdvqGE/Emd+W6R90W2fveZcJ0AyS8Y0w==} + cpu: [arm64] + os: [darwin] + + '@lmdb/lmdb-darwin-x64@3.4.4': + resolution: {integrity: sha512-GPHGEVcwJlkD01GmIr7B4kvbIcUDS2+kBadVEd7lU4can1RZaZQLDDBJRrrNfS2Kavvl0VLI/cMv7UASAXGrww==} + cpu: [x64] + os: [darwin] + + '@lmdb/lmdb-linux-arm64@3.4.4': + resolution: {integrity: sha512-mALqr7DE42HsiwVTKpQWxacjHoJk+e9p00RWIJqTACh/hpucxp/0lK/XMh5XzWnU/TDCZLukq1+vNqnNumTP/Q==} + cpu: [arm64] + os: [linux] + + '@lmdb/lmdb-linux-arm@3.4.4': + resolution: {integrity: sha512-cmev5/dZr5ACKri9f6GU6lZCXTjMhV72xujlbOhFCgFXrt4W0TxGsmY8kA1BITvH60JBKE50cSxsiulybAbrrw==} + cpu: [arm] + os: [linux] + + '@lmdb/lmdb-linux-x64@3.4.4': + resolution: {integrity: sha512-QjLs8OcmCNcraAcLoZyFlo0atzBJniQLLwhtR+ymQqS5kLYpV5RqwriL87BW+ZiR9ZiGgZx3evrz5vnWPtJ1fQ==} + cpu: [x64] + os: [linux] + + '@lmdb/lmdb-win32-arm64@3.4.4': + resolution: {integrity: sha512-tr/pwHDlZ33forLGAr0tI04cRmP4SgF93yHbb+2zvZiDEyln5yMHhbKDySxY66aUOkhvBvTuHq9q/3YmTj6ZHQ==} + cpu: [arm64] + os: [win32] + + '@lmdb/lmdb-win32-x64@3.4.4': + resolution: {integrity: sha512-KRzfocJzB/mgoTCqnMawuLSKheHRVTqWfSmouIgYpFs6Hx4zvZSvsZKSCEb5gHmICy7qsx9l06jk3MFTtiFVAQ==} + cpu: [x64] + os: [win32] + '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} @@ -1768,9 +2331,155 @@ packages: '@microsoft/tsdoc@0.14.2': resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': + resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==} + cpu: [arm64] + os: [darwin] + + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3': + resolution: {integrity: sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==} + cpu: [x64] + os: [darwin] + + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3': + resolution: {integrity: sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==} + cpu: [arm64] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3': + resolution: {integrity: sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==} + cpu: [arm] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3': + resolution: {integrity: sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==} + cpu: [x64] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': + resolution: {integrity: sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==} + cpu: [x64] + os: [win32] + + '@napi-rs/nice-android-arm-eabi@1.1.1': + resolution: {integrity: sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [android] + + '@napi-rs/nice-android-arm64@1.1.1': + resolution: {integrity: sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@napi-rs/nice-darwin-arm64@1.1.1': + resolution: {integrity: sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@napi-rs/nice-darwin-x64@1.1.1': + resolution: {integrity: sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@napi-rs/nice-freebsd-x64@1.1.1': + resolution: {integrity: sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@napi-rs/nice-linux-arm-gnueabihf@1.1.1': + resolution: {integrity: sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@napi-rs/nice-linux-arm64-gnu@1.1.1': + resolution: {integrity: sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@napi-rs/nice-linux-arm64-musl@1.1.1': + resolution: {integrity: sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@napi-rs/nice-linux-ppc64-gnu@1.1.1': + resolution: {integrity: sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==} + engines: {node: '>= 10'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@napi-rs/nice-linux-riscv64-gnu@1.1.1': + resolution: {integrity: sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==} + engines: {node: '>= 10'} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@napi-rs/nice-linux-s390x-gnu@1.1.1': + resolution: {integrity: sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==} + engines: {node: '>= 10'} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@napi-rs/nice-linux-x64-gnu@1.1.1': + resolution: {integrity: sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@napi-rs/nice-linux-x64-musl@1.1.1': + resolution: {integrity: sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@napi-rs/nice-openharmony-arm64@1.1.1': + resolution: {integrity: sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [openharmony] + + '@napi-rs/nice-win32-arm64-msvc@1.1.1': + resolution: {integrity: sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@napi-rs/nice-win32-ia32-msvc@1.1.1': + resolution: {integrity: sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@napi-rs/nice-win32-x64-msvc@1.1.1': + resolution: {integrity: sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@napi-rs/nice@1.1.1': + resolution: {integrity: sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==} + engines: {node: '>= 10'} + '@napi-rs/wasm-runtime@0.2.4': resolution: {integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==} + '@napi-rs/wasm-runtime@1.1.1': + resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@next/env@15.5.12': resolution: {integrity: sha512-pUvdJN1on574wQHjaBfNGDt9Mz5utDSZFsIIQkMzPgNS8ZvT4H2mwOrOIClwsQOb6EGx5M76/CZr6G8i6pSpLg==} @@ -1911,6 +2620,9 @@ packages: '@one-ini/wasm@0.1.1': resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + '@oxc-project/types@0.106.0': + resolution: {integrity: sha512-QdsH3rZq480VnOHSHgPYOhjL8O8LBdcnSjM408BpPCCUc0JYYZPG9Gafl9i3OcGk/7137o+gweb4cCv3WAUykg==} + '@parcel/watcher-android-arm64@2.5.1': resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} engines: {node: '>= 10.0.0'} @@ -2059,6 +2771,90 @@ packages: '@types/react': optional: true + '@rolldown/binding-android-arm64@1.0.0-beta.58': + resolution: {integrity: sha512-mWj5eE4Qc8TbPdGGaaLvBb9XfDPvE1EmZkJQgiGKwchkWH4oAJcRAKMTw7ZHnb1L+t7Ah41sBkAecaIsuUgsug==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-beta.58': + resolution: {integrity: sha512-wFxUymI/5R8bH8qZFYDfAxAN9CyISEIYke+95oZPiv6EWo88aa5rskjVcCpKA532R+klFmdqjbbaD56GNmTF4Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-beta.58': + resolution: {integrity: sha512-ybp3MkPj23VDV9PhtRwdU5qrGhlViWRV5BjKwO6epaSlUD5lW0WyY+roN3ZAzbma/9RrMTgZ/a/gtQq8YXOcqw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-beta.58': + resolution: {integrity: sha512-Evxj3yh7FWvyklUYZa0qTVT9N2zX9TPDqGF056hl8hlCZ9/ndQ2xMv6uw9PD1VlLpukbsqL+/C6M0qwipL0QMg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.58': + resolution: {integrity: sha512-tYeXprDOrEgVHUbPXH6MPso4cM/c6RTkmJNICMQlYdki4hGMh92aj3yU6CKs+4X5gfG0yj5kVUw/L4M685SYag==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.58': + resolution: {integrity: sha512-N78vmZzP6zG967Ohr+MasCjmKtis0geZ1SOVmxrA0/bklTQSzH5kHEjW5Qn+i1taFno6GEre1E40v0wuWsNOQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.58': + resolution: {integrity: sha512-l+p4QVtG72C7wI2SIkNQw/KQtSjuYwS3rV6AKcWrRBF62ClsFUcif5vLaZIEbPrCXu5OFRXigXFJnxYsVVZqdQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.58': + resolution: {integrity: sha512-urzJX0HrXxIh0FfxwWRjfPCMeInU9qsImLQxHBgLp5ivji1EEUnOfux8KxPPnRQthJyneBrN2LeqUix9DYrNaQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.58': + resolution: {integrity: sha512-7ijfVK3GISnXIwq/1FZo+KyAUJjL3kWPJ7rViAL6MWeEBhEgRzJ0yEd9I8N9aut8Y8ab+EKFJyRNMWZuUBwQ0A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.58': + resolution: {integrity: sha512-/m7sKZCS+cUULbzyJTIlv8JbjNohxbpAOA6cM+lgWgqVzPee3U6jpwydrib328JFN/gF9A99IZEnuGYqEDJdww==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.58': + resolution: {integrity: sha512-6SZk7zMgv+y3wFFQ9qE5P9NnRHcRsptL1ypmudD26PDY+PvFCvfHRkJNfclWnvacVGxjowr7JOL3a9fd1wWhUw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.58': + resolution: {integrity: sha512-sFqfYPnBZ6xBhMkadB7UD0yjEDRvs7ipR3nCggblN+N4ODCXY6qhg/bKL39+W+dgQybL7ErD4EGERVbW9DAWvg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.58': + resolution: {integrity: sha512-AnFWJdAqB8+IDPcGrATYs67Kik/6tnndNJV2jGRmwlbeNiQQ8GhRJU8ETRlINfII0pqi9k4WWLnb00p1QCxw/Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-beta.58': + resolution: {integrity: sha512-qWhDs6yFGR5xDfdrwiSa3CWGIHxD597uGE/A9xGqytBjANvh4rLCTTkq7szhMV4+Ygh+PMS90KVJ8xWG/TkX4w==} + '@rollup/plugin-commonjs@25.0.7': resolution: {integrity: sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==} engines: {node: '>=14.0.0'} @@ -2086,6 +2882,15 @@ packages: rollup: optional: true + '@rollup/plugin-json@6.1.0': + resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/plugin-node-resolve@15.2.3': resolution: {integrity: sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==} engines: {node: '>=14.0.0'} @@ -2342,12 +3147,20 @@ packages: cpu: [x64] os: [win32] + '@rollup/wasm-node@4.58.0': + resolution: {integrity: sha512-G4YrvWabOgRPfRSYEM95ZZGESbzVGUS+uvO/gVPNs3P93z8lBLTDpRwoo6zeEg6AqK9AdIshWbvDGOehZOikMw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} @@ -2513,6 +3326,12 @@ packages: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} + '@ts-morph/common@0.22.0': + resolution: {integrity: sha512-HqNBuV/oIlMKdkLshXd1zKBqNQCsuPEsgQOkfFQ/eUKjRlwndXW1AjN9LVkBEIukm00gGXSRmfkl0Wv5VXLnlw==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} @@ -2739,6 +3558,12 @@ packages: peerDependencies: vite: ^6.0.0 + '@vitejs/plugin-basic-ssl@2.1.0': + resolution: {integrity: sha512-dOxxrhgyDIEUADhb/8OlV9JIqYLgos03YorAueTIeOUskLJSEsfwCByjbu98ctXitUN3znXKp0bYD/WHSudCeA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + peerDependencies: + vite: ^6.0.0 || ^7.0.0 + '@vitejs/plugin-react@4.4.1': resolution: {integrity: sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==} engines: {node: ^14.18.0 || >=16.0.0} @@ -2983,6 +3808,14 @@ packages: resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} engines: {node: '>= 14'} + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -2996,6 +3829,10 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} + engines: {node: '>=18'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -3133,6 +3970,15 @@ packages: resolution: {integrity: sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==} engines: {node: '>=6.0.0'} + baseline-browser-mapping@2.10.0: + resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} + engines: {node: '>=6.0.0'} + hasBin: true + + beasties@0.3.5: + resolution: {integrity: sha512-NaWu+f4YrJxEttJSm16AzMIFtVldCvaJ68b1L098KpqXmxt9xOLtKoLkKxb8ekhOrLqEJAbvT6n6SEvB/sac7A==} + engines: {node: '>=14.0.0'} + better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} @@ -3192,6 +4038,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + buffer-builder@0.2.0: resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} @@ -3249,6 +4100,9 @@ packages: caniuse-lite@1.0.30001718: resolution: {integrity: sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==} + caniuse-lite@1.0.30001770: + resolution: {integrity: sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==} + chai@5.2.0: resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} engines: {node: '>=12'} @@ -3257,6 +4111,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + chardet@2.1.1: resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} @@ -3272,6 +4130,10 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + chownr@3.0.0: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} @@ -3291,10 +4153,26 @@ packages: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + cli-spinners@2.6.1: resolution: {integrity: sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==} engines: {node: '>=6'} + cli-spinners@3.4.0: + resolution: {integrity: sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==} + engines: {node: '>=18.20'} + + cli-truncate@5.1.1: + resolution: {integrity: sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==} + engines: {node: '>=20'} + + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} @@ -3302,6 +4180,10 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + cliui@9.0.1: + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} + engines: {node: '>=20'} + clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} @@ -3310,6 +4192,9 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} + code-block-writer@12.0.0: + resolution: {integrity: sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -3320,6 +4205,9 @@ packages: colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + colorjs.io@0.5.2: resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} @@ -3331,6 +4219,10 @@ packages: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -3338,6 +4230,9 @@ packages: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} + common-path-prefix@3.0.0: + resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} + commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} @@ -3382,6 +4277,9 @@ packages: resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} engines: {node: '>=18'} + copy-anything@2.0.6: + resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} + core-js@3.42.0: resolution: {integrity: sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==} @@ -3437,6 +4335,9 @@ packages: css-select@4.3.0: resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} + css-select@6.0.0: + resolution: {integrity: sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==} + css-tree@1.1.3: resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} engines: {node: '>=8.0.0'} @@ -3453,6 +4354,10 @@ packages: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} + css-what@7.0.0: + resolution: {integrity: sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==} + engines: {node: '>= 6'} + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -3595,6 +4500,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + dependency-graph@1.0.0: + resolution: {integrity: sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==} + engines: {node: '>=4'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -3611,10 +4520,6 @@ packages: engines: {node: '>=0.10'} hasBin: true - detect-libc@2.0.4: - resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} - engines: {node: '>=8'} - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -3644,6 +4549,9 @@ packages: dom-serializer@1.4.1: resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dom-walk@0.1.2: resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==} @@ -3654,12 +4562,19 @@ packages: resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} engines: {node: '>= 4'} + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dompurify@3.2.7: resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + dotenv-expand@11.0.7: resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} engines: {node: '>=12'} @@ -3690,9 +4605,15 @@ packages: electron-to-chromium@1.5.155: resolution: {integrity: sha512-ps5KcGGmwL8VaeJlvlDlu4fORQpv3+GIcF5I3f9tUKUlJ/wsysh6HU8P5L1XWRYeXfA0oJd4PyM8ds8zTFf6Ng==} + electron-to-chromium@1.5.302: + resolution: {integrity: sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==} + elliptic@6.6.1: resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -3729,6 +4650,18 @@ packages: resolution: {integrity: sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==} engines: {node: '>=0.12'} + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + errno@0.1.8: + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} + hasBin: true + error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} @@ -3792,6 +4725,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.27.2: + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} + engines: {node: '>=18'} + hasBin: true + esbuild@0.27.3: resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} engines: {node: '>=18'} @@ -4086,6 +5024,9 @@ packages: eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + evp_bytestokey@1.0.3: resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} @@ -4169,9 +5110,17 @@ packages: resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} engines: {node: '>=8'} + find-cache-directory@6.0.0: + resolution: {integrity: sha512-CvFd5ivA6HcSHbD+59P7CyzINHXzwhuQK8RY7CxJZtgDSAtRlHiCaQpZQ2lMR/WRyUIEmzUvL6G2AGurMfegZA==} + engines: {node: '>=20'} + find-root@1.1.0: resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + find-up-simple@1.0.1: + resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} + engines: {node: '>=18'} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -4280,6 +5229,10 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.5.0: + resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} + engines: {node: '>=18'} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -4307,6 +5260,9 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me @@ -4453,6 +5409,9 @@ packages: resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} engines: {node: '>=8'} + htmlparser2@10.1.0: + resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} + http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} @@ -4494,6 +5453,11 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + image-size@0.5.5: + resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} + engines: {node: '>=0.10.0'} + hasBin: true + immutable@4.3.7: resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} @@ -4529,6 +5493,9 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + injection-js@2.6.1: + resolution: {integrity: sha512-dbR5bdhi7TWDoCye9cByZqeg/gAfamm8Vu3G1KZOTYkOif8WkuM8CD0oeDPtZYMzT5YH76JAFB7bkmyY9OJi2A==} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -4597,6 +5564,10 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-fullwidth-code-point@5.1.0: + resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} + engines: {node: '>=18'} + is-generator-function@1.1.2: resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} engines: {node: '>= 0.4'} @@ -4609,6 +5580,10 @@ packages: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} + is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} @@ -4681,6 +5656,10 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -4693,6 +5672,9 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} + is-what@3.14.1: + resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} + is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} @@ -4718,6 +5700,10 @@ packages: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + istanbul-lib-report@3.0.1: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} @@ -4837,6 +5823,9 @@ packages: jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -4864,6 +5853,11 @@ packages: resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} engines: {node: '>=0.10'} + less@4.5.1: + resolution: {integrity: sha512-UKgI3/KON4u6ngSsnDADsUERqhZknsVZbnuzlRZXLQCmfC/MDld42fTydUE9B+Mla1AL6SJ/Pp6SlEFi/AVGfw==} + engines: {node: '>=14'} + hasBin: true + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -4947,6 +5941,14 @@ packages: resolution: {integrity: sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + listr2@9.0.5: + resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} + engines: {node: '>=20.0.0'} + + lmdb@3.4.4: + resolution: {integrity: sha512-+Y2DqovevLkb6DrSQ6SXTYLEd6kvlRbhsxzgJrk7BUfOVA/mt21ak6pFDZDKxiAczHMWxrb02kXBTSTIA0O94A==} + hasBin: true + local-pkg@1.1.1: resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} engines: {node: '>=14'} @@ -4984,6 +5986,14 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + log-symbols@7.0.1: + resolution: {integrity: sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==} + engines: {node: '>=18'} + + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -4994,10 +6004,6 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.1.0: - resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} - engines: {node: 20 || >=22} - lru-cache@11.2.4: resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} engines: {node: 20 || >=22} @@ -5021,9 +6027,16 @@ packages: magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magicast@0.3.5: resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + make-dir@2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} + make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} @@ -5102,10 +6115,19 @@ packages: resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} engines: {node: '>= 0.6'} + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + min-document@2.19.1: resolution: {integrity: sha512-8lqe85PkqQJzIcs2iD7xW/WSxcncC3/DPVbTOafKNJDIMXwGfwXS350mH4SJslomntN2iYtFBuC0yNO3CEap6g==} @@ -5161,6 +6183,11 @@ packages: resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} engines: {node: '>= 18'} + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + mlly@1.7.4: resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} @@ -5175,9 +6202,20 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + msgpackr-extract@3.0.3: + resolution: {integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==} + hasBin: true + + msgpackr@1.11.8: + resolution: {integrity: sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA==} + muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + mute-stream@2.0.0: + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -5189,6 +6227,11 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + needle@3.3.1: + resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==} + engines: {node: '>= 4.4.x'} + hasBin: true + negotiator@1.0.0: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} @@ -5214,6 +6257,22 @@ packages: sass: optional: true + ng-packagr@21.1.0: + resolution: {integrity: sha512-UlQOhH8DRlaYsBGQMjOYvg70J70hD4i/55NV9vAsYvsxEskmp86xjUtZgEeVKeoLq8tYMjMXDgaYjYde153sZQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@angular/compiler-cli': ^21.0.0 || ^21.1.0-next + tailwindcss: ^2.0.0 || ^3.0.0 || ^4.0.0 + tslib: ^2.3.0 + typescript: '>=5.9 <6.0' + peerDependenciesMeta: + tailwindcss: + optional: true + + node-addon-api@6.1.0: + resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} + node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} @@ -5226,12 +6285,19 @@ packages: encoding: optional: true + node-gyp-build-optional-packages@5.2.2: + resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} + hasBin: true + node-machine-id@1.1.12: resolution: {integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==} node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + nopt@7.2.1: resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -5321,6 +6387,10 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} @@ -5333,6 +6403,13 @@ packages: resolution: {integrity: sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==} engines: {node: '>=10'} + ora@9.3.0: + resolution: {integrity: sha512-lBX72MWFduWEf7v7uWf5DHp9Jn5BI8bNPGuFgtXMmr2uDz2Gz2749y3am3agSDdkhHPHYmmxEGSKH85ZLGzgXw==} + engines: {node: '>=20'} + + ordered-binary@1.6.1: + resolution: {integrity: sha512-QkCdPooczexPLiXIrbVOPYkR3VO3T6v2OyKRkR1Xbhpy7/LAVXwahnRCgRp78Oe/Ehf0C/HATAxfSr6eA1oX+w==} + outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} @@ -5398,6 +6475,16 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-node-version@1.0.1: + resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} + engines: {node: '>= 0.10'} + + parse5-html-rewriting-stream@8.0.0: + resolution: {integrity: sha512-wzh11mj8KKkno1pZEu+l2EVeWsuKDfR5KNWZOTsslfUX8lPDZx77m9T0kIoAVkFtD1nx6YF8oh4BnPHvxMtNMw==} + + parse5-sax-parser@8.0.0: + resolution: {integrity: sha512-/dQ8UzHZwnrzs3EvDj6IkKrD/jIZyTlB+8XrHJvcjNgRdmWruNdN9i9RK/JtxakmlUdPwKubKPTCqvbTgzGhrw==} + parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} @@ -5464,10 +6551,22 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + piscina@5.1.4: + resolution: {integrity: sha512-7uU4ZnKeQq22t9AsmHGD2w4OYQGonwFnTypDypaWi7Qr2EvQIFVtG8J5D/3bE7W123Wdc9+v4CZDu5hJXVCtBg==} + engines: {node: '>=20.x'} + pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + pkg-dir@8.0.0: + resolution: {integrity: sha512-4peoBq4Wks0riS0z8741NVv+/8IiTvqnZAr8QGgtdifrtpdXbNw/FxRS1l6NFqm4EMzuS0EDqNNx4XGaz8cuyQ==} + engines: {node: '>=18'} + pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} @@ -5769,6 +6868,9 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + public-encrypt@4.0.3: resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} @@ -5867,10 +6969,17 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} + redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -5926,10 +7035,17 @@ packages: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported @@ -5947,6 +7063,11 @@ packages: resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} engines: {node: '>= 0.8'} + rolldown@1.0.0-beta.58: + resolution: {integrity: sha512-v1FCjMZCan7f+xGAHBi+mqiE4MlH7I+SXEHSQSJoMOGNNB2UYtvMiejsq9YuUOiZjNeUeV/a21nSFbrUR+4ZCQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rollup-plugin-dts@6.1.0: resolution: {integrity: sha512-ijSCPICkRMDKDLBK9torss07+8dl9UpY9z1N/zTeA1cIqdzMlpkV3MOOC7zukyvQfDyxa1s3Dl2+DeiP/G6DOw==} engines: {node: '>=16'} @@ -5954,6 +7075,13 @@ packages: rollup: ^3.29.4 || ^4 typescript: ^4.5 || ^5.0 + rollup-plugin-dts@6.3.0: + resolution: {integrity: sha512-d0UrqxYd8KyZ6i3M2Nx7WOMy708qsV/7fTHMHxCMCBOAe3V/U7OMPu5GkX8hC+cmkHhzGnfeYongl1IgiooddA==} + engines: {node: '>=16'} + peerDependencies: + rollup: ^3.29.4 || ^4 + typescript: ^4.5 || ^5.0 + rollup-plugin-polyfill-node@0.13.0: resolution: {integrity: sha512-FYEvpCaD5jGtyBuBFcQImEGmTxDTPbiHjJdrYIp+mFIwgXiXabxvKUK7ZT9P31ozu2Tqm9llYQMRWsfvTMTAOw==} peerDependencies: @@ -5985,6 +7113,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} @@ -6136,6 +7267,15 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + sass@1.97.1: + resolution: {integrity: sha512-uf6HoO8fy6ClsrShvMgaKUn14f2EHQLQRtpsZZLeU/Mv0Q1K5P0+x2uvH6Cub39TVVbWNSrraUhDAoFph6vh0A==} + engines: {node: '>=14.0.0'} + hasBin: true + + sax@1.4.4: + resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==} + engines: {node: '>=11.0.0'} + saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -6260,6 +7400,10 @@ packages: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} engines: {node: '>=10'} + slice-ansi@7.1.2: + resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} + engines: {node: '>=18'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -6275,6 +7419,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + spawndamnit@3.0.1: resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} @@ -6312,6 +7460,10 @@ packages: std-env@3.9.0: resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + stdin-discarder@0.3.1: + resolution: {integrity: sha512-reExS1kSGoElkextOcPkel4NE99S0BWxjUHQeDFnR8S993JxpPX7KU4MNmO19NXhlJp+8dmdCbKQVNgLJh2teA==} + engines: {node: '>=18'} + stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} @@ -6331,6 +7483,14 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string-width@8.2.0: + resolution: {integrity: sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==} + engines: {node: '>=20'} + string.prototype.includes@2.0.1: resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} engines: {node: '>= 0.4'} @@ -6539,10 +7699,6 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyglobby@0.2.14: - resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} - engines: {node: '>=12.0.0'} - tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} @@ -6628,6 +7784,9 @@ packages: peerDependencies: typescript: '>=4.8.4' + ts-morph@21.0.1: + resolution: {integrity: sha512-dbDtVdEAncKctzrVZ+Nr7kHpHkv+0JDJb2MjjpBaj8bFeCkePU9rHfMklmhuLFnpeq/EJZk2IhStY6NzqgjOkg==} + tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -6720,6 +7879,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + ufo@1.6.1: resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} @@ -6736,6 +7900,10 @@ packages: undici-types@7.8.0: resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} + undici@7.20.0: + resolution: {integrity: sha512-MJZrkjyd7DeC+uPZh+5/YaMDxFiiEEaDgbUSVMXayofAkDWF1088CDo+2RPg7B1BuS1qf1vgNE7xqwPxE0DuSQ==} + engines: {node: '>=20.18.1'} + undici@7.21.0: resolution: {integrity: sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==} engines: {node: '>=20.18.1'} @@ -6758,6 +7926,12 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -6876,6 +8050,46 @@ packages: yaml: optional: true + vite@7.3.0: + resolution: {integrity: sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + vitest@3.0.8: resolution: {integrity: sha512-dfqAsNqRGUc8hB9OVR2P0w8PZPEckti2+5rdZip0WIz9WW0MnImJ8XiR61QhqLa92EQzKP2uPkzenKOAHyEIbA==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -6968,9 +8182,16 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} + watchpack@2.5.0: + resolution: {integrity: sha512-e6vZvY6xboSwLz2GD36c16+O/2Z6fKvIf4pOXptw2rY9MVwE/TXc6RGqxD3I3x0a28lwBY7DE+76uTPSsBrrCA==} + engines: {node: '>=10.13.0'} + wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + weak-lru-cache@1.2.2: + resolution: {integrity: sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -7040,6 +8261,10 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -7048,6 +8273,10 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -7121,70 +8350,261 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yargs@18.0.0: + resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yoctocolors-cjs@2.1.3: + resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} + engines: {node: '>=18'} + + yoctocolors@2.1.2: + resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} + engines: {node: '>=18'} + + zone.js@0.16.1: + resolution: {integrity: sha512-dpvY17vxYIW3+bNrP0ClUlaiY0CiIRK3tnoLaGoQsQcY9/I/NpzIWQ7tQNhbV7LacQMpCII6wVzuL3tuWOyfuA==} + snapshots: '@acemir/cssom@0.9.31': {} '@ampproject/remapping@2.3.0': dependencies: - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 - '@asamuzakjp/css-color@3.2.0': + '@analogjs/vite-plugin-angular@2.2.3(@angular/build@21.1.4(@angular/compiler-cli@21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3))(@angular/compiler@21.1.5)(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)))(@types/node@24.0.3)(chokidar@5.0.0)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(ng-packagr@21.1.0(@angular/compiler-cli@21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3))(tailwindcss@4.1.8)(tslib@2.8.1)(typescript@5.9.3))(postcss@8.5.6)(sass-embedded@1.92.1)(tailwindcss@4.1.8)(terser@5.39.2)(tslib@2.8.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.0))(typescript@5.9.3)': dependencies: - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - lru-cache: 10.4.3 + ts-morph: 21.0.1 + typescript: 5.9.3 + optionalDependencies: + '@angular/build': 21.1.4(@angular/compiler-cli@21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3))(@angular/compiler@21.1.5)(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)))(@types/node@24.0.3)(chokidar@5.0.0)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(ng-packagr@21.1.0(@angular/compiler-cli@21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3))(tailwindcss@4.1.8)(tslib@2.8.1)(typescript@5.9.3))(postcss@8.5.6)(sass-embedded@1.92.1)(tailwindcss@4.1.8)(terser@5.39.2)(tslib@2.8.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.0) - '@asamuzakjp/css-color@4.1.1': + '@angular-devkit/architect@0.2101.4(chokidar@5.0.0)': dependencies: - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - lru-cache: 11.2.4 + '@angular-devkit/core': 21.1.4(chokidar@5.0.0) + rxjs: 7.8.2 + transitivePeerDependencies: + - chokidar - '@asamuzakjp/dom-selector@6.7.6': + '@angular-devkit/core@21.1.4(chokidar@5.0.0)': dependencies: - '@asamuzakjp/nwsapi': 2.3.9 - bidi-js: 1.0.3 - css-tree: 3.1.0 - is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.4 - - '@asamuzakjp/nwsapi@2.3.9': {} - - '@asgardeo/auth-js@5.1.2': {} + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + jsonc-parser: 3.3.1 + picomatch: 4.0.3 + rxjs: 7.8.2 + source-map: 0.7.6 + optionalDependencies: + chokidar: 5.0.0 - '@asgardeo/auth-spa@3.3.2': + '@angular/build@21.1.4(@angular/compiler-cli@21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3))(@angular/compiler@21.1.5)(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)))(@types/node@24.0.3)(chokidar@5.0.0)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(ng-packagr@21.1.0(@angular/compiler-cli@21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3))(tailwindcss@4.1.8)(tslib@2.8.1)(typescript@5.9.3))(postcss@8.5.6)(sass-embedded@1.92.1)(tailwindcss@4.1.8)(terser@5.39.2)(tslib@2.8.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.0)': dependencies: - '@asgardeo/auth-js': 5.1.2 - await-semaphore: 0.1.3 - axios: 1.13.5 - base64url: 3.0.1 - buffer: 6.0.3 - fast-sha256: 1.3.0 - jose: 4.15.9 - randombytes: 2.1.0 + '@ampproject/remapping': 2.3.0 + '@angular-devkit/architect': 0.2101.4(chokidar@5.0.0) + '@angular/compiler': 21.1.5 + '@angular/compiler-cli': 21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3) + '@babel/core': 7.28.5 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-split-export-declaration': 7.24.7 + '@inquirer/confirm': 5.1.21(@types/node@24.0.3) + '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.3.0(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + beasties: 0.3.5 + browserslist: 4.28.1 + esbuild: 0.27.2 + https-proxy-agent: 7.0.6 + istanbul-lib-instrument: 6.0.3 + jsonc-parser: 3.3.1 + listr2: 9.0.5 + magic-string: 0.30.21 + mrmime: 2.0.1 + parse5-html-rewriting-stream: 8.0.0 + picomatch: 4.0.3 + piscina: 5.1.4 + rolldown: 1.0.0-beta.58 + sass: 1.97.1 + semver: 7.7.3 + source-map-support: 0.5.21 + tinyglobby: 0.2.15 + tslib: 2.8.1 + typescript: 5.9.3 + undici: 7.20.0 + vite: 7.3.0(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + watchpack: 2.5.0 + optionalDependencies: + '@angular/core': 21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1) + '@angular/platform-browser': 21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)) + less: 4.5.1 + lmdb: 3.4.4 + ng-packagr: 21.1.0(@angular/compiler-cli@21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3))(tailwindcss@4.1.8)(tslib@2.8.1)(typescript@5.9.3) + postcss: 8.5.6 + tailwindcss: 4.1.8 transitivePeerDependencies: - - debug + - '@types/node' + - chokidar + - jiti + - lightningcss + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml - '@asgardeo/js@0.1.3': + '@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1)': dependencies: - '@asgardeo/auth-js': 5.1.2 - csstype: 3.1.3 - lodash.isempty: 4.4.0 - lodash.merge: 4.6.2 + '@angular/core': 21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1) + rxjs: 7.8.1 + tslib: 2.8.1 + + '@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2)': + dependencies: + '@angular/core': 21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1) + rxjs: 7.8.2 + tslib: 2.8.1 + + '@angular/compiler-cli@21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3)': + dependencies: + '@angular/compiler': 21.1.5 + '@babel/core': 7.28.5 + '@jridgewell/sourcemap-codec': 1.5.5 + chokidar: 5.0.0 + convert-source-map: 1.9.0 + reflect-metadata: 0.2.2 + semver: 7.7.3 + tslib: 2.8.1 + yargs: 18.0.0 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@angular/compiler@21.1.5': + dependencies: + tslib: 2.8.1 + + '@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)': + dependencies: + rxjs: 7.8.1 + tslib: 2.8.1 + optionalDependencies: + '@angular/compiler': 21.1.5 + zone.js: 0.16.1 + + '@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1)': + dependencies: + rxjs: 7.8.2 + tslib: 2.8.1 + optionalDependencies: + '@angular/compiler': 21.1.5 + zone.js: 0.16.1 + + '@angular/forms@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)))(rxjs@7.8.1)': + dependencies: + '@angular/common': 21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1) + '@angular/core': 21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1) + '@angular/platform-browser': 21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)) + '@standard-schema/spec': 1.1.0 + rxjs: 7.8.1 + tslib: 2.8.1 + + '@angular/platform-browser-dynamic@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/compiler@21.1.5)(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)))': + dependencies: + '@angular/common': 21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1) + '@angular/compiler': 21.1.5 + '@angular/core': 21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1) + '@angular/platform-browser': 21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)) + tslib: 2.8.1 + + '@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))': + dependencies: + '@angular/common': 21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1) + '@angular/core': 21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1) + tslib: 2.8.1 + + '@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1))': + dependencies: + '@angular/common': 21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2) + '@angular/core': 21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1) + tslib: 2.8.1 + + '@angular/router@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)))(rxjs@7.8.1)': + dependencies: + '@angular/common': 21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1) + '@angular/core': 21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1) + '@angular/platform-browser': 21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1))(rxjs@7.8.1))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.1)(zone.js@0.16.1)) + rxjs: 7.8.1 + tslib: 2.8.1 + + '@angular/router@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1)))(rxjs@7.8.2)': + dependencies: + '@angular/common': 21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2) + '@angular/core': 21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1) + '@angular/platform-browser': 21.1.5(@angular/common@21.1.5(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.1.5(@angular/compiler@21.1.5)(rxjs@7.8.2)(zone.js@0.16.1)) + rxjs: 7.8.2 + tslib: 2.8.1 + + '@asamuzakjp/css-color@3.2.0': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + lru-cache: 10.4.3 + + '@asamuzakjp/css-color@4.1.1': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + lru-cache: 11.2.4 + + '@asamuzakjp/dom-selector@6.7.6': + dependencies: + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.1.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.2.4 + + '@asamuzakjp/nwsapi@2.3.9': {} + + '@asgardeo/auth-js@5.1.2': {} + + '@asgardeo/auth-spa@3.3.2': + dependencies: + '@asgardeo/auth-js': 5.1.2 + await-semaphore: 0.1.3 + axios: 1.13.5 + base64url: 3.0.1 + buffer: 6.0.3 + fast-sha256: 1.3.0 + jose: 4.15.9 + randombytes: 2.1.0 + transitivePeerDependencies: + - debug + + '@asgardeo/js@0.1.3': + dependencies: + '@asgardeo/auth-js': 5.1.2 + csstype: 3.1.3 + lodash.isempty: 4.4.0 + lodash.merge: 4.6.2 '@babel/code-frame@7.27.1': dependencies: @@ -7192,6 +8612,12 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/compat-data@7.27.2': {} '@babel/core@7.27.1': @@ -7214,6 +8640,26 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/core@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.28.5) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.27.2 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/eslint-parser@7.28.5(@babel/core@7.27.1)(eslint@8.57.0)': dependencies: '@babel/core': 7.27.1 @@ -7230,6 +8676,18 @@ snapshots: '@jridgewell/trace-mapping': 0.3.25 jsesc: 3.1.0 + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.27.3': + dependencies: + '@babel/types': 7.29.0 + '@babel/helper-compilation-targets@7.27.2': dependencies: '@babel/compat-data': 7.27.2 @@ -7238,6 +8696,8 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-globals@7.28.0': {} + '@babel/helper-module-imports@7.27.1': dependencies: '@babel/traverse': 7.27.1 @@ -7245,6 +8705,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-transforms@7.27.1(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 @@ -7254,12 +8721,27 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-transforms@7.28.6(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-plugin-utils@7.27.1': {} + '@babel/helper-split-export-declaration@7.24.7': + dependencies: + '@babel/types': 7.27.1 + '@babel/helper-string-parser@7.27.1': {} '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-option@7.27.1': {} '@babel/helpers@7.27.1': @@ -7267,10 +8749,19 @@ snapshots: '@babel/template': 7.27.2 '@babel/types': 7.27.1 + '@babel/helpers@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + '@babel/parser@7.27.2': dependencies: '@babel/types': 7.27.1 + '@babel/parser@7.29.0': + dependencies: + '@babel/types': 7.29.0 + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 @@ -7289,6 +8780,12 @@ snapshots: '@babel/parser': 7.27.2 '@babel/types': 7.27.1 + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@babel/traverse@7.27.1': dependencies: '@babel/code-frame': 7.27.1 @@ -7301,11 +8798,28 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + '@babel/types@7.27.1': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@bcoe/v8-coverage@1.0.2': {} '@bufbuild/protobuf@2.7.0': @@ -7512,6 +9026,12 @@ snapshots: '@emnapi/wasi-threads': 1.0.2 tslib: 2.8.1 + '@emnapi/core@1.8.1': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.4.3': dependencies: tslib: 2.8.1 @@ -7525,6 +9045,11 @@ snapshots: dependencies: tslib: 2.8.1 + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + '@emotion/babel-plugin@11.13.5': dependencies: '@babel/helper-module-imports': 7.27.1 @@ -7582,156 +9107,234 @@ snapshots: '@esbuild/aix-ppc64@0.25.9': optional: true + '@esbuild/aix-ppc64@0.27.2': + optional: true + '@esbuild/aix-ppc64@0.27.3': optional: true '@esbuild/android-arm64@0.25.9': optional: true + '@esbuild/android-arm64@0.27.2': + optional: true + '@esbuild/android-arm64@0.27.3': optional: true '@esbuild/android-arm@0.25.9': optional: true + '@esbuild/android-arm@0.27.2': + optional: true + '@esbuild/android-arm@0.27.3': optional: true '@esbuild/android-x64@0.25.9': optional: true + '@esbuild/android-x64@0.27.2': + optional: true + '@esbuild/android-x64@0.27.3': optional: true '@esbuild/darwin-arm64@0.25.9': optional: true + '@esbuild/darwin-arm64@0.27.2': + optional: true + '@esbuild/darwin-arm64@0.27.3': optional: true '@esbuild/darwin-x64@0.25.9': optional: true + '@esbuild/darwin-x64@0.27.2': + optional: true + '@esbuild/darwin-x64@0.27.3': optional: true '@esbuild/freebsd-arm64@0.25.9': optional: true + '@esbuild/freebsd-arm64@0.27.2': + optional: true + '@esbuild/freebsd-arm64@0.27.3': optional: true '@esbuild/freebsd-x64@0.25.9': optional: true + '@esbuild/freebsd-x64@0.27.2': + optional: true + '@esbuild/freebsd-x64@0.27.3': optional: true '@esbuild/linux-arm64@0.25.9': optional: true + '@esbuild/linux-arm64@0.27.2': + optional: true + '@esbuild/linux-arm64@0.27.3': optional: true '@esbuild/linux-arm@0.25.9': optional: true + '@esbuild/linux-arm@0.27.2': + optional: true + '@esbuild/linux-arm@0.27.3': optional: true '@esbuild/linux-ia32@0.25.9': optional: true + '@esbuild/linux-ia32@0.27.2': + optional: true + '@esbuild/linux-ia32@0.27.3': optional: true '@esbuild/linux-loong64@0.25.9': optional: true + '@esbuild/linux-loong64@0.27.2': + optional: true + '@esbuild/linux-loong64@0.27.3': optional: true '@esbuild/linux-mips64el@0.25.9': optional: true + '@esbuild/linux-mips64el@0.27.2': + optional: true + '@esbuild/linux-mips64el@0.27.3': optional: true '@esbuild/linux-ppc64@0.25.9': optional: true + '@esbuild/linux-ppc64@0.27.2': + optional: true + '@esbuild/linux-ppc64@0.27.3': optional: true '@esbuild/linux-riscv64@0.25.9': optional: true + '@esbuild/linux-riscv64@0.27.2': + optional: true + '@esbuild/linux-riscv64@0.27.3': optional: true '@esbuild/linux-s390x@0.25.9': optional: true + '@esbuild/linux-s390x@0.27.2': + optional: true + '@esbuild/linux-s390x@0.27.3': optional: true '@esbuild/linux-x64@0.25.9': optional: true + '@esbuild/linux-x64@0.27.2': + optional: true + '@esbuild/linux-x64@0.27.3': optional: true '@esbuild/netbsd-arm64@0.25.9': optional: true + '@esbuild/netbsd-arm64@0.27.2': + optional: true + '@esbuild/netbsd-arm64@0.27.3': optional: true '@esbuild/netbsd-x64@0.25.9': optional: true + '@esbuild/netbsd-x64@0.27.2': + optional: true + '@esbuild/netbsd-x64@0.27.3': optional: true '@esbuild/openbsd-arm64@0.25.9': optional: true + '@esbuild/openbsd-arm64@0.27.2': + optional: true + '@esbuild/openbsd-arm64@0.27.3': optional: true '@esbuild/openbsd-x64@0.25.9': optional: true + '@esbuild/openbsd-x64@0.27.2': + optional: true + '@esbuild/openbsd-x64@0.27.3': optional: true '@esbuild/openharmony-arm64@0.25.9': optional: true + '@esbuild/openharmony-arm64@0.27.2': + optional: true + '@esbuild/openharmony-arm64@0.27.3': optional: true '@esbuild/sunos-x64@0.25.9': optional: true + '@esbuild/sunos-x64@0.27.2': + optional: true + '@esbuild/sunos-x64@0.27.3': optional: true '@esbuild/win32-arm64@0.25.9': optional: true + '@esbuild/win32-arm64@0.27.2': + optional: true + '@esbuild/win32-arm64@0.27.3': optional: true '@esbuild/win32-ia32@0.25.9': optional: true + '@esbuild/win32-ia32@0.27.2': + optional: true + '@esbuild/win32-ia32@0.27.3': optional: true '@esbuild/win32-x64@0.25.9': optional: true + '@esbuild/win32-x64@0.27.2': + optional: true + '@esbuild/win32-x64@0.27.3': optional: true @@ -7951,6 +9554,28 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true + '@inquirer/ansi@1.0.2': {} + + '@inquirer/confirm@5.1.21(@types/node@24.0.3)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@24.0.3) + '@inquirer/type': 3.0.10(@types/node@24.0.3) + optionalDependencies: + '@types/node': 24.0.3 + + '@inquirer/core@10.3.2(@types/node@24.0.3)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@24.0.3) + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 24.0.3 + '@inquirer/external-editor@1.0.3(@types/node@24.0.3)': dependencies: chardet: 2.1.1 @@ -7958,6 +9583,12 @@ snapshots: optionalDependencies: '@types/node': 24.0.3 + '@inquirer/figures@1.0.15': {} + + '@inquirer/type@3.0.10(@types/node@24.0.3)': + optionalDependencies: + '@types/node': 24.0.3 + '@isaacs/balanced-match@4.0.1': {} '@isaacs/brace-expansion@5.0.1': @@ -7987,7 +9618,6 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/trace-mapping': 0.3.29 - optional: true '@jridgewell/gen-mapping@0.3.8': dependencies: @@ -7995,6 +9625,11 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/set-array@1.2.1': {} @@ -8007,8 +9642,7 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.0': {} - '@jridgewell/sourcemap-codec@1.5.5': - optional: true + '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.25': dependencies: @@ -8019,10 +9653,30 @@ snapshots: dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - optional: true '@jspm/core@2.1.0': {} + '@lmdb/lmdb-darwin-arm64@3.4.4': + optional: true + + '@lmdb/lmdb-darwin-x64@3.4.4': + optional: true + + '@lmdb/lmdb-linux-arm64@3.4.4': + optional: true + + '@lmdb/lmdb-linux-arm@3.4.4': + optional: true + + '@lmdb/lmdb-linux-x64@3.4.4': + optional: true + + '@lmdb/lmdb-win32-arm64@3.4.4': + optional: true + + '@lmdb/lmdb-win32-x64@3.4.4': + optional: true + '@manypkg/find-root@1.1.0': dependencies: '@babel/runtime': 7.27.1 @@ -8048,12 +9702,109 @@ snapshots: '@microsoft/tsdoc@0.14.2': {} + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': + optional: true + + '@napi-rs/nice-android-arm-eabi@1.1.1': + optional: true + + '@napi-rs/nice-android-arm64@1.1.1': + optional: true + + '@napi-rs/nice-darwin-arm64@1.1.1': + optional: true + + '@napi-rs/nice-darwin-x64@1.1.1': + optional: true + + '@napi-rs/nice-freebsd-x64@1.1.1': + optional: true + + '@napi-rs/nice-linux-arm-gnueabihf@1.1.1': + optional: true + + '@napi-rs/nice-linux-arm64-gnu@1.1.1': + optional: true + + '@napi-rs/nice-linux-arm64-musl@1.1.1': + optional: true + + '@napi-rs/nice-linux-ppc64-gnu@1.1.1': + optional: true + + '@napi-rs/nice-linux-riscv64-gnu@1.1.1': + optional: true + + '@napi-rs/nice-linux-s390x-gnu@1.1.1': + optional: true + + '@napi-rs/nice-linux-x64-gnu@1.1.1': + optional: true + + '@napi-rs/nice-linux-x64-musl@1.1.1': + optional: true + + '@napi-rs/nice-openharmony-arm64@1.1.1': + optional: true + + '@napi-rs/nice-win32-arm64-msvc@1.1.1': + optional: true + + '@napi-rs/nice-win32-ia32-msvc@1.1.1': + optional: true + + '@napi-rs/nice-win32-x64-msvc@1.1.1': + optional: true + + '@napi-rs/nice@1.1.1': + optionalDependencies: + '@napi-rs/nice-android-arm-eabi': 1.1.1 + '@napi-rs/nice-android-arm64': 1.1.1 + '@napi-rs/nice-darwin-arm64': 1.1.1 + '@napi-rs/nice-darwin-x64': 1.1.1 + '@napi-rs/nice-freebsd-x64': 1.1.1 + '@napi-rs/nice-linux-arm-gnueabihf': 1.1.1 + '@napi-rs/nice-linux-arm64-gnu': 1.1.1 + '@napi-rs/nice-linux-arm64-musl': 1.1.1 + '@napi-rs/nice-linux-ppc64-gnu': 1.1.1 + '@napi-rs/nice-linux-riscv64-gnu': 1.1.1 + '@napi-rs/nice-linux-s390x-gnu': 1.1.1 + '@napi-rs/nice-linux-x64-gnu': 1.1.1 + '@napi-rs/nice-linux-x64-musl': 1.1.1 + '@napi-rs/nice-openharmony-arm64': 1.1.1 + '@napi-rs/nice-win32-arm64-msvc': 1.1.1 + '@napi-rs/nice-win32-ia32-msvc': 1.1.1 + '@napi-rs/nice-win32-x64-msvc': 1.1.1 + optional: true + '@napi-rs/wasm-runtime@0.2.4': dependencies: '@emnapi/core': 1.4.3 '@emnapi/runtime': 1.4.3 '@tybys/wasm-util': 0.9.0 + '@napi-rs/wasm-runtime@1.1.1': + dependencies: + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.8.1 + '@tybys/wasm-util': 0.10.1 + optional: true + '@next/env@15.5.12': {} '@next/eslint-plugin-next@13.5.11': @@ -8132,6 +9883,8 @@ snapshots: '@one-ini/wasm@0.1.1': {} + '@oxc-project/types@0.106.0': {} + '@parcel/watcher-android-arm64@2.5.1': optional: true @@ -8235,6 +9988,49 @@ snapshots: optionalDependencies: '@types/react': 19.1.5 + '@rolldown/binding-android-arm64@1.0.0-beta.58': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-beta.58': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-beta.58': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-beta.58': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.58': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.58': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.58': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.58': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.58': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.58': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.58': + dependencies: + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.58': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.58': + optional: true + + '@rolldown/pluginutils@1.0.0-beta.58': {} + '@rollup/plugin-commonjs@25.0.7(rollup@4.32.0)': dependencies: '@rollup/pluginutils': 5.1.4(rollup@4.32.0) @@ -8261,6 +10057,12 @@ snapshots: optionalDependencies: rollup: 4.32.0 + '@rollup/plugin-json@6.1.0(rollup@4.32.0)': + dependencies: + '@rollup/pluginutils': 5.1.4(rollup@4.32.0) + optionalDependencies: + rollup: 4.32.0 + '@rollup/plugin-node-resolve@15.2.3(rollup@4.32.0)': dependencies: '@rollup/pluginutils': 5.1.4(rollup@4.32.0) @@ -8414,10 +10216,18 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.50.0': optional: true + '@rollup/wasm-node@4.58.0': + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + '@rtsao/scc@1.1.0': {} '@sinclair/typebox@0.27.8': {} + '@standard-schema/spec@1.1.0': {} + '@swc/helpers@0.5.15': dependencies: tslib: 2.8.1 @@ -8470,7 +10280,7 @@ snapshots: '@tailwindcss/oxide@4.1.8': dependencies: - detect-libc: 2.0.4 + detect-libc: 2.1.2 tar: 7.5.8 optionalDependencies: '@tailwindcss/oxide-android-arm64': 4.1.8 @@ -8486,12 +10296,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.8 '@tailwindcss/oxide-win32-x64-msvc': 4.1.8 - '@tailwindcss/vite@4.1.8(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': + '@tailwindcss/vite@4.1.8(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': dependencies: '@tailwindcss/node': 4.1.8 '@tailwindcss/oxide': 4.1.8 tailwindcss: 4.1.8 - vite: 6.4.1(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite: 6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) '@tanstack/history@1.154.7': {} @@ -8562,6 +10372,18 @@ snapshots: '@trysound/sax@0.2.0': {} + '@ts-morph/common@0.22.0': + dependencies: + fast-glob: 3.3.3 + minimatch: 9.0.5 + mkdirp: 3.0.1 + path-browserify: 1.0.1 + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + '@tybys/wasm-util@0.9.0': dependencies: tslib: 2.8.1 @@ -8667,13 +10489,33 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2)': + '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.4.3 + eslint: 8.57.0 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + semver: 7.7.3 + ts-api-utils: 1.4.3(typescript@5.7.2) + optionalDependencies: + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.9.3) '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.7.2) - '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.9.3) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.9.3) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.4.3 eslint: 8.57.0 @@ -8681,9 +10523,9 @@ snapshots: ignore: 5.3.2 natural-compare: 1.4.0 semver: 7.7.3 - ts-api-utils: 1.4.3(typescript@5.7.2) + ts-api-utils: 1.4.3(typescript@5.9.3) optionalDependencies: - typescript: 5.7.2 + typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -8720,6 +10562,14 @@ snapshots: - supports-color - typescript + '@typescript-eslint/experimental-utils@5.62.0(eslint@8.57.0)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.9.3) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + '@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6)': dependencies: '@typescript-eslint/scope-manager': 6.21.0 @@ -8746,6 +10596,19 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.4.3 + eslint: 8.57.0 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@8.30.1(eslint@9.25.0(jiti@2.6.0))(typescript@5.8.3)': dependencies: '@typescript-eslint/scope-manager': 8.30.1 @@ -8797,6 +10660,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/type-utils@6.21.0(eslint@8.57.0)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.9.3) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.9.3) + debug: 4.4.3 + eslint: 8.57.0 + ts-api-utils: 1.4.3(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/type-utils@8.30.1(eslint@9.25.0(jiti@2.6.0))(typescript@5.8.3)': dependencies: '@typescript-eslint/typescript-estree': 8.30.1(typescript@5.8.3) @@ -8842,6 +10717,20 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@5.62.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + debug: 4.4.3 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.7.3 + tsutils: 3.21.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/typescript-estree@6.21.0(typescript@5.1.6)': dependencies: '@typescript-eslint/types': 6.21.0 @@ -8872,6 +10761,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@6.21.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.4.3 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.3 + semver: 7.7.3 + ts-api-utils: 1.4.3(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/typescript-estree@8.30.1(typescript@5.8.3)': dependencies: '@typescript-eslint/types': 8.30.1 @@ -8916,6 +10820,21 @@ snapshots: - supports-color - typescript + '@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.7.0 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.9.3) + eslint: 8.57.0 + eslint-scope: 5.1.1 + semver: 7.7.3 + transitivePeerDependencies: + - supports-color + - typescript + '@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.1.6)': dependencies: '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) @@ -8944,6 +10863,20 @@ snapshots: - supports-color - typescript + '@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.7.0 + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.9.3) + eslint: 8.57.0 + semver: 7.7.3 + transitivePeerDependencies: + - supports-color + - typescript + '@typescript-eslint/utils@8.30.1(eslint@9.25.0(jiti@2.6.0))(typescript@5.8.3)': dependencies: '@eslint-community/eslint-utils': 4.8.0(eslint@9.25.0(jiti@2.6.0)) @@ -8972,36 +10905,40 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-basic-ssl@2.0.0(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': + '@vitejs/plugin-basic-ssl@2.0.0(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': + dependencies: + vite: 6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + + '@vitejs/plugin-basic-ssl@2.1.0(vite@7.3.0(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': dependencies: - vite: 6.4.1(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite: 7.3.0(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) - '@vitejs/plugin-react@4.4.1(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': + '@vitejs/plugin-react@4.4.1(vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': dependencies: '@babel/core': 7.27.1 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.27.1) '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.27.1) '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.4.1(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite: 6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@5.2.4(vite@7.1.12(@types/node@20.12.7)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vue@3.5.13(typescript@5.1.6))': + '@vitejs/plugin-vue@5.2.4(vite@7.1.12(@types/node@20.12.7)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vue@3.5.13(typescript@5.1.6))': dependencies: - vite: 7.1.12(@types/node@20.12.7)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite: 7.1.12(@types/node@20.12.7)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) vue: 3.5.13(typescript@5.1.6) - '@vitest/browser@3.1.3(playwright@1.55.1)(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3)': + '@vitest/browser@3.1.3(playwright@1.55.1)(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3)': dependencies: '@testing-library/dom': 10.4.0 '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0) - '@vitest/mocker': 3.1.3(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + '@vitest/mocker': 3.1.3(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) '@vitest/utils': 3.1.3 magic-string: 0.30.17 sirv: 3.0.1 tinyrainbow: 2.0.0 - vitest: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vitest: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) ws: 8.18.2 optionalDependencies: playwright: 1.55.1 @@ -9011,16 +10948,16 @@ snapshots: - utf-8-validate - vite - '@vitest/browser@3.1.3(playwright@1.58.2)(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3)': + '@vitest/browser@3.1.3(playwright@1.58.2)(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3)': dependencies: '@testing-library/dom': 10.4.0 '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0) - '@vitest/mocker': 3.1.3(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + '@vitest/mocker': 3.1.3(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) '@vitest/utils': 3.1.3 magic-string: 0.30.17 sirv: 3.0.1 tinyrainbow: 2.0.0 - vitest: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vitest: 3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@26.1.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) ws: 8.18.2 optionalDependencies: playwright: 1.58.2 @@ -9031,16 +10968,16 @@ snapshots: - vite optional: true - '@vitest/browser@3.1.3(playwright@1.58.2)(vite@6.4.1(@types/node@22.15.30)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3)': + '@vitest/browser@3.1.3(playwright@1.58.2)(vite@6.4.1(@types/node@22.15.30)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3)': dependencies: '@testing-library/dom': 10.4.0 '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0) - '@vitest/mocker': 3.1.3(vite@6.4.1(@types/node@22.15.30)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + '@vitest/mocker': 3.1.3(vite@6.4.1(@types/node@22.15.30)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) '@vitest/utils': 3.1.3 magic-string: 0.30.17 sirv: 3.0.1 tinyrainbow: 2.0.0 - vitest: 3.1.3(@types/node@22.15.30)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vitest: 3.1.3(@types/node@22.15.30)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) ws: 8.18.2 optionalDependencies: playwright: 1.58.2 @@ -9051,7 +10988,7 @@ snapshots: - vite optional: true - '@vitest/coverage-v8@3.0.8(vitest@3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': + '@vitest/coverage-v8@3.0.8(vitest@3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -9065,7 +11002,7 @@ snapshots: std-env: 3.9.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vitest: 3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) transitivePeerDependencies: - supports-color @@ -9083,29 +11020,29 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.8(vite@6.4.1(@types/node@20.12.7)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': + '@vitest/mocker@3.0.8(vite@6.4.1(@types/node@20.12.7)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': dependencies: '@vitest/spy': 3.0.8 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.4.1(@types/node@20.12.7)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite: 6.4.1(@types/node@20.12.7)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) - '@vitest/mocker@3.1.3(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': + '@vitest/mocker@3.1.3(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': dependencies: '@vitest/spy': 3.1.3 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite: 6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) - '@vitest/mocker@3.1.3(vite@6.4.1(@types/node@22.15.30)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': + '@vitest/mocker@3.1.3(vite@6.4.1(@types/node@22.15.30)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': dependencies: '@vitest/spy': 3.1.3 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.4.1(@types/node@22.15.30)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite: 6.4.1(@types/node@22.15.30)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) '@vitest/pretty-format@3.0.8': dependencies: @@ -9157,10 +11094,10 @@ snapshots: loupe: 3.1.3 tinyrainbow: 2.0.0 - '@vitest/web-worker@3.0.8(vitest@3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': + '@vitest/web-worker@3.0.8(vitest@3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))': dependencies: debug: 4.4.1 - vitest: 3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vitest: 3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) transitivePeerDependencies: - supports-color @@ -9297,14 +11234,14 @@ snapshots: '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6) '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.1.6) eslint: 8.57.0 - eslint-config-airbnb: 19.0.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.37.5(eslint@8.57.0))(eslint@8.57.0) - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0) - eslint-config-airbnb-typescript: 17.1.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb: 19.0.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.37.5(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb-typescript: 17.1.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint@8.57.0) eslint-config-prettier: 8.10.0(eslint@8.57.0) eslint-plugin-eslint-plugin: 5.5.1(eslint@8.57.0) eslint-plugin-header: 3.1.1(eslint@8.57.0) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0) - eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.1.6) + eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.0) eslint-plugin-node: 11.1.0(eslint@8.57.0) eslint-plugin-prettier: 4.2.5(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.6.2) @@ -9357,6 +11294,40 @@ snapshots: - jest - supports-color + '@wso2/eslint-plugin@https://codeload.github.com/brionmario/wso2-ui-configs/tar.gz/d3041825a4f8f235c8f9fa36b55cf29d54e791c8#path:packages/eslint-plugin(eslint@8.57.0)(typescript@5.9.3)': + dependencies: + '@babel/core': 7.27.1 + '@babel/eslint-parser': 7.28.5(@babel/core@7.27.1)(eslint@8.57.0) + '@next/eslint-plugin-next': 13.5.11 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0)(typescript@5.9.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.9.3) + eslint: 8.57.0 + eslint-config-airbnb: 19.0.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.37.5(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb-typescript: 17.1.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0)(typescript@5.9.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0))(eslint@8.57.0) + eslint-config-prettier: 8.10.0(eslint@8.57.0) + eslint-plugin-eslint-plugin: 5.5.1(eslint@8.57.0) + eslint-plugin-header: 3.1.1(eslint@8.57.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0) + eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0)(typescript@5.9.3) + eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.0) + eslint-plugin-node: 11.1.0(eslint@8.57.0) + eslint-plugin-prettier: 4.2.5(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.6.2) + eslint-plugin-react: 7.37.5(eslint@8.57.0) + eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) + eslint-plugin-testing-library: 5.11.1(eslint@8.57.0)(typescript@5.9.3) + eslint-plugin-tsdoc: 0.2.17 + eslint-plugin-typescript-sort-keys: 2.3.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0)(typescript@5.9.3) + prettier: 2.6.2 + requireindex: 1.2.0 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - jest + - supports-color + '@wso2/prettier-config@https://codeload.github.com/brionmario/wso2-ui-configs/tar.gz/d3041825a4f8f235c8f9fa36b55cf29d54e791c8#path:packages/prettier-config(prettier@2.6.2)(typescript@5.1.6)': dependencies: prettier: 2.6.2 @@ -9369,6 +11340,12 @@ snapshots: optionalDependencies: typescript: 5.7.2 + '@wso2/prettier-config@https://codeload.github.com/brionmario/wso2-ui-configs/tar.gz/d3041825a4f8f235c8f9fa36b55cf29d54e791c8#path:packages/prettier-config(prettier@2.6.2)(typescript@5.9.3)': + dependencies: + prettier: 2.6.2 + optionalDependencies: + typescript: 5.9.3 + '@wso2/stylelint-config@https://codeload.github.com/brionmario/wso2-ui-configs/tar.gz/d3041825a4f8f235c8f9fa36b55cf29d54e791c8#path:packages/stylelint-config(postcss@8.5.6)(stylelint@15.1.0(typescript@5.1.6))(typescript@5.1.6)': dependencies: postcss-scss: 4.0.9(postcss@8.5.6) @@ -9405,6 +11382,10 @@ snapshots: agent-base@7.1.3: {} + ajv-formats@3.0.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -9423,6 +11404,10 @@ snapshots: ansi-colors@4.1.3: {} + ansi-escapes@7.3.0: + dependencies: + environment: 1.1.0 + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -9577,6 +11562,19 @@ snapshots: base64url@3.0.1: {} + baseline-browser-mapping@2.10.0: {} + + beasties@0.3.5: + dependencies: + css-select: 6.0.0 + css-what: 7.0.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + htmlparser2: 10.1.0 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-media-query-parser: 0.2.3 + better-path-resolve@1.0.0: dependencies: is-windows: 1.0.2 @@ -9671,11 +11669,18 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.5) + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.10.0 + caniuse-lite: 1.0.30001770 + electron-to-chromium: 1.5.302 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + buffer-builder@0.2.0: optional: true - buffer-from@1.1.2: - optional: true + buffer-from@1.1.2: {} buffer-xor@1.0.3: {} @@ -9731,6 +11736,8 @@ snapshots: caniuse-lite@1.0.30001718: {} + caniuse-lite@1.0.30001770: {} + chai@5.2.0: dependencies: assertion-error: 2.0.1 @@ -9744,6 +11751,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.6.2: {} + chardet@2.1.1: {} check-error@2.1.1: {} @@ -9763,7 +11772,10 @@ snapshots: chokidar@4.0.3: dependencies: readdirp: 4.1.2 - optional: true + + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 chownr@3.0.0: {} @@ -9782,8 +11794,21 @@ snapshots: dependencies: restore-cursor: 3.1.0 + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + cli-spinners@2.6.1: {} + cli-spinners@3.4.0: {} + + cli-truncate@5.1.1: + dependencies: + slice-ansi: 7.1.2 + string-width: 8.2.0 + + cli-width@4.1.0: {} + client-only@0.0.1: {} cliui@8.0.1: @@ -9792,10 +11817,18 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + cliui@9.0.1: + dependencies: + string-width: 7.2.0 + strip-ansi: 7.1.2 + wrap-ansi: 9.0.2 + clone@1.0.4: {} clsx@2.1.1: {} + code-block-writer@12.0.0: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -9804,6 +11837,8 @@ snapshots: colord@2.9.3: {} + colorette@2.0.20: {} + colorjs.io@0.5.2: optional: true @@ -9813,11 +11848,15 @@ snapshots: commander@10.0.1: {} + commander@14.0.3: {} + commander@2.20.3: optional: true commander@7.2.0: {} + common-path-prefix@3.0.0: {} + commondir@1.0.1: {} confbox@0.1.8: {} @@ -9849,6 +11888,10 @@ snapshots: cookie@1.0.2: {} + copy-anything@2.0.6: + dependencies: + is-what: 3.14.1 + core-js@3.42.0: {} core-util-is@1.0.3: {} @@ -9940,6 +11983,14 @@ snapshots: domutils: 2.8.0 nth-check: 2.1.1 + css-select@6.0.0: + dependencies: + boolbase: 1.0.0 + css-what: 7.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + css-tree@1.1.3: dependencies: mdn-data: 2.0.14 @@ -9957,6 +12008,8 @@ snapshots: css-what@6.1.0: {} + css-what@7.0.0: {} + cssesc@3.0.0: {} cssnano-preset-default@5.2.14(postcss@8.4.31): @@ -10106,6 +12159,8 @@ snapshots: depd@2.0.0: {} + dependency-graph@1.0.0: {} + dequal@2.0.3: {} des.js@1.1.0: @@ -10118,10 +12173,7 @@ snapshots: detect-libc@1.0.3: optional: true - detect-libc@2.0.4: {} - - detect-libc@2.1.2: - optional: true + detect-libc@2.1.2: {} diff-sequences@29.6.3: {} @@ -10151,6 +12203,12 @@ snapshots: domhandler: 4.3.1 entities: 2.2.0 + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + dom-walk@0.1.2: {} domelementtype@2.3.0: {} @@ -10159,6 +12217,10 @@ snapshots: dependencies: domelementtype: 2.3.0 + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + dompurify@3.2.7: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -10169,6 +12231,12 @@ snapshots: domelementtype: 2.3.0 domhandler: 4.3.1 + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dotenv-expand@11.0.7: dependencies: dotenv: 16.4.7 @@ -10196,6 +12264,8 @@ snapshots: electron-to-chromium@1.5.155: {} + electron-to-chromium@1.5.302: {} + elliptic@6.6.1: dependencies: bn.js: 4.12.2 @@ -10206,6 +12276,8 @@ snapshots: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 + emoji-regex@10.6.0: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -10236,6 +12308,15 @@ snapshots: entities@6.0.0: {} + entities@7.0.1: {} + + environment@1.1.0: {} + + errno@0.1.8: + dependencies: + prr: 1.0.1 + optional: true + error-ex@1.3.2: dependencies: is-arrayish: 0.2.1 @@ -10394,6 +12475,35 @@ snapshots: '@esbuild/win32-ia32': 0.25.9 '@esbuild/win32-x64': 0.25.9 + esbuild@0.27.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.2 + '@esbuild/android-arm': 0.27.2 + '@esbuild/android-arm64': 0.27.2 + '@esbuild/android-x64': 0.27.2 + '@esbuild/darwin-arm64': 0.27.2 + '@esbuild/darwin-x64': 0.27.2 + '@esbuild/freebsd-arm64': 0.27.2 + '@esbuild/freebsd-x64': 0.27.2 + '@esbuild/linux-arm': 0.27.2 + '@esbuild/linux-arm64': 0.27.2 + '@esbuild/linux-ia32': 0.27.2 + '@esbuild/linux-loong64': 0.27.2 + '@esbuild/linux-mips64el': 0.27.2 + '@esbuild/linux-ppc64': 0.27.2 + '@esbuild/linux-riscv64': 0.27.2 + '@esbuild/linux-s390x': 0.27.2 + '@esbuild/linux-x64': 0.27.2 + '@esbuild/netbsd-arm64': 0.27.2 + '@esbuild/netbsd-x64': 0.27.2 + '@esbuild/openbsd-arm64': 0.27.2 + '@esbuild/openbsd-x64': 0.27.2 + '@esbuild/openharmony-arm64': 0.27.2 + '@esbuild/sunos-x64': 0.27.2 + '@esbuild/win32-arm64': 0.27.2 + '@esbuild/win32-ia32': 0.27.2 + '@esbuild/win32-x64': 0.27.2 + esbuild@0.27.3: optionalDependencies: '@esbuild/aix-ppc64': 0.27.3 @@ -10431,6 +12541,15 @@ snapshots: escape-string-regexp@4.0.0: {} + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint@8.57.0): + dependencies: + confusing-browser-globals: 1.0.11 + eslint: 8.57.0 + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0) + object.assign: 4.1.7 + object.entries: 1.1.9 + semver: 6.3.1 + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0): dependencies: confusing-browser-globals: 1.0.11 @@ -10440,13 +12559,22 @@ snapshots: object.entries: 1.1.9 semver: 6.3.1 - eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0): + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0))(eslint@8.57.0): dependencies: - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2) + confusing-browser-globals: 1.0.11 + eslint: 8.57.0 + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0) + object.assign: 4.1.7 + object.entries: 1.1.9 + semver: 6.3.1 + + eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint@8.57.0): + dependencies: + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6) '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.1.6) eslint: 8.57.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0) eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0): dependencies: @@ -10456,6 +12584,25 @@ snapshots: eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0) + eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0)(typescript@5.9.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0))(eslint@8.57.0): + dependencies: + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0)(typescript@5.9.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.9.3) + eslint: 8.57.0 + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0) + + eslint-config-airbnb@19.0.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.37.5(eslint@8.57.0))(eslint@8.57.0): + dependencies: + eslint: 8.57.0 + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0) + eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.0) + eslint-plugin-react: 7.37.5(eslint@8.57.0) + eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) + object.assign: 4.1.7 + object.entries: 1.1.9 + eslint-config-airbnb@19.0.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.37.5(eslint@8.57.0))(eslint@8.57.0): dependencies: eslint: 8.57.0 @@ -10467,6 +12614,17 @@ snapshots: object.assign: 4.1.7 object.entries: 1.1.9 + eslint-config-airbnb@19.0.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.37.5(eslint@8.57.0))(eslint@8.57.0): + dependencies: + eslint: 8.57.0 + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0) + eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.0) + eslint-plugin-react: 7.37.5(eslint@8.57.0) + eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) + object.assign: 4.1.7 + object.entries: 1.1.9 + eslint-config-prettier@8.10.0(eslint@8.57.0): dependencies: eslint: 8.57.0 @@ -10499,6 +12657,16 @@ snapshots: transitivePeerDependencies: - supports-color + eslint-module-utils@2.12.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.9.3) + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + eslint-plugin-es@3.0.1(eslint@8.57.0): dependencies: eslint: 8.57.0 @@ -10573,9 +12741,48 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.1.6): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.9.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6): + dependencies: + '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.1.6) + eslint: 8.57.0 + optionalDependencies: + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6) + transitivePeerDependencies: + - supports-color + - typescript + + eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2): dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.1.6) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.7.2) eslint: 8.57.0 optionalDependencies: '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2) @@ -10583,12 +12790,12 @@ snapshots: - supports-color - typescript - eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2): + eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0)(typescript@5.9.3): dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.9.3) eslint: 8.57.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0)(typescript@5.9.3) transitivePeerDependencies: - supports-color - typescript @@ -10689,6 +12896,14 @@ snapshots: - supports-color - typescript + eslint-plugin-testing-library@5.11.1(eslint@8.57.0)(typescript@5.9.3): + dependencies: + '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.9.3) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + eslint-plugin-tsdoc@0.2.17: dependencies: '@microsoft/tsdoc': 0.14.2 @@ -10716,6 +12931,17 @@ snapshots: transitivePeerDependencies: - supports-color + eslint-plugin-typescript-sort-keys@2.3.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0)(typescript@5.9.3): + dependencies: + '@typescript-eslint/experimental-utils': 5.62.0(eslint@8.57.0)(typescript@5.9.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.9.3) + eslint: 8.57.0 + json-schema: 0.4.0 + natural-compare-lite: 1.4.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + eslint-plugin-vue@10.1.0(eslint@8.57.0)(vue-eslint-parser@10.1.3(eslint@8.57.0)): dependencies: '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) @@ -10772,7 +12998,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.1 + debug: 4.4.3 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -10880,6 +13106,8 @@ snapshots: eventemitter3@4.0.7: {} + eventemitter3@5.0.4: {} + evp_bytestokey@1.0.3: dependencies: md5.js: 1.3.5 @@ -10989,8 +13217,15 @@ snapshots: make-dir: 3.1.0 pkg-dir: 4.2.0 + find-cache-directory@6.0.0: + dependencies: + common-path-prefix: 3.0.0 + pkg-dir: 8.0.0 + find-root@1.1.0: {} + find-up-simple@1.0.1: {} + find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -11092,6 +13327,8 @@ snapshots: get-caller-file@2.0.5: {} + get-east-asian-width@1.5.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -11132,6 +13369,8 @@ snapshots: dependencies: is-glob: 4.0.3 + glob-to-regexp@0.4.1: {} + glob@10.5.0: dependencies: foreground-child: 3.3.1 @@ -11296,6 +13535,13 @@ snapshots: html-tags@3.3.1: {} + htmlparser2@10.1.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 7.0.1 + http-errors@2.0.0: dependencies: depd: 2.0.0 @@ -11344,10 +13590,12 @@ snapshots: ignore@5.3.2: {} + image-size@0.5.5: + optional: true + immutable@4.3.7: {} - immutable@5.1.2: - optional: true + immutable@5.1.2: {} import-fresh@3.3.1: dependencies: @@ -11371,6 +13619,10 @@ snapshots: ini@1.3.8: {} + injection-js@2.6.1: + dependencies: + tslib: 2.8.1 + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -11439,6 +13691,10 @@ snapshots: is-fullwidth-code-point@3.0.0: {} + is-fullwidth-code-point@5.1.0: + dependencies: + get-east-asian-width: 1.5.0 + is-generator-function@1.1.2: dependencies: call-bound: 1.0.4 @@ -11453,6 +13709,8 @@ snapshots: is-interactive@1.0.0: {} + is-interactive@2.0.0: {} + is-map@2.0.3: {} is-module@1.0.0: {} @@ -11514,6 +13772,8 @@ snapshots: is-unicode-supported@0.1.0: {} + is-unicode-supported@2.1.0: {} + is-weakmap@2.0.2: {} is-weakref@1.1.1: @@ -11525,6 +13785,8 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-what@3.14.1: {} + is-windows@1.0.2: {} is-wsl@2.2.0: @@ -11541,6 +13803,16 @@ snapshots: istanbul-lib-coverage@3.2.2: {} + istanbul-lib-instrument@6.0.3: + dependencies: + '@babel/core': 7.28.5 + '@babel/parser': 7.27.2 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.7.3 + transitivePeerDependencies: + - supports-color + istanbul-lib-report@3.0.1: dependencies: istanbul-lib-coverage: 3.2.2 @@ -11693,6 +13965,8 @@ snapshots: jsonc-parser@3.2.0: {} + jsonc-parser@3.3.1: {} + jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 @@ -11724,6 +13998,20 @@ snapshots: dependencies: language-subtag-registry: 0.3.23 + less@4.5.1: + dependencies: + copy-anything: 2.0.6 + parse-node-version: 1.0.1 + tslib: 2.8.1 + optionalDependencies: + errno: 0.1.8 + graceful-fs: 4.2.11 + image-size: 0.5.5 + make-dir: 2.1.0 + mime: 1.6.0 + needle: 3.3.1 + source-map: 0.6.1 + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -11761,7 +14049,7 @@ snapshots: lightningcss@1.30.1: dependencies: - detect-libc: 2.0.4 + detect-libc: 2.1.2 optionalDependencies: lightningcss-darwin-arm64: 1.30.1 lightningcss-darwin-x64: 1.30.1 @@ -11780,6 +14068,32 @@ snapshots: lines-and-columns@2.0.3: {} + listr2@9.0.5: + dependencies: + cli-truncate: 5.1.1 + colorette: 2.0.20 + eventemitter3: 5.0.4 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.2 + + lmdb@3.4.4: + dependencies: + msgpackr: 1.11.8 + node-addon-api: 6.1.0 + node-gyp-build-optional-packages: 5.2.2 + ordered-binary: 1.6.1 + weak-lru-cache: 1.2.2 + optionalDependencies: + '@lmdb/lmdb-darwin-arm64': 3.4.4 + '@lmdb/lmdb-darwin-x64': 3.4.4 + '@lmdb/lmdb-linux-arm': 3.4.4 + '@lmdb/lmdb-linux-arm64': 3.4.4 + '@lmdb/lmdb-linux-x64': 3.4.4 + '@lmdb/lmdb-win32-arm64': 3.4.4 + '@lmdb/lmdb-win32-x64': 3.4.4 + optional: true + local-pkg@1.1.1: dependencies: mlly: 1.7.4 @@ -11813,6 +14127,19 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 + log-symbols@7.0.1: + dependencies: + is-unicode-supported: 2.1.0 + yoctocolors: 2.1.2 + + log-update@6.1.0: + dependencies: + ansi-escapes: 7.3.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.2 + strip-ansi: 7.1.2 + wrap-ansi: 9.0.2 + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -11821,8 +14148,6 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.1.0: {} - lru-cache@11.2.4: {} lru-cache@5.1.1: @@ -11843,12 +14168,22 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + magicast@0.3.5: dependencies: '@babel/parser': 7.27.2 '@babel/types': 7.27.1 source-map-js: 1.2.1 + make-dir@2.1.0: + dependencies: + pify: 4.0.1 + semver: 5.7.2 + optional: true + make-dir@3.1.0: dependencies: semver: 6.3.1 @@ -11922,8 +14257,13 @@ snapshots: dependencies: mime-db: 1.54.0 + mime@1.6.0: + optional: true + mimic-fn@2.1.0: {} + mimic-function@5.0.1: {} + min-document@2.19.1: dependencies: dom-walk: 0.1.2 @@ -11974,6 +14314,8 @@ snapshots: dependencies: minipass: 7.1.2 + mkdirp@3.0.1: {} + mlly@1.7.4: dependencies: acorn: 8.15.0 @@ -11987,17 +14329,42 @@ snapshots: ms@2.1.3: {} + msgpackr-extract@3.0.3: + dependencies: + node-gyp-build-optional-packages: 5.2.2 + optionalDependencies: + '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3 + optional: true + + msgpackr@1.11.8: + optionalDependencies: + msgpackr-extract: 3.0.3 + optional: true + muggle-string@0.4.1: {} + mute-stream@2.0.0: {} + nanoid@3.3.11: {} natural-compare-lite@1.4.0: {} natural-compare@1.4.0: {} + needle@3.3.1: + dependencies: + iconv-lite: 0.6.3 + sax: 1.4.4 + optional: true + negotiator@1.0.0: {} - next@15.5.12(@babel/core@7.27.1)(@playwright/test@1.58.2)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)(sass@1.92.1): + next@15.5.12(@playwright/test@1.58.2)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)(sass@1.97.1): dependencies: '@next/env': 15.5.12 '@swc/helpers': 0.5.15 @@ -12005,7 +14372,7 @@ snapshots: postcss: 8.4.31 react: 19.1.4 react-dom: 19.1.4(react@19.1.4) - styled-jsx: 5.1.6(@babel/core@7.27.1)(react@19.1.4) + styled-jsx: 5.1.6(react@19.1.4) optionalDependencies: '@next/swc-darwin-arm64': 15.5.12 '@next/swc-darwin-x64': 15.5.12 @@ -12016,12 +14383,45 @@ snapshots: '@next/swc-win32-arm64-msvc': 15.5.12 '@next/swc-win32-x64-msvc': 15.5.12 '@playwright/test': 1.58.2 - sass: 1.92.1 + sass: 1.97.1 sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros + ng-packagr@21.1.0(@angular/compiler-cli@21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3))(tailwindcss@4.1.8)(tslib@2.8.1)(typescript@5.9.3): + dependencies: + '@ampproject/remapping': 2.3.0 + '@angular/compiler-cli': 21.1.5(@angular/compiler@21.1.5)(typescript@5.9.3) + '@rollup/plugin-json': 6.1.0(rollup@4.32.0) + '@rollup/wasm-node': 4.58.0 + ajv: 8.17.1 + ansi-colors: 4.1.3 + browserslist: 4.28.1 + chokidar: 5.0.0 + commander: 14.0.3 + dependency-graph: 1.0.0 + esbuild: 0.27.3 + find-cache-directory: 6.0.0 + injection-js: 2.6.1 + jsonc-parser: 3.3.1 + less: 4.5.1 + ora: 9.3.0 + piscina: 5.1.4 + postcss: 8.5.6 + rollup-plugin-dts: 6.3.0(rollup@4.32.0)(typescript@5.9.3) + rxjs: 7.8.1 + sass: 1.92.1 + tinyglobby: 0.2.15 + tslib: 2.8.1 + typescript: 5.9.3 + optionalDependencies: + rollup: 4.32.0 + tailwindcss: 4.1.8 + + node-addon-api@6.1.0: + optional: true + node-addon-api@7.1.1: optional: true @@ -12029,10 +14429,17 @@ snapshots: dependencies: whatwg-url: 5.0.0 + node-gyp-build-optional-packages@5.2.2: + dependencies: + detect-libc: 2.1.2 + optional: true + node-machine-id@1.1.12: {} node-releases@2.0.19: {} + node-releases@2.0.27: {} + nopt@7.2.1: dependencies: abbrev: 2.0.0 @@ -12171,6 +14578,10 @@ snapshots: dependencies: mimic-fn: 2.1.0 + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + open@8.4.2: dependencies: define-lazy-prop: 2.0.0 @@ -12197,6 +14608,20 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 + ora@9.3.0: + dependencies: + chalk: 5.6.2 + cli-cursor: 5.0.0 + cli-spinners: 3.4.0 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 7.0.1 + stdin-discarder: 0.3.1 + string-width: 8.2.0 + + ordered-binary@1.6.1: + optional: true + outdent@0.5.0: {} own-keys@1.0.1: @@ -12266,6 +14691,18 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-node-version@1.0.1: {} + + parse5-html-rewriting-stream@8.0.0: + dependencies: + entities: 6.0.0 + parse5: 8.0.0 + parse5-sax-parser: 8.0.0 + + parse5-sax-parser@8.0.0: + dependencies: + parse5: 8.0.0 + parse5@7.3.0: dependencies: entities: 6.0.0 @@ -12293,7 +14730,7 @@ snapshots: path-scurry@2.0.0: dependencies: - lru-cache: 11.1.0 + lru-cache: 11.2.4 minipass: 7.1.2 path-to-regexp@8.2.0: {} @@ -12319,10 +14756,21 @@ snapshots: picomatch@4.0.3: {} + pify@4.0.1: + optional: true + + piscina@5.1.4: + optionalDependencies: + '@napi-rs/nice': 1.1.1 + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 + pkg-dir@8.0.0: + dependencies: + find-up-simple: 1.0.1 + pkg-types@1.3.1: dependencies: confbox: 0.1.8 @@ -12609,6 +15057,9 @@ snapshots: proxy-from-env@1.1.0: {} + prr@1.0.1: + optional: true + public-encrypt@4.0.3: dependencies: bn.js: 4.12.2 @@ -12716,14 +15167,17 @@ snapshots: dependencies: picomatch: 2.3.1 - readdirp@4.1.2: - optional: true + readdirp@4.1.2: {} + + readdirp@5.0.0: {} redent@3.0.0: dependencies: indent-string: 4.0.0 strip-indent: 3.0.0 + reflect-metadata@0.2.2: {} + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -12782,8 +15236,15 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + reusify@1.1.0: {} + rfdc@1.4.1: {} + rimraf@3.0.2: dependencies: glob: 7.2.3 @@ -12803,6 +15264,25 @@ snapshots: hash-base: 3.1.2 inherits: 2.0.4 + rolldown@1.0.0-beta.58: + dependencies: + '@oxc-project/types': 0.106.0 + '@rolldown/pluginutils': 1.0.0-beta.58 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-beta.58 + '@rolldown/binding-darwin-arm64': 1.0.0-beta.58 + '@rolldown/binding-darwin-x64': 1.0.0-beta.58 + '@rolldown/binding-freebsd-x64': 1.0.0-beta.58 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.58 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.58 + '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.58 + '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.58 + '@rolldown/binding-linux-x64-musl': 1.0.0-beta.58 + '@rolldown/binding-openharmony-arm64': 1.0.0-beta.58 + '@rolldown/binding-wasm32-wasi': 1.0.0-beta.58 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.58 + '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.58 + rollup-plugin-dts@6.1.0(rollup@4.32.0)(typescript@5.1.6): dependencies: magic-string: 0.30.17 @@ -12811,6 +15291,14 @@ snapshots: optionalDependencies: '@babel/code-frame': 7.27.1 + rollup-plugin-dts@6.3.0(rollup@4.32.0)(typescript@5.9.3): + dependencies: + magic-string: 0.30.21 + rollup: 4.32.0 + typescript: 5.9.3 + optionalDependencies: + '@babel/code-frame': 7.27.1 + rollup-plugin-polyfill-node@0.13.0(rollup@4.32.0): dependencies: '@rollup/plugin-inject': 5.0.5(rollup@4.32.0) @@ -12906,10 +15394,13 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.1: + dependencies: + tslib: 2.8.1 + rxjs@7.8.2: dependencies: tslib: 2.8.1 - optional: true safe-array-concat@1.1.3: dependencies: @@ -13000,7 +15491,7 @@ snapshots: buffer-builder: 0.2.0 colorjs.io: 0.5.2 immutable: 5.1.2 - rxjs: 7.8.2 + rxjs: 7.8.1 supports-color: 8.1.1 sync-child-process: 1.0.2 varint: 6.0.0 @@ -13038,6 +15529,16 @@ snapshots: source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.1 + + sass@1.97.1: + dependencies: + chokidar: 4.0.3 + immutable: 5.1.2 + source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.5.1 + + sax@1.4.4: optional: true saxes@6.0.0: @@ -13211,18 +15712,24 @@ snapshots: astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 + slice-ansi@7.1.2: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + source-map-js@1.2.1: {} source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - optional: true source-map@0.5.7: {} source-map@0.6.1: {} + source-map@0.7.6: {} + spawndamnit@3.0.1: dependencies: cross-spawn: 7.0.6 @@ -13254,6 +15761,8 @@ snapshots: std-env@3.9.0: {} + stdin-discarder@0.3.1: {} + stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -13278,6 +15787,17 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.2 + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.5.0 + strip-ansi: 7.1.2 + + string-width@8.2.0: + dependencies: + get-east-asian-width: 1.5.0 + strip-ansi: 7.1.2 + string.prototype.includes@2.0.1: dependencies: call-bind: 1.0.8 @@ -13356,12 +15876,10 @@ snapshots: style-search@0.1.0: {} - styled-jsx@5.1.6(@babel/core@7.27.1)(react@19.1.4): + styled-jsx@5.1.6(react@19.1.4): dependencies: client-only: 0.0.1 react: 19.1.4 - optionalDependencies: - '@babel/core': 7.27.1 stylehacks@5.1.1(postcss@8.4.31): dependencies: @@ -13553,11 +16071,6 @@ snapshots: tinyexec@0.3.2: {} - tinyglobby@0.2.14: - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) @@ -13625,10 +16138,19 @@ snapshots: dependencies: typescript: 5.7.2 + ts-api-utils@1.4.3(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + ts-api-utils@2.1.0(typescript@5.8.3): dependencies: typescript: 5.8.3 + ts-morph@21.0.1: + dependencies: + '@ts-morph/common': 0.22.0 + code-block-writer: 12.0.0 + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -13658,6 +16180,11 @@ snapshots: tslib: 1.14.1 typescript: 5.7.2 + tsutils@3.21.0(typescript@5.9.3): + dependencies: + tslib: 1.14.1 + typescript: 5.9.3 + tsx@4.21.0: dependencies: esbuild: 0.27.3 @@ -13734,6 +16261,8 @@ snapshots: typescript@5.8.3: {} + typescript@5.9.3: {} + ufo@1.6.1: {} unbox-primitive@1.1.0: @@ -13750,6 +16279,8 @@ snapshots: undici-types@7.8.0: optional: true + undici@7.20.0: {} + undici@7.21.0: {} universalify@0.1.2: {} @@ -13764,6 +16295,12 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -13788,13 +16325,13 @@ snapshots: vary@1.1.2: {} - vite-node@3.0.8(@types/node@20.12.7)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): + vite-node@3.0.8(@types/node@20.12.7)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): dependencies: cac: 6.7.14 debug: 4.4.1 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.4.1(@types/node@20.12.7)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite: 6.4.1(@types/node@20.12.7)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) transitivePeerDependencies: - '@types/node' - jiti @@ -13809,13 +16346,13 @@ snapshots: - tsx - yaml - vite-node@3.1.3(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): + vite-node@3.1.3(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): dependencies: cac: 6.7.14 - debug: 4.4.1 + debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite: 6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) transitivePeerDependencies: - '@types/node' - jiti @@ -13830,13 +16367,13 @@ snapshots: - tsx - yaml - vite-node@3.1.3(@types/node@22.15.30)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): + vite-node@3.1.3(@types/node@22.15.30)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): dependencies: cac: 6.7.14 - debug: 4.4.1 + debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.4.1(@types/node@22.15.30)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite: 6.4.1(@types/node@22.15.30)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) transitivePeerDependencies: - '@types/node' - jiti @@ -13851,18 +16388,19 @@ snapshots: - tsx - yaml - vite@6.4.1(@types/node@20.12.7)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): + vite@6.4.1(@types/node@20.12.7)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): dependencies: esbuild: 0.25.9 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 rollup: 4.50.0 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 optionalDependencies: '@types/node': 20.12.7 fsevents: 2.3.3 jiti: 2.6.0 + less: 4.5.1 lightningcss: 1.30.1 sass: 1.75.0 sass-embedded: 1.92.1 @@ -13870,64 +16408,67 @@ snapshots: tsx: 4.21.0 yaml: 2.8.0 - vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): + vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): dependencies: esbuild: 0.25.9 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 rollup: 4.50.0 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 optionalDependencies: '@types/node': 22.15.3 fsevents: 2.3.3 jiti: 2.6.0 + less: 4.5.1 lightningcss: 1.30.1 - sass: 1.92.1 + sass: 1.97.1 sass-embedded: 1.92.1 terser: 5.39.2 tsx: 4.21.0 yaml: 2.8.0 - vite@6.4.1(@types/node@22.15.30)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): + vite@6.4.1(@types/node@22.15.30)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): dependencies: esbuild: 0.25.9 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 rollup: 4.50.0 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 optionalDependencies: '@types/node': 22.15.30 fsevents: 2.3.3 jiti: 2.6.0 + less: 4.5.1 lightningcss: 1.30.1 - sass: 1.92.1 + sass: 1.97.1 sass-embedded: 1.92.1 terser: 5.39.2 tsx: 4.21.0 yaml: 2.8.0 - vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): + vite@6.4.1(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): dependencies: esbuild: 0.25.9 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 rollup: 4.50.0 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.0.3 fsevents: 2.3.3 jiti: 2.6.0 + less: 4.5.1 lightningcss: 1.30.1 - sass: 1.92.1 + sass: 1.97.1 sass-embedded: 1.92.1 terser: 5.39.2 tsx: 4.21.0 yaml: 2.8.0 - vite@7.1.12(@types/node@20.12.7)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): + vite@7.1.12(@types/node@20.12.7)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): dependencies: esbuild: 0.25.9 fdir: 6.5.0(picomatch@4.0.3) @@ -13939,6 +16480,7 @@ snapshots: '@types/node': 20.12.7 fsevents: 2.3.3 jiti: 2.6.0 + less: 4.5.1 lightningcss: 1.30.1 sass: 1.75.0 sass-embedded: 1.92.1 @@ -13946,10 +16488,30 @@ snapshots: tsx: 4.21.0 yaml: 2.8.0 - vitest@3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): + vite@7.3.0(@types/node@24.0.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): + dependencies: + esbuild: 0.27.3 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.50.0 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 24.0.3 + fsevents: 2.3.3 + jiti: 2.6.0 + less: 4.5.1 + lightningcss: 1.30.1 + sass: 1.97.1 + sass-embedded: 1.92.1 + terser: 5.39.2 + tsx: 4.21.0 + yaml: 2.8.0 + + vitest@3.0.8(@types/node@20.12.7)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): dependencies: '@vitest/expect': 3.0.8 - '@vitest/mocker': 3.0.8(vite@6.4.1(@types/node@20.12.7)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + '@vitest/mocker': 3.0.8(vite@6.4.1(@types/node@20.12.7)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) '@vitest/pretty-format': 3.1.3 '@vitest/runner': 3.0.8 '@vitest/snapshot': 3.0.8 @@ -13965,8 +16527,8 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.4.1(@types/node@20.12.7)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) - vite-node: 3.0.8(@types/node@20.12.7)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite: 6.4.1(@types/node@20.12.7)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite-node: 3.0.8(@types/node@20.12.7)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.75.0)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.12.7 @@ -13985,32 +16547,32 @@ snapshots: - tsx - yaml - vitest@3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@26.1.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): + vitest@3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@26.1.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): dependencies: '@vitest/expect': 3.1.3 - '@vitest/mocker': 3.1.3(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + '@vitest/mocker': 3.1.3(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) '@vitest/pretty-format': 3.1.3 '@vitest/runner': 3.1.3 '@vitest/snapshot': 3.1.3 '@vitest/spy': 3.1.3 '@vitest/utils': 3.1.3 chai: 5.2.0 - debug: 4.4.1 + debug: 4.4.3 expect-type: 1.2.1 magic-string: 0.30.17 pathe: 2.0.3 std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) - vite-node: 3.1.3(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite: 6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite-node: 3.1.3(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.15.3 - '@vitest/browser': 3.1.3(playwright@1.58.2)(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3) + '@vitest/browser': 3.1.3(playwright@1.58.2)(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3) jsdom: 26.1.0 transitivePeerDependencies: - jiti @@ -14026,32 +16588,32 @@ snapshots: - tsx - yaml - vitest@3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): + vitest@3.1.3(@types/node@22.15.3)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): dependencies: '@vitest/expect': 3.1.3 - '@vitest/mocker': 3.1.3(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + '@vitest/mocker': 3.1.3(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) '@vitest/pretty-format': 3.1.3 '@vitest/runner': 3.1.3 '@vitest/snapshot': 3.1.3 '@vitest/spy': 3.1.3 '@vitest/utils': 3.1.3 chai: 5.2.0 - debug: 4.4.1 + debug: 4.4.3 expect-type: 1.2.1 magic-string: 0.30.17 pathe: 2.0.3 std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) - vite-node: 3.1.3(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite: 6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite-node: 3.1.3(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.15.3 - '@vitest/browser': 3.1.3(playwright@1.55.1)(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3) + '@vitest/browser': 3.1.3(playwright@1.55.1)(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3) jsdom: 27.4.0 transitivePeerDependencies: - jiti @@ -14067,32 +16629,32 @@ snapshots: - tsx - yaml - vitest@3.1.3(@types/node@22.15.30)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): + vitest@3.1.3(@types/node@22.15.30)(@vitest/browser@3.1.3)(jiti@2.6.0)(jsdom@27.4.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0): dependencies: '@vitest/expect': 3.1.3 - '@vitest/mocker': 3.1.3(vite@6.4.1(@types/node@22.15.30)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) + '@vitest/mocker': 3.1.3(vite@6.4.1(@types/node@22.15.30)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0)) '@vitest/pretty-format': 3.1.3 '@vitest/runner': 3.1.3 '@vitest/snapshot': 3.1.3 '@vitest/spy': 3.1.3 '@vitest/utils': 3.1.3 chai: 5.2.0 - debug: 4.4.1 + debug: 4.4.3 expect-type: 1.2.1 magic-string: 0.30.17 pathe: 2.0.3 std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.4.1(@types/node@22.15.30)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) - vite-node: 3.1.3(@types/node@22.15.30)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite: 6.4.1(@types/node@22.15.30)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) + vite-node: 3.1.3(@types/node@22.15.30)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.15.30 - '@vitest/browser': 3.1.3(playwright@1.58.2)(vite@6.4.1(@types/node@22.15.30)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3) + '@vitest/browser': 3.1.3(playwright@1.58.2)(vite@6.4.1(@types/node@22.15.30)(jiti@2.6.0)(less@4.5.1)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.97.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3) jsdom: 27.4.0 transitivePeerDependencies: - jiti @@ -14158,10 +16720,18 @@ snapshots: dependencies: xml-name-validator: 5.0.0 + watchpack@2.5.0: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + wcwidth@1.0.1: dependencies: defaults: 1.0.4 + weak-lru-cache@1.2.2: + optional: true + webidl-conversions@3.0.1: {} webidl-conversions@7.0.0: {} @@ -14247,6 +16817,12 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -14259,6 +16835,12 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.2 + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.1.2 + wrappy@1.0.2: {} write-file-atomic@5.0.1: @@ -14292,6 +16874,8 @@ snapshots: yargs-parser@21.1.1: {} + yargs-parser@22.0.0: {} + yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -14302,4 +16886,19 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yargs@18.0.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 7.2.0 + y18n: 5.0.8 + yargs-parser: 22.0.0 + yocto-queue@0.1.0: {} + + yoctocolors-cjs@2.1.3: {} + + yoctocolors@2.1.2: {} + + zone.js@0.16.1: {} diff --git a/samples/teamspace-angular/.env.local.example b/samples/teamspace-angular/.env.local.example new file mode 100644 index 000000000..da7cf4a6a --- /dev/null +++ b/samples/teamspace-angular/.env.local.example @@ -0,0 +1,5 @@ +# Asgardeo Configuration +VITE_ASGARDEO_BASE_URL='https://api.asgardeo.io/t/' +VITE_ASGARDEO_CLIENT_ID='' +VITE_ASGARDEO_AFTER_SIGN_IN_URL='https://localhost:5173/dashboard' +VITE_ASGARDEO_AFTER_SIGN_OUT_URL='https://localhost:5173' diff --git a/samples/teamspace-angular/.gitignore b/samples/teamspace-angular/.gitignore new file mode 100644 index 000000000..cbdfe197f --- /dev/null +++ b/samples/teamspace-angular/.gitignore @@ -0,0 +1,27 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local +# allow .env.local.example to be committed with sample values. +!.env.local.example + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +.angular diff --git a/samples/teamspace-angular/index.html b/samples/teamspace-angular/index.html new file mode 100644 index 000000000..11763a2e8 --- /dev/null +++ b/samples/teamspace-angular/index.html @@ -0,0 +1,14 @@ + + + + + + + Teamspace Angular + + + + + + + diff --git a/samples/teamspace-angular/package.json b/samples/teamspace-angular/package.json new file mode 100644 index 000000000..4f496c25c --- /dev/null +++ b/samples/teamspace-angular/package.json @@ -0,0 +1,34 @@ +{ + "private": true, + "name": "@asgardeo/teamspace-angular", + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "@asgardeo/angular": "workspace:*", + "@angular/common": "21.1.5", + "@angular/core": "21.1.5", + "@angular/forms": "21.1.5", + "@angular/platform-browser": "21.1.5", + "@angular/platform-browser-dynamic": "21.1.5", + "@angular/router": "21.1.5", + "rxjs": "7.8.1", + "tslib": "2.8.1", + "zone.js": "0.16.1" + }, + "devDependencies": { + "@analogjs/vite-plugin-angular": "2.2.3", + "@angular/build": "21.1.4", + "@angular/compiler": "21.1.5", + "@angular/compiler-cli": "21.1.5", + "@tailwindcss/vite": "4.1.8", + "@vitejs/plugin-basic-ssl": "2.0.0", + "tailwindcss": "4.1.8", + "typescript": "5.9.3", + "vite": "6.4.1" + } +} diff --git a/samples/teamspace-angular/public/vite.svg b/samples/teamspace-angular/public/vite.svg new file mode 100644 index 000000000..e7b8dfb1b --- /dev/null +++ b/samples/teamspace-angular/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/samples/teamspace-angular/src/app/app.component.ts b/samples/teamspace-angular/src/app/app.component.ts new file mode 100644 index 000000000..12d455b92 --- /dev/null +++ b/samples/teamspace-angular/src/app/app.component.ts @@ -0,0 +1,10 @@ +import {Component} from '@angular/core'; +import {RouterOutlet} from '@angular/router'; + +@Component({ + selector: 'app-root', + standalone: true, + imports: [RouterOutlet], + template: '', +}) +export class AppComponent {} diff --git a/samples/teamspace-angular/src/app/app.config.ts b/samples/teamspace-angular/src/app/app.config.ts new file mode 100644 index 000000000..d5fdca589 --- /dev/null +++ b/samples/teamspace-angular/src/app/app.config.ts @@ -0,0 +1,21 @@ +import {ApplicationConfig, provideZoneChangeDetection} from '@angular/core'; +import {provideRouter} from '@angular/router'; +import {provideHttpClient, withInterceptors} from '@angular/common/http'; +import {provideAsgardeo, asgardeoInterceptor} from '@asgardeo/angular'; +import {routes} from './app.routes'; + +export const appConfig: ApplicationConfig = { + providers: [ + provideZoneChangeDetection({eventCoalescing: true}), + provideRouter(routes), + provideHttpClient(withInterceptors([asgardeoInterceptor])), + provideAsgardeo({ + baseUrl: import.meta.env['VITE_ASGARDEO_BASE_URL'] || '', + clientId: import.meta.env['VITE_ASGARDEO_CLIENT_ID'] || '', + afterSignInUrl: import.meta.env['VITE_ASGARDEO_AFTER_SIGN_IN_URL'] || window.location.origin + '/dashboard', + afterSignOutUrl: import.meta.env['VITE_ASGARDEO_AFTER_SIGN_OUT_URL'] || window.location.origin, + scopes: + 'openid address email profile internal_organization_create internal_organization_view internal_organization_update internal_organization_delete internal_org_organization_update internal_org_organization_create internal_org_organization_view internal_org_organization_delete', + }), + ], +}; diff --git a/samples/teamspace-angular/src/app/app.routes.ts b/samples/teamspace-angular/src/app/app.routes.ts new file mode 100644 index 000000000..c29ca5272 --- /dev/null +++ b/samples/teamspace-angular/src/app/app.routes.ts @@ -0,0 +1,13 @@ +import {Routes} from '@angular/router'; +import {authGuard} from './guards/auth.guard'; + +export const routes: Routes = [ + {path: '', loadComponent: () => import('./pages/landing.component').then(m => m.LandingComponent)}, + {path: 'callback', loadComponent: () => import('./pages/callback.component').then(m => m.CallbackPageComponent)}, + {path: 'dashboard', loadComponent: () => import('./pages/dashboard.component').then(m => m.DashboardComponent), canActivate: [authGuard]}, + {path: 'profile', loadComponent: () => import('./pages/profile.component').then(m => m.ProfileComponent), canActivate: [authGuard]}, + {path: 'organizations', loadComponent: () => import('./pages/organizations.component').then(m => m.OrganizationsComponent), canActivate: [authGuard]}, + {path: 'organizations/new', loadComponent: () => import('./pages/create-org.component').then(m => m.CreateOrgComponent), canActivate: [authGuard]}, + {path: 'debug', loadComponent: () => import('./pages/debug.component').then(m => m.DebugComponent), canActivate: [authGuard]}, + {path: '**', redirectTo: ''}, +]; diff --git a/samples/teamspace-angular/src/app/components/header.component.ts b/samples/teamspace-angular/src/app/components/header.component.ts new file mode 100644 index 000000000..5f25b0a18 --- /dev/null +++ b/samples/teamspace-angular/src/app/components/header.component.ts @@ -0,0 +1,400 @@ +import {Component, inject, signal, HostListener, computed} from '@angular/core'; +import {RouterLink} from '@angular/router'; +import {AsgardeoAuthService, AsgardeoSignedInDirective, AsgardeoSignedOutDirective, AsgardeoUserProfileComponent, AsgardeoOrganizationSwitcherComponent} from '@asgardeo/angular'; + +@Component({ + selector: 'app-header', + standalone: true, + imports: [RouterLink, AsgardeoSignedInDirective, AsgardeoSignedOutDirective, AsgardeoUserProfileComponent, AsgardeoOrganizationSwitcherComponent], + template: ` +
+
+
+ + + + + + + +
+ +
+ +
+ + +
+ + + @if (dropdownOpen()) { +
+ +
+ @if (getProfileUrl(); as url) { + + } @else { +
+ {{ getInitials() }} +
+ } +
+ {{ getDisplayName() }} + {{ getUserName() }} +
+
+ + +
+ + + + + Dashboard + + + + + + Organizations + + + + + + Debug + + + +
+ + + + + + +
+
+ } +
+ + + @if (!authService.isSignedIn()) { +
+ + +
+ } +
+
+
+
+ + + + `, + styles: ` + /* Matches the React SDK's BaseUserDropdown styles */ + .asgardeo-user-dropdown__trigger { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 4px; + background: none; + border: none; + cursor: pointer; + border-radius: 8px; + transition: none; + box-shadow: none; + + &:hover { + background-color: rgba(0, 0, 0, 0.05); + } + + &:focus { + outline: 2px solid #4f46e5; + outline-offset: 2px; + } + } + + .asgardeo-avatar { + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 500; + overflow: hidden; + flex-shrink: 0; + } + + .asgardeo-avatar img { + width: 100%; + height: 100%; + object-fit: cover; + } + + .asgardeo-user-dropdown__content { + position: absolute; + right: 0; + margin-top: 5px; + min-width: 250px; + max-width: 600px; + background: #fff; + border-radius: 12px; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + border: 1px solid #e5e7eb; + overflow: hidden; + z-index: 9999; + } + + .asgardeo-user-dropdown__header { + display: flex; + align-items: center; + gap: 8px; + padding: 12px; + border-bottom: 1px solid #e5e7eb; + } + + .asgardeo-user-dropdown__header-info { + display: flex; + flex-direction: column; + gap: 2px; + flex: 1; + min-width: 0; + overflow: hidden; + } + + .asgardeo-user-dropdown__header-name { + font-size: 1rem; + font-weight: 500; + color: #111827; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .asgardeo-user-dropdown__header-email { + font-size: 0.875rem; + color: #6b7280; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .asgardeo-user-dropdown__menu { + display: flex; + flex-direction: column; + width: 100%; + } + + .asgardeo-user-dropdown__menu-item { + display: flex; + align-items: center; + gap: 8px; + padding: 10px 16px; + width: 100%; + color: #111827; + text-decoration: none; + border: none; + background: transparent; + cursor: pointer; + font-size: 0.875rem; + text-align: start; + border-radius: 0; + font-family: inherit; + + &:hover { + background-color: rgba(0, 0, 0, 0.05); + } + } + + .asgardeo-user-dropdown__menu-divider { + margin: 4px 0; + border-bottom: 1px solid #e5e7eb; + } + `, +}) +export class HeaderComponent { + authService = inject(AsgardeoAuthService); + dropdownOpen = signal(false); + showProfile = signal(false); + signingIn = signal(false); + + /** Computed gradient background matching the React SDK Avatar's name-seeded algorithm */ + avatarGradient = computed(() => { + const name = this.getDisplayName(); + if (!name) return 'linear-gradient(135deg, #6366f1, #8b5cf6)'; + return this.generateBackgroundColor(name); + }); + + @HostListener('document:click') + onDocumentClick(): void { + if (this.dropdownOpen()) { + this.dropdownOpen.set(false); + } + } + + toggleDropdown(event: Event): void { + event.stopPropagation(); + this.dropdownOpen.update(v => !v); + } + + closeDropdown(): void { + this.dropdownOpen.set(false); + } + + getProfileUrl(): string | null { + const user = this.authService.user(); + if (!user) return null; + return ( + (user as any)['profile'] || + (user as any)['profileUrl'] || + (user as any)['picture'] || + (user as any)['URL'] || + null + ); + } + + getUserName(): string { + const user = this.authService.user(); + if (!user) return ''; + return (user as any)['userName'] || (user as any)['username'] || (user as any)['user_name'] || ''; + } + + getEmail(): string { + const user = this.authService.user(); + if (!user) return ''; + const emails = (user as any)['emails']; + if (Array.isArray(emails)) return emails[0] || ''; + return (user as any)['email'] || ''; + } + + getDisplayName(): string { + const user = this.authService.user(); + if (!user) return ''; + const firstName = + (user as any)['name']?.['givenName'] || (user as any)['given_name'] || ''; + const lastName = + (user as any)['name']?.['familyName'] || (user as any)['family_name'] || ''; + if (firstName && lastName) return `${firstName} ${lastName}`; + return this.getUserName() || this.getEmail() || (user as any)['name'] || 'User'; + } + + getInitials(): string { + const name = this.getDisplayName(); + return name + .split(' ') + .map((part: string) => part[0]) + .slice(0, 2) + .join('') + .toUpperCase(); + } + + openProfile(): void { + this.closeDropdown(); + this.showProfile.set(true); + } + + signIn(): void { + this.signingIn.set(true); + this.authService.signIn(); + } + + signUp(): void { + this.authService.signUp(); + } + + signOut(): void { + this.closeDropdown(); + this.authService.signOut(); + } + + /** Same algorithm as React SDK's Avatar component for name-seeded gradient */ + private generateBackgroundColor(inputString: string): string { + let hash = inputString.split('').reduce((acc: number, char: string) => { + const charCode = char.charCodeAt(0); + return ((acc << 5) - acc + charCode) & 0xffffffff; + }, 0); + + const seed = Math.abs(hash); + const hue1 = (seed + seed) % 360; + const hue2 = (hue1 + 60 + (seed % 120)) % 360; + const saturation = 70 + (seed % 20); + const lightness1 = 55 + (seed % 15); + const lightness2 = 60 + ((seed + seed) % 15); + const angle = 45 + (seed % 91); + + return `linear-gradient(${angle}deg, hsl(${hue1}, ${saturation}%, ${lightness1}%), hsl(${hue2}, ${saturation}%, ${lightness2}%))`; + } +} diff --git a/samples/teamspace-angular/src/app/guards/auth.guard.ts b/samples/teamspace-angular/src/app/guards/auth.guard.ts new file mode 100644 index 000000000..337a4e2e4 --- /dev/null +++ b/samples/teamspace-angular/src/app/guards/auth.guard.ts @@ -0,0 +1,60 @@ +import {inject} from '@angular/core'; +import {CanActivateFn, Router, UrlTree} from '@angular/router'; +import {AsgardeoAuthService} from '@asgardeo/angular'; + +/** + * Auth guard that waits for the OAuth token exchange to complete + * before checking authentication status. + * + * The SDK's APP_INITIALIZER may resolve before the async token exchange finishes, + * so this guard polls isSignedIn() when OAuth params are detected in the URL. + */ +export const authGuard: CanActivateFn = async (): Promise => { + const authService = inject(AsgardeoAuthService); + const router = inject(Router); + + // If already signed in, allow immediately + if (authService.isSignedIn()) { + return true; + } + + // If the URL has OAuth params (code), the token exchange is likely in progress. + // Wait for it to complete. + const urlParams = new URLSearchParams(window.location.search); + if (urlParams.has('code')) { + await waitForSignal(() => authService.isSignedIn(), 10000); + + if (authService.isSignedIn()) { + router.navigateByUrl(window.location.pathname); + return true; + } + } + + // If still loading, wait for loading to finish + if (authService.isLoading()) { + await waitForSignal(() => !authService.isLoading(), 10000); + + if (authService.isSignedIn()) { + return true; + } + } + + // Not signed in — redirect to landing page + return router.createUrlTree(['/']); +}; + +function waitForSignal(predicate: () => boolean, timeoutMs: number): Promise { + return new Promise((resolve) => { + if (predicate()) { + resolve(); + return; + } + const start = Date.now(); + const interval = setInterval(() => { + if (predicate() || Date.now() - start > timeoutMs) { + clearInterval(interval); + resolve(); + } + }, 50); + }); +} diff --git a/samples/teamspace-angular/src/app/layouts/dashboard-layout.component.ts b/samples/teamspace-angular/src/app/layouts/dashboard-layout.component.ts new file mode 100644 index 000000000..571d15b38 --- /dev/null +++ b/samples/teamspace-angular/src/app/layouts/dashboard-layout.component.ts @@ -0,0 +1,17 @@ +import {Component} from '@angular/core'; +import {HeaderComponent} from '../components/header.component'; + +@Component({ + selector: 'app-dashboard-layout', + standalone: true, + imports: [HeaderComponent], + template: ` +
+ +
+ +
+
+ `, +}) +export class DashboardLayoutComponent {} diff --git a/samples/teamspace-angular/src/app/layouts/landing-layout.component.ts b/samples/teamspace-angular/src/app/layouts/landing-layout.component.ts new file mode 100644 index 000000000..6c0dfce43 --- /dev/null +++ b/samples/teamspace-angular/src/app/layouts/landing-layout.component.ts @@ -0,0 +1,15 @@ +import {Component} from '@angular/core'; +import {HeaderComponent} from '../components/header.component'; + +@Component({ + selector: 'app-landing-layout', + standalone: true, + imports: [HeaderComponent], + template: ` +
+ + +
+ `, +}) +export class LandingLayoutComponent {} diff --git a/samples/teamspace-angular/src/app/pages/callback.component.ts b/samples/teamspace-angular/src/app/pages/callback.component.ts new file mode 100644 index 000000000..e4c1e46b5 --- /dev/null +++ b/samples/teamspace-angular/src/app/pages/callback.component.ts @@ -0,0 +1,33 @@ +import {Component, effect, inject} from '@angular/core'; +import {Router} from '@angular/router'; +import {AsgardeoAuthService} from '@asgardeo/angular'; + +@Component({ + selector: 'app-callback-page', + standalone: true, + template: ` +
+
+
+

Processing authentication...

+
+
+ `, +}) +export class CallbackPageComponent { + private authService = inject(AsgardeoAuthService); + private router = inject(Router); + + constructor() { + effect(() => { + const loading = this.authService.isLoading(); + if (loading) return; + + if (this.authService.isSignedIn()) { + this.router.navigate(['/dashboard']); + } else { + this.router.navigate(['/']); + } + }); + } +} diff --git a/samples/teamspace-angular/src/app/pages/create-org.component.ts b/samples/teamspace-angular/src/app/pages/create-org.component.ts new file mode 100644 index 000000000..0c3e04fb9 --- /dev/null +++ b/samples/teamspace-angular/src/app/pages/create-org.component.ts @@ -0,0 +1,49 @@ +import {Component, inject} from '@angular/core'; +import {Router, RouterLink} from '@angular/router'; +import {AsgardeoCreateOrganizationComponent} from '@asgardeo/angular'; +import {HeaderComponent} from '../components/header.component'; + +@Component({ + selector: 'app-create-org', + standalone: true, + imports: [RouterLink, HeaderComponent, AsgardeoCreateOrganizationComponent], + template: ` +
+ + +
+ +
+ + + + + Back to organizations + +

Create a new organization

+

+ Organizations are shared accounts where teams can collaborate across many projects at once. +

+
+ +
+ +
+
+
+ `, +}) +export class CreateOrgComponent { + private router = inject(Router); + + onCreated(): void { + this.router.navigate(['/organizations']); + } + + onCancel(): void { + this.router.navigate(['/organizations']); + } +} diff --git a/samples/teamspace-angular/src/app/pages/dashboard.component.ts b/samples/teamspace-angular/src/app/pages/dashboard.component.ts new file mode 100644 index 000000000..5121e9a29 --- /dev/null +++ b/samples/teamspace-angular/src/app/pages/dashboard.component.ts @@ -0,0 +1,214 @@ +import {Component, computed, inject} from '@angular/core'; +import {RouterLink} from '@angular/router'; +import {AsgardeoAuthService} from '@asgardeo/angular'; +import {HeaderComponent} from '../components/header.component'; + +@Component({ + selector: 'app-dashboard', + standalone: true, + imports: [RouterLink, HeaderComponent], + template: ` +
+ + +
+ +
+

+ Welcome back {{ userFullName() }}! +

+ @if (authService.currentOrganization(); as org) { +

+ Here's what's happening with + {{ org.orgHandle ? '@' + org.orgHandle : org.name || org.id }} + today. +

+ } +
+ + +
+ @for (stat of stats; track stat.name) { +
+
+
+

{{ stat.name }}

+

{{ stat.value }}

+
+
+ + + +
+
+
+ + + + + {{ stat.change }} + + from last month +
+
+ } +
+ +
+ +
+
+

Recent Activity

+
+
+
+ @for (activity of recentActivity; track activity.id) { +
+
+
+ + + +
+
+
+

+ {{ activity.user }} {{ activity.action }} +

+

{{ activity.time }}

+
+
+ } +
+
+
+ + +
+
+

Upcoming Tasks

+
+
+
+ @for (task of upcomingTasks; track task.id) { +
+
+

{{ task.title }}

+

{{ task.project }}

+
+
+
+ + + + {{ task.dueDate }} +
+ + @if (task.priority === 'high') { + + + + } + {{ task.priority }} + +
+
+ } +
+
+
+
+
+
+ `, +}) +export class DashboardComponent { + authService = inject(AsgardeoAuthService); + + stats = [ + { + name: 'Active Projects', + value: '12', + change: '+2.1%', + changeType: 'positive', + iconPath: 'M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z', + }, + { + name: 'Team Members', + value: '0', + change: '+5.4%', + changeType: 'positive', + iconPath: 'M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z', + }, + { + name: 'Messages Today', + value: '89', + change: '+12.5%', + changeType: 'positive', + iconPath: 'M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z', + }, + { + name: 'Meetings This Week', + value: '7', + change: '-2.3%', + changeType: 'negative', + iconPath: 'M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z', + }, + ]; + + recentActivity = [ + { + id: 1, + user: 'Sarah Chen', + action: 'completed task "Design Review"', + time: '2 hours ago', + bgClass: 'bg-green-100', + iconClass: 'text-green-600', + iconPath: 'M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z', + }, + { + id: 2, + user: 'Mike Johnson', + action: 'created new project "Mobile App"', + time: '4 hours ago', + bgClass: 'bg-blue-100', + iconClass: 'text-blue-600', + iconPath: 'M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z', + }, + { + id: 3, + user: 'Emily Davis', + action: 'scheduled team meeting', + time: '6 hours ago', + bgClass: 'bg-purple-100', + iconClass: 'text-purple-600', + iconPath: 'M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z', + }, + { + id: 4, + user: 'Alex Rodriguez', + action: 'uploaded 3 files to "Q4 Planning"', + time: '1 day ago', + bgClass: 'bg-orange-100', + iconClass: 'text-orange-600', + iconPath: 'M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z', + }, + ]; + + upcomingTasks = [ + {id: 1, title: 'Review quarterly reports', dueDate: 'Today, 3:00 PM', priority: 'high', project: 'Q4 Planning'}, + {id: 2, title: 'Team standup meeting', dueDate: 'Tomorrow, 9:00 AM', priority: 'medium', project: 'Daily Operations'}, + {id: 3, title: 'Client presentation prep', dueDate: 'Friday, 2:00 PM', priority: 'high', project: 'Client Work'}, + ]; + + userFullName = computed(() => { + const user = this.authService.user(); + if (!user) return ''; + const givenName = (user as any)['givenName'] || (user as any)['name']?.['givenName'] || (user as any)['given_name'] || ''; + const familyName = (user as any)['name']?.['familyName'] || (user as any)['familyName'] || (user as any)['family_name'] || ''; + return [givenName, familyName].filter(Boolean).join(' '); + }); +} diff --git a/samples/teamspace-angular/src/app/pages/debug.component.ts b/samples/teamspace-angular/src/app/pages/debug.component.ts new file mode 100644 index 000000000..09e708712 --- /dev/null +++ b/samples/teamspace-angular/src/app/pages/debug.component.ts @@ -0,0 +1,236 @@ +import {Component, inject, signal, OnInit} from '@angular/core'; +import {JsonPipe} from '@angular/common'; +import {RouterLink} from '@angular/router'; +import {AsgardeoAuthService} from '@asgardeo/angular'; +import {HeaderComponent} from '../components/header.component'; + +@Component({ + selector: 'app-debug', + standalone: true, + imports: [JsonPipe, RouterLink, HeaderComponent], + template: ` +
+ + +
+ +
+ + + + + Back to dashboard + +

+ + + + Debug Information +

+

View session data and decoded tokens for debugging purposes.

+
+ + +
+
+

Signed In

+

+ {{ authService.isSignedIn() ? 'Yes' : 'No' }} +

+
+
+

Loading

+

+ {{ authService.isLoading() ? 'Yes' : 'No' }} +

+
+
+

Initialized

+

+ {{ authService.isInitialized() ? 'Yes' : 'No' }} +

+
+
+ +
+ +
+
+

Access Token

+ +
+
+ @if (accessToken()) { +
+
{{ accessToken() }}
+
+ } @else { +

No access token available

+ } +
+
+ + +
+
+

ID Token (JWT)

+ +
+
+ @if (idToken()) { +
+
{{ idToken() }}
+
+ } @else { +

No ID token available

+ } +
+
+ + +
+
+

Decoded ID Token

+ +
+
+ @if (decodedIdToken()) { +
+
{{ decodedIdToken() | json }}
+
+ } @else { +

No decoded ID token available

+ } +
+
+ + +
+
+

User Signal

+
+
+ @if (authService.user()) { +
+
{{ authService.user() | json }}
+
+ } @else { +

No user data available

+ } +
+
+ + +
+
+

Current Organization

+
+
+ @if (authService.currentOrganization()) { +
+
{{ authService.currentOrganization() | json }}
+
+ } @else { +

No organization context

+ } +
+
+ + +
+
+

My Organizations

+
+
+ @if (authService.myOrganizations().length > 0) { +
+
{{ authService.myOrganizations() | json }}
+
+ } @else { +

No organizations

+ } +
+
+
+ + +
+
+

SDK Configuration

+
+
+
+
{{ getConfig() | json }}
+
+
+
+
+
+ `, +}) +export class DebugComponent implements OnInit { + authService = inject(AsgardeoAuthService); + + accessToken = signal(null); + idToken = signal(null); + decodedIdToken = signal | null>(null); + + ngOnInit(): void { + this.fetchAll(); + } + + async fetchAll(): Promise { + await Promise.all([this.fetchAccessToken(), this.fetchIdToken(), this.fetchDecodedIdToken()]); + } + + async fetchAccessToken(): Promise { + try { + const token = await this.authService.getAccessToken(); + this.accessToken.set(token); + } catch { + this.accessToken.set(null); + } + } + + async fetchIdToken(): Promise { + try { + const token = await this.authService.getIdToken(); + this.idToken.set(token); + } catch { + this.idToken.set(null); + } + } + + async fetchDecodedIdToken(): Promise { + try { + const token = await this.authService.getDecodedIdToken(); + this.decodedIdToken.set(token as Record); + } catch { + this.decodedIdToken.set(null); + } + } + + getConfig(): Record { + try { + const config = this.authService.getConfiguration(); + return config as unknown as Record; + } catch { + return {}; + } + } +} diff --git a/samples/teamspace-angular/src/app/pages/landing.component.ts b/samples/teamspace-angular/src/app/pages/landing.component.ts new file mode 100644 index 000000000..bf48855c1 --- /dev/null +++ b/samples/teamspace-angular/src/app/pages/landing.component.ts @@ -0,0 +1,264 @@ +import {Component, inject, signal} from '@angular/core'; +import {RouterLink} from '@angular/router'; +import { + AsgardeoAuthService, + AsgardeoSignedInDirective, +} from '@asgardeo/angular'; +import {HeaderComponent} from '../components/header.component'; + +@Component({ + selector: 'app-landing', + standalone: true, + imports: [RouterLink, HeaderComponent, AsgardeoSignedInDirective], + template: ` +
+ + + +
+
+
+
+ Powered by Asgardeo Angular SDK +
+ +

+ Where teams + collaborate and ideas come to life +

+ +

+ Streamline your team's workflow with our all-in-one collaboration platform. Built with Angular and + Asgardeo authentication. +

+ + @if (!authService.isSignedIn()) { +
+ + +
+ } + + + +
+
+ + + + Redirect-based authentication +
+
+ + + + Angular Signals +
+
+
+
+
+ + +
+
+
+

SDK Features Demonstrated

+
+
+
+
3
+
Services
+
+
+
3
+
Directives
+
+
+
1
+
Route Guard
+
+
+
1
+
HTTP Interceptor
+
+
+
+
+ + +
+
+
+

SDK Features

+

+ This sample app demonstrates all the key features of the Asgardeo Angular SDK. +

+
+ +
+
+
+ + + +
+

Redirect Authentication

+

+ Sign in and sign up via Asgardeo's hosted login page with OAuth 2.0 redirect flow. +

+
+ +
+
+ + + +
+

Route Guards

+

+ Protect routes with asgardeoGuard — automatically redirects unauthenticated users. +

+
+ +
+
+ + + +
+

User Profile

+

+ Access user data via Angular Signals — user, userProfile, flattenedProfile, and more. +

+
+ +
+
+ + + +
+

Organizations

+

+ List, create, and switch between organizations using AsgardeoOrganizationService. +

+
+ +
+
+ + + +
+

Token Management

+

+ Access and decode tokens, with automatic Bearer token attachment via HTTP interceptor. +

+
+ +
+
+ + + +
+

Structural Directives

+

+ Conditionally render content with *asgardeoSignedIn, *asgardeoSignedOut, and *asgardeoLoading. +

+
+
+
+
+ + +
+
+
+
+ T +
+ Teamspace +
+

+ Built with Angular 21 and @asgardeo/angular SDK. A sample application for demonstration purposes. +

+
+
+
+ `, +}) +export class LandingComponent { + authService = inject(AsgardeoAuthService); + signingIn = signal(false); + + signIn(): void { + this.signingIn.set(true); + this.authService.signIn(); + } + + signUp(): void { + this.authService.signUp(); + } +} diff --git a/samples/teamspace-angular/src/app/pages/organizations.component.ts b/samples/teamspace-angular/src/app/pages/organizations.component.ts new file mode 100644 index 000000000..7c60a3ec9 --- /dev/null +++ b/samples/teamspace-angular/src/app/pages/organizations.component.ts @@ -0,0 +1,47 @@ +import {Component} from '@angular/core'; +import {RouterLink} from '@angular/router'; +import {AsgardeoOrganizationListComponent} from '@asgardeo/angular'; +import {HeaderComponent} from '../components/header.component'; + +@Component({ + selector: 'app-organizations', + standalone: true, + imports: [RouterLink, HeaderComponent, AsgardeoOrganizationListComponent], + template: ` +
+ + +
+ +
+ + + + + Back to dashboard + +
+
+

Organizations

+

Manage your organizations and switch between them

+
+ + + + + New Organization + +
+
+ +
+ +
+
+
+ `, +}) +export class OrganizationsComponent {} diff --git a/samples/teamspace-angular/src/app/pages/profile.component.ts b/samples/teamspace-angular/src/app/pages/profile.component.ts new file mode 100644 index 000000000..595bfb1ec --- /dev/null +++ b/samples/teamspace-angular/src/app/pages/profile.component.ts @@ -0,0 +1,154 @@ +import {Component, inject} from '@angular/core'; +import {RouterLink} from '@angular/router'; +import {JsonPipe} from '@angular/common'; +import {AsgardeoAuthService} from '@asgardeo/angular'; +import {HeaderComponent} from '../components/header.component'; + +@Component({ + selector: 'app-profile', + standalone: true, + imports: [RouterLink, JsonPipe, HeaderComponent], + template: ` +
+ + +
+ +
+ + + + + Back to dashboard + +

Profile

+

+ View your profile information, including your display name, email, and other details. +

+
+ + @if (authService.isLoading()) { +
+
+
+ } @else { + +
+ +
+
+
+ {{ getInitials() }} +
+
+

{{ getDisplayName() }}

+ @if (getEmail()) { +

{{ getEmail() }}

+ } +
+
+
+ + +
+ @if (authService.flattenedProfile(); as profile) { + +
+

Basic Information

+
+ @if (profile['given_name'] || profile['name']?.['givenName']) { +
+ First Name + {{ profile['given_name'] || profile['name']?.['givenName'] }} +
+ } + @if (profile['family_name'] || profile['name']?.['familyName']) { +
+ Last Name + {{ profile['family_name'] || profile['name']?.['familyName'] }} +
+ } + @if (getEmail()) { +
+ Email + {{ getEmail() }} +
+ } + @if (profile['phone_number']) { +
+ Phone + {{ profile['phone_number'] }} +
+ } + @if (profile['sub']) { +
+ User ID + {{ profile['sub'] }} +
+ } +
+
+ } + + +
+

Raw Profile Data

+
+
{{ authService.flattenedProfile() | json }}
+
+
+ + +
+ +
+
+
+ } +
+
+ `, +}) +export class ProfileComponent { + authService = inject(AsgardeoAuthService); + + getDisplayName(): string { + const profile = this.authService.flattenedProfile(); + if (!profile) return 'User'; + return ( + (profile as Record)['given_name'] || + (profile as Record)['name']?.['givenName'] || + (profile as Record)['email'] || + 'User' + ); + } + + getEmail(): string { + const profile = this.authService.flattenedProfile(); + if (!profile) return ''; + return (profile as Record)['email'] || ''; + } + + getInitials(): string { + const name = this.getDisplayName(); + return name + .split(' ') + .map((n: string) => n[0]) + .join('') + .toUpperCase() + .slice(0, 2); + } + + async refresh(): Promise { + await this.authService.reInitialize({}); + } +} diff --git a/samples/teamspace-angular/src/env.d.ts b/samples/teamspace-angular/src/env.d.ts new file mode 100644 index 000000000..f481c1db3 --- /dev/null +++ b/samples/teamspace-angular/src/env.d.ts @@ -0,0 +1,16 @@ +/// + +interface ImportMetaEnv { + readonly VITE_ASGARDEO_BASE_URL: string; + readonly VITE_ASGARDEO_CLIENT_ID: string; + readonly VITE_ASGARDEO_AFTER_SIGN_IN_URL?: string; + readonly VITE_ASGARDEO_AFTER_SIGN_OUT_URL?: string; + readonly VITE_ASGARDEO_SIGN_IN_URL?: string; + readonly VITE_ASGARDEO_SIGN_UP_URL?: string; + readonly VITE_ASGARDEO_APPLICATION_ID?: string; + readonly VITE_ASGARDEO_PLATFORM?: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/samples/teamspace-angular/src/main.ts b/samples/teamspace-angular/src/main.ts new file mode 100644 index 000000000..698395dce --- /dev/null +++ b/samples/teamspace-angular/src/main.ts @@ -0,0 +1,7 @@ +import 'zone.js'; +import '@angular/compiler'; +import {bootstrapApplication} from '@angular/platform-browser'; +import {AppComponent} from './app/app.component'; +import {appConfig} from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err: unknown) => console.error(err)); diff --git a/samples/teamspace-angular/src/styles.css b/samples/teamspace-angular/src/styles.css new file mode 100644 index 000000000..0ff56f21d --- /dev/null +++ b/samples/teamspace-angular/src/styles.css @@ -0,0 +1,32 @@ +@import "tailwindcss"; +@source "./**/*.ts"; + +:root { + --radius: 0.625rem; +} + +/* Custom scrollbar */ +::-webkit-scrollbar { + width: 6px; +} + +::-webkit-scrollbar-track { + background: #f1f5f9; +} + +::-webkit-scrollbar-thumb { + background: #cbd5e1; + border-radius: 3px; +} + +::-webkit-scrollbar-thumb:hover { + background: #94a3b8; +} + +body { + font-family: + -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; + margin: 0; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/samples/teamspace-angular/tsconfig.app.json b/samples/teamspace-angular/tsconfig.app.json new file mode 100644 index 000000000..22fef6040 --- /dev/null +++ b/samples/teamspace-angular/tsconfig.app.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./dist/out-tsc", + "types": ["node"] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.ts"] +} diff --git a/samples/teamspace-angular/tsconfig.json b/samples/teamspace-angular/tsconfig.json new file mode 100644 index 000000000..c3088529a --- /dev/null +++ b/samples/teamspace-angular/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "bundler", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "declaration": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + "isolatedModules": true, + "useDefineForClassFields": false, + "sourceMap": true, + "outDir": "./dist/out-tsc", + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/samples/teamspace-angular/vite.config.ts b/samples/teamspace-angular/vite.config.ts new file mode 100644 index 000000000..f8f4c6576 --- /dev/null +++ b/samples/teamspace-angular/vite.config.ts @@ -0,0 +1,11 @@ +import {defineConfig} from 'vite'; +import angular from '@analogjs/vite-plugin-angular'; +import tailwindcss from '@tailwindcss/vite'; +import basicSsl from '@vitejs/plugin-basic-ssl'; + +export default defineConfig({ + plugins: [angular(), tailwindcss(), basicSsl()], + resolve: { + mainFields: ['browser', 'module', 'main'], + }, +}); diff --git a/tsconfig.json b/tsconfig.json index dc121f199..c88e56dc4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,7 @@ "baseUrl": ".", "paths": { "@asgardeo/react": ["packages/react/src/index.ts"], + "@asgardeo/angular": ["packages/angular/src/index.ts"], } } }