Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,34 @@ module.exports = {
jest: false,
node: true
}
},
{
// The core is framework-independent, and its main entry point loads
// no optional peer: those get entry points of their own.
files: ['projects/ui-watchtower/src/**/*.ts'],
rules: {
'no-restricted-imports': [
'error',
{
patterns: [
{
group: [
'@angular/*',
'zone.js',
'@absaoss-cps/ngx-ui-watchtower',
'@absaoss-cps/ngx-ui-watchtower/*'
],
message: 'The core is framework-independent.'
},
{
group: ['rxjs', 'rxjs/*', 'aws-rum-web', 'aws-rum-web/*'],
message:
'The main entry point loads no optional peer; use an entry point of its own.'
}
]
}
]
}
}
]
};
14 changes: 13 additions & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
run: npm run test:coverage

- name: Comment coverage on PR
uses: ArtiomTr/jest-coverage-report-action@v2
uses: ArtiomTr/jest-coverage-report-action@262a7bb0b20c4d1d6b6b026af0f008f78da72788 # v2.3.1
if: github.event_name == 'pull_request'
continue-on-error: true
with:
Expand All @@ -69,6 +69,18 @@ jobs:
# Tests already ran above; the action only formats the report.
skip-step: all

- name: Comment core coverage on PR
uses: ArtiomTr/jest-coverage-report-action@262a7bb0b20c4d1d6b6b026af0f008f78da72788 # v2.3.1
if: github.event_name == 'pull_request'
continue-on-error: true
with:
custom-title: Core coverage report
coverage-file: ./coverage/ui-watchtower/report.json
# The same file as the base: no comparison with a base branch,
# which would run the Angular package's tests.
base-coverage-file: ./coverage/ui-watchtower/report.json
skip-step: all

lint:
name: Lint and format
runs-on: ubuntu-latest
Expand Down
46 changes: 29 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@

