diff --git a/common/api-review/telemetry-angular.api.md b/common/api-review/telemetry-angular.api.md new file mode 100644 index 00000000000..b0078e25fc1 --- /dev/null +++ b/common/api-review/telemetry-angular.api.md @@ -0,0 +1,32 @@ +## API Report File for "@firebase/telemetry-angular" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { ErrorHandler } from '@angular/core'; +import { FirebaseApp } from '@firebase/app'; +import { LoggerProvider } from '@opentelemetry/sdk-logs'; + +// @public (undocumented) +export class FirebaseErrorHandler implements ErrorHandler { + constructor(telemetryOptions?: TelemetryOptions | undefined); + // (undocumented) + handleError(error: unknown): void; + } + +// @public +export interface Telemetry { + app: FirebaseApp; + loggerProvider: LoggerProvider; +} + +// @public +export interface TelemetryOptions { + endpointUrl?: string; +} + + +// (No @packageDocumentation comment for this package) + +``` diff --git a/docs-devsite/_toc.yaml b/docs-devsite/_toc.yaml index 81078cb2618..edf5621e889 100644 --- a/docs-devsite/_toc.yaml +++ b/docs-devsite/_toc.yaml @@ -701,6 +701,15 @@ toc: path: /docs/reference/js/telemetry_.telemetry.md - title: TelemetryOptions path: /docs/reference/js/telemetry_.telemetryoptions.md +- title: telemetry/angular + path: /docs/reference/js/telemetry_angular.md + section: + - title: FirebaseErrorHandler + path: /docs/reference/js/telemetry_angular.firebaseerrorhandler.md + - title: Telemetry + path: /docs/reference/js/telemetry_angular.telemetry.md + - title: TelemetryOptions + path: /docs/reference/js/telemetry_angular.telemetryoptions.md - title: telemetry/react path: /docs/reference/js/telemetry_react.md section: diff --git a/docs-devsite/telemetry.md b/docs-devsite/telemetry.md index c533e886f4f..8ddb78b2787 100644 --- a/docs-devsite/telemetry.md +++ b/docs-devsite/telemetry.md @@ -14,5 +14,6 @@ https://github.com/firebase/firebase-js-sdk | Entry Point | Description | | --- | --- | | [/](./telemetry_.md#@firebase/telemetry) | | +| [/angular](./telemetry_angular.md#@firebase/telemetry/angular) | | | [/react](./telemetry_react.md#@firebase/telemetry/react) | | diff --git a/docs-devsite/telemetry_angular.firebaseerrorhandler.md b/docs-devsite/telemetry_angular.firebaseerrorhandler.md new file mode 100644 index 00000000000..11a115d9696 --- /dev/null +++ b/docs-devsite/telemetry_angular.firebaseerrorhandler.md @@ -0,0 +1,65 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# FirebaseErrorHandler class +Signature: + +```typescript +export declare class FirebaseErrorHandler implements ErrorHandler +``` +Implements: ErrorHandler + +## Constructors + +| Constructor | Modifiers | Description | +| --- | --- | --- | +| [(constructor)(telemetryOptions)](./telemetry_angular.firebaseerrorhandler.md#firebaseerrorhandlerconstructor) | | Constructs a new instance of the FirebaseErrorHandler class | + +## Methods + +| Method | Modifiers | Description | +| --- | --- | --- | +| [handleError(error)](./telemetry_angular.firebaseerrorhandler.md#firebaseerrorhandlerhandleerror) | | | + +## FirebaseErrorHandler.(constructor) + +Constructs a new instance of the `FirebaseErrorHandler` class + +Signature: + +```typescript +constructor(telemetryOptions?: TelemetryOptions | undefined); +``` + +#### Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| telemetryOptions | [TelemetryOptions](./telemetry_.telemetryoptions.md#telemetryoptions_interface) \| undefined | | + +## FirebaseErrorHandler.handleError() + +Signature: + +```typescript +handleError(error: unknown): void; +``` + +#### Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| error | unknown | | + +Returns: + +void + diff --git a/docs-devsite/telemetry_angular.md b/docs-devsite/telemetry_angular.md new file mode 100644 index 00000000000..bb341d2eb2e --- /dev/null +++ b/docs-devsite/telemetry_angular.md @@ -0,0 +1,26 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# @firebase/telemetry/angular + +## Classes + +| Class | Description | +| --- | --- | +| [FirebaseErrorHandler](./telemetry_angular.firebaseerrorhandler.md#firebaseerrorhandler_class) | | + +## Interfaces + +| Interface | Description | +| --- | --- | +| [Telemetry](./telemetry_angular.telemetry.md#telemetry_interface) | An instance of the Firebase Telemetry SDK.Do not create this instance directly. Instead, use [getTelemetry()](./telemetry_.md#gettelemetry_448bdc6). | +| [TelemetryOptions](./telemetry_angular.telemetryoptions.md#telemetryoptions_interface) | Options for initialized the Telemetry service using [getTelemetry()](./telemetry_.md#gettelemetry_448bdc6). | + diff --git a/docs-devsite/telemetry_angular.telemetry.md b/docs-devsite/telemetry_angular.telemetry.md new file mode 100644 index 00000000000..d376755090d --- /dev/null +++ b/docs-devsite/telemetry_angular.telemetry.md @@ -0,0 +1,48 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# Telemetry interface +An instance of the Firebase Telemetry SDK. + +Do not create this instance directly. Instead, use [getTelemetry()](./telemetry_.md#gettelemetry_448bdc6). + +Signature: + +```typescript +export interface Telemetry +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [app](./telemetry_angular.telemetry.md#telemetryapp) | [FirebaseApp](./app.firebaseapp.md#firebaseapp_interface) | The [FirebaseApp](./app.firebaseapp.md#firebaseapp_interface) this [Telemetry](./telemetry_.telemetry.md#telemetry_interface) instance is associated with. | +| [loggerProvider](./telemetry_angular.telemetry.md#telemetryloggerprovider) | LoggerProvider | The this [Telemetry](./telemetry_.telemetry.md#telemetry_interface) instance uses. | + +## Telemetry.app + +The [FirebaseApp](./app.firebaseapp.md#firebaseapp_interface) this [Telemetry](./telemetry_.telemetry.md#telemetry_interface) instance is associated with. + +Signature: + +```typescript +app: FirebaseApp; +``` + +## Telemetry.loggerProvider + +The this [Telemetry](./telemetry_.telemetry.md#telemetry_interface) instance uses. + +Signature: + +```typescript +loggerProvider: LoggerProvider; +``` diff --git a/docs-devsite/telemetry_angular.telemetryoptions.md b/docs-devsite/telemetry_angular.telemetryoptions.md new file mode 100644 index 00000000000..5a9075f49fa --- /dev/null +++ b/docs-devsite/telemetry_angular.telemetryoptions.md @@ -0,0 +1,35 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# TelemetryOptions interface +Options for initialized the Telemetry service using [getTelemetry()](./telemetry_.md#gettelemetry_448bdc6). + +Signature: + +```typescript +export interface TelemetryOptions +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [endpointUrl](./telemetry_angular.telemetryoptions.md#telemetryoptionsendpointurl) | string | The URL for the endpoint to which telemetry data should be sent, in the Open Telemetry format. By default, data will be sent to Firebase. | + +## TelemetryOptions.endpointUrl + +The URL for the endpoint to which telemetry data should be sent, in the Open Telemetry format. By default, data will be sent to Firebase. + +Signature: + +```typescript +endpointUrl?: string; +``` diff --git a/packages/telemetry/api-extractor.json b/packages/telemetry/api-extractor.json index 7bc55b00d75..e2abd62b21d 100644 --- a/packages/telemetry/api-extractor.json +++ b/packages/telemetry/api-extractor.json @@ -5,6 +5,10 @@ { "modulePath": "react", "filePath": "/dist/react/index.d.ts" + }, + { + "modulePath": "angular", + "filePath": "/dist/angular/index.d.ts" } ], "dtsRollup": { diff --git a/packages/telemetry/package.json b/packages/telemetry/package.json index 084b15d03f8..0393651a3a4 100644 --- a/packages/telemetry/package.json +++ b/packages/telemetry/package.json @@ -31,6 +31,18 @@ }, "default": "./dist/react/index.esm.js" }, + "./angular": { + "types": "./dist/angular/index-public.d.ts", + "node": { + "import": "./dist/angular/index.esm.js", + "default": "./dist/angular/index.cjs.js" + }, + "browser": { + "require": "./dist/angular/index.cjs.js", + "import": "./dist/angular/index.esm.js" + }, + "default": "./dist/angular/index.esm.js" + }, "./package.json": "./package.json" }, "files": [ @@ -39,6 +51,7 @@ "scripts": { "lint": "eslint -c .eslintrc.js '**/*.ts' --ignore-path '../../.gitignore'", "lint:fix": "eslint --fix -c .eslintrc.js '**/*.ts' --ignore-path '../../.gitignore'", + "build-only": "rollup -c", "build": "rollup -c && yarn api-report", "build:deps": "lerna run --scope @firebase/telemetry --include-dependencies build", "dev": "rollup -c -w", @@ -46,11 +59,12 @@ "test:ci": "node ../../scripts/run_tests_in_ci.js -s test:all", "test:all": "run-p --npm-path npm test:browser test:node", "test:browser": "karma start", - "test:node": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha **/*.test.ts src/**/*.test.ts --config ../../config/mocharc.node.js", + "test:node": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha **/*.test.ts src/**/*.test.ts --exclude src/angular/*.test.ts --config ../../config/mocharc.node.js", "trusted-type-check": "tsec -p tsconfig.json --noEmit", - "api-report": "yarn api-report:main && yarn api-report:react && yarn api-report:api-json", + "api-report": "yarn api-report:main && yarn api-report:react && yarn api-report:angular && yarn api-report:api-json", "api-report:main": "ts-node-script ../../repo-scripts/prune-dts/extract-public-api.ts --package telemetry --packageRoot . --typescriptDts ./dist/index.d.ts --rollupDts ./dist/private.d.ts --untrimmedRollupDts ./dist/internal.d.ts --publicDts ./dist/index-public.d.ts", "api-report:react": "ts-node-script ../../repo-scripts/prune-dts/extract-public-api.ts --package telemetry-react --packageRoot . --typescriptDts ./dist/react/index.d.ts --rollupDts ./dist/react/private.d.ts --untrimmedRollupDts ./dist/react/internal.d.ts --publicDts ./dist/react/index-public.d.ts", + "api-report:angular": "ts-node-script ../../repo-scripts/prune-dts/extract-public-api.ts --package telemetry-angular --packageRoot . --typescriptDts ./dist/angular/index.d.ts --rollupDts ./dist/angular/private.d.ts --untrimmedRollupDts ./dist/angular/internal.d.ts --publicDts ./dist/angular/index-public.d.ts", "api-report:api-json": "api-extractor run --local --verbose", "typings:public": "node ../../scripts/build/use_typings.js ./dist/index-public.d.ts" }, @@ -66,6 +80,12 @@ }, "@types/react": { "optional": true + }, + "@angular/core": { + "optional": true + }, + "@angular/router": { + "optional": true } }, "dependencies": { @@ -82,6 +102,11 @@ }, "license": "Apache-2.0", "devDependencies": { + "@angular/common": "19.2.15", + "@angular/compiler": "19.2.15", + "@angular/core": "19.2.15", + "@angular/platform-browser": "19.2.15", + "@angular/router": "19.2.15", "@firebase/app": "0.14.4", "@opentelemetry/sdk-trace-web": "2.1.0", "@rollup/plugin-json": "6.1.0", @@ -95,7 +120,9 @@ "rollup-plugin-copy": "3.5.0", "rollup-plugin-replace": "2.2.0", "rollup-plugin-typescript2": "0.36.0", - "typescript": "5.5.4" + "rxjs": "7.8.2", + "typescript": "5.5.4", + "zone.js": "0.15.1" }, "repository": { "directory": "packages/telemetry", diff --git a/packages/telemetry/rollup.config.js b/packages/telemetry/rollup.config.js index a9a6df94188..5ffe3844148 100644 --- a/packages/telemetry/rollup.config.js +++ b/packages/telemetry/rollup.config.js @@ -123,4 +123,56 @@ const reactBuilds = [ } ]; -export default [...browserBuilds, ...nodeBuilds, ...reactBuilds]; +const angularBuilds = [ + { + input: 'src/angular/index.ts', + output: { + file: pkg.exports['./angular'].browser.import, + format: 'es', + sourcemap: true + }, + plugins: [ + typescriptPlugin({ + typescript, + tsconfig: 'tsconfig.angular.json' + }), + json(), + copy({ + targets: [ + { + src: 'dist/src/angular/index.d.ts', + dest: 'dist/angular' + }, + { + src: 'dist/src/public-types.d.ts', + dest: 'dist' + } + ] + }) + ], + external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) + }, + { + input: 'src/angular/index.ts', + output: { + file: pkg.exports['./angular'].browser.require, + format: 'cjs', + sourcemap: true + }, + plugins: [ + typescriptPlugin({ + typescript, + tsconfig: 'tsconfig.angular.json' + }), + json() + ], + external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)) + } +]; + +export default [ + ...browserBuilds, + ...nodeBuilds, + ...reactBuilds, + ...angularBuilds +]; diff --git a/packages/telemetry/src/angular/index.test.ts b/packages/telemetry/src/angular/index.test.ts new file mode 100644 index 00000000000..044467d93d4 --- /dev/null +++ b/packages/telemetry/src/angular/index.test.ts @@ -0,0 +1,110 @@ +/** + * @license + * Copyright 2025 Google LLC + * + * Licensed 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 'zone.js'; +import 'zone.js/testing'; +import { expect, use } from 'chai'; +import sinonChai from 'sinon-chai'; +import chaiAsPromised from 'chai-as-promised'; +import { restore, stub } from 'sinon'; +import { FirebaseApp, deleteApp, initializeApp } from '@firebase/app'; +import * as telemetry from '../api'; +import { + Component, + Injector, + provideZoneChangeDetection, + runInInjectionContext +} from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { FirebaseErrorHandler } from '.'; +import { Telemetry } from '../public-types'; +import { Router, RouterModule } from '@angular/router'; +import { + BrowserTestingModule, + platformBrowserTesting +} from '@angular/platform-browser/testing'; + +use(sinonChai); +use(chaiAsPromised); + +TestBed.initTestEnvironment(BrowserTestingModule, platformBrowserTesting()); + +@Component({ template: '' }) +class DummyComponent {} + +describe('FirebaseErrorHandler', () => { + let errorHandler: FirebaseErrorHandler; + let router: Router; + let app: FirebaseApp; + + let fakeTelemetry: Telemetry; + + let captureErrorStub: sinon.SinonStub; + let getTelemetryStub: sinon.SinonStub; + + beforeEach(() => { + app = initializeApp({ projectId: 'p', appId: 'fakeapp' }); + fakeTelemetry = {} as Telemetry; + + captureErrorStub = stub(telemetry, 'captureError'); + getTelemetryStub = stub(telemetry, 'getTelemetry').returns(fakeTelemetry); + + TestBed.configureTestingModule({ + imports: [ + RouterModule.forRoot([ + { path: 'static-route', component: DummyComponent }, + { path: 'dynamic/:id/route', component: DummyComponent } + ]) + ], + providers: [provideZoneChangeDetection()] + }); + const testInjector = TestBed.inject(Injector); + errorHandler = runInInjectionContext( + testInjector, + () => new FirebaseErrorHandler() + ); + router = TestBed.inject(Router); + }); + + afterEach(async () => { + restore(); + await deleteApp(app); + }); + + it('should log the error to the console', async () => { + await router.navigate(['/static-route']); + + const testError = new Error('Test error message'); + errorHandler.handleError(testError); + expect(getTelemetryStub).to.have.been.called; + expect(captureErrorStub).to.have.been.calledWith(fakeTelemetry, testError, { + 'angular_route_path': '/static-route' + }); + }); + + it('should remove dynamic content from route', async () => { + await router.navigate(['/dynamic/my-name/route']); + + const testError = new Error('Test error message'); + errorHandler.handleError(testError); + expect(captureErrorStub).to.have.been.called; + expect(captureErrorStub).to.have.been.calledWith(fakeTelemetry, testError, { + // eslint-disable-next-line camelcase + angular_route_path: '/dynamic/:id/route' + }); + }); +}); diff --git a/packages/telemetry/src/angular/index.ts b/packages/telemetry/src/angular/index.ts new file mode 100644 index 00000000000..a761f46df9b --- /dev/null +++ b/packages/telemetry/src/angular/index.ts @@ -0,0 +1,67 @@ +/** + * @license + * Copyright 2025 Google LLC + * + * Licensed 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 { ErrorHandler, inject } from '@angular/core'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { registerTelemetry } from '../register'; +import { captureError, getTelemetry } from '../api'; +import { TelemetryOptions } from '../public-types'; +import { getApp } from '@firebase/app'; + +registerTelemetry(); + +export * from '../public-types'; + +export class FirebaseErrorHandler implements ErrorHandler { + private readonly router = inject(Router); + + constructor(private telemetryOptions?: TelemetryOptions) {} + + handleError(error: unknown): void { + const telemetry = getTelemetry(getApp(), this.telemetryOptions); + + const attributes = { + 'angular_route_path': this.getSafeRoutePath(this.router) + }; + + captureError(telemetry, error, attributes); + } + + /** + * Constructs the safe, templated route path from the router state. + * Example output: '/users/:id/posts' + */ + private getSafeRoutePath(router: Router): string { + let currentRoute: ActivatedRouteSnapshot | null = + router.routerState.snapshot.root; + + // Find the deepest activated child route + while (currentRoute.firstChild) { + currentRoute = currentRoute.firstChild; + } + + // Traverse up from the deepest child to the root, collecting configured paths + const pathFromRoot = currentRoute.pathFromRoot + .map(route => route.routeConfig?.path) + .filter(path => path !== undefined && path !== '') // Filter out empty or undefined paths + .join('/'); + + return `/${pathFromRoot}`; + } +} diff --git a/packages/telemetry/src/api.test.ts b/packages/telemetry/src/api.test.ts index 2085aa879f1..6a6c68deebf 100644 --- a/packages/telemetry/src/api.test.ts +++ b/packages/telemetry/src/api.test.ts @@ -29,7 +29,8 @@ import { FirebaseApp, initializeApp, _registerComponent, - _addOrOverwriteComponent + _addOrOverwriteComponent, + deleteApp } from '@firebase/app'; import { Component, ComponentType } from '@firebase/component'; import { FirebaseAppCheckInternal } from '@firebase/app-check-interop-types'; @@ -70,9 +71,16 @@ const fakeTelemetry: Telemetry = { }; describe('Top level API', () => { + let app: FirebaseApp; + beforeEach(() => { // Clear the logs before each test. emittedLogs.length = 0; + app = getFakeApp(); + }); + + afterEach(async () => { + await deleteApp(app); }); describe('getTelemetry()', () => { diff --git a/packages/telemetry/src/react/index.test.tsx b/packages/telemetry/src/react/index.test.tsx index 29643393133..44ede8922f9 100644 --- a/packages/telemetry/src/react/index.test.tsx +++ b/packages/telemetry/src/react/index.test.tsx @@ -30,7 +30,7 @@ import { render } from '@testing-library/react'; use(sinonChai); use(chaiAsPromised); -describe.only('FirebaseTelemetry', () => { +describe('FirebaseTelemetry', () => { let getTelemetryStub: sinon.SinonStub; let captureErrorStub: sinon.SinonStub; let initializeAppStub: sinon.SinonStub; diff --git a/packages/telemetry/tsconfig.angular.json b/packages/telemetry/tsconfig.angular.json new file mode 100644 index 00000000000..e870c27ba49 --- /dev/null +++ b/packages/telemetry/tsconfig.angular.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "dist/angular", + "declarationDir": "dist/angular" + }, + "include": ["src/angular/index.ts"] +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index e6e4692d51e..a5e54f121ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,6 +10,41 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" +"@angular/common@19.2.15": + version "19.2.15" + resolved "https://registry.npmjs.org/@angular/common/-/common-19.2.15.tgz#934d7ead5c8a3c4660ab131ba129fce6096def1d" + integrity sha512-aVa/ctBYH/4qgA7r4sS7TV+/DzRYmcS+3d6l89pNKUXkI8gpmsd+r3FjccaemX4Wqru1QOrMvC+i+e7IBIVv0g== + dependencies: + tslib "^2.3.0" + +"@angular/compiler@19.2.15": + version "19.2.15" + resolved "https://registry.npmjs.org/@angular/compiler/-/compiler-19.2.15.tgz#20fb21e77d6c6ace9a0c427a3ca9bcb4415b6336" + integrity sha512-hMHZU6/03xG0tbPDIm1hbVSTFLnRkGYfh+xdBwUMnIFYYTS0QJ2hdPfEZKCJIXm+fz9IAI5MPdDTfeyp0sgaHQ== + dependencies: + tslib "^2.3.0" + +"@angular/core@19.2.15": + version "19.2.15" + resolved "https://registry.npmjs.org/@angular/core/-/core-19.2.15.tgz#0395b60a8ef9c715a97df7a59fe4973ee3d35a51" + integrity sha512-PxhzCwwm23N4Mq6oV7UPoYiJF4r6FzGhRSxOBBlEp322k7zEQbIxd/XO6F3eoG73qC1UsOXMYYv6GnQpx42y3A== + dependencies: + tslib "^2.3.0" + +"@angular/platform-browser@19.2.15": + version "19.2.15" + resolved "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-19.2.15.tgz#efc814efd98f6e2b958f2a2588de862dcea364a0" + integrity sha512-OelQ6weCjon8kZD8kcqNzwugvZJurjS3uMJCwsA2vXmP/3zJ31SWtNqE2zLT1R2csVuwnp0h+nRMgq+pINU7Rg== + dependencies: + tslib "^2.3.0" + +"@angular/router@19.2.15": + version "19.2.15" + resolved "https://registry.npmjs.org/@angular/router/-/router-19.2.15.tgz#1d2748a9168a524d5ec8490849df2796bda0ab53" + integrity sha512-0TM1D8S7RQ00drKy7hA/ZLBY14dUBqFBgm06djcNcOjNzVAtgkeV0i+0Smq9tCC7UsGKdpZu4RgfYjHATBNlTQ== + dependencies: + tslib "^2.3.0" + "@apidevtools/json-schema-ref-parser@^9.0.3": version "9.1.2" resolved "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz#8ff5386b365d4c9faa7c8b566ff16a46a577d9b8" @@ -14700,6 +14735,13 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rxjs@7.8.2: + version "7.8.2" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b" + integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA== + dependencies: + tslib "^2.1.0" + rxjs@^6.3.3, rxjs@^6.5.1, rxjs@^6.6.0: version "6.6.7" resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" @@ -16461,7 +16503,7 @@ tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.6.2, tslib@^2.8.0: +tslib@^2.0.1, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.6.2, tslib@^2.8.0: version "2.8.1" resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -17870,3 +17912,8 @@ zip-stream@^6.0.1: archiver-utils "^5.0.0" compress-commons "^6.0.2" readable-stream "^4.0.0" + +zone.js@0.15.1: + version "0.15.1" + resolved "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz#1e109adb75f80e9e004ee8e0d4a0a52e0a336481" + integrity sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==