Skip to content

feat: enhance type safety with Zod branded types and performance optimizations - #109

Merged
ryoppippi merged 3 commits into
mainfrom
brand
Jun 18, 2025
Merged

ryoppippi merged 3 commits into
mainfrom
brand

Conversation

@ryoppippi

@ryoppippi ryoppippi commented Jun 18, 2025 •

Copy link
Copy Markdown
Member

Summary

This comprehensive implementation introduces branded types for enhanced type safety while maintaining performance through strategic optimizations.

🎯 Key Features

Branded Types Implementation

  • Core Identifiers: ModelName, SessionId, ProjectPath, Version for compile-time safety
  • Date Types: DailyDate, ActivityDate, MonthlyDate, ISOTimestamp for temporal data validation
  • Helper Functions: Type-safe constructors with validation (createModelName, createActivityDate, etc.)
  • Type Safety: Prevents runtime errors and improves IDE support

Performance Optimizations

  • Smart Parsing: Use type assertions for already-validated data in hot paths
  • Loop Optimization: Avoid expensive regex validation in array mapping operations
  • Balanced Approach: Maintain type safety while optimizing critical performance paths

Backward Compatibility

  • Legacy Support: Relaxed model name validation for synthetic/unknown models
  • Data Migration: Seamless compatibility with existing JSONL data formats
  • Non-breaking: All existing functionality preserved

📊 Performance Analysis

Bundle Size Impact

  • Main Branch: 919.38 kB
  • Current Branch: 922.96 kB
  • Difference: +3.58 kB (+0.4%) - minimal overhead for comprehensive type safety

Runtime Performance (hyperfine benchmarks, offline mode)

Daily Command Performance

```bash

Main Branch

Time (mean ± σ): 612.7 ms ± 20.9 ms
Range (min … max): 590.7 ms … 684.4 ms

Brand Types Branch

Time (mean ± σ): 631.3 ms ± 7.0 ms
Range (min … max): 618.5 ms … 645.3 ms

Result: ~3% slower (18.6ms difference)

```

Session Command Performance

```bash

Main Branch

Time (mean ± σ): 606.0 ms ± 9.8 ms
Range (min … max): 593.1 ms … 630.4 ms

Brand Types Branch

Time (mean ± σ): 620.7 ms ± 6.0 ms
Range (min … max): 608.5 ms … 630.9 ms

Result: ~2.4% slower (14.7ms difference)

```

Monthly Command Performance

```bash

Main Branch

Time (mean ± σ): 607.9 ms ± 6.4 ms
Range (min … max): 597.5 ms … 618.9 ms

Brand Types Branch

Time (mean ± σ): 622.9 ms ± 7.4 ms
Range (min … max): 611.1 ms … 637.7 ms

Result: ~2.5% slower (15.0ms difference)

```

Performance Trade-off Analysis

  • Impact: ~3% performance decrease (~15-20ms average)
  • User Experience: Imperceptible difference (< 100ms threshold)
  • Benefits: Significant compile-time safety, better IDE support, runtime error prevention
  • Conclusion: Excellent trade-off for enhanced development experience

🔧 Technical Implementation

Before (Performance Issues)

```typescript
// Expensive regex validation in loops
modelsUsed: modelsUsed.map(createModelName), // Validates each model with regex
versions: Array.from(versionSet).sort().map(createVersion), // Validates each version
modelName: createModelName(modelName), // Individual validation calls
```

After (Optimized Approach)

```typescript
// Type assertions for already-validated data
modelsUsed: modelsUsed as ModelName[], // Direct assertion, no re-validation
versions: Array.from(versionSet).sort() as Version[], // Direct assertion
modelName: modelName as ModelName, // Direct assertion in aggregation
```

Safety Guarantees

✅ Input Validation: All data validated by Zod schemas during initial JSONL parsing
✅ Type Safety: Branded types prevent identifier mix-ups at compile time
✅ Runtime Safety: Type assertions only used after validation, not before
✅ IDE Support: Enhanced autocomplete, refactoring, and error detection

📝 Key Changes

Core Files Modified

  • src/types.internal.ts: Comprehensive branded type system with Zod schemas
  • src/data-loader.ts: Performance-optimized parsing with branded type integration
  • src/calculate-cost.ts: Updated test data with proper branded type constructors

New Branded Types

```typescript
type ModelName = string & { readonly brand: ModelName };
type SessionId = string & { readonly brand: SessionId };
type ActivityDate = string & { readonly brand: ActivityDate }; // YYYY-MM-DD
type DailyDate = string & { readonly brand: DailyDate }; // YYYY-MM-DD
type Version = string & { readonly brand: Version }; // SemVer format
```

Validation Strategy

  • Strict Validation: Input parsing from JSONL files
  • Type Assertions: Internal data transformations and aggregations
  • Helper Functions: Safe construction with validation when needed

🧪 Test Plan

  • Type Checking: All TypeScript compilation passes without errors
  • Unit Tests: All 182 tests pass successfully
  • Performance Testing: Comprehensive hyperfine benchmarking across all commands
  • Bundle Analysis: Size impact verification (+0.4% acceptable)
  • Compatibility Testing: Verified with existing data including synthetic model names
  • Offline Testing: All benchmarks run with --offline flag to avoid network interference
  • Integration Testing: End-to-end functionality verified

💡 Benefits

Developer Experience

  • Type Safety: Compile-time validation prevents common string identifier errors
  • IDE Support: Better autocomplete, navigation, and refactoring capabilities
  • Debugging: Clear type information makes issues easier to identify and fix
  • Maintainability: Self-documenting code with explicit type contracts

Runtime Benefits

  • Error Prevention: Branded types catch identifier mix-ups before they cause issues
  • Data Integrity: Ensured format consistency across the application
  • Performance Balance: Optimizations where they matter most (hot paths)

Future-Proofing

  • Extensibility: Easy to add new branded types for additional domain concepts
  • Migration Path: Smooth upgrade path for existing data and usage patterns
  • Type Evolution: Foundation for more advanced type safety features

🔄 Migration Notes

This change is backward compatible - no user action required:

  • Existing JSONL data continues to work unchanged
  • All CLI commands maintain identical behavior
  • API contracts preserved for programmatic usage
  • Performance characteristics remain within acceptable bounds

Trade-off Summary: ~3% performance cost for significant type safety improvements - excellent value proposition for a development tool prioritizing reliability and maintainability.