Source of [`@absaoss-cps/ngx-ui-watchtower`](https://www.npmjs.com/package/@absaoss-cps/ngx-ui-watchtower),
a telemetry library for Angular apps: scenarios (user end-to-end journeys or specific functional workflows through an app), BI events and
logs, with an optional AWS CloudWatch RUM sink.
logs, with an optional AWS CloudWatch RUM sink. It builds on
[`@absaoss-cps/ui-watchtower`](projects/ui-watchtower/README.md), the
framework-independent engine, which lives here too.

How to use the library: [projects/ngx-ui-watchtower/README.md](projects/ngx-ui-watchtower/README.md)
(also the npm page).
Expand All @@ -19,14 +21,22 @@ How it is designed: [projects/ngx-ui-watchtower/DESIGN.md](projects/ngx-ui-watch
## Layout

```text
projects/ui-watchtower/
src/ @absaoss-cps/ui-watchtower — the framework-independent engine
README.md usage guide, published to npm
package.json the published package's manifest
projects/ngx-ui-watchtower/
src/ main entry point — @absaoss-cps/ngx-ui-watchtower
rum/ secondary entry point — @absaoss-cps/ngx-ui-watchtower/rum
type-tests/ consumer type tests
README.md usage guide, published to npm
DESIGN.md full design
package.json the published package's manifest
scripts/ the public API snapshot
```

The Angular package depends on the core, never the other way round.

## Getting started

Requires Node.js 22 or later.
Expand All @@ -37,32 +47,34 @@ npm run test
npm run build
```

The package is built to `dist/ngx-ui-watchtower`.
The packages are built to `dist/ui-watchtower` and `dist/ngx-ui-watchtower`,
the core first: the Angular package compiles against the built core, as an
application does. Tests and the typecheck read the core's source.

## Scripts

| Script | What it does |
| ----------------------- | --------------------------------------------------------------- |
| `npm run build` | Builds the package (production, partial compilation) |
| `npm run watch` | Rebuilds on change (development) |
| `npm run test` | Runs the unit tests (Jest) |
| `npm run test:coverage` | Runs the unit tests with coverage, as CI does |
| `npm run typecheck` | Type-checks every library and spec tsconfig, and the type tests |
| `npm run api:check` | Builds, then compares the public API with its snapshot |
| `npm run api:update` | Builds, then rewrites the snapshot, for an intended change |
| `npm run lint` | ESLint, no warnings allowed |
| `npm run format` | Formats with Prettier |
| `npm run format:check` | Checks formatting without writing |
| Script | What it does |
| ----------------------- | -------------------------------------------------------------- |
| `npm run build` | Builds both packages (production), the core first |
| `npm run watch` | Builds the core, then rebuilds the Angular package on change |
| `npm run test` | Runs the unit tests of both packages (Jest) |
| `npm run test:core` | Runs the core's unit tests only: plain Jest, no Angular |
| `npm run test:coverage` | Runs the unit tests with coverage, as CI does |
| `npm run typecheck` | Builds the core, then type-checks every tsconfig and type test |
| `npm run api:check` | Builds both packages, then compares their public APIs |
| `npm run api:update` | Builds both packages, then rewrites their snapshots |
| `npm run lint` | ESLint, no warnings allowed |
| `npm run format` | Formats with Prettier |
| `npm run format:check` | Checks formatting without writing |

Three checks guard what consumers depend on:

- **Type tests** (`projects/ngx-ui-watchtower/type-tests/`) compile, with the
Angular compiler, a consumer that uses every public export, and one that
augments the name registries: registered names accepted, others rejected,
`string` while nothing is registered.
- **The API snapshot** (`projects/ngx-ui-watchtower/public-api.snapshot.json`)
records every export of the built package with its members and
signatures. After an intended change, run `npm run api:update` and review
- **The API snapshots** (`public-api.snapshot.json` in each package) record
every export of the built packages with its members and signatures. After an intended change, run `npm run api:update` and review
the diff.
- **The broadcast wire fixture**
(`projects/ngx-ui-watchtower/src/lib/sinks/uwt-broadcast/uwt-broadcast.wire.fixture.json`) records
Expand Down
23 changes: 23 additions & 0 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,29 @@
"analytics": false
},
"projects": {
"ui-watchtower": {
"projectType": "library",
"root": "projects/ui-watchtower",
"sourceRoot": "projects/ui-watchtower/src",
"prefix": "uwt",
"architect": {
"build": {
"builder": "@angular/build:ng-packagr",
"options": {
"project": "projects/ui-watchtower/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "projects/ui-watchtower/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "projects/ui-watchtower/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
}
}
},
"ngx-ui-watchtower": {
"projectType": "library",
"root": "projects/ngx-ui-watchtower",
Expand Down
4 changes: 3 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
module.exports = {
roots: ['<rootDir>/projects'],
roots: ['<rootDir>/projects/ngx-ui-watchtower'],
coverageDirectory: '<rootDir>/coverage',
preset: 'jest-preset-angular',
moduleNameMapper: {
'^@absaoss-cps/ui-watchtower$':
'<rootDir>/projects/ui-watchtower/src/public-api.ts',
'^@absaoss-cps/ngx-ui-watchtower$':
'<rootDir>/projects/ngx-ui-watchtower/src/public-api.ts',
'^@absaoss-cps/ngx-ui-watchtower/rum$':
Expand Down
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 7 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
"version": "0.0.0",
"scripts": {
"ng": "ng",
"build": "ng build --configuration=production --project=ngx-ui-watchtower",
"watch": "ng build ngx-ui-watchtower --watch --configuration development",
"test": "ng test --project=ngx-ui-watchtower",
"test:coverage": "ng test --project=ngx-ui-watchtower --coverage --coverage-reporters text-summary --coverage-reporters lcov --json --output-file=./coverage/report.json",
"build": "ng build --configuration=production --project=ui-watchtower && ng build --configuration=production --project=ngx-ui-watchtower",
"watch": "ng build ui-watchtower --configuration development && ng build ngx-ui-watchtower --watch --configuration development",
"test": "npm run test:core && ng test --project=ngx-ui-watchtower",
"test:core": "jest --config projects/ui-watchtower/jest.config.js",
"test:coverage": "jest --config projects/ui-watchtower/jest.config.js --coverage --coverageReporters=text-summary --coverageReporters=lcov --json --outputFile=./coverage/ui-watchtower/report.json && ng test --project=ngx-ui-watchtower --coverage --coverage-reporters text-summary --coverage-reporters lcov --json --output-file=./coverage/report.json",
"lint": "eslint \"**/*.ts\" --max-warnings=0",
"format": "prettier --write \"**/*.{ts,mjs,html}\"",
"format:check": "prettier --check \"**/*.{ts,mjs,html}\"",
"typecheck": "tsc -p projects/ngx-ui-watchtower/tsconfig.lib.json --noEmit && tsc -p projects/ngx-ui-watchtower/tsconfig.spec.json --noEmit && tsc -p projects/ngx-ui-watchtower/rum/tsconfig.lib.json --noEmit && tsc -p projects/ngx-ui-watchtower/rum/tsconfig.spec.json --noEmit && ngc -p projects/ngx-ui-watchtower/type-tests/tsconfig.json && ngc -p projects/ngx-ui-watchtower/type-tests/tsconfig.augmented.json",
"typecheck": "tsc -p projects/ui-watchtower/tsconfig.lib.json --noEmit && tsc -p projects/ui-watchtower/tsconfig.spec.json --noEmit && ng build --configuration=production --project=ui-watchtower && tsc -p projects/ngx-ui-watchtower/tsconfig.lib.json --noEmit && tsc -p projects/ngx-ui-watchtower/tsconfig.spec.json --noEmit && tsc -p projects/ngx-ui-watchtower/rum/tsconfig.lib.json --noEmit && tsc -p projects/ngx-ui-watchtower/rum/tsconfig.spec.json --noEmit && ngc -p projects/ngx-ui-watchtower/type-tests/tsconfig.json && ngc -p projects/ngx-ui-watchtower/type-tests/tsconfig.augmented.json",
"api:check": "npm run build && node scripts/api-snapshot.mjs",
"api:update": "npm run build && node scripts/api-snapshot.mjs --update"
},
Expand Down Expand Up @@ -48,6 +49,7 @@
"jest-preset-angular": "^17.0.0",
"ng-packagr": "~21.0.1",
"prettier": "^3.4.2",
"ts-jest": "^29.4.14",
"typescript": "~5.9.3"
},
"engines": {
Expand Down
7 changes: 7 additions & 0 deletions projects/ngx-ui-watchtower/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,13 @@ providers: [

### Packaging and internals

- **The framework-independent code lives in `@absaoss-cps/ui-watchtower`.**
This package depends on it as a regular dependency, so installing this
package installs it too, and re-exports what it has always exported, under
the same names. The dependency runs one way: the core imports neither
Angular nor this package, which a lint rule enforces. The library build
compiles against the core's built declarations, not its source, so it sees
the core exactly as an application does.
- **Every export is explicit.** The barrels list their exports one by one —
in a published package each exported name is a compatibility promise. Id
generation, the clock, the fail-open wrappers, User Timings and the
Expand Down
5 changes: 4 additions & 1 deletion projects/ngx-ui-watchtower/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ npm install @absaoss-cps/ngx-ui-watchtower
npm install aws-rum-web # only for the AWS RUM sink
```

Requires Angular 21 or 22 and RxJS 7.8.
Requires Angular 21 or 22 and RxJS 7.8. It brings
[`@absaoss-cps/ui-watchtower`](https://www.npmjs.com/package/@absaoss-cps/ui-watchtower),
the framework-independent engine it builds on, with it: there is nothing more
to install or configure.

## Setup

Expand Down
3 changes: 2 additions & 1 deletion projects/ngx-ui-watchtower/ng-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"dest": "../../dist/ngx-ui-watchtower",
"lib": {
"entryFile": "src/public-api.ts"
}
},
"allowedNonPeerDependencies": ["@absaoss-cps/ui-watchtower"]
}
1 change: 1 addition & 0 deletions projects/ngx-ui-watchtower/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"homepage": "https://github.com/AbsaOSS/ui-watchtower",
"license": "Apache-2.0",
"dependencies": {
"@absaoss-cps/ui-watchtower": "^0.1.0",
"tslib": "^2.8.1"
},
"sideEffects": false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
UWT_TELEMETRY_EVENT_TYPE,
UWT_TELEMETRY_IDENTITY
} from '@absaoss-cps/ngx-ui-watchtower';
import { uwtSessionElapsed } from '../../../../src/lib/utils/uwt-session-start.util/uwt-session-start.util';
import { uwtSessionElapsed } from '@absaoss-cps/ui-watchtower';
import {
UWT_RUM_CREDENTIALS_PROVIDER,
UwtRumBootstrap
Expand Down
3 changes: 2 additions & 1 deletion projects/ngx-ui-watchtower/rum/tsconfig.lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "../../../out-tsc/lib-rum",
"rootDir": "..",
// Includes the core: tests and typecheck read its source.
"rootDir": "../..",
"lib": ["ES2022", "DOM"],
"moduleResolution": "bundler",
"declaration": true,
Expand Down
3 changes: 2 additions & 1 deletion projects/ngx-ui-watchtower/rum/tsconfig.spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "../../../out-tsc/spec-rum",
"rootDir": "..",
// Includes the core: tests and typecheck read its source.
"rootDir": "../..",
"types": ["jest"],
"resolveJsonModule": true,
"isolatedModules": false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { UwtScenarioRecord } from '../../models/uwt-scenario.models/uwt-scenario
import { UwtTelemetryMetadata } from '../../models/uwt-telemetry-common.models/uwt-telemetry-common.models';
import { UwtTelemetrySink } from '../../sinks/uwt-telemetry/uwt-telemetry-abstract.sink/uwt-telemetry-abstract.sink';
import { UWT_DEFAULT_REDACT_CONFIG } from '../../utils/uwt-telemetry-redact.util/uwt-telemetry-redact.util';
import { uwtMarkSessionStart } from '../../utils/uwt-session-start.util/uwt-session-start.util';
import { uwtMarkSessionStart } from '@absaoss-cps/ui-watchtower';
import { UwtScenario, UwtScenarioDeps } from './uwt-scenario';

/** Captures what the scenario emitted, so a test can assert on it. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
uwtRedactMetadata,
uwtScrubString
} from '../../utils/uwt-telemetry-redact.util/uwt-telemetry-redact.util';
import { uwtSessionElapsed } from '../../utils/uwt-session-start.util/uwt-session-start.util';
import { uwtSessionElapsed } from '@absaoss-cps/ui-watchtower';
import {
uwtDeepClone,
uwtElapsedNow,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
UwtLogQuery
} from '../../providers/uwt-log-api.provider/uwt-log-api.provider';
import { uwtClassifyTelemetryEvent } from '../../utils/uwt-telemetry-event.util/uwt-telemetry-event.util';
import { uwtSessionElapsed } from '../../utils/uwt-session-start.util/uwt-session-start.util';
import { uwtSessionElapsed } from '@absaoss-cps/ui-watchtower';

/** The identity fields scenario, BI and log records carry. */
interface UwtIdentified {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import {
uwtIsBroadcastMessage
} from './uwt-broadcast.messages';
import { UwtTelemetrySink } from '../uwt-telemetry/uwt-telemetry-abstract.sink/uwt-telemetry-abstract.sink';
import { uwtMarkSessionStart } from '../../utils/uwt-session-start.util/uwt-session-start.util';
import { uwtMarkSessionStart } from '@absaoss-cps/ui-watchtower';

/**
* Each realm gets its own injector — the shell and every fragment run in a
Expand Down
2 changes: 1 addition & 1 deletion projects/ngx-ui-watchtower/src/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export type { UwtTraceScenarioOptions } from './lib/scenario/uwt-scenario-operat
export { uwtIsDebugEnabled } from './lib/utils/uwt-debug-flag.util/uwt-debug-flag.util';
export type { UwtDebugFlag } from './lib/utils/uwt-debug-flag.util/uwt-debug-flag.util';
export { uwtUuid } from './lib/utils/uwt-telemetry-safe.util/uwt-telemetry-safe.util';
export { uwtMarkSessionStart } from './lib/utils/uwt-session-start.util/uwt-session-start.util';
export { uwtMarkSessionStart } from '@absaoss-cps/ui-watchtower';
export {
UWT_DEFAULT_REDACT_CONFIG,
UWT_REDACTED,
Expand Down
6 changes: 5 additions & 1 deletion projects/ngx-ui-watchtower/tsconfig.lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
"skipLibCheck": true,
"isolatedModules": false,
"types": [],
"paths": {}
// The core as published: its built declarations, not its source. Build
// it first (npm run build does).
"paths": {
"@absaoss-cps/ui-watchtower": ["../../dist/ui-watchtower"]
}
},
"include": ["src/**/*.ts"],
"exclude": ["**/*.spec.ts"],
Expand Down
3 changes: 2 additions & 1 deletion projects/ngx-ui-watchtower/tsconfig.spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/spec",
"rootDir": "./src",
// Includes the core: tests and typecheck read its source.
"rootDir": "..",
"types": ["jest", "node"],
"resolveJsonModule": true
},
Expand Down
Loading
Loading