All MicroEvals
# TypeScript MicroEval: Resilient Shipping Quote Service Yo...
Create MicroEval
Header image for # TypeScript MicroEval: Resilient Shipping Quote Service

Yo...

# TypeScript MicroEval: Resilient Shipping Quote Service Yo...

Prompt

# TypeScript MicroEval: Resilient Shipping Quote Service You are participating in a staff-level TypeScript technical interview. Your task is to design and write the core application code for a shipping quote service. This is a static code-review exercise: the answer will be assessed by reading it, not by running it. ## Non-execution constraint This problem is completely self-contained. It has no setup or prerequisite steps. Do not: - run commands or use tools; - use web search; - install packages or dependencies; - create a project or write files; - compile, execute, or benchmark the code; - provide `package.json`, `tsconfig.json`, build configuration, shell commands, or setup instructions; - import third-party libraries or refer to external files. Write the requested TypeScript directly in your response. Assume standard modern TypeScript and the standard ECMAScript and DOM APIs, including `Promise`, `AbortController`, `AbortSignal`, `setTimeout`, and `clearTimeout`. The code should be internally consistent and plausibly type-check under strict TypeScript settings, but it will not be executed during the interview. ## Scenario Implement the application layer of a shipping quote service. The service receives an untrusted request, asks every configured external shipping provider for quotes, validates all external data, and returns a deterministic aggregate result. The public API is: ```ts export interface QuoteService { search( input: unknown, signal?: AbortSignal, ): Promise<QuoteSearchResult>; } export function createQuoteService( dependencies: QuoteServiceDependencies, ): QuoteService; ``` Define all supporting types and provide the complete implementation. ## Request boundary A valid request has this logical shape: ```ts { originPostalCode: string; destinationPostalCode: string; currency: "PHP" | "USD"; parcels: Array<{ weightGrams: number; lengthCm: number; widthCm: number; heightCm: number; }>; } ``` Rules: - Treat `input` as untrusted. - Do not access a property before safely establishing that its containing value is a non-null object. - Postal codes must be non-empty after trimming. - Normalize postal codes by trimming and converting them to uppercase. - There must be between 1 and 20 parcels. - Every parcel measurement must be a finite positive integer. - Collect useful field-level validation issues rather than returning only the first issue. - Input validation happens before cancellation is considered. Invalid input therefore returns `invalidInput` even when the supplied signal is already aborted. - Validation failures are expected outcomes and must not be implemented as thrown exceptions. - No provider may be called when the input is invalid. ## Provider boundary External providers implement: ```ts export interface QuoteProvider { readonly id: string; getQuotes( request: QuoteRequest, signal: AbortSignal, ): Promise<unknown>; } ``` Provider implementations are outside the service's trust boundary. A provider may: - resolve with any JavaScript value; - reject with any JavaScript value; - throw synchronously instead of returning a promise; - ignore its `AbortSignal`; - settle after cancellation or timeout; or - never settle. A valid provider response is an array, including an empty array, with this logical item shape: ```ts { serviceCode: string; amountMinor: number; currency: string; estimatedDays: number; } ``` A quote is valid only when: - `serviceCode` is non-empty after trimming; - the output and deduplication key use the trimmed `serviceCode`; - `amountMinor` is a finite, non-negative integer; - `currency` exactly matches the request currency; and - `estimatedDays` is a finite positive integer. If any array item is invalid, the entire response from that provider attempt is malformed. Validate responses at runtime. Do not convert `unknown` to a trusted response type through an unchecked assertion. ## Provider failures and retries The following structured rejection may be recognized only after validating its complete shape: ```ts { kind: "transient" | "permanent"; code: string; message: string; } ``` Retry policy: - A structured transient rejection is retried once. - A timeout is retried once. - There are at most two attempts per provider. - Permanent, malformed, and unexpected failures are never retried. - A retry must use a fresh attempt controller and a fresh timeout. - Call the injected `sleep` exactly once between attempts. - Do not begin a retry after caller cancellation. - If `sleep` rejects while the caller is not cancelled, classify that provider as `unexpected`; other providers must remain unaffected. Do not expose raw thrown values, stack traces, structured failure codes, or provider messages to callers. ## Dependencies and configuration Define a minimal `QuoteServiceDependencies` interface containing: - configured providers; - provider timeout duration; - retry delay; - an injected cancellation-aware sleep operation. The sleep contract is: ```ts sleep(delayMs: number, signal: AbortSignal): Promise<void> ``` The injected sleep operation is trusted to settle promptly by rejecting when its signal is aborted. Its rejection value is not trusted and must not be exposed. `createQuoteService` must synchronously reject invalid programmer configuration with `TypeError`. Validate these invariants once during creation: - at least one provider is configured; - every provider ID is a non-empty string after trimming and contains no leading or trailing whitespace; - provider IDs are unique; - `providerTimeoutMs` is a finite positive integer; and - `retryDelayMs` is a finite non-negative integer. Configuration errors are programmer errors. They are distinct from expected `search` outcomes. Do not introduce a dependency-injection container. ## Required result model Model `QuoteSearchResult` as a discriminated union with these logical variants: ```ts type QuoteSearchResult = | { status: "success"; quotes: readonly Quote[]; providerFailures: readonly ProviderFailure[]; } | { status: "invalidInput"; issues: readonly InputIssue[]; } | { status: "cancelled"; } | { status: "allProvidersFailed"; providerFailures: readonly ProviderFailure[]; }; ``` Each `ProviderFailure` must contain only: - `providerId`; - `kind`: `"transient" | "permanent" | "malformed" | "timeout" | "unexpected"`; and - `attempts`: `1 | 2`. Do not manufacture provider failures for a caller-cancelled search. Caller cancellation is represented only by the top-level `cancelled` result. ## Aggregation behavior - Start the initial attempt for every configured provider without waiting for another provider. - One provider failure must not prevent other provider workflows from completing. - A valid empty response counts as a successful provider response. - Return `success` when at least one provider produced a valid response, even if the final quote array is empty. - A partial `success` must include failures from unsuccessful providers. - Return `allProvidersFailed` only when no provider produced a valid response. - Preserve provider failures in configured-provider order, regardless of completion order. - Deduplicate quotes using the tuple `(providerId, serviceCode)` without relying on delimiter concatenation. - For duplicates, retain the lowest `amountMinor`. - If duplicate prices are equal, retain the lowest `estimatedDays`. - If both values are equal, retaining either identical-key quote is acceptable. - Sort quotes deterministically by: 1. `amountMinor`, ascending; 2. `estimatedDays`, ascending; 3. `providerId`, using JavaScript code-unit ordering with `<` and `>`; 4. `serviceCode`, using the same ordering. Do not use locale-sensitive comparison. ## Cancellation and timeout semantics - After valid input is established, a pre-aborted caller signal returns `cancelled` without invoking any provider. - Caller cancellation aborts every currently active provider attempt through that attempt's own child signal. - Caller cancellation must make `search` settle promptly without waiting for providers that ignore abort or never settle. - If caller cancellation is observed before the result is returned, `cancelled` wins and partial quotes are discarded. - Each attempt has an independent timeout and `AbortController`. - A timeout aborts only that attempt through its signal. - A provider resolution after its timeout or caller cancellation must be ignored. - A late provider rejection must remain observed and must not become an unhandled rejection. - A failed, timed-out, or cancelled attempt must never abort an unrelated provider attempt. - Clear timers and remove abort listeners as soon as they are no longer needed. Merely passing an `AbortSignal` to a provider is not sufficient to satisfy prompt cancellation or timeout behavior. The orchestration must be able to settle independently of an uncooperative provider promise while still observing that promise. ## Design expectations The implementation should demonstrate: - safe boundary validation; - explicit modeling of expected outcomes; - exhaustive handling of discriminated unions where appropriate; - clear separation between request validation, provider-boundary handling, orchestration, and aggregation; - dependency inversion at external boundaries; - deterministic behavior; - high cohesion and low coupling; - easy addition of another provider without central provider-specific branching; - appropriate resource cleanup; and - minimal but meaningful abstractions. Avoid: - `any`; - `@ts-ignore` or `@ts-expect-error`; - unchecked double assertions; - direct assertions from provider `unknown` data to trusted response types; - pervasive assertions or non-null assertions used to bypass weak modeling; - expected-outcome control flow based primarily on exceptions; - inheritance-based service hierarchies; - `BaseService` or `BaseProvider`; - decorators; - service locators or dependency-injection frameworks; - generic repository abstractions; - middleware frameworks; - event buses; and - speculative patterns unrelated to the requirements. Ordinary functions and small interfaces are preferred. A class is acceptable only when it makes lifecycle or state ownership clearer. ## Scope limit - Keep production code at or below 380 nonblank lines of TypeScript across all code blocks. - Use at most four logically named files. - Do not provide executable tests or test-framework code. - Do not provide configuration, prerequisite, installation, build, or execution instructions. - After the implementation, provide at most eight behavior-focused test cases that should be written. ## Required response format Return exactly these sections: ### 1. Design In no more than 180 words, explain: - the main boundaries; - the result and failure model; - how timeout, caller cancellation, and late provider settlement interact; and - one abstraction deliberately omitted because it would add unnecessary complexity. ### 2. Code Provide the complete TypeScript implementation. Put each file in a separate code block with its path immediately above it. The code must contain no placeholders, ellipses, pseudocode, omitted implementations, or comments claiming production code would behave differently. ### 3. Review In no more than 180 words, discuss: - the most important invariant; - the most likely lifecycle bug in a naive implementation; - one security or information-exposure decision; and - the first architectural change you would make for provider-specific authentication and rate limiting. ### 4. Test cases List at most eight behavior-focused test cases. Do not write executable test code. Do not provide an internal chain-of-thought transcript.

Drag to resize
Drag to resize
Drag to resize

Response not available

Drag to resize