Summary by CodeRabbit

  • New Features

    • Introduced enhanced validation and type safety for key data fields, including dates, identifiers, and model names.
    • Added helper functions for safely creating and validating these branded data types.
  • Refactor

    • Updated internal data handling to use stricter schemas and branded types, improving consistency and reliability across the application.
  • Tests

    • Adjusted test data to conform to the new type-safe schemas and branded types.

@coderabbitai

coderabbitai Bot commented Jun 18, 2025 •

Copy link
Copy Markdown

Warning

Rate limit exceeded

@ryoppippi has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 3 minutes and 59 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 8fc6713f379b30d6bf6779e76f1d5f9d8e57607f and 659ae08.

📒 Files selected for processing (3)
  • src/calculate-cost.ts (3 hunks)
  • src/data-loader.ts (66 hunks)
  • src/types.internal.ts (1 hunks)

Walkthrough

The updates introduce branded types and Zod schemas for domain-specific strings such as dates, IDs, model names, and versions. Factory functions and schema validations are used throughout the codebase and tests to enforce type safety. Test data and schemas are refactored to utilize these branded types, without altering core logic or control flow.

Changes

File(s) Change Summary
src/types.internal.ts Added branded Zod schemas and TypeScript types for IDs, dates, model names, versions; added factory functions; deprecated generic date schema.
src/data-loader.ts Refactored to use branded types and schemas for all relevant fields; updated type annotations accordingly.
src/calculate-cost.ts Replaced string literals in test data with calls to branded type factory functions; updated imports accordingly.

Sequence Diagram(s)

sequenceDiagram
    participant TestCase
    participant FactoryFunc as Factory Function
    participant BrandedType
    TestCase->>FactoryFunc: Pass raw string (e.g., date, id, model name)
    FactoryFunc->>BrandedType: Validate and brand value
    BrandedType-->>TestCase: Return branded type for use in test/schema
Loading

Poem

In fields of types, the rabbits hop,
Branded strings now mark each stop.
Dates and IDs, models with flair,
Factory functions everywhere!
Schemas strong, validation tight—
The code hops forward, pure and right.
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @ryoppippi, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request focuses on a significant performance enhancement by optimizing the handling of branded types within the application. By strategically replacing repetitive Zod parsing operations in performance-critical loops with type assertions and initial parsing, the changes achieve a measurable improvement in runtime efficiency while rigorously maintaining the integrity and safety of the type system. This refactoring also centralizes and formalizes type definitions, contributing to a more robust and maintainable codebase.

Highlights

  • Performance Optimization: Replaced expensive zod.parse() calls with more efficient type assertions or single create* function calls in data processing loops, resulting in approximately a 4% runtime performance improvement for data processing.
  • Branded Types Implementation: Introduced a comprehensive set of Zod branded types (ModelName, ISOTimestamp, Version, SessionId, etc.) and their corresponding creation helper functions in src/types.internal.ts to enforce stricter type safety and enable the performance optimizations.
  • Schema and Data Alignment: Updated existing Zod schemas in src/data-loader.ts to leverage the new branded types, ensuring that validated data is correctly typed. Test data across src/calculate-cost.ts and src/data-loader.ts was also updated to use these new branded types and their creation methods for consistency.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces branded types and replaces expensive zod.parse() calls with type assertions to optimize branded type parsing in loops. It also includes changes to test data to use proper branded type assertions.

Comment thread src/data-loader.ts Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consider using modelNameSchema instead of a string literal for better type safety and consistency.

						model: 'claude-sonnet-4-20250514' as ModelName,

Comment thread src/data-loader.ts Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consider using modelNameSchema instead of a string literal for better type safety and consistency.

										model: 'claude-sonnet-4-20250514' as ModelName,

Comment thread src/data-loader.ts Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consider using versionSchema instead of a string literal for better type safety and consistency.

									version: '1.0.0' as Version,

Comment thread src/data-loader.ts Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consider using modelNameSchema instead of a string literal for better type safety and consistency.

										model: 'claude-sonnet-4-20250514' as ModelName,

Comment thread src/data-loader.ts Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consider using versionSchema instead of a string literal for better type safety and consistency.

									version: '1.0.0' as Version,

Comment thread src/data-loader.ts Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consider using messageIdSchema instead of a string literal for better type safety and consistency.

					timestamp: '2025-01-10T10:00:00Z' as ISOTimestamp,
					message: {
						id: 'msg_123' as MessageId,

Comment thread src/data-loader.ts Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consider using messageIdSchema instead of a string literal for better type safety and consistency.

						id: 'msg_123' as MessageId,

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (4)
src/types.internal.ts (2)

47-50: versionSchema allows unwanted suffixes
Without an end-anchor the pattern matches 1.2.3beta or 2.0.0-rc.1, which defeats strict semver validation. If you intend to accept only MAJOR.MINOR.PATCH, terminate the regex:

-	.regex(/^\d+\.\d+\.\d+/, 'Invalid version format')
+	.regex(/^\d+\.\d+\.\d+$/, 'Invalid version format')

If prerelease/build metadata should be allowed, consider a dedicated semver regex instead.


69-78: Helper functions still parse on every call – defeats the “perf” objective
The PR description emphasises replacing expensive parsing inside hot loops with type assertions. These helpers still invoke .parse, so any caller using them inside a loop will regress performance.

Consider providing lightweight “unsafe*” cast helpers (clearly named) that do value as ModelName etc., and mandate their use only after a single upfront validation step.

src/calculate-cost.ts (2)

2-9: Import list can be pruned to what the file actually uses
createProjectPath and createVersion are only referenced inside test blocks behind import.meta.vitest. If this file is built for production, the extra imports add to bundle size. Either:

  1. Move test utilities to a *.test.ts file, or
  2. Lazy-import them inside the if (import.meta.vitest) guard.

Not critical but keeps runtime code lean.


96-115: Validation in test data adds unnecessary runtime cost
Each call to createDailyDate / createModelName runs a regex parse. While acceptable in tests, it slightly slows the suite and obscures the literals. Consider validating once in a helper or using the new type-assertion pattern for test fixtures:

- date: createDailyDate('2024-01-01'),
+ date: '2024-01-01' as DailyDate,

Same applies to the other branded fields in fixtures.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 880cea0 and 369706626a01e1a48532e20bbfb1223092d56268.

📒 Files selected for processing (3)
  • src/calculate-cost.ts (3 hunks)
  • src/data-loader.ts (72 hunks)
  • src/types.internal.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/calculate-cost.ts (1)
src/types.internal.ts (6)
  • createDailyDate (74-74)
  • createModelName (69-69)
  • createSessionId (70-70)
  • createProjectPath (77-77)
  • createISOTimestamp (73-73)
  • createVersion (78-78)
🪛 ESLint
src/calculate-cost.ts

[error] 96-96: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 106-106: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 128-128: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 129-129: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 135-135: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 141-141: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 142-142: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 148-148: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)

