@onroad/core 4.0.0-alpha.1 → 4.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> TypeScript backend framework for multi-tenant Express APIs — DI Container, Filter Chain, EventBus, Provider Pattern.
|
|
4
4
|
|
|
5
|
-
**v4.0.0-alpha.
|
|
5
|
+
**v4.0.0-alpha.1** — Full TypeScript rewrite of the onRoad framework.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
- [Graceful Shutdown](#graceful-shutdown)
|
|
28
28
|
- [Testing](#testing)
|
|
29
29
|
- [Subpath Exports](#subpath-exports)
|
|
30
|
+
- [Known Pitfalls](#known-pitfalls)
|
|
30
31
|
|
|
31
32
|
---
|
|
32
33
|
|
|
@@ -665,6 +666,103 @@ import { StorageProvider } from "@onroad/core/storage" // Storag
|
|
|
665
666
|
|
|
666
667
|
---
|
|
667
668
|
|
|
669
|
+
## Known Pitfalls
|
|
670
|
+
|
|
671
|
+
### Controller base path must not be empty
|
|
672
|
+
|
|
673
|
+
Always pass `/` or a non-empty path to `@Controller()`. An empty string is falsy and previously caused the route guard to **silently drop all routes** of that controller.
|
|
674
|
+
|
|
675
|
+
```ts
|
|
676
|
+
// ❌ Wrong — all routes silently skipped
|
|
677
|
+
@Controller("")
|
|
678
|
+
class UserController extends AbstractController<UserService> { ... }
|
|
679
|
+
|
|
680
|
+
// ✅ Correct — root-level routes
|
|
681
|
+
@Controller("/")
|
|
682
|
+
class UserController extends AbstractController<UserService> { ... }
|
|
683
|
+
|
|
684
|
+
// ✅ Correct — prefixed routes
|
|
685
|
+
@Controller("/users")
|
|
686
|
+
class UserController extends AbstractController<UserService> { ... }
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
> Since **v4.0.0-alpha.1** the path guard was tightened (`basePath === undefined || basePath === null`) and paths are normalized (`//auth` → `/auth`), so `@Controller("/")` + route `"/auth"` resolves correctly to `/auth` instead of `//auth`.
|
|
690
|
+
|
|
691
|
+
---
|
|
692
|
+
|
|
693
|
+
### Circular service dependencies
|
|
694
|
+
|
|
695
|
+
When two services reference each other (e.g. `UserService ↔ CompanyService`), eager instantiation inside `configDependencies()` causes a `RangeError: Maximum call stack size exceeded` at startup because the constructors recurse infinitely.
|
|
696
|
+
|
|
697
|
+
```ts
|
|
698
|
+
// ❌ Wrong — infinite recursion on startup
|
|
699
|
+
@Service()
|
|
700
|
+
class UserService extends AbstractService<UserRepository> {
|
|
701
|
+
companySVC!: CompanyService
|
|
702
|
+
|
|
703
|
+
configDependencies() {
|
|
704
|
+
this.companySVC = new CompanyService() // → CompanyService() → new UserService() → ...
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
Fix: replace the eager field with a **lazy getter**. The getter body only runs on first access, never during construction, which breaks the cycle:
|
|
710
|
+
|
|
711
|
+
```ts
|
|
712
|
+
// ✅ Correct — lazy getter breaks the circular chain
|
|
713
|
+
@Service()
|
|
714
|
+
class UserService extends AbstractService<UserRepository> {
|
|
715
|
+
private _companySVC?: CompanyService
|
|
716
|
+
|
|
717
|
+
protected get companySVC(): CompanyService {
|
|
718
|
+
if (!this._companySVC) this._companySVC = new CompanyService()
|
|
719
|
+
return this._companySVC
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
@Service()
|
|
724
|
+
class CompanyService extends AbstractService<CompanyRepository> {
|
|
725
|
+
private _userSVC?: UserService
|
|
726
|
+
|
|
727
|
+
protected get userSVC(): UserService {
|
|
728
|
+
if (!this._userSVC) this._userSVC = new UserService()
|
|
729
|
+
return this._userSVC
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
> **Why it was masked before**: the `if (!basePath)` bug meant controllers (and therefore services) were never instantiated during `buildServer()`. The circular dep crash only surfaced after fixing the route guard.
|
|
735
|
+
|
|
736
|
+
---
|
|
737
|
+
|
|
738
|
+
### Overriding `fullAssociation` in Repositories
|
|
739
|
+
|
|
740
|
+
When using `@onroad/core`, the `@Repository` decorator automatically builds relations and injects the `fullAssociation` property populated with the appropriate Sequelize Models. Manually overriding this property in your repository class using raw ES classes will cause crashes during runtime (e.g., `TypeError: include.model.getTableName is not a function`) because Sequelize expects internal model objects, not raw classes.
|
|
741
|
+
|
|
742
|
+
```ts
|
|
743
|
+
// ❌ Wrong — overriding fullAssociation with raw ES classes crashes Sequelize
|
|
744
|
+
@Repository({ entity: User })
|
|
745
|
+
export class UserRepository extends BaseRepository<User> {
|
|
746
|
+
readonly fullAssociation = [{ model: FilterPref, as: "filters" }]
|
|
747
|
+
}
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
**Fix:** Remove the hardcoded override. If you are extending a custom `BaseRepository` and need TypeScript to recognize the property without emitting an overriding value in the compiled JavaScript, use the `declare` modifier:
|
|
751
|
+
|
|
752
|
+
```ts
|
|
753
|
+
// ✅ Correct — Let the decorator inject the value and use `declare` for typings
|
|
754
|
+
export abstract class BaseRepository<TEntity = unknown> extends SequelizeRepository<TEntity> {
|
|
755
|
+
declare readonly fullAssociation: any[] // Tells TS it exists without overriding it
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
@Repository({ entity: User })
|
|
759
|
+
export class UserRepository extends BaseRepository<User> {
|
|
760
|
+
// No fullAssociation override here!
|
|
761
|
+
}
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
---
|
|
765
|
+
|
|
668
766
|
## License
|
|
669
767
|
|
|
670
768
|
UNLICENSED — HashCodeTI-Brasil
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onroad/core",
|
|
3
|
-
"version": "4.0.0-alpha.
|
|
4
|
-
"description": "TypeScript backend framework
|
|
3
|
+
"version": "4.0.0-alpha.2",
|
|
4
|
+
"description": "TypeScript backend framework — DI Container, Filter Chain, EventBus, Provider Pattern",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|