Files
zeekay 3311b1eae8 the Hanzo API as Angular services, over HttpClient and returning Observable
A projection of hanzoai/cloud's openapi.yaml at the ref .spec-lock names —
2479 operations, 192 injectable services, 2460 models — generated by
hanzoai/openapi's generate.py from the `angular` row of its sdks.yaml. Nothing
under src/ is written by hand.

It exists because the framework owns the transport and the return type: an
axios client is a second HTTP stack no interceptor sees, and a wrapped promise
is an Observable that cannot be cancelled. serviceSuffix is Api rather than the
generator's Service default because this API has a product called `base`, whose
default class name is the generated transport's own parent.
2026-08-14 21:13:44 -07:00

4.2 KiB

hanzoai-angular

This repo holds no decisions. src/ is generated and .spec-lock says from what.

One of three TypeScript projections of hanzoai/cloud's openapi.yaml:

package repo generator for
hanzoai hanzoai/js-sdk typescript-axios the default — Node, bundled browser apps
hanzoai-fetch hanzo-js/sdk-fetch typescript-fetch hosts where a dependency tree is the cost
hanzoai-angular hanzo-js/sdk-angular typescript-angular Angular DI, HttpClient, Observable

All three are regenerated from ONE document at ONE digest by a cloud release, so they never describe different releases.

The rule that put this repo here

A variant earns a package when a runtime or a framework cannot use the default projection. Angular is the strongest case there is: it owns the transport and the return type. Interceptors, HttpContext, SSR transfer-cache, cancellable Observables and HttpTestingController all follow from calls going through HttpClient, and an axios client is a second HTTP stack none of them can see. Wrapping it yields promises inside a framework whose surface composes Observables.

192 services, one @Injectable({providedIn: 'root'}) each — so a service nobody injects is unreachable and the bundler drops it. Both entry shapes ship: provideApi() for a standalone application, ApiModule.forRoot() for an NgModule one.

Editing

Nothing under src/. To change what the client says, change the route in hanzoai/cloud; to change how it is projected, change the angular row of hanzoai/openapi's sdks.yaml and regenerate. .generated records every file this driver wrote, and --check is what makes "nobody edited it" a fact.

OPENAPI=../../hanzo/openapi ./scripts/generate.sh --check   # clean, or the diff

Repo-owned (the generator never writes these): package.json, tsconfig.json, ng-package.json, .spec-lock, hanzo.yml, scripts/, README.md, LICENSE.

Three things measured here, worth not re-learning

serviceSuffix: Api is forced, not preferred. The API has a product called base, so under the generator's Service default its class is BaseService — the name of the generated transport's own parent in api.base.service.ts — and base.service.ts compiles to export class BaseService extends BaseService (TS2440, TS2395, TS2506, five TS2339s). Generator 7.14.0 has --model-name-mappings and --name-mappings but no per-tag api mapping, so this global suffix is the only lever that reaches an API class name. It also removes a second collision for free — the schema o11y.Service Pascal-cases to O11yService, which was the o11y tag's own class, TS2308 in src/index.ts — and it puts all three TypeScript clients on one class name per product (KeysApi everywhere).

ng-package.json is the repo's, not the generator's. The row takes the whole output into src/, so the emitted manifest would land at src/ng-package.json; ng-packagr resolves dest relative to the manifest, so the build would write into the tree it compiles. It is on hanzoai/openapi's drop list and the repo's own sits at the root, naming src/index.ts.

ngVersion is deliberately unset. Measured: generated at the generator's default 19.0.0 and again at 22.0.0, exactly one of 2671 files differs and it is package.json, which is dropped. So the value would reach nothing this repo keeps; the peer range is a fact about the published package and lives in the package.json the repo owns.

o11y.GettableAgentCheckIn collides the same way it does in every other language — integration_config/integrationConfig and removed_at/removedAt are both live wire, both camel-case to one field. The row renames the identifier and never the wire name.

Building and publishing

npm run build is ng-packagr, which is also the gate: it runs the Angular compiler over all 192 services and 2460 models in partial compilation mode (full compilation would pin the output to one Angular, and ngcc — which used to bridge that — was removed in Angular 16), then bundles to FESM2022.

The publishable package is dist/, which ng-packagr writes with scripts and devDependencies stripped. npm publish runs from there, not from the repo root.