src/types.internal.ts

[error] 9-11: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 9-11: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 9-10: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 9-9: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 9-9: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 10-10: Unsafe member access .regex on an error typed value.

(ts/no-unsafe-member-access)


[error] 11-11: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 13-15: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 13-15: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 13-14: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 13-13: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 13-13: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 14-14: Unsafe member access .min on an error typed value.

(ts/no-unsafe-member-access)


[error] 15-15: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 17-19: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 17-19: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 17-18: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 17-17: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 17-17: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 18-18: Unsafe member access .min on an error typed value.

(ts/no-unsafe-member-access)


[error] 19-19: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 21-23: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 21-23: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 21-22: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 21-21: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 21-21: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 22-22: Unsafe member access .min on an error typed value.

(ts/no-unsafe-member-access)


[error] 23-23: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 26-28: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 26-28: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 26-27: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 26-26: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 26-26: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 27-27: Unsafe member access .regex on an error typed value.

(ts/no-unsafe-member-access)


[error] 28-28: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 30-32: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 30-32: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 30-31: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 30-30: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 30-30: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 31-31: Unsafe member access .regex on an error typed value.

(ts/no-unsafe-member-access)


[error] 32-32: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 34-36: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 34-36: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 34-35: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 34-34: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 34-34: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 35-35: Unsafe member access .regex on an error typed value.

(ts/no-unsafe-member-access)


[error] 36-36: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 38-40: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 38-40: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 38-39: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 38-38: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 38-38: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 39-39: Unsafe member access .regex on an error typed value.

(ts/no-unsafe-member-access)


[error] 40-40: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 43-45: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 43-45: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 43-44: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 43-43: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 43-43: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 44-44: Unsafe member access .min on an error typed value.

(ts/no-unsafe-member-access)


[error] 45-45: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 47-49: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 47-49: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 47-48: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 47-47: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 47-47: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 48-48: Unsafe member access .regex on an error typed value.

(ts/no-unsafe-member-access)


[error] 49-49: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 69-69: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 69-69: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 70-70: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 70-70: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 71-71: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 71-71: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 72-72: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 72-72: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 73-73: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 73-73: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 74-74: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 74-74: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 75-75: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 75-75: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 76-76: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 76-76: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 77-77: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 77-77: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 78-78: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 78-78: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)

src/data-loader.ts

[error] 86-86: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 87-87: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 87-87: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 87-87: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 88-97: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 88-88: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 88-88: Unsafe member access .object on an error typed value.

(ts/no-unsafe-member-access)


[error] 89-94: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 89-89: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 89-89: Unsafe member access .object on an error typed value.

(ts/no-unsafe-member-access)


[error] 90-90: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 90-90: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 90-90: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 91-91: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 91-91: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 91-91: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 92-92: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 92-92: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 92-92: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 92-92: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 92-92: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 93-93: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 93-93: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 93-93: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 93-93: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 93-93: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 95-95: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 95-95: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 95-95: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 96-96: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 96-96: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 96-96: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 98-98: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 98-98: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 98-98: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 98-98: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 98-98: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 99-99: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 99-99: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 99-99: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 111-111: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 128-128: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 129-129: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 129-129: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 129-129: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 130-130: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 130-130: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 130-130: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 131-131: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 131-131: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 131-131: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 132-132: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 132-132: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 132-132: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 133-133: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 133-133: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 133-133: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 134-134: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 134-134: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 134-134: Unsafe member access .array on an error typed value.

(ts/no-unsafe-member-access)


[error] 147-147: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 148-148: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 149-149: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 149-149: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 149-149: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 150-150: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 150-150: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 150-150: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 151-151: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 151-151: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 151-151: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 152-152: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 152-152: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 152-152: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 153-153: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 153-153: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 153-153: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 154-154: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 155-155: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 155-155: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 155-155: Unsafe member access .array on an error typed value.

(ts/no-unsafe-member-access)


[error] 156-156: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 156-156: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 156-156: Unsafe member access .array on an error typed value.

(ts/no-unsafe-member-access)


[error] 169-169: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 170-170: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 170-170: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 170-170: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 171-171: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 171-171: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 171-171: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 172-172: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 172-172: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 172-172: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 173-173: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 173-173: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 173-173: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 174-174: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 174-174: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 174-174: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 175-175: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 175-175: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 175-175: Unsafe member access .array on an error typed value.

(ts/no-unsafe-member-access)


[error] 280-280: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 683-683: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 845-845: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 845-845: Unsafe argument of type error typed assigned to a parameter of type string.

(ts/no-unsafe-argument)


[error] 845-845: Unsafe member access .sessionId on an error typed value.

(ts/no-unsafe-member-access)


[error] 846-846: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 846-846: Unsafe argument of type error typed assigned to a parameter of type string.

(ts/no-unsafe-argument)


[error] 846-846: Unsafe member access .projectPath on an error typed value.

(ts/no-unsafe-member-access)


[error] 848-848: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 848-848: Unsafe argument of type error typed assigned to a parameter of type string.

(ts/no-unsafe-argument)


[error] 848-848: Unsafe member access .timestamp on an error typed value.

(ts/no-unsafe-member-access)


[error] 917-917: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1153-1153: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1158-1158: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1165-1165: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1194-1194: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1225-1225: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1230-1230: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1235-1235: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1265-1265: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1270-1270: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1275-1275: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1301-1301: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1306-1306: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1311-1311: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1341-1341: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1346-1346: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1351-1351: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1438-1438: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1443-1443: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1448-1448: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1516-1516: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1521-1521: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1562-1562: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1567-1567: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1572-1572: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1577-1577: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1602-1602: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1607-1607: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1612-1612: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1617-1617: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1645-1645: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1650-1650: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1655-1655: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1660-1660: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1696-1696: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1701-1701: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1706-1706: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1737-1737: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1749-1749: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1792-1792: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1826-1826: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1838-1838: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1878-1878: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1880-1880: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1884-1884: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1886-1886: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1890-1890: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1892-1892: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1918-1918: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1926-1926: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1934-1934: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1964-1964: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1972-1972: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 1980-1980: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2013-2013: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2021-2021: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2029-2029: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2062-2062: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2070-2070: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2078-2078: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2111-2111: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2145-2145: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2185-2185: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2222-2222: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2228-2228: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2231-2231: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2236-2236: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2264-2264: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2291-2291: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2297-2297: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2300-2300: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2334-2334: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2363-2363: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2371-2371: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2400-2400: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2439-2439: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2445-2445: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2448-2448: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2473-2473: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2476-2476: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2503-2503: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2506-2506: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2512-2512: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2515-2515: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2541-2541: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2544-2544: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2578-2578: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2581-2581: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2608-2608: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2611-2611: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2639-2639: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2642-2642: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2669-2669: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2672-2672: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2699-2699: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2734-2734: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2742-2742: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2775-2775: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2781-2781: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2816-2816: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 2816-2816: Unsafe member access .message on an error typed value.

