- Seed cleanup (Greptile): rimraf 3 took the failure callback for its options
argument and called the success one either way, so a failed cleanup of
generated files never stopped a seed. With rimraf 6's promise, the seed
service's `.finally()` left the rejection unhandled (Node ends the process on
that) and cleanAssets / the feature and report cleaners rejected. All four
log the failure and go on; seed-cleanup.spec.ts fails on the old code.
- Tray icons: jimp 1's brightness() multiplies each channel by its argument,
so 0.22's brightness(-0.1) made every *_gray tray icon black. 0.9 is the
same 90%.
- CI static checks: the jest-config type check installed TypeScript 5.9.3,
which refuses ignoreDeprecations "6.0" (TS5103); it now uses 6.0.3. Under
6.0.3 the check found the 75 Node jest configs restating
`require(jest.patterns).nodeTransformIgnorePatterns` (typed unknown by the
check's shim). jest.preset.js already picks that variant, so they inherit it
again, as core's config says they should.
- engines: the 114 workspace manifests still said node >=22; now >=26, as the
root does.
- The desktop Dockerfiles (no workflow uses them): the Windows ones copy
vendor/ before the install, the Linux ones build on node:26-trixie-slim
(libayatana-appindicator3-1 replaces libappindicator3-1, gone after bullseye).
- jest-angular-projects.js declares the arrays it pushes to with `let`
(repository convention, Greptile).
- jest.patterns.js: `yarn ng test <node project>` runs without the ES-module
flag (the ng script already sets NODE_OPTIONS, and Nx never overrides a set
variable with a .env value); documented, with `yarn nx test` as the way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What each upgrade needed, by area. Public behaviour is unchanged unless a line says otherwise.
API / Nest 12:
- MikroOrmBaseEntityRepository: the entity-name argument is no longer injected by token. Nest 12 keeps a
base class's @Inject for a subclass with its own constructor but reads @Optional() from the subclass
only, so the token became a required dependency of those repositories and the API did not start.
- ClassSerializerInterceptor.intercept resolves to the stream in Nest 12: ours is async to match.
- posthog/sentry interceptors import the ArgumentsHost types from their new subpath.
- mjml 5 compiles asynchronously: compileMjml and its callers (email templates, accounting templates,
previews, seeds) await it.
- node-redis 5/6 (sessions, health check, auth code cache): keepAlive is a switch plus
keepAliveInitialDelay; replies are typed string | Buffer. connect-redis exports RedisStore by name.
- OpenTelemetry 2: resourceFromAttributes / ATTR_SERVICE_NAME. unleash-client 6: EnhancedFeatureInterface.
- jimp 1 (named exports, resize({ w })), sharp 0.35 (default export under types), rimraf 6 (named),
pdfmake 0.3 (singleton API; URL and local-file access refused except the bundled fonts, CVE-2026-26801,
with tests), Apollo Client 4 in the Gauzy AI client (errorPolicy also covers network errors, so the
wrapper rethrows those as before), smee-client 5, express-session 1.19 types, Knex binding types.
- yargs 18 has no global parser: the migration CLI and the .scripts build helpers parse hideBin(argv).
envalid 8: .scripts/env.ts loads .env itself and keeps envalid 6's num/bool parsing. simple-git 4: named.
Desktop / Electron 44:
- electron-store 11 / conf 15 types (IStore = ElectronStoreOf<StoreSchema>), electron-log 5 onError
options, screen.on per event (Electron types one overload per event), node-fetch 3 json(): unknown,
pdfjs-dist 6 loadingTask.destroy(), hash-it named export, ngx-draggable-dom 22 directive.
Web / Angular 22, ngx-translate 18:
- ComponentFactoryResolver is gone: createComponent(type). ChangeDetectorRef.checkNoChanges is gone.
- ngx-translate: provideTranslateService + TranslatePipe in I18nModule, currentLang is a Signal
(getCurrentLang()), onDefaultLangChange -> onFallbackLangChange; the removed `extend` is accepted and
ignored (deprecated in our options).
- Jest: the Node projects' configs take nodeTransformIgnorePatterns (ES modules load natively under
--experimental-vm-modules), the Angular defaults provide the translate service; a few specs follow the
APIs above.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dependencies (root + 132 workspace package.json files, lockfile regenerated and deduplicated):
Node 24 -> 26 (.nvmrc, every Dockerfile stage, CI node-version, engines, @types/node), TypeScript 6.0.3,
Angular/CDK/Material 22.2.2, Nx 23.3.0, NestJS 12.1.3, Electron 44.7.0, Jest 30.5.2, and the rest to latest.
- Nebular has no npm release for Angular 22: vendor/nebular holds 18.0.0 built from the open upstream port
(akveo/nebular#3319, commit 9f3a1f9; sha256 in the README), referenced as file: dependencies and pinned in
resolutions. Remove it when Nebular publishes.
- resolutions: one copy each of @nestjs/* 12 (including under the plane-api integration, which still
declares Nest 11), moment, graphql 16, ioredis 6 and @jridgewell/sourcemap-codec (the Angular schematics
need encodeRangeMappings).
- TypeScript 6 changed defaults the code was written against; tsconfig.base.json and the Electron configs
pin strict, esModuleInterop and noUncheckedSideEffectImports to false, and the Electron configs keep
rootDir ./src (output layout). types: the configs that relied on the automatic @types sweep list theirs.
- Angular migrations rewrote the tsconfigs (strictTemplates off where it was implicit; extendedDiagnostics
only where strictTemplates is on, NG4003).
- Jest: NestJS 12 is ES modules, so the Node projects run with --experimental-vm-modules and load ES
modules natively (transforming one to CommonJS breaks it under the flag: uuid 14 and jose 6 threw
"exports is not defined"); the Angular projects must run without the flag. jest.preset.js picks the
transform rule from the mode the process runs in; the workspace .env.test sets the flag and each Angular
project's .env.test clears it; test-unit.yml runs the two groups separately, with the list from
.github/scripts/jest-angular-projects.js (which also fails when an Angular project lacks its .env.test).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts resolved (develop since 10-10 vs feat):
- packages/core/src/lib/tasks/task.service.ts: import both ForbiddenException (develop #10509
deleteTask) and NotFoundException (feat softDeleteTask/recoverTask/taskByNumber).
- packages/core/src/lib/request-approval/request-approval.service.spec.ts: develop #10497 rewrote
this file into its MySQL join spec and dropped feat's six GHSA-gwpq-mmw7-vx85 tenant-scope tests.
Keep both: develop's spec stays here, feat's suite moves to request-approval.service.approvers.spec.ts
(the two need different @gauzy/config module mocks).
- .gitignore: keep both additions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts resolved:
- package.json: keep this branch's Nx 23.1.1 / webpack 5.108.4 / verdaccio 6.8.0 pins,
take develop's new typescript-eslint and its removal of @nx/eslint-plugin-nx.
- apps/gauzy/project.json: develop's jest.config.ts (the file that exists).
- ai-provider-* project.json: develop's type:plugin tags.
- yarn.lock: develop's for now; regenerated after the feat/platform-extensions merge.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The branch was 121 commits behind and the pull request was unmergeable. Nine files
conflicted; every one is resolved as a union, so nothing either side added is lost:
- `core/project.json` — takes develop's `tags: ["type:core"]`.
- `core/src/index.ts` — keeps the kernel exports and adds develop's `auth/purpose-token`.
- `bootstrap/index.ts` — CORS now allows both header sets (`X-APP-ID`, `X-API-KEY`,
`X-Channel-Id`, `Idempotency-Key`, `If-Match`, `If-None-Match` and `X-Correlation-Id`)
and keeps develop's `exposedHeaders`.
- `crud.service.ts` — keeps this branch's `findOneByOptions(): Promise<T>` (a miss raises,
which is what the route contract wants) and adds develop's `assertRelationsPermitted`
guard, which is a security check and must run on this path too.
- `column-numeric-transformer.pipe.ts` — keeps develop's `roundToScale` half-away-from-zero
rounding and its refusal of a non-finite value, and keeps this branch's `undefined`
pass-through so a column's own `DEFAULT` still applies when the caller omits the field.
`to()` now distinguishes `undefined` (omit from the statement) from `null` (clear it).
- `shared/pipes/index.ts`, `role.module.ts`, `time-log.module.ts`, `time-slot.module.ts` —
both sides' providers, exports and re-exports.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds test harnesses for tenant isolation, TypeORM/MikroORM parity, persistence invariants and idempotency; startup validation for DB config; Nx plugin/core boundary rules; a fresh-database migration smoke test; and a correlation id carried from HTTP requests into docs queue jobs and logs.
Testing (packages/core/src/lib/core/testing):
- tenant-isolation: an in-memory tenant-aware repository, fixtures and strict assertions (a non-empty page, every row in the caller's tenant). Applied to EmployeeService and OrganizationProjectService.
- orm-conformance and persistence-invariants: suites that run the same checks under TypeORM and MikroORM (run-both-orms.sh uses yarn nx).
- idempotency: assertion helpers and specs for token cleanup (positive control), employee notifications and the Zapier timer webhook.
- database/migration-smoke.spec.ts: runs the full migration chain on a fresh better-sqlite3 database. It is excluded from the default core jest run; run it with `nx run core:test-migration-smoke`.
Idempotency:
- EmployeeNotificationService.create() takes an opt-in `absorbRedelivery`. With it set, an identical unread, unarchived notification under 60 s old (same receiver, entity, type, sender, title and message) is returned instead of inserted, and a missing key or a failed lookup inserts as usual. The event handler does not enable it (the in-process EventBus never redelivers), so every caller inserts one row per event as before.
- ZapierWebhookService skips resending a webhook that already succeeded for the same subscription, action and time log within 5 minutes. The key is reserved while in flight, failed deliveries stay retryable, pruning stops at the first unexpired entry, and the cache is capped at 10,000 entries.
Config (packages/config):
- An unknown DB_TYPE fails fast with the list of supported values; an empty DB_TYPE still means better-sqlite3; mongodb throws an Error.
- Pool and timeout variables are parsed with Number.parseInt semantics, only for postgres and mysql. They throw only where tarn already refused to start and warn otherwise. SQLite ignores them and still prints the startup values.
Observability:
- RequestContextMiddleware accepts an inbound x-correlation-id of 1-128 visible ASCII characters (otherwise it generates a UUIDv4) and echoes it on the response. CORS allows and exposes X-Correlation-Id. RequestContext.currentCorrelationId() is added.
- The docs queue carries the correlation id through job payloads (including bulk reindex) into pipeline outcome, error, dead-letter and enqueue-failure logs.
Boundaries and build:
- Every project gets a type tag. The ESLint depConstraints stop type:core depending on plugins, and plugins may depend only on core, shared libs and the known extension points (ai-chat, job-proposal, integration-ai, job-*-ui).
- core declares @gauzy/scheduler (package.json and implicitDependencies); the webapp Dockerfile copies scheduler's package.json.
- The integration-zapier jest config can import @gauzy/core (transformIgnorePatterns, allowJs, isolatedModules).
- Fixes the stale @nrwl/nx eslint-disable id in the e2e roles-permissions steps and the broken @gauzy/core mock in the docs document-scope spec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The build was green and the server would not start. Everything here was found by starting it, and
none of it was visible to a type-checker.
**`dependsOn` was enforced for one of its two spellings.** The resolver indexes a plugin under its
class name and its package name, but a plugin that imports its prerequisite declares the *class* —
which is legal, and was unresolvable, so the boot was refused with a message naming a prerequisite
that was sitting in the list. Both spellings are now indexed. Fifteen of the sixteen packages booted
in exactly the order their declarations imply once this was right.
**A bidirectional relation made two entity files import each other, and one of them read the other
before it existed.** The compiled decorator metadata reads the property's *type*, and `typeof X` does
not cover a class that exists but is not yet initialised — that guard is for a name that does not
exist. Whether it throws depends only on which file the loader reaches first, so this is a landmine
rather than a style question: the same code that boots today can fail after an unrelated reordering.
The warehouse package's seven relation properties are now typed by their contract interface, which is
what the platform's own entities do and what erases at compile time. Seventy-one more properties
across nine packages have the same shape and are recorded as a known hazard by a check script; they
did not trip, and converting them needs an interface each that does not exist yet.
**`promotion` declared its entity list beside its own plugin class.** The module registers those
entities and the plugin declares them, so the module imports the array and the plugin imports the
module — a cycle in which the array is undefined when the module reads it, and the boot fails with a
message about `entities` that names no entity. The list lives in its own module now, which both of
them import.
**The promotion migration declared a primary key twice in its SQLite branch**: the inherited columns
already carry one, and each table also named a `CONSTRAINT ... PRIMARY KEY`. SQLite refuses that
outright. The PostgreSQL and MySQL branches need the named constraint — their inherited columns do
not declare one — so the fix is in the SQLite statement builder alone.
**The fresh-install feature catalogue** is committed separately; this is the rest of what a real boot
demanded.
Verified: the API builds (65 tasks, webpack clean, 65 packages copied into `dist`) and starts with all
sixteen commerce plugins registered, in dependency order, against a database the migrations took to
399 tables and 337 applied migrations. The permission and feature seeds are applied (SUPER_ADMIN 381
enabled grants, ADMIN 349, 90 catalogue rows, 66 toggles) and a real commerce write now answers 201
over REST where it answered 403 before. One defect remains open and is not hidden by that: the
GraphQL collection query passes its guards and then throws inside the resolver, so the field fails a
non-null check; and the REST surface requires the caller to state its tenant in the `tenant-id`
header, which the end-to-end script now does.
Everything here is foundation work the commerce packages sit on. It is one commit because the parts
are load-bearing for each other: the columns the plugins reference, the grants that let anyone call
them, and the plugin list that mounts them in a defined order.
**The additive columns the specification requires.** `AlterCoreTablesForExtensions1791000000095` adds
126 columns and 54 indexes across thirteen platform tables — product identity and publication,
variant measures and units, warehouse type and cut-off, currency precision and rounding, the contact
party fields, tenant-scoped settings, the payment row's authorization and settlement amounts, vendor
terms, and the invoice's payment-term and vendor pointers. Every addition is guarded, so the
migration is a no-op when a column is already there, and every index is created only after asking the
dialect's own catalogue whether the name is taken. SQLite carries no table rebuild: each statement is
an `ADD COLUMN` or a `CREATE INDEX`, verified by executing the real migration against a real
in-memory database, twice, and then reversing it. The two mistyped search columns are corrected at
creation — `jsonb` on PostgreSQL, `json` on MySQL, `text` on SQLite, which is what each entity's
decorator produces — and the PostgreSQL generated search vector casts through `::text`, because a
`jsonb` column has no implicit cast and the old expression would have failed `CREATE TABLE` outright.
**Commerce permissions never reached a role.** The platform grants what `DEFAULT_ROLE_PERMISSIONS`
lists, and none of this programme's permissions were in it, so every commerce endpoint answered 403
to every user including the owner. `PermissionsEnum` gains 117 members, the defaults gain 174 grants
for SUPER_ADMIN and 143 for ADMIN, and `PermissionGroups` gains all 174 so the role editor can show
and grant them. Three data-only migrations follow: `CoreRolePermissionsReload1791000000500`,
`SeedCoreFeatures1791000000510` and `SeedCoreDefaults1791000000520`. The reload delegates to the
platform's own insert-only helper, and additionally enables rows that already exist disabled — 51 of
the 174 had been created disabled by an earlier seed, which the helper would never revisit — limited
to the resource prefixes this programme introduces, so a tenant's own decision elsewhere is
untouched. The defaults seed runs nine steps, each guarded by both the schema and the row, and
reports each step it skips because its table or column does not exist yet rather than failing the
boot; on today's schema it seeds the default tax category, a price preference and the seven document
numbering series.
**The feature flag cache served one tenant's answer to every other tenant.** `FeatureFlagGuard` asked
`FeatureService` a question whose answer is tenant-scoped and cached it under a key that was not:
the first tenant to resolve a flag stored its own answer where every other tenant read it. The key
now carries the tenant and the organization, the entry has a bounded lifetime, and a context with no
request resolves a stable key instead of throwing. This is a data-exposure bug, not a performance
one, and it becomes reachable the moment tenants hold different flag sets — which the seed above
makes true for the first time.
**`dependsOn` was a declaration nothing read.** `resolvePluginLoadOrder` existed, was documented, and
was never called, so a plugin could be mounted before the package whose tables it references; the
order was whatever the list happened to say. It is now applied where the plugin list is installed, so
a declared prerequisite loads first and a prerequisite that is missing is refused at boot with the
plugin and the dependency named, rather than surfacing later as a missing provider. The resolver also
answers to the bare stem a dependency is written with — `dependsOn: ['pricing']` — because a
declaration that resolves only under one spelling turns a correct declaration into a boot failure.
**The HTTP error filters crashed on every GraphQL failure.** Both global filters render an HTTP reply,
and both were consulted for GraphQL contexts, where the host's response object has no `status`
method: a resolver that threw reported `response.status is not a function` and the caller's real
error was lost behind it. Each filter now recognises a context that has no HTTP response and steps
aside, and the documented GraphQL error contract is wired to the driver's `formatError` — the same
stable code, the status the REST route would have answered, the structured detail and the trace id —
so a client switching on `extensions.code` no longer needs a second table for the GraphQL surface.
**The outbox retry ladder was unreachable, and its ordering promise did not hold.** A failed dispatch
wrote `FAILED` with a backoff while the claim query selected `PENDING` only, so an event that failed
once was never retried and never dead-lettered; and because the head-of-line rule was computed over
the rows the query could see, the next event of the same aggregate overtook it. The claim now reads
every non-terminal row, takes each partition's *first* row as its head, and holds a partition back
while its head is inside its backoff — so a retry happens, the attempt budget still ends in
`DEAD`, and no partition is ever dispatched out of order.
Smaller corrections in the same pass: `tax-line` refuses one owner that mixes an inclusive and an
exclusive line of one rate, under the documented `TAX_INCLUSIVE_MISMATCH` code; `sequence.allocate`
takes an idempotency key so a retry does not burn a number, and `ensure` keeps the scope its caller
stated instead of overwriting it with an absent request context; `packages/contracts` re-exports the
fulfilment model its barrel had never reached, which is why that package could not build.
Not everything is wired yet: the build is red on twenty-nine `TS2416` errors where three packages'
controllers override the CRUD base with a DTO-typed parameter, and that is being fixed separately.
The permission reload, the feature seed and the defaults seed have been executed against a copy of
the local database (SUPER_ADMIN 234 → 381 grants, idempotent, reversible) but the application has not
been booted with them yet.
Three fixes, all found by agents reading the real toolchain instead of guessing.
**The core build.** nx's tsc executor sets rootDir to the project root, and rewrites the path
mappings of a project's declared dependencies to their built output. core imports scheduler, but
scheduler was the one sibling missing from core's implicitDependencies, so it alone was never
remapped and resolved to source - outside rootDir. The same bare compile without the remapping
reports 383 of these across eight packages, so scheduler was never special; it was simply the one
nx had not been told about. One name added to a list that exists for exactly this, and the count
is zero.
**BaseEvent was unreachable.** The event-bus barrel exported four modules and omitted the one
defining BaseEvent, so every domain publishing an event off it failed to compile against
@gauzy/core - nineteen errors across two packages from one missing line.
**A prerequisite may now be declared by package name, in the type as well as at runtime.** The
loader was taught to resolve a package name last round, but the declaration still said classes
only, so three packages cast their way around the type. The declaration and the accessor now both
say what the runtime accepts, the cast inside the loader is gone, and a plugin can declare what it
must load after without importing it - which is the only way to express a prerequisite on a
package that is not independently importable.
A plugin may declare what it must load after either as the plugin class or as the
package name. The class form is the one the compiler checks; the package form is
not a mistake, because it is the only way to declare a prerequisite on a package
the declaring plugin must not import at build time.
The resolver could not express that. It built a Set of the configured plugin
classes and tested membership against it, so a package name could never be a
member and every plugin declaring one threw. The message made it worse: it
reported `dependency.name`, and a string has no `name`, so an operator was told
the plugin required "an unnamed plugin" with nothing to search for.
Configured plugins are now indexed under both spellings they answer to - the
class name, and the package name derived from it - and a missing prerequisite is
reported as it was written. What is looked up is the plugin identity, and what is
visited and emitted is the entry as configured, so a dynamic module is still
loaded as itself.
Three packages here declare prerequisites by package name, so this is the
difference between the dependency metadata being usable and being a trap: wired
up as it stood, it would have failed the boot of the first plugin it reached.
Also corrects a comment in the API plugin list that claimed the platform resolves
the declared load order. It does not yet: the migrations are ordered by the
platform, the plugin list is not, and the list is kept topologically sorted by
hand until every declared prerequisite is itself registered.
A list route has always accepted filters, a sort, a page, a sparse fieldset and a
relation expansion, and each route grew its own reading of them. The two surfaces
then had to agree about what a query means, which is not something two
hand-written readers reliably do.
So the grammar is now one set of pure functions. REST spells it as a query
string, GraphQL as generated input types, and both hand the result to the same
parser, which is why they cannot disagree: there is one implementation and it
takes values rather than a request. That is also what makes the grammar testable
at all — a query language whose behaviour can only be observed through an HTTP
request is one nobody regression-tests.
What the layer decides:
- Every filter field and every sort field is checked against what the resource
declares, so a caller cannot filter on a column it was never offered, and a
refusal carries the allow-list it was measured against rather than just saying
no.
- A value is coerced to the field's declared kind, and a coercion that would
change meaning is refused instead of performed. Money is the sharp edge: a
fractional JSON number has already lost the caller's precision by the time it
arrives, so it is rejected in favour of a decimal string. `isNull` carries a
boolean rather than a bare null, so the translator can only ever emit an
explicit null test — the historical null-semantics trap stays closed.
- The grammar is statically bounded rather than dependent on how deep a caller is
willing to nest brackets: a filter path is at most two segments, a boolean group
nests at most two levels, and the group, list, key, sort, field, expand and byte
caps all live in one table, so a limit cannot be raised on one surface and
forgotten on the other.
- A cursor names a position in one specific order, so it carries a fingerprint of
the sort it was minted under and is refused if presented against a different
one. An offset request and a cursor request are alternatives; asking for both is
refused rather than resolved.
- The legacy single-JSON parameter keeps working, and stays as forgiving as its
callers need: a field it may no longer sort by is dropped rather than refused,
because those callers have been sending the same order objects for years and
must not start receiving errors for them.
A plugin declares its resources the same way a built-in one does. The platform
unions the declarations, so a plugin's list endpoint is served by the generated
GraphQL inputs on exactly the same terms as a core resource, and no plugin has to
reimplement the grammar to be reachable over both protocols.
Four defects that together made a plugin-contributed GraphQL resolver
impossible and blocked browser clients that authenticate with a key pair:
- The tenant guard asked the execution context for an HTTP request
unconditionally, so the tenant guard chain threw on every GraphQL operation.
Authenticated guards already branch on the operation type; the tenant guard
now does too, and checks the stated tenant only when the caller states one.
- A plugin could declare resolvers but nothing read them. The resolver host is
now a dynamic module that imports every plugin module, so a contributed
resolver can inject the services of the plugin that contributed it.
- The allowed header list omitted the key pair, the channel header and the
retry-safe write headers on all three CORS configurations, so a browser
client could not preflight.
- Resolver and scalar readers are exported from the plugin package.
Adds four additive metadata keys to the plugin decorator so a package can ship
what it owns instead of editing platform files:
- migrations: the migration classes for the tables a package owns are merged
into the connection's migration list before the connection is created, and
ordered by each migration's own timestamp. A missing or duplicated timestamp
is refused at boot rather than applied in file-system order.
- permissions and features: a package declares the permission values and feature
flags it needs; the platform unions them with the built-in catalogue at boot.
- settings: a package declares the settings it reads, with types, defaults,
scope and secret marking, so the value always comes from the settings store.
- dependsOn: prerequisites are ordered deterministically and a missing or
circular dependency is refused at boot.
The contribution registries are global because contributions are consulted from
the role guard, the feature guard, the catalogue endpoints and any service that
reads a declared setting.
No lint invocation in this repo could reach a single file. `nx run-many -t lint --all` failed for
93 of 93 projects, and no CI workflow runs lint, so nothing ever noticed. Two independent bugs,
either of which alone was fatal.
1. The root `eslint.config.js` was `module.exports = new FlatESLint({ overrides: [] })`, importing
a `FlatESLint` class from `@nx/eslint-plugin-nx`. That could never have worked: a flat config
must export an array, and no Nx package has ever exported such a class. `@nx/eslint-plugin-nx`
is the beta-only predecessor NAME of `@nx/eslint-plugin` — the repo declared both, the real one
at ^22.5.2 and this one pinned at 16.0.0-beta.1. The v16 beta drags a nested `@nx/devkit@16`
that expects an `nx` internal path nx@22 no longer ships, so every `eslint` invocation died
with `Cannot find module 'nx/src/utils/typescript'`.
2. All 41 project configs did `[...require('../../.eslintrc.json')]`. That file is a JSON object,
so the spread threw `TypeError: baseConfig is not iterable` — a different failure, on the path
`nx lint <project>` actually takes. `packages/mcp-server` also had the wrong depth.
Changes: remove `@nx/eslint-plugin-nx`, add `typescript-eslint@^8.40.0` (the only genuinely
missing package — `@nx/eslint-plugin`'s flat configs require it unconditionally); rewrite the root
config as a real flat array shaped like Nx 22's own generator output, with real `ignores`
replacing the legacy `"ignorePatterns": ["**/*"]` that disabled linting workspace-wide; repoint
all 41 project configs at the root flat config, dropping the FlatCompat bridge the 12 `.cjs` ones
used; disable the deprecated `@typescript-eslint/no-empty-interface`, which Nx's presets still
enable alongside its v8 replacement `no-empty-object-type` and so double-reported every
occurrence; and re-enable `no-dupe-keys`, `no-dupe-class-members`, `no-dupe-args` and
`no-unreachable`, which typescript-eslint's `eslint-recommended` overlay turns off on the grounds
that `tsc` reports them — no CI job here runs `tsc --noEmit`, and a duplicate key in
`packages/core/jest.config.ts` has already silently changed behaviour once.
The legacy `.eslintrc.json` files are deliberately KEPT: `.codacy/codacy.yaml` pins eslint@8.57.0,
which does read them.
The guardrail is proven, not assumed — against the real historical bug:
packages/core/jest.config.ts
29:2 error Duplicate key 'transformIgnorePatterns' no-dupe-keys
Findings are REPORTED, NOT FIXED (a separate job): 8,887 files linted, 2,290 with problems,
2,649 errors / 6,110 warnings, zero parse errors. Lint should not become a required check until
that backlog is triaged.
Verified: packages/core 56/56 suites and 612/612 tests; build-monorepo-root, build-api, build-libs
and build-web all green; all 42 configs load; `nx lint <project>` now runs and reports instead of
crashing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Pin typescript to ^5.9.3 across the root package.json and all app/package
manifests, and drop the TypeScript 6 only compiler options that came with
the upgrade:
- Remove "ignoreDeprecations": "6.0" from every tsconfig.
- Remove the strict/noUncheckedSideEffectImports/types/esModuleInterop
overrides added to tsconfig.base.json for the TS 6 trial.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Add ignoreDeprecations: '6.0' to tsconfig.base.json and all sub-package tsconfig.json
- Add TS6 compat flags to tsconfig.base.json: strict: false, noUncheckedSideEffectImports: false, types: ['*']
- Reformat electron tsconfig files to use tabs consistently
- Fix path formatting in root tsconfig.json
* @rahul-rocket chore(deps): chore(deps): bump @angular/core from ^20.2.4 to 21.1.2
* fix(ui): update missing jest.preset.js
* fix(nx-migrations): migrate nx from 21.5.1 to 22.4.4
* chore(deps): bump jest-preset-angular to 16.0.0
* chore(deps): bump @nebular/* packages to 17.0.0 for Angular 21 compatibility
* chore(deps): upgrade all packages to Angular 21 and compatible dependencies
* chore(deps): upgrade all packages to Angular 21 and compatible dependencies
* fix(nx-migrations): migrate nx from 21.5.1 to 22.4.4
* Update yarn.lock
* Update yarn.lock
* fix(nx-migrations): migrate nx from 21.5.1 to 22.4.4
* fix(nx-migrations): migrate nx from 21.5.1 to 22.4.4
Replace 'jest-preset-angular/setup-jest' imports with the new 'setupZoneTestEnv' function.
* @nx/jest: replace-removed-matcher-aliases-v22-3
Replace removed matcher aliases in Jest v30 with their corresponding matcher
* chore(deps): @angular/common and @angular/core peerDependencies to ^21.1.0
* Update package.json
* fix(nx-migrations): migrate nx from 21.5.1 to 22.4.4
* chore(deps): bump @nebular/theme from ^16.0.0 to ^17.0.0
* chore(deps): upgrade all packages to Angular 21
* chore(deps): upgrade all packages to Angular 21
* fix(build): update helmet import to support 8.x default export
* fix(build): resolve TypeScript errors and improve code quality
- Fix TemplateRef type conflicts caused by duplicate @angular/core packages (ngx-permissions)
- Change moment imports from namespace to default imports for ESM compatibility
- Convert constructor injection to inject() function in multiple components
- Add OnPush change detection strategy to WindowLayoutComponent
- Make CountdownConfirmationComponent standalone
- Update LayoutWithDraggableObject to use any[] for draggableObject type
* fix(build): fix moment & timezone namespace packages
* fix(build): add jest config for missing packages
* chore(deps): bump swiper from 8.3.1 to 12.1.0
* fix(build): update swiper module and syntax
* Update time-tracking.component.ts
* chore(deps): downgrade `node-polyfill-webpack-plugin` from 4.1.0 to 1.1.4
* fix(deps): resolve browserslist "Unknown version 143 of and_chr" error
Add caniuse-lite and browserslist to yarn resolutions to force all
* fix(nx-migrations): migrate nx from 21.5.1 to 22.4.4
* fix(deps): standardize Angular 21.0.0 versions across all packages and fix compatibility issues
- Fix @angular/* packages to use exact version 21.0.0 (remove caret ^) across all apps, packages, and plugins
- Add @angular/cdk resolution to 21.0.0 to force consistent version
* fix(build): `ui-config` replace env files module issue
* fix(build): `ui-config` replace env files module issue
* fix(build): replace all TemplateRef<HTMLElement> with TemplateRef<any>
* Update package.json
* Update apps\agent\tsconfig.json
* chore(deps): upgrade packages to latest version
* Update yarn.lock
* Update yarn.lock
* fix(build): apply AI suggestion by bot agent reviewers
* fix(build): apply AI suggestion by bot agent reviewers
* fix(nx-migrations): migrate nx from 21.5.1 to 22.4.4
* chore(deps): bump @nestjs/common and @nestjs/core to 11.1.14
* fix(build): replace all TemplateRef<HTMLElement> with TemplateRef<any>
* fix(plugins): apply AI suggestion by bot agent reviewers
* Update yarn.lock
* chore(deps): bump packages
* Update yarn.lock
* chore(deps): bump packages
* chore(deps): bump packages
* fix(plugins): replace 'jest-preset-angular/setup-jest' imports with the new 'setupZoneTestEnv'
* fix(plugins): apply AI suggestion by bot agent reviewers
* fix(cspell): typo spelling :-)
* fix(plugins): apply AI suggestion by bot agent reviewers
* fix: fontawesome icon change version to FA 7
* refactor(ui-core): migrate dashboard directives to standalone
* refactor(ui-core): migrate pipes/directives to standalone
* fix(plugins): apply AI suggestion by bot agent reviewers
* fix(plugins): apply AI suggestion by bot agent reviewers
* chore(deps): bump packages
* refactor(ui-core): migrate directives to standalone
* fix(plugins): apply AI suggestion by bot agent reviewers
---------
Co-authored-by: Ruslan Konviser <evereq@gmail.com>
Co-authored-by: syns2191 <sutralian@gmail.com>
* chore(nx): migrate @nx/workspace to version 20.3.0
* chore(material): run migration-v19 for Angular Material update
* chore(packages): run explicit-standalone-flag migration for Angular v19
* chore(deps): downgrade TypeScript to 5.5.4 for Angular compatibility
* chore(deps): bump Angular ESLint dependencies to version 19
* chore(deps): bump @ng-select/ng-select to version 14.1.0
* chore(deps): bump @commitlint packages to latest versions
* fix(cspell): typo spelling :-)
* chore(packages): migrate initializers to new provider functions
* chore(deps): update the @angular/cli package version to ~19.0.0
* chore(deps): update packages to support Angular v19
* chore(packages): migrate initializers to new provider functions
* fix: correct Sentry.TraceService injection in AppInitializer
* Update yarn.lock
* Update yarn.lock
* fix: update yarn.lock
* fix(cspell): typo spelling :-)
* fix: update yarn.lock
* chore(deps): bump @angular/common to version 19.0.0
* chore(nx): migrate @nx/workspace to version 20.4.2
* chore(deps): update yarn.lock
* chore(nx): migrate @nx/workspace to version 20.4.4
* chore(deps): bump @angular/core from 19.1.5 to 19.1.6
* chore(deps): upgrade @nebular/auth and @nebular/theme to v15
- Upgrade @nebular/auth from ^14.0.2 to ^15.0.0
- Upgrade @nebular/theme from ^14.0.2 to ^15.0.0
* chore(deps): bump @angular-slider/ngx-slider from ^18.0.0 to ^19.0.0
* chore(deps): bump ngx-page-scroll and ngx-page-scroll-core to v14
- Bump ngx-page-scroll from ^13.0.0 to ^14.0.0
- Bump ngx-page-scroll-core from ^13.0.0 to ^14.0.0
* chore(deps): bump ngx-permissions from ^17.1.0 to ^19.0.0
* chore(deps): bump @ng-select/ng-select from ^14.1.0 to ^14.2.2
* chore(deps): bump @fortawesome/angular-fontawesome from 0.15.0 to 1.0.0
* fix: desktop build (make component standalone disabled)
* chore(deps): bump @angular/core from 18.2.12 to 19.1.6
* chore(nx): migrate @nx/workspace to version 20.8.0
* chore(deps): bump ng2-file-upload to version ^8.0.0
* chore(deps): bump @angular/core from 19.1.6 to 19.2.7
* chore(deps): bump @fullcalendar/core from ^6.1.15 to ^6.1.17
* chore(deps): bump @angular-eslint packages to v19.3.0
* fix: add `standalone: false` to angular components
* chore(deps): downgrade @angular-builders/custom-webpack from v19.0.1 to v18.0.0
* chore(deps): bump angular2-smart-table from ^3.5.0 to ^3.6.1
* refactor(styles): replace @import with @use for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* chore(deps): bump @angular/core from 19.0.0 to 19.2.0
* chore(deps): updated dependencies for `@fullcalendar/angular`
* fix(cspell): typo spelling :-)
* Revert "chore(deps): updated dependencies for `@fullcalendar/angular`"
This reverts commit 4b34d72071.
* chore(deps): switch @angular/* to ^19.2.7
* fix: revert nx migrations.json
* Revert "chore(deps): switch @angular/* to ^19.2.7"
This reverts commit edd9105c51.
* fix: align @angular/cdk version with @angular/core version
* chore(deps): bump @angular-builders/custom-webpack from 18.0.0 to 19.0.1
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* refactor(styles): replace `@import` with `@use` for SCSS module
* chore(deps): bump typescript from 5.5.4 to ^5.8.3
* fix(server-dashboard): remove redundant nullish coalescing from autoStart check
* fix: add suggestions from greptile-apps bot review
* fix: add suggestions from greptile-apps bot review