Skip to content
Open
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
18 changes: 17 additions & 1 deletion apps/iracing-data-cli/src/api.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { CarApi, Configuration, DocApi } from "@iracing-data/api-client-fetch";
import {
CarApi,
Configuration,
DocApi,
SeriesApi,
} from "@iracing-data/api-client-fetch";

/** Shared SDK configuration and lazy generated Data API clients, without CLI policy. */
export class IRacingAPI {
private documentation?: DocApi;
private cars?: CarApi;
private seriesClient?: SeriesApi;

/**
* Keep the generated SDK defaults, including its canonical Data API base URL.
Expand Down Expand Up @@ -34,6 +40,16 @@ export class IRacingAPI {
return this.cars;
}

/**
* Access the generated series client on first use.
* @returns {SeriesApi} Cached generated series client.
*/
get series(): SeriesApi {
this.seriesClient ??= new SeriesApi(this.configuration);

return this.seriesClient;
}

/**
* Retain one configuration for all generated clients exposed by this facade.
* @param {Configuration} configuration - Shared generated SDK configuration.
Expand Down
2 changes: 1 addition & 1 deletion apps/iracing-data-cli/src/commands/assets/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Assets commands

`iracing-data assets` is the CLI surface for runtime Data API `*/assets` operations. The command group is structural; each leaf chooses its generated API operation and delegates credentials, generated request handling, and JSON publication to the shared document request executor. Car uses that executor in this layer; series and track migrate in the following stacked changes. The returned-link materializer remains an injected, shared HTTPS-only transport boundary.
`iracing-data assets` is the CLI surface for runtime Data API `*/assets` operations. The command group is structural; each leaf chooses its generated API operation and delegates credentials, generated request handling, and JSON publication to the shared document request executor. Car and series use the shared executor in this layer; track migrates in the final stacked change. The returned-link materializer remains an injected, shared HTTPS-only transport boundary.

Current authored leaves:

Expand Down
33 changes: 14 additions & 19 deletions apps/iracing-data-cli/src/commands/assets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,50 @@ import { Command } from "@commander-js/extra-typings";
import { createCarAssetsCommand, type CarAssetsService } from "./car/index.js";
import {
createSeriesAssetsCommand,
type SeriesAssetsScopeDependencies,
type SeriesAssetsService,
} from "./series/index.js";
import {
createTrackAssetsCommand,
type TrackAssetsScopeDependencies,
} from "./track/index.js";
import type { Diagnostics } from "../../diagnostics.js";

/** Service composition during the car-only migration phase. */
/** Transitional registration contract while track remains on its old scope. */
export interface CreateAssetsCommandOptions {
/** Already-composed service for the migrated car command. */
/** Already-composed car service. */
carService: CarAssetsService;

/** Still needed by the series and track commands until their stack layers. */
diagnostics: Diagnostics;
/** Already-composed series service. */
seriesService: SeriesAssetsService;

/** Legacy series injection until PR B. */
seriesDependencies?: SeriesAssetsScopeDependencies;
/** Still required by the old track-assets implementation. */
diagnostics: Diagnostics;

/** Legacy track injection until PR C. */
/** Legacy track dependencies until PR C. */
trackDependencies?: TrackAssetsScopeDependencies;
}

/**
* Group independently registered leaves without executing external effects.
* @param {CreateAssetsCommandOptions} root0 - Leaf service and transitional scopes.
* Group independently registered leaves without external effects.
* @param {CreateAssetsCommandOptions} root0 - Services and transitional track wiring.
* @param {CarAssetsService} root0.carService - Migrated car service.
* @param {Diagnostics} root0.diagnostics - Legacy leaf diagnostics.
* @param {SeriesAssetsScopeDependencies} root0.seriesDependencies - Legacy series I/O.
* @param {SeriesAssetsService} root0.seriesService - Migrated series service.
* @param {Diagnostics} root0.diagnostics - Legacy track diagnostics.
* @param {TrackAssetsScopeDependencies} root0.trackDependencies - Legacy track I/O.
* @returns {Command} Structural assets command.
*/
export function createAssetsCommand({
carService,
seriesService,
diagnostics,
seriesDependencies,
trackDependencies,
}: CreateAssetsCommandOptions) {
const assets = new Command("assets").description(
"Data API asset metadata commands",
);

assets.addCommand(createCarAssetsCommand(carService));
assets.addCommand(
createSeriesAssetsCommand({
diagnostics,
dependencies: seriesDependencies,
}),
);
assets.addCommand(createSeriesAssetsCommand(seriesService));
assets.addCommand(
createTrackAssetsCommand({
diagnostics,
Expand Down
59 changes: 8 additions & 51 deletions apps/iracing-data-cli/src/commands/assets/series/command.ts
Original file line number Diff line number Diff line change
@@ -1,62 +1,19 @@
/** Thin Commander adapter for the series-assets service. */
import { Command } from "@commander-js/extra-typings";
import type { CredentialOptions } from "../../../credentials.js";
import type { Diagnostics } from "../../../diagnostics.js";

/** Credential options accepted by the series-assets command. */
export type SeriesAssetsOptions = CredentialOptions;

/** Per-invocation capabilities required by the series-assets command handler. */
export interface SeriesAssetsCommandScope {
/** Retrieves the selected asset metadata through the generated API client. */
assets: {
get(): Promise<unknown>;
};

/** Writes the command result to the configured destination. */
output: {
write(payload: unknown): void;
};

/** Secret-safe diagnostic sink for command progress and failures. */
diagnostics: Diagnostics;
}

/**
* Factory contract for one isolated series-assets invocation scope.
* @param {SeriesAssetsOptions} options - Configuration and injected capabilities for this operation.
* @returns {Promise<SeriesAssetsCommandScope>} Resolved capabilities for one command invocation.
*/
export type CreateSeriesAssetsCommandScope = (
options: SeriesAssetsOptions,
) => Promise<SeriesAssetsCommandScope>;

/** Application-registration dependencies for the series-assets command. */
export interface SeriesAssetsCommandDependencies {
/** Resolves dependencies once for each command invocation. */
createScope: CreateSeriesAssetsCommandScope;
}
import { OptionsSchema } from "./schema.js";
import type { SeriesAssetsService } from "./service.js";

/**
* Build `iracing-data assets series` around one command-scoped dependency resolution.
* @param {SeriesAssetsCommandDependencies} root0 - Command composition inputs and dependency overrides.
* @param {CreateSeriesAssetsCommandScope} root0.createScope - Factory resolving dependencies once per command invocation.
* @returns {Command} Configured CLI command ready for registration.
* Register without credential, network, or output effects.
* @param {SeriesAssetsService} service - Opinionated series-assets execution.
* @returns {Command} Configured series-assets command.
*/
export function createSeriesAssetsCommand({
createScope,
}: SeriesAssetsCommandDependencies) {
export function createSeriesAssetsCommand(service: SeriesAssetsService) {
return new Command("series")
.description("Fetch and materialize Data API series asset metadata")
.option(
"--credentials <path>",
"Read access_token from an auth login JSON or YAML file",
)
.action(async (options) => {
const { assets, output, diagnostics } = await createScope(options);

const payload = await assets.get();

output.write(payload);
diagnostics.info("Series assets fetched.");
});
.action((options) => service.execute(OptionsSchema.parse(options)));
}
48 changes: 6 additions & 42 deletions apps/iracing-data-cli/src/commands/assets/series/index.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,6 @@
import {
createSeriesAssetsCommand as createCommand,
type SeriesAssetsCommandDependencies,
} from "./command.js";
import {
createSeriesAssetsCommandScopeFactory,
type SeriesAssetsScopeDependencies,
} from "./scope.js";
import type { Diagnostics } from "../../../diagnostics.js";

/** Composition inputs used to bind the series-assets leaf command. */
export interface CreateSeriesAssetsCommandOptions {
/** Secret-safe diagnostic sink for command progress and failures. */
diagnostics: Diagnostics;

/** Optional overrides for command-scoped external capabilities. */
dependencies?: SeriesAssetsScopeDependencies;
}

/**
* Public registration boundary for `iracing-data assets series`.
* Production callers use defaults while tests may inject command-scoped seams.
* @param {CreateSeriesAssetsCommandOptions} root0 - Command composition inputs and dependency overrides.
* @param {Diagnostics} root0.diagnostics - Secret-safe sink for command progress and failure messages.
* @param {SeriesAssetsScopeDependencies | undefined} root0.dependencies - Injected external capabilities used by the command scope.
* @returns {Command} Configured CLI command ready for registration.
*/
export function createSeriesAssetsCommand({
diagnostics,
dependencies,
}: CreateSeriesAssetsCommandOptions) {
const commandDependencies: SeriesAssetsCommandDependencies = {
createScope: createSeriesAssetsCommandScopeFactory(
diagnostics,
dependencies,
),
};

return createCommand(commandDependencies);
}

export type { SeriesAssetsScopeDependencies } from "./scope.js";
/** Series-assets registration, schema, and service entry points. */
export { createSeriesAssetsCommand } from "./command.js";
export { makeSeriesAssetsService } from "./service.js";
export { RawOptionsSchema, OptionsSchema } from "./schema.js";
export type { RawOptions, Options } from "./schema.js";
export type { SeriesAssetsService } from "./service.js";
18 changes: 18 additions & 0 deletions apps/iracing-data-cli/src/commands/assets/series/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/** Series-assets RawOptions-to-Options schema normalization. */
import { DocumentInputSchema } from "../../../services/request.js";
import type { z } from "zod";

/** Only public series-assets flag: --credentials. */
export const RawOptionsSchema = DocumentInputSchema.pick({ credentials: true });

/** Raw Commander options derived from the Zod schema. */
export type RawOptions = z.input<typeof RawOptionsSchema>;

/** Force JSON stdout without exposing a new output flag. */
export const OptionsSchema = RawOptionsSchema.transform((options) => ({
...options,
format: "json" as const,
}));

/** Validated series-assets options. */
export type Options = z.output<typeof OptionsSchema>;
Loading
Loading