(ts/no-unsafe-member-access)


[error] 2816-2816: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2830-2830: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2836-2836: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2860-2860: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2866-2866: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2984-2984: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2988-2988: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 2998-2998: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3002-3002: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3012-3012: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3016-3016: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3047-3047: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3051-3051: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3090-3090: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3094-3094: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3101-3101: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3105-3105: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3112-3112: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3116-3116: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3159-3159: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3163-3163: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3170-3170: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3174-3174: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3210-3210: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3214-3214: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3222-3222: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3226-3226: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3253-3253: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3257-3257: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3279-3279: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3281-3281: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3287-3287: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3296-3296: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3303-3303: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3312-3312: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3314-3314: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3330-3330: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3331-3331: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3332-3332: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3360-3360: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3414-3414: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3416-3416: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3422-3422: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3428-3428: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3430-3430: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3436-3436: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3460-3460: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3462-3462: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3468-3468: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3472-3472: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3474-3474: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3480-3480: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3506-3506: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3508-3508: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3514-3514: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3520-3520: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3522-3522: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 3528-3528: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)

🪛 GitHub Actions: CI
src/data-loader.ts

[error] 1872-1872: Test failure: expected '' to be '2024-01-01' (Object.is equality) in loadSessionData > aggregates session usage data.


[error] 2103-2103: Test failure: expected '' to be '2024-01-15' (Object.is equality) in loadSessionData > filters by date range based on last activity.


[error] 2353-2353: Test failure: expected [] to have a length of 1 but got 0 in data-loader cost calculation with real pricing > loadSessionData with mixed schemas > should handle unknown models gracefully.


[error] 2726-2726: Test failure: expected [] to have a length of 1 but got 0 in data-loader cost calculation with real pricing > pricing data fetching optimization > display mode should work without network access.

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Socket Security: Pull Request Alerts
🔇 Additional comments (1)
src/data-loader.ts (1)

169-176: Monthly aggregation inherits unsound modelsUsed cast

The modelsSet may contain raw strings; casting to ModelName[] without checks repeats the previous issue.

-			modelsUsed: Array.from(modelsSet) as ModelName[],
+			modelsUsed: Array.from(modelsSet).map(createModelName),

A single pass here is not performance-sensitive.

Comment thread src/types.internal.ts Outdated
Comment on lines 26 to 29

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

ISO-8601 regex is too restrictive – offsets like “+00:00” will be rejected
The current pattern only accepts the trailing Z notation. Valid ISO-8601 timestamps that include an explicit offset (2024-01-01T00:00:00+00:00, 2024-01-01T00:00:00-05:00, etc.) will fail to parse and force callers to strip the offset or coerce the value, defeating the purpose of validation.

-	.regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/, 'Invalid ISO timestamp')
+	.regex(
+		/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?(?:Z|[+-]\d{2}:\d{2})$/,
+		'Invalid ISO-8601 timestamp',
+	)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const isoTimestampSchema = z.string()
.regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/, 'Invalid ISO timestamp')
.brand<'ISOTimestamp'>();
export const isoTimestampSchema = z.string()
.regex(
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?(?:Z|[+-]\d{2}:\d{2})$/,
'Invalid ISO-8601 timestamp',
)
.brand<'ISOTimestamp'>();
🧰 Tools
🪛 ESLint

[error] 26-28: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 26-28: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 26-27: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 26-26: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 26-26: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 27-27: Unsafe member access .regex on an error typed value.

(ts/no-unsafe-member-access)


[error] 28-28: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)

🤖 Prompt for AI Agents
In src/types.internal.ts around lines 26 to 29, the regex for isoTimestampSchema
only accepts timestamps ending with 'Z' and rejects valid ISO-8601 timestamps
with offsets like '+00:00' or '-05:00'. Update the regex to allow either a 'Z'
or a timezone offset in the format ±HH:MM at the end of the string, ensuring it
matches all valid ISO-8601 timestamp formats including those with explicit
offsets.

Comment thread src/data-loader.ts Outdated
Comment on lines 95 to 100

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Over-strict model validation is dropping legitimate records

Changing message.model from z.string() to modelNameSchema means every log line whose model name does not match the branded-type regex is now rejected by usageDataSchema.safeParse.
Tests that intentionally feed unknown-model-xyz now fail (results.length === 0). In production this will silently discard usage coming from future/experimental models and break cost reports.

-		model: modelNameSchema.optional(), // Model is inside message object
+		// Accept any string → keep record, brand later if recognised
+		model: z.string().optional(),

If you still want strong typing for known models, brand after parsing:

const model = isKnownModel(data.message.model)
	? (data.message.model as ModelName)
	: data.message.model ?? 'unknown';

This preserves data while retaining the optimisation goal of avoiding zod.parse() inside hot paths.

🧰 Tools
🪛 ESLint

[error] 88-97: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 95-95: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 95-95: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 95-95: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 96-96: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 96-96: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 96-96: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)

🤖 Prompt for AI Agents
In src/data-loader.ts around lines 95 to 97, the current validation uses
modelNameSchema for the model field, which is too strict and causes legitimate
records with unknown or experimental model names to be dropped. To fix this,
revert the model field validation to a more permissive type like z.string().
Then, after parsing, apply branding or type narrowing by checking if the model
is known and casting it accordingly, defaulting to 'unknown' if not. This
approach preserves all data while maintaining strong typing where possible.

Comment thread src/data-loader.ts Outdated
Comment on lines 845 to 849

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

lastActivity now returns an ISO timestamp – breaks API contract & tests

Previously lastActivity was a plain YYYY-MM-DD date (see failing tests).
Switching to createISOTimestamp() returns the full timestamp, which:

  1. Violates callers that expect a date string.
  2. Makes filterByDateRange() do an unnecessary substring on an ISO value.
  3. Causes CI failures (expected '2024-01-01', got '').

Use the branded daily date instead:

-				lastActivity: createISOTimestamp(latestEntry.timestamp),
+				lastActivity: createDailyDate(formatDate(latestEntry.timestamp)),

