ngx-data-core
v0.0.2
Published
Shared base classes for the Service/State/Facade data-access pattern used across this Angular workspace's sibling projects (e.g. `bookmarks`, `characters`).
Readme
ngx-data-core
Shared base classes for the Service/State/Facade data-access pattern used across this Angular workspace's sibling projects (e.g. bookmarks, characters).
What's in here
StateService<T>(base-state.service.ts) — a signal-based state holder. Subclass it, callsuper(initialState), and use the protectedupdateState()/reset()methods plus the publicstate/loading/errorsignals.BaseDataService<T>(base-data.service.ts) — a generic CRUD-over-HttpClientbase. Subclass it and declareprotected override readonly endpoint: string; you getgetAll/getById/create/update/deletefor free.BaseFacade<T, State>(base-facade.service.ts) — extendsStateService, addscreateResource(), a thin wrapper aroundrxResourcefor building auto-reloading resources from reactive params.
None of these classes are Supabase-specific. The consuming app is expected to provide its own HttpClient interceptor (e.g. a PostgREST-rewrite interceptor) if it's talking to Supabase — see bookmarks/src/app/core/supabase/supabase-rest.interceptor.ts for a working example.
Usage
// my-entity-data.service.ts
@Injectable({ providedIn: 'root' })
export class MyEntityDataService extends BaseDataService<MyEntity> {
protected override readonly endpoint = `${inject(AppConfigService).restUrl}/my_entity`;
}// my-entity.facade.ts
interface MyEntityState {
selectedId: string | null;
}
@Injectable({ providedIn: 'root' })
export class MyEntityFacade extends BaseFacade<MyEntity, MyEntityState> {
constructor() {
super({ selectedId: null });
}
}Building and consuming locally
This library isn't published to npm. Consuming projects reference a packed tarball, not the raw dist/ directory:
# in angular-data-lib/
ng build ngx-data-core
cd dist/ngx-data-core
npm pack # produces ngx-data-core-<version>.tgz// in the consuming project's package.json
"dependencies": {
"ngx-data-core": "file:../angular-data-lib/dist/ngx-data-core/ngx-data-core-0.0.1.tgz"
}Then run npm install in the consuming project.
Why a tarball and not a plain file:../.../dist/ngx-data-core directory reference: npm installs directory-style file: dependencies as a symlink. Since the symlink target lives outside the consumer's own directory tree, Node resolves bare imports like @angular/core from within the linked package relative to its real path (angular-data-lib/node_modules/@angular/core) instead of the consumer's node_modules/@angular/core — a classic dual-package hazard. In practice this made inject() calls inside BaseFacade/StateService throw NG0203 under the consumer's Vitest test runner (it worked fine in production builds, since esbuild's app bundling happened to dedupe it there, but broke under @angular/build:unit-test). Packing into a tarball makes npm extract a real, independent copy into the consumer's node_modules, resolving @angular/core the normal way.
Whenever this library changes: rebuild, re-pack (bump the version in projects/ngx-data-core/package.json if you want to avoid stale-tarball confusion), and re-run npm install in the consumer — there's no watch-mode wiring between the two repos yet.
Development
ng test ngx-data-core # run the unit tests (Vitest)
ng build ngx-data-core # build to dist/ngx-data-core