This restores the previous behaviour while still avoiding expensive validation in loops.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sessionId: createSessionId(latestEntry.sessionId),
projectPath: createProjectPath(latestEntry.projectPath),
...totals,
lastActivity: formatDate(latestEntry.timestamp),
versions: Array.from(versionSet).sort(),
modelsUsed,
lastActivity: createISOTimestamp(latestEntry.timestamp),
versions: Array.from(versionSet).sort() as Version[],
sessionId: createSessionId(latestEntry.sessionId),
projectPath: createProjectPath(latestEntry.projectPath),
...totals,
- lastActivity: createISOTimestamp(latestEntry.timestamp),
+ lastActivity: createDailyDate(formatDate(latestEntry.timestamp)),
versions: Array.from(versionSet).sort() as Version[],
🧰 Tools
🪛 ESLint

[error] 845-845: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 845-845: Unsafe argument of type error typed assigned to a parameter of type string.

(ts/no-unsafe-argument)


[error] 845-845: Unsafe member access .sessionId on an error typed value.

(ts/no-unsafe-member-access)


[error] 846-846: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 846-846: Unsafe argument of type error typed assigned to a parameter of type string.

(ts/no-unsafe-argument)


[error] 846-846: Unsafe member access .projectPath on an error typed value.

(ts/no-unsafe-member-access)


[error] 848-848: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 848-848: Unsafe argument of type error typed assigned to a parameter of type string.

(ts/no-unsafe-argument)


[error] 848-848: Unsafe member access .timestamp on an error typed value.

(ts/no-unsafe-member-access)

🤖 Prompt for AI Agents
In src/data-loader.ts around lines 845 to 849, the lastActivity field is
currently set using createISOTimestamp(latestEntry.timestamp), which returns a
full ISO timestamp string instead of the expected plain YYYY-MM-DD date string.
This breaks the API contract and causes test failures. To fix this, replace
createISOTimestamp(latestEntry.timestamp) with a function or method that returns
the branded daily date string (YYYY-MM-DD) format, restoring the previous
behavior and ensuring compatibility with filterByDateRange and existing tests.

Comment thread src/data-loader.ts Outdated
Comment thread src/data-loader.ts Outdated
@ryoppippi
ryoppippi requested a review from Copilot June 18, 2025 13:25
@pkg-pr-new

pkg-pr-new Bot commented Jun 18, 2025 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/ryoppippi/ccusage@109

commit: 659ae08

This comment was marked as outdated.

This comment was marked as outdated.

@ryoppippi ryoppippi changed the title perf: optimize branded type parsing in loops using type assertions feat: enhance type safety with Zod branded types and performance optimizations Jun 18, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

♻️ Duplicate comments (1)
src/types.internal.ts (1)

26-28: ISO-8601 regex is still too restrictive

The regex still mandates a trailing Z, disallowing valid ISO-8601 timestamps with an explicit offset (+00:00, -05:00, etc.). This was raised earlier and hasn’t been addressed. Consider the previously suggested, more permissive pattern:

-	.regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/, 'Invalid ISO timestamp')
+	.regex(
+		/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?(?:Z|[+-]\d{2}:\d{2})$/,
+		'Invalid ISO-8601 timestamp',
+	)
🧹 Nitpick comments (4)
src/calculate-cost.ts (2)

2-9: Imports for test-only helpers are pulled into the production bundle

createActivityDate, createDailyDate, … are only referenced inside the if (import.meta.vitest) block, yet they are imported at module-top scope. Depending on the bundler / tree-shaker settings these runtime-heavy helpers (each performs a zod.parse) may leak into the production chunk even though they are never executed.

-import {
-	createActivityDate,
-	createDailyDate,
-	createModelName,
-	createProjectPath,
-	createSessionId,
-	createVersion,
-} from './types.internal.ts';
+if (import.meta.vitest != null) {
+	const {
+		createActivityDate,
+		createDailyDate,
+		createModelName,
+		createProjectPath,
+		createSessionId,
+		createVersion,
+	} = await import('./types.internal.ts');
+  // … tests …
+}

This keeps the helpers completely out of the production graph while preserving type safety inside tests.


94-113: ESLint no-unsafe-assignment flags every create*() usage

zodSchema.parse() returns unknown, so each assignment is considered unsafe. A tiny wrapper fixes this without disabling the rule:

function safeParse<T>(schema: z.ZodType<T>, value: unknown): T {
	return schema.parse(value) as T;
}

export const createDailyDate   = (v: string) => safeParse(dailyDateSchema, v);
export const createModelName   = (v: string) => safeParse(modelNameSchema, v);

Alternatively, cast at call-site:

date: createDailyDate('2024-01-01') as DailyDate,

Either silence the ESLint noise or adopt the helper to keep the codebase warning-free.

src/types.internal.ts (2)

51-53: Anchor versionSchema regex to avoid partial matches

/^\d+\.\d+\.\d+/ allows extras after the patch number (1.2.3foo). Anchoring the end removes false positives:

-	.regex(/^\d+\.\d+\.\d+/, 'Invalid version format')
+	.regex(/^\d+\.\d+\.\d+$/, 'Invalid version format')

30-37: Redundant daily vs. activity date schemas

dailyDateSchema and activityDateSchema share an identical pattern. Unless their semantics diverge later, you can DRY this up to reduce maintenance overhead:

const yyyyMmDd = z.string()
  .regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be in YYYY-MM-DD format');

export const dailyDateSchema = yyyyMmDd.brand<'DailyDate'>();
export const activityDateSchema = yyyyMmDd.brand<'ActivityDate'>();
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6a0f82340b6384670ef8f4ec5e33ac6630fa8c6 and 8fc6713f379b30d6bf6779e76f1d5f9d8e57607f.

📒 Files selected for processing (3)
  • src/calculate-cost.ts (3 hunks)
  • src/data-loader.ts (6 hunks)
  • src/types.internal.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/calculate-cost.ts (1)
src/types.internal.ts (6)
  • createDailyDate (79-79)
  • createModelName (74-74)
  • createSessionId (75-75)
  • createProjectPath (83-83)
  • createActivityDate (80-80)
  • createVersion (84-84)
src/data-loader.ts (1)
src/types.internal.ts (9)
  • isoTimestampSchema (26-28)
  • versionSchema (51-53)
  • modelNameSchema (9-11)
  • messageIdSchema (21-23)
  • requestIdSchema (17-19)
  • dailyDateSchema (30-32)
  • sessionIdSchema (13-15)
  • projectPathSchema (47-49)
  • monthlyDateSchema (38-40)
🪛 ESLint
src/calculate-cost.ts

[error] 96-96: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 106-106: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 128-128: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 129-129: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 135-135: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 141-141: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 142-142: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 148-148: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)

src/data-loader.ts

[error] 73-73: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 74-74: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 74-74: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 74-74: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 75-84: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 75-75: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 75-75: Unsafe member access .object on an error typed value.

(ts/no-unsafe-member-access)


[error] 76-81: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 76-76: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 76-76: Unsafe member access .object on an error typed value.

(ts/no-unsafe-member-access)


[error] 77-77: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 77-77: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 77-77: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 78-78: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 78-78: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 78-78: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 79-79: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 79-79: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 79-79: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 79-79: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 79-79: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 80-80: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 80-80: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 80-80: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 80-80: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 80-80: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 82-82: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 82-82: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 82-82: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 83-83: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 83-83: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 83-83: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 85-85: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 85-85: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 85-85: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 85-85: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 85-85: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 86-86: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 86-86: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 86-86: Unsafe member access .optional on an error typed value.

(ts/no-unsafe-member-access)


[error] 98-98: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 115-115: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 116-116: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 116-116: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 116-116: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 117-117: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 117-117: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 117-117: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 118-118: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 118-118: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 118-118: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 119-119: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 119-119: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 119-119: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 120-120: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 120-120: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 120-120: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 121-121: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 121-121: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 121-121: Unsafe member access .array on an error typed value.

(ts/no-unsafe-member-access)


[error] 134-134: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 135-135: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 136-136: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 136-136: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 136-136: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 137-137: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 137-137: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 137-137: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 138-138: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 138-138: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 138-138: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 139-139: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 139-139: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 139-139: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 140-140: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 140-140: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 140-140: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 141-141: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 142-142: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 142-142: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 142-142: Unsafe member access .array on an error typed value.

(ts/no-unsafe-member-access)


[error] 143-143: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 143-143: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 143-143: Unsafe member access .array on an error typed value.

(ts/no-unsafe-member-access)


[error] 156-156: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 157-157: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 157-157: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 157-157: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 158-158: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 158-158: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 158-158: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 159-159: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 159-159: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 159-159: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 160-160: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 160-160: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 160-160: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 161-161: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 161-161: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 161-161: Unsafe member access .number on an error typed value.

(ts/no-unsafe-member-access)


[error] 162-162: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 162-162: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 162-162: Unsafe member access .array on an error typed value.

(ts/no-unsafe-member-access)

src/types.internal.ts

[error] 9-11: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 9-11: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 9-10: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 9-9: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 9-9: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 10-10: Unsafe member access .min on an error typed value.

(ts/no-unsafe-member-access)


[error] 11-11: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 13-15: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 13-15: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 13-14: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 13-13: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 13-13: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 14-14: Unsafe member access .min on an error typed value.

(ts/no-unsafe-member-access)


[error] 15-15: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 17-19: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 17-19: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 17-18: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 17-17: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 17-17: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 18-18: Unsafe member access .min on an error typed value.

(ts/no-unsafe-member-access)


[error] 19-19: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 21-23: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 21-23: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 21-22: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 21-21: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 21-21: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 22-22: Unsafe member access .min on an error typed value.

(ts/no-unsafe-member-access)


[error] 23-23: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 26-28: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 26-28: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 26-27: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 26-26: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 26-26: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 27-27: Unsafe member access .regex on an error typed value.

(ts/no-unsafe-member-access)


[error] 28-28: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 30-32: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 30-32: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 30-31: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 30-30: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 30-30: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 31-31: Unsafe member access .regex on an error typed value.

(ts/no-unsafe-member-access)


[error] 32-32: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 34-36: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 34-36: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 34-35: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 34-34: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 34-34: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 35-35: Unsafe member access .regex on an error typed value.

(ts/no-unsafe-member-access)


[error] 36-36: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 38-40: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 38-40: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 38-39: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 38-38: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 38-38: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 39-39: Unsafe member access .regex on an error typed value.

(ts/no-unsafe-member-access)


[error] 40-40: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 42-44: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 42-44: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 42-43: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 42-42: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 42-42: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 43-43: Unsafe member access .regex on an error typed value.

(ts/no-unsafe-member-access)


[error] 44-44: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 47-49: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 47-49: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 47-48: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 47-47: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 47-47: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 48-48: Unsafe member access .min on an error typed value.

(ts/no-unsafe-member-access)


[error] 49-49: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 51-53: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 51-53: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 51-52: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 51-51: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 51-51: Unsafe member access .string on an error typed value.

(ts/no-unsafe-member-access)


[error] 52-52: Unsafe member access .regex on an error typed value.

(ts/no-unsafe-member-access)


[error] 53-53: Unsafe member access .brand on an error typed value.

(ts/no-unsafe-member-access)


[error] 74-74: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 74-74: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 75-75: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 75-75: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 76-76: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 76-76: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 77-77: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 77-77: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 78-78: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 78-78: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 79-79: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 79-79: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 80-80: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 80-80: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 81-81: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 81-81: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 82-82: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 82-82: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 83-83: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 83-83: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)


[error] 84-84: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 84-84: Unsafe member access .parse on an error typed value.

(ts/no-unsafe-member-access)

🪛 GitHub Actions: CI
src/calculate-cost.ts

[error] 135-135: TypeScript TS2322: Type 'string & BRAND<"ActivityDate">' is not assignable to type 'string & BRAND<"ISOTimestamp">'. Property 'ISOTimestamp' is missing in type '{ ActivityDate: true; }' but required in type '{ ISOTimestamp: true; }'.


[error] 148-148: TypeScript TS2322: Type 'string & BRAND<"ActivityDate">' is not assignable to type 'string & BRAND<"ISOTimestamp">'. Property 'ISOTimestamp' is missing in type '{ ActivityDate: true; }' but required in type '{ ISOTimestamp: true; }'.

src/data-loader.ts

[error] 265-265: TypeScript TS2322: Type '{ inputTokens: number; outputTokens: number; cacheCreationTokens: number; cacheReadTokens: number; cost: number; modelName: string; }[]' is not assignable to type '{ modelName: string & BRAND<"ModelName">; inputTokens: number; outputTokens: number; cacheCreationTokens: number; cacheReadTokens: number; cost: number; }[]'. Property 'modelName' type mismatch: 'string' is not assignable to 'string & BRAND<"ModelName">'.


[error] 682-682: TypeScript TS2322: Type '{ inputTokens: number; outputTokens: number; cacheCreationTokens: number; cacheReadTokens: number; cost: number; totalCost: number; date: string; modelsUsed: string[]; modelBreakdowns: { modelName: string & BRAND<"ModelName">; ... }[]; }[]' is not assignable to type '{ date: string & BRAND<"DailyDate">; inputTokens: number; outputTokens: number; cacheCreationTokens: number; cacheReadTokens: number; totalCost: number; modelsUsed: (string & BRAND<"ModelName">)[]; modelBreakdowns: { ... }[]; }[]'. Property 'date' type mismatch: 'string' is not assignable to 'string & BRAND<"DailyDate">'.


[error] 846-846: TypeScript TS2322: Type '{ inputTokens: number; outputTokens: number; cacheCreationTokens: number; cacheReadTokens: number; cost: number; totalCost: number; sessionId: string; projectPath: string; lastActivity: string; versions: string[]; modelsUsed: string[]; modelBreakdowns: { ... }[]; }[]' is not assignable to type '{ sessionId: string & BRAND<"SessionId">; projectPath: string & BRAND<"ProjectPath">; inputTokens: number; outputTokens: number; cacheCreationTokens: number; cacheReadTokens: number; ... }[]'. Property 'sessionId' type mismatch: 'string' is not assignable to 'string & BRAND<"SessionId">'.


[error] 904-904: TypeScript TS2322: Type 'string' is not assignable to type 'string & BRAND<"MonthlyDate">'. Property 'MonthlyDate' is missing in type 'string'.


[error] 910-910: TypeScript TS2322: Type 'string[]' is not assignable to type '(string & BRAND<"ModelName">)[]'. Property 'modelsUsed' type mismatch: 'string' is not assignable to 'string & BRAND<"ModelName">'.


[error] 1140-1140: TypeScript TS2322: Type 'string' is not assignable to type 'string & BRAND<"ISOTimestamp">'. Property 'ISOTimestamp' is missing in type 'string'.


[error] 1867-1867: TypeScript TS2322: Type 'string' is not assignable to type 'string & BRAND<"Version">'. Property 'Version' is missing in type 'string'.


[error] 1873-1873: TypeScript TS2322: Type 'string' is not assignable to type 'string & BRAND<"Version">'. Property 'Version' is missing in type 'string'.


[error] 2729-2729: TypeScript TS2322: Type 'string' is not assignable to type 'string & BRAND<"ModelName">'. Property 'ModelName' is missing in type 'string'.


[error] 2768-2768: TypeScript TS2322: Type 'string' is not assignable to type 'string & BRAND<"ModelName">'. Property 'ModelName' is missing in type 'string'.


[error] 2808-2808: TypeScript TS2345: Argument type mismatch in property 'message.model': 'string' is not assignable to 'string & BRAND<"ModelName">'.


[error] 2823-2823: TypeScript TS2322: Type 'string' is not assignable to type 'string & BRAND<"ModelName">'. Property 'ModelName' is missing in type 'string'.


[error] 2853-2853: TypeScript TS2322: Type 'string' is not assignable to type 'string & BRAND<"ModelName">'. Property 'ModelName' is missing in type 'string'.


[error] 3277-3277: TypeScript TS2345: Argument type mismatch in property 'timestamp': 'string' is not assignable to 'string & BRAND<"ISOTimestamp">'.


[error] 3293-3293: TypeScript TS2345: Argument type mismatch in property 'timestamp': 'string' is not assignable to 'string & BRAND<"ISOTimestamp">'.


[error] 3309-3309: TypeScript TS2345: Argument type mismatch in property 'timestamp': 'string' is not assignable to 'string & BRAND<"ISOTimestamp">'.


[error] 135-2721: Multiple TypeScript TS2322 errors: Numerous type mismatches where 'string' is assigned to branded string types such as 'ISOTimestamp', 'ModelName', 'Version', 'SessionId', 'MonthlyDate', 'DailyDate', etc. These errors indicate that plain strings are used where branded types are expected, causing type incompatibility.

🔇 Additional comments (1)
src/data-loader.ts (1)

73-87: Strict branding inside usageDataSchema creates an asymmetry

isoTimestampSchema, versionSchema, modelNameSchema, … enforce branding on raw log lines, which is fine, but make sure:

  1. lastActivity later derived via formatDate() is not re-parsed against isoTimestampSchema (it isn’t a full ISO string anymore).
  2. Synthetic or unknown model names still pass the relaxed min(1) rule (they do).

No immediate action required here, but keep the asymmetry in mind when fixing the aggregate builders.

Comment thread src/calculate-cost.ts Outdated
Comment on lines 128 to 150

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

lastActivity now expects ActivityDate, but the public type still requires ISOTimestamp → compilation fails

CI shows TS2322 at these lines:

Type 'string & BRAND<"ActivityDate">' is not assignable to type 'string & BRAND<"ISOTimestamp">'.

SessionUsage.lastActivity is still branded as ISOTimestamp, yet the code supplies an ActivityDate. Align the two in one of the following ways:

  1. Update the domain type
    Change SessionUsage.lastActivity (and its zod schema) from ISOTimestamp to ActivityDate, reflecting the PR’s intention to relax the format to YYYY-MM-DD.

  2. Keep the old type and adjust the test
    Revert to the existing helper:

- lastActivity: createActivityDate('2024-01-01'),
+ lastActivity: createIsoTimestamp('2024-01-01T00:00:00Z'),

Pick one direction and make it consistent across src/data-loader.ts, schemas, and all call-sites, otherwise the build will stay red.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sessionId: createSessionId('session-1'),
projectPath: createProjectPath('project/path'),
inputTokens: 100,
outputTokens: 50,
cacheCreationTokens: 25,
cacheReadTokens: 10,
totalCost: 0.01,
lastActivity: '2024-01-01',
versions: ['1.0.3'],
modelsUsed: ['claude-sonnet-4-20250514'],
lastActivity: createActivityDate('2024-01-01'),
versions: [createVersion('1.0.3')],
modelsUsed: [createModelName('claude-sonnet-4-20250514')],
modelBreakdowns: [],
},
{
sessionId: 'session-2',
projectPath: 'project/path',
sessionId: createSessionId('session-2'),
projectPath: createProjectPath('project/path'),
inputTokens: 200,
outputTokens: 100,
cacheCreationTokens: 50,
cacheReadTokens: 20,
totalCost: 0.02,
lastActivity: '2024-01-02',
versions: ['1.0.3', '1.0.4'],
modelsUsed: ['claude-opus-4-20250514'],
lastActivity: createActivityDate('2024-01-02'),
versions: [createVersion('1.0.3'), createVersion('1.0.4')],
modelsUsed: [createModelName('claude-opus-4-20250514')],
{
sessionId: createSessionId('session-1'),
projectPath: createProjectPath('project/path'),
inputTokens: 100,
outputTokens: 50,
cacheCreationTokens: 25,
cacheReadTokens: 10,
totalCost: 0.01,
- lastActivity: createActivityDate('2024-01-01'),
+ lastActivity: createIsoTimestamp('2024-01-01T00:00:00Z'),
versions: [createVersion('1.0.3')],
modelsUsed: [createModelName('claude-sonnet-4-20250514')],
modelBreakdowns: [],
},
{
sessionId: createSessionId('session-2'),
projectPath: createProjectPath('project/path'),
inputTokens: 200,
outputTokens: 100,
cacheCreationTokens: 50,
cacheReadTokens: 20,
totalCost: 0.02,
lastActivity: createActivityDate('2024-01-02'),
versions: [createVersion('1.0.3'), createVersion('1.0.4')],
modelsUsed: [createModelName('claude-opus-4-20250514')],
🧰 Tools
🪛 ESLint

[error] 128-128: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 129-129: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 135-135: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 141-141: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 142-142: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 148-148: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)

🪛 GitHub Actions: CI

[error] 135-135: TypeScript TS2322: Type 'string & BRAND<"ActivityDate">' is not assignable to type 'string & BRAND<"ISOTimestamp">'. Property 'ISOTimestamp' is missing in type '{ ActivityDate: true; }' but required in type '{ ISOTimestamp: true; }'.


[error] 148-148: TypeScript TS2322: Type 'string & BRAND<"ActivityDate">' is not assignable to type 'string & BRAND<"ISOTimestamp">'. Property 'ISOTimestamp' is missing in type '{ ActivityDate: true; }' but required in type '{ ISOTimestamp: true; }'.

🤖 Prompt for AI Agents
In src/calculate-cost.ts around lines 128 to 150, the lastActivity field is
assigned an ActivityDate type but the SessionUsage.lastActivity property and its
schema still expect an ISOTimestamp type, causing a type mismatch error TS2322.
To fix this, choose one approach: either update the SessionUsage.lastActivity
type and its zod schema to ActivityDate to match the new relaxed date format, or
revert the lastActivity assignments to use ISOTimestamp format consistently.
Ensure this change is applied consistently in src/data-loader.ts, all relevant
schemas, and all call-sites to resolve the compilation error.

Comment thread src/data-loader.ts Outdated
Comment thread src/data-loader.ts Outdated
Comment thread src/data-loader.ts Outdated
Comment thread src/data-loader.ts Outdated
Comment thread src/data-loader.ts Outdated
- Add core branded types: ModelName, SessionId, ProjectPath, Version
- Add date-specific branded types: DailyDate, ActivityDate, MonthlyDate, ISOTimestamp, FilterDate
- Add identifier types: RequestId, MessageId for message tracking
- Create validation schemas with appropriate format constraints (regex, length)
- Add helper functions for safe type construction (createModelName, createActivityDate, etc.)
- Relax model name validation to support synthetic/unknown models for backward compatibility
- Maintain existing CostMode and SortOrder types

This establishes the foundation for compile-time type safety across the application.
**Schema Integration:**
- Update usageDataSchema to use branded types (modelNameSchema, isoTimestampSchema, etc.)
- Update dailyUsageSchema, sessionUsageSchema, monthlyUsageSchema with branded fields
- Change sessionUsage.lastActivity from ISOTimestamp to ActivityDate for YYYY-MM-DD format

**Performance Optimizations:**
- Use type assertions (as ModelName[]) for array mapping in hot paths
- Optimize modelsUsed.map(createModelName) → modelsUsed as ModelName[]
- Optimize versions array mapping and model breakdown creation
- Balance type safety with runtime performance in aggregation loops

**Import & Type Updates:**
- Add comprehensive imports for branded types and create functions
- Update type imports for ActivityDate, ModelName, Version, etc.
- Add proper error handling for branded type validation

This maintains full type safety while optimizing performance-critical paths.
**Test Data Standardization:**
- Replace direct string assignments with proper branded type constructors
- Use createModelName() for all Claude model references in tests
- Use createActivityDate() for lastActivity fields (YYYY-MM-DD format)
- Use createDailyDate(), createSessionId(), createProjectPath() in test scenarios

**Type Safety in Tests:**
- Ensure all test data validates through branded type schemas
- Update test expectations to work with branded types
- Maintain test coverage while enforcing type constraints

**Model Updates:**
- Update test models to use current Claude 4 naming (claude-sonnet-4-20250514, claude-opus-4-20250514)
- Ensure backward compatibility testing with various model name formats

This ensures tests validate the same type constraints as production code.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR enhances type safety by introducing Zod branded types throughout the application while optimizing performance through selective use of type assertions.

  • Introduces branded Zod schemas and helper functions in src/types.internal.ts.
  • Refactors data parsing and aggregation in src/data-loader.ts to utilize branded types.
  • Updates cost calculation tests in src/calculate-cost.ts to use branded type constructors.

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/types.internal.ts Implements branded Zod schemas and helper functions for type-safe string validation.
src/data-loader.ts Integrates branded types into JSONL parsing and usage aggregation for improved safety.
src/calculate-cost.ts Adjusts tests and cost calculations to leverage branded type helpers for improved clarity.

Comment thread src/data-loader.ts
lastActivity: formatDate(latestEntry.timestamp),
versions: uniq(versions).sort(),
modelsUsed,
lastActivity: formatDate(latestEntry.timestamp) as ActivityDate,

Copilot AI Jun 18, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider replacing the direct type assertion with a branded helper such as createActivityDate to ensure consistent runtime validation across date conversions.

Copilot uses AI. Check for mistakes.
Comment thread src/data-loader.ts
return {
date,
date: createDailyDate(date),
...totals,

Copilot AI Jun 18, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] While using a type assertion here is effective for performance, adding a brief inline comment to clarify that the data has been pre-validated could improve code clarity for future maintainers.

Suggested change
...totals,
...totals,
// `modelsUsed` has been pre-validated to match the `ModelName[]` type.

Copilot uses AI. Check for mistakes.
@ryoppippi
ryoppippi merged commit 6ec4752 into main Jun 18, 2025
@ryoppippi
ryoppippi deleted the brand branch June 18, 2025 13:46
ryoppippi added a commit that referenced this pull request Jun 22, 2025
feat: enhance type safety with Zod branded types and performance optimizations
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants