Skip to content

fix: enforce typed billable meter contracts - #1555

Merged
kang-heewon merged 9 commits into
trunkfrom
issue-1515-typed-meters
Jul 26, 2026
Merged

fix: enforce typed billable meter contracts#1555
kang-heewon merged 9 commits into
trunkfrom
issue-1515-typed-meters

Conversation

@kang-heewon

@kang-heewon kang-heewon commented Jul 25, 2026

Copy link
Copy Markdown
Member

Outcome

  • Defines immutable typed meter descriptors with compile-time aggregation, billing, and dimension contracts.
  • Enforces billing event identifiers and declared dimensions at runtime while preserving the legacy recording API.
  • Persists usage envelopes through Redis and Drizzle, with exported PostgreSQL and SQLite migrations for existing tables.
  • Adds generated API documentation, public API snapshots, Problem registry entries, and release changesets.

Verification

  • Full pre-push test suite: 226 tasks passed.
  • Full pre-push typecheck: 225 tasks passed.
  • Metering core: 185 tests passed.
  • Metering Drizzle: 31 tests passed.
  • Public API, Problem registry, documentation examples, API documentation drift, and changeset-required checks passed.
  • Independent adversarial review: approved with no high- or medium-severity findings.

Review gates

  • Correctness and regression coverage: passed.
  • API compatibility, persistence, migrations, and release readiness: passed.
  • Maintainability and issue-scope discipline: passed.

Deployment note

Applications that opt into typed usage envelopes with Drizzle must add the eventId and dimensions mappings and apply the exported dialect-specific migration. Legacy configurations remain source-compatible, but typed fields fail explicitly until storage is upgraded.

Metering storage failures from the typed decorator propagate after the wrapped method completes; transactional delivery remains outside this issue.

Fixes #1515

Summary by CodeRabbit

  • 새 기능
    • defineMeter/dimension 기반 타입 미터와 결정적 사용량 기록을 지원합니다.
    • record(meter, input)@Metered에서 eventId·dimensions를 사용량 엔벨로프에 포함해 검증하며, 청구 필수는 fail-closed로 처리합니다.
    • Redis/드리즐 어댑터에 eventId·dimensions 저장이 반영됩니다(typed 엔벨로프 포맷 포함).
    • PostgreSQL·SQLite용 엔벨로프 컬럼 추가/제거 마이그레이션을 제공합니다.
  • 문서
    • record 오버로드, 관련 타입/데코레이터 옵션, API 레퍼런스 및 예시를 확장·정리했습니다.
  • 오류 처리
    • InvalidMeterDimensionProblem, InvalidUsageEnvelopeProblem, UsageEnvelopeConfigurationProblem로 차원/엔벨로프/설정 누락을 명확히 구분합니다.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

정의 우선 typed meter와 billable usage envelope이 추가되었습니다. eventIddimensions 검증, Redis v2 저장 형식 및 레거시 호환, Drizzle 스키마·마이그레이션, 데코레이터 오버로드, 공개 API와 문서가 함께 갱신되었습니다.

Changes

Typed metering flow

Layer / File(s) Summary
Meter contracts and descriptors
packages/metering-core/src/libs/MeterRef.ts, packages/metering-core/src/libs/problems/*, packages/metering-core/src/index.ts
defineMeter, dimension.enum, branded MeterRef, 조건부 MeterRecordInput, 결정적 정규화, dimension 오류가 추가되고 공개 API로 노출되었습니다.
Typed recording and decorator flow
packages/metering-core/src/libs/MeteringService.ts, packages/metering-core/src/libs/decorators/Metered.ts, packages/metering-core/src/libs/types.ts, packages/metering-core/src/tests/*
typed record(meter, input)과 typed @Metered 경로가 추가되었으며, billing-required eventId, dimension schema, fail-closed 동작과 기존 문자열 API 호환이 검증됩니다.
Redis usage envelope persistence
packages/metering-core/src/libs/RedisUsageStorage.ts, packages/metering-core/src/tests/RedisUsageStorage.spec.ts
eventId, dimensions, metadata, idempotency key를 포함하는 v2 JSON member 형식과 레거시 member 읽기·삭제 처리가 추가되었습니다.
Drizzle schema and migrations
packages/metering-drizzle/src/libs/*, packages/metering-drizzle/src/migrations/*, packages/metering-drizzle/src/tests/*
PostgreSQL과 SQLite usage_recordsevent_iddimensions가 추가되고, 누락된 매핑 오류와 add/remove migration helper가 구현·검증되었습니다.
Release metadata and API documentation
.changeset/*, packages/docs/src/content/docs/api/*, docs/*, public-api-surface.snapshot.json, packages/*/README.md
새 타입·문제 코드·migration exports·사용 예시와 API 문서가 갱신되었고 릴리스 changeset이 추가되었습니다.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Application
  participant MeteringService
  participant RedisUsageStorage
  participant DrizzleMeterRepository
  Application->>MeteringService: record(meterRef, input)
  MeteringService->>MeteringService: validate eventId and dimensions
  MeteringService->>RedisUsageStorage: serialize v2 usage envelope
  MeteringService->>DrizzleMeterRepository: save mapped usage fields
  DrizzleMeterRepository-->>Application: persisted usage record
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Metered의 metadataExtractor 같은 return-value extraction 콜백 추가는 링크된 이슈의 비목표 범위입니다. 해당 콜백 관련 변경을 분리하거나 제거하고, 범위를 정의 우선 meter/usage envelope 계약과 기존 record 호환성에 맞추세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 typed billable meter contracts라는 핵심 변경을 직접 요약합니다.
Linked Issues check ✅ Passed 정의 우선 meter API, typed record 경로, eventId/dimensions 검증, @Metered 지원, 문서/스냅샷까지 요구사항을 충족합니다.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-1515-typed-meters

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

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 25, 2026

Copy link
Copy Markdown

📊 Benchmark Results

✅ All benchmarks passed

Benchmark p75 Threshold Baseline vs Baseline Status Notes
CrocoApp constructor 8.9μs 30.0ms 8.2μs +8.6% -
CrocoApp lambdaHandler (10 controllers) 404.1μs 50.0ms 258.4μs +56.4% -
Lambda cold-start simulation 440.6μs 80.0ms 418.1μs +5.4% -
Lambda cold-start with headers 423.4μs 80.0ms 369.7μs +14.5% -
Lambda cold-start with binary body 388.4μs 80.0ms 339.1μs +14.5% -
Lambda cold-start with query params 330.4μs 80.0ms 301.3μs +9.7% -
Lambda cold-start with authorizer context 329.2μs 80.0ms 299.8μs +9.8% -
Lambda cold-start realistic scenario 329.2μs 80.0ms 299.2μs +10.0% -
EventBusConfig.start (10 handlers) 1.6μs 10.0ms 1.4μs +9.8% -
EventPublisher.publishNow single event 1.8μs 2.0ms 1.7μs +7.2% -
DefaultHandlerResolver.resolve × 10 0.1μs 5.0ms 0.1μs -11.2% -
Container.get singleton (cold) 78.2μs 5.0ms 70.3μs +11.3% -
Container.register × 50 components 3.7ms 10.0ms 3.2ms +14.6% -
Container.validate (50 components) 4.2ms 20.0ms 3.4ms +23.8% -
Container.get singleton (warm) 1.7μs 500.0μs 1.6μs +5.6% -
TelemetryRuntime.init (lambda preset) 2.4μs 200.0ms 1.1ms -99.8% -
lambdaPreset config creation 1.5μs 2.0ms 1.4μs +5.7% -

Updated: 2026-07-26T11:00:16.773Z · Commit: 2a89ff6

@kang-heewon
kang-heewon force-pushed the issue-1515-typed-meters branch 2 times, most recently from 1b1e848 to 45a3fb3 Compare July 25, 2026 22:48

@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: 12

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/typed-billable-meters.md:
- Around line 7-11: Update the release note to explicitly state that
`@croco/metering-drizzle` users must configure eventId and dimensions mappings and
apply the corresponding Drizzle migration when adopting typed usage envelopes.
Mention that both steps are required before recording typed fields, while
preserving the existing compatibility-path guidance.

In
`@packages/docs/src/content/docs/api/metering-core/src/classes/InvalidMeterDimensionProblem.md`:
- Line 8: InvalidMeterDimensionProblem과 InvalidUsageEnvelopeProblem의 공통 JSDoc이
잘못된 RFC 7807 기본 클래스 설명을 사용하고 있습니다. 원본 클래스 JSDoc을 각각 구체적인 dimension validation
문제와 usage-envelope validation 문제 설명으로 수정하고 TypeDoc을 재생성하세요.
packages/docs/src/content/docs/api/metering-core/src/classes/InvalidMeterDimensionProblem.md:8-8
및
packages/docs/src/content/docs/api/metering-core/src/classes/InvalidUsageEnvelopeProblem.md:8-8
생성물이 갱신되도록 한 뒤 pnpm docs:api:check로 검증하세요.

In
`@packages/docs/src/content/docs/api/metering-core/src/classes/MeteringService.md`:
- Around line 50-91: Add InvalidUsageEnvelopeProblem to the `@throws`
documentation for the record<Meter>(meter, input) overload in MeteringService,
alongside the existing quota, duplicate-record, and invalid-meter exceptions, so
generated docs reflect validateTypedRecord() behavior.

In `@packages/metering-core/README.md`:
- Around line 78-91: Align the meter identifiers in the README example by
changing the class-level `@Meter` meterId to match apiCalls.key, "api.calls". Keep
the existing COUNT type and quota unchanged so usage recorded by `@Metered` is
enforced by the registered quota.

In `@packages/metering-core/src/index.ts`:
- Line 92: Reorganize the barrel exports in index.ts by category: move
InvalidUsageEnvelopeProblem and InvalidMeterDimensionProblem into the Problems
section, and move the type-only export of MeteredMetadata, MeteredOptions, and
MeteredRefOptions into the final Types section. Preserve all existing exports
and their names while removing the misplaced duplicates.
- Around line 216-228: 상단 JSDoc import 목록에 예시에서 사용하는 defineMeter와 dimension을
추가하세요. 문서의 definition-first 예시가 해당 심볼을 별도 선언 없이 참조할 수 있도록 기존 import 형식과 일관되게
갱신합니다.

In `@packages/metering-core/src/libs/decorators/Metered.ts`:
- Around line 107-110: The generic Metered<Meter extends CountMeterRef> overload
lacks its own typed usage example. In
packages/metering-core/src/libs/decorators/Metered.ts lines 107-110, add a
distinct JSDoc `@example` above that overload demonstrating `@Metered`({ meter:
apiCalls, eventIdExtractor: ... });
packages/docs/src/content/docs/api/metering-core/src/functions/Metered.md lines
39-86 require no direct change because they will regenerate from the corrected
source documentation.

In `@packages/metering-core/src/libs/MeteringService.ts`:
- Around line 66-75: In the input-handling branch of MeteringService, after
validateTypedRecord validates input.dimensions, pass a shallow copy of the
dimensions object in the recordUsage payload instead of the original mutable
reference. Preserve undefined dimensions as undefined while ensuring later
caller mutations cannot alter the validated values or add keys.
- Around line 183-188: Update the billing-required validation in the meter usage
flow to reject any eventId that is not a string, including nullish or blank
values, by throwing InvalidUsageEnvelopeProblem instead of allowing trim() to
raise a TypeError. Preserve acceptance of non-empty string eventId values.

In `@packages/metering-core/src/libs/RedisUsageStorage.ts`:
- Around line 458-476: Extract the shared usage-envelope shape into a private
type alias in RedisUsageStorage, then reuse it for parseUsageMember’s return
type, decodeUsageEnvelope’s return type, and the JSON.parse cast inside
decodeUsageEnvelope. Remove the duplicated inline object definitions while
preserving the existing optional fields and value types.

In `@packages/metering-drizzle/src/libs/DrizzleMeterRepository.ts`:
- Around line 177-212: Update the values construction in the repository method
so dimensions remains the original object for PostgreSQL jsonb columns, while
SQLite text columns continue using serializeJson. Apply the same dialect-aware
handling to any other JSON field only if required by the existing schema
abstraction, and add a PostgreSQL round-trip test covering dimensions to verify
it is stored and read back as an object.

In `@packages/metering-drizzle/src/migrations/addUsageEnvelopeFields.ts`:
- Around line 19-27: Update addUsageEnvelopeFieldsSqlite and
removeUsageEnvelopeFieldsSqlite to inspect PRAGMA table_info('usage_records')
and execute only missing additions or existing-column removals, making both
migrations safely rerunnable. Wrap each migration’s schema changes in an atomic
transaction with rollback so a partial failure, such as event_id succeeding
before dimensions fails, does not leave an unrecoverable schema state; preserve
compatibility with concurrent callers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 71cc0dd1-d659-4410-ac9a-9a7ae3803790

📥 Commits

Reviewing files that changed from the base of the PR and between f0e9c0d and 45a3fb3.

⛔ Files ignored due to path filters (1)
  • packages/problems-core/src/generated/problem-code-registry.ts is excluded by !**/generated/**
📒 Files selected for processing (56)
  • .changeset/typed-billable-meters.md
  • docs/problem-code-registry.json
  • packages/docs/src/content/docs/api/metering-core/src/classes/InvalidMeterDimensionProblem.md
  • packages/docs/src/content/docs/api/metering-core/src/classes/InvalidUsageEnvelopeProblem.md
  • packages/docs/src/content/docs/api/metering-core/src/classes/MeteringService.md
  • packages/docs/src/content/docs/api/metering-core/src/functions/Metered.md
  • packages/docs/src/content/docs/api/metering-core/src/functions/defineMeter.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/CountMeterRef.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/EnumDimension.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterAggregation.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterBillingIntent.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDefinitionOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDimensionSchema.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDimensionValue.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterRecordInput.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterRef.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredMetadata.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredRefOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/RecordOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/UsageRecord.md
  • packages/docs/src/content/docs/api/metering-core/src/variables/dimension.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/classes/UsageEnvelopeConfigurationProblem.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/addUsageEnvelopeFieldsPostgres.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/addUsageEnvelopeFieldsSqlite.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/removeUsageEnvelopeFieldsPostgres.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/removeUsageEnvelopeFieldsSqlite.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/type-aliases/MeteringMigrationClient.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/type-aliases/UsageRecordTable.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/variables/usageRecordsPg.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/variables/usageRecordsSqlite.md
  • packages/docs/src/content/docs/api/problems-core/src/classes/Problem.md
  • packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md
  • packages/docs/src/content/docs/en/reference/problem-recovery-cookbook.md
  • packages/metering-core/README.md
  • packages/metering-core/src/index.ts
  • packages/metering-core/src/libs/MeterRef.ts
  • packages/metering-core/src/libs/MeteringService.ts
  • packages/metering-core/src/libs/RedisUsageStorage.ts
  • packages/metering-core/src/libs/decorators/Metered.ts
  • packages/metering-core/src/libs/problems/InvalidMeterDimensionProblem.ts
  • packages/metering-core/src/libs/problems/InvalidUsageEnvelopeProblem.ts
  • packages/metering-core/src/libs/types.ts
  • packages/metering-core/src/tests/MeterRef.spec.ts
  • packages/metering-core/src/tests/MeterRefTypes.spec.ts
  • packages/metering-core/src/tests/MeteringService.spec.ts
  • packages/metering-core/src/tests/RedisUsageStorage.spec.ts
  • packages/metering-core/src/tests/decorators/Metered.spec.ts
  • packages/metering-drizzle/README.md
  • packages/metering-drizzle/src/index.ts
  • packages/metering-drizzle/src/libs/DrizzleMeterRepository.ts
  • packages/metering-drizzle/src/libs/index.ts
  • packages/metering-drizzle/src/libs/problems/UsageEnvelopeConfigurationProblem.ts
  • packages/metering-drizzle/src/libs/schema.ts
  • packages/metering-drizzle/src/migrations/addUsageEnvelopeFields.ts
  • packages/metering-drizzle/src/tests/DrizzleMeterRepository.spec.ts
  • public-api-surface.snapshot.json

Comment thread .changeset/typed-billable-meters.md
Comment thread packages/docs/src/content/docs/api/metering-core/src/classes/MeteringService.md Outdated
Comment thread packages/metering-core/README.md
Comment thread packages/metering-core/src/index.ts Outdated
Comment thread packages/metering-core/src/libs/MeteringService.ts
Comment thread packages/metering-core/src/libs/MeteringService.ts
Comment thread packages/metering-core/src/libs/RedisUsageStorage.ts Outdated
Comment thread packages/metering-drizzle/src/libs/DrizzleMeterRepository.ts
Comment thread packages/metering-drizzle/src/migrations/addUsageEnvelopeFields.ts
@kang-heewon
kang-heewon force-pushed the issue-1515-typed-meters branch 2 times, most recently from 8316ee3 to afe8bb8 Compare July 25, 2026 23:53

@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: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/metering-core/src/libs/decorators/Metered.ts (1)

156-217: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

billing: "required" 미터의 record() 실패는 원본 메서드 호출 이후에 전파됩니다.

service.record()가 거부되면 예외를 전파하지만, 이미 originalMethod가 완료되어 결과를 얻은 뒤입니다. 같은 요청이 이 예외에 의해 재시도되면 멱등하지 않은 비즈니스 로직(결제, 이메일 발송, 외부 API 호출 등)이 중복 실행될 수 있으므로, 최소한 Metered 문서/JSDoc에 billing-required 미터는 재시도 안전장치가 없으므로 구현이 멱등이어야 한다는 제약과 위험을 명시하세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/metering-core/src/libs/decorators/Metered.ts` around lines 156 -
217, Update the JSDoc/documentation for the Metered decorator to explicitly
state that billing-required meter record failures are propagated after
originalMethod completes, so retries can repeat non-idempotent business
operations. Document that implementations using billing-required meters must
provide their own retry safety and ensure the underlying business logic is
idempotent; do not alter the execution flow in descriptor.value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/metering-core/src/index.ts`:
- Around line 256-266: Move the type-only export block containing CountMeterRef,
EnumDimension, MeterAggregation, MeterBillingIntent, MeterDefinitionOptions,
MeterDimensionSchema, MeterDimensionValue, MeterRecordInput, and MeterRef to the
final type-export section of index.ts, after all runtime exports. Keep the
exported symbols and source module unchanged.

In `@packages/metering-core/src/libs/MeteringService.ts`:
- Around line 76-93: Normalize input.eventId by trimming it once in the
typed-record branch before calling recordUsage, then use that normalized value
for both idempotencyKey and eventId. Keep validateTypedRecord and the existing
handling of other fields unchanged so validation and deduplication use the same
event identifier.

In `@packages/metering-core/src/libs/MeterRef.ts`:
- Around line 105-120: 직접 descriptor 경로에서 enum 값의 유효성 검사가 누락되어 NaN 같은 비유한 숫자가
통과합니다. 공통 값 검증 헬퍼를 추출해 `dimension.enum()`과 `normalizeDimensions()`에서 모두 호출하고,
enum 값은 유한한 숫자만 허용하도록 유지하세요. `defineMeter()`에 직접 descriptor를 전달하면서 NaN을 포함한 회귀
테스트도 추가하세요.

In `@packages/metering-core/src/libs/RedisUsageStorage.ts`:
- Line 374: v2 envelope 직렬화를 JSON.stringify의 삽입 순서 의존 방식에서 재귀적으로 객체 키를 정렬하는 결정적
직렬화 방식으로 변경하세요. 생성 경로와 deleteUsageRecords의 ZREM 재직렬화가 동일한 안정적 직렬화 로직을 재사용하도록 하고,
중첩 dimensions 및 metadata의 키 순서가 달라도 동일한 member가 생성되어 삭제되는 회귀 테스트를 추가하세요.

In `@packages/metering-drizzle/README.md`:
- Around line 79-94: README의 기존 테이블 업그레이드 migration 예시를 사용하는 dialect 하나만 실행하는
형태로 수정하세요. SQLite 사용법에 맞춰 addUsageEnvelopeFieldsSqlite만 import하고 sqliteClient에
호출하며, Postgres 사용 시에는 addUsageEnvelopeFieldsPostgres를 대신 사용한다는 안내를 추가하세요.

In `@packages/metering-drizzle/src/libs/index.ts`:
- Line 15: Reorder the exports in the index.ts barrel so the runtime
exports—DrizzleMeterRepository, problem exports, and schema exports—appear
first, then move the type export block to the end. Preserve all existing exports
and only change their grouping order.

In `@packages/metering-drizzle/src/tests/DrizzleMeterRepository.spec.ts`:
- Around line 901-928: 보정 마이그레이션 재시도 후 컬럼 복구 여부 검증이 누락되었습니다.
`addUsageEnvelopeFieldsSqlite(migrationClient)` 호출 직후 `usage_records`의 `PRAGMA
table_info` 결과를 확인하는 assertion을 추가해 `event_id`와 `dimensions`가 모두 존재하는지 검증하세요.

---

Outside diff comments:
In `@packages/metering-core/src/libs/decorators/Metered.ts`:
- Around line 156-217: Update the JSDoc/documentation for the Metered decorator
to explicitly state that billing-required meter record failures are propagated
after originalMethod completes, so retries can repeat non-idempotent business
operations. Document that implementations using billing-required meters must
provide their own retry safety and ensure the underlying business logic is
idempotent; do not alter the execution flow in descriptor.value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d983a97f-f33c-4e60-bd2f-fcbbc18a3971

📥 Commits

Reviewing files that changed from the base of the PR and between 45a3fb3 and 8316ee3.

⛔ Files ignored due to path filters (1)
  • packages/problems-core/src/generated/problem-code-registry.ts is excluded by !**/generated/**
📒 Files selected for processing (57)
  • .changeset/typed-billable-meters.md
  • docs/problem-code-registry.json
  • packages/docs/src/content/docs/api/metering-core/src/classes/InvalidMeterDimensionProblem.md
  • packages/docs/src/content/docs/api/metering-core/src/classes/InvalidUsageEnvelopeProblem.md
  • packages/docs/src/content/docs/api/metering-core/src/classes/MeteringService.md
  • packages/docs/src/content/docs/api/metering-core/src/functions/Metered.md
  • packages/docs/src/content/docs/api/metering-core/src/functions/defineMeter.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/CountMeterRef.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/EnumDimension.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterAggregation.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterBillingIntent.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDefinitionOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDimensionSchema.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDimensionValue.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterRecordInput.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterRef.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredMetadata.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredRefOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/RecordOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/UsageRecord.md
  • packages/docs/src/content/docs/api/metering-core/src/variables/dimension.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/classes/UsageEnvelopeConfigurationProblem.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/addUsageEnvelopeFieldsPostgres.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/addUsageEnvelopeFieldsSqlite.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/removeUsageEnvelopeFieldsPostgres.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/removeUsageEnvelopeFieldsSqlite.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/type-aliases/MeteringMigrationClient.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/type-aliases/UsageRecordTable.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/variables/usageRecordsPg.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/variables/usageRecordsSqlite.md
  • packages/docs/src/content/docs/api/problems-core/src/classes/Problem.md
  • packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md
  • packages/docs/src/content/docs/en/reference/problem-recovery-cookbook.md
  • packages/metering-core/README.md
  • packages/metering-core/src/index.ts
  • packages/metering-core/src/libs/MeterRef.ts
  • packages/metering-core/src/libs/MeteringService.ts
  • packages/metering-core/src/libs/RedisUsageStorage.ts
  • packages/metering-core/src/libs/decorators/Metered.ts
  • packages/metering-core/src/libs/problems/InvalidMeterDimensionProblem.ts
  • packages/metering-core/src/libs/problems/InvalidUsageEnvelopeProblem.ts
  • packages/metering-core/src/libs/types.ts
  • packages/metering-core/src/tests/MeterRef.spec.ts
  • packages/metering-core/src/tests/MeterRefTypes.spec.ts
  • packages/metering-core/src/tests/MeteringService.spec.ts
  • packages/metering-core/src/tests/RedisUsageStorage.spec.ts
  • packages/metering-core/src/tests/decorators/Metered.spec.ts
  • packages/metering-drizzle/README.md
  • packages/metering-drizzle/src/index.ts
  • packages/metering-drizzle/src/libs/DrizzleMeterRepository.ts
  • packages/metering-drizzle/src/libs/index.ts
  • packages/metering-drizzle/src/libs/problems/UsageEnvelopeConfigurationProblem.ts
  • packages/metering-drizzle/src/libs/schema.ts
  • packages/metering-drizzle/src/migrations/addUsageEnvelopeFields.ts
  • packages/metering-drizzle/src/tests/DrizzleMeterRepository.spec.ts
  • public-api-surface.snapshot.json

Comment thread packages/metering-core/src/index.ts Outdated
Comment thread packages/metering-core/src/libs/MeteringService.ts
Comment thread packages/metering-core/src/libs/MeterRef.ts
Comment thread packages/metering-core/src/libs/RedisUsageStorage.ts Outdated
Comment thread packages/metering-drizzle/README.md
Comment thread packages/metering-drizzle/src/libs/index.ts Outdated
Comment thread packages/metering-drizzle/src/tests/DrizzleMeterRepository.spec.ts
@kang-heewon
kang-heewon force-pushed the issue-1515-typed-meters branch from afe8bb8 to eb9cfe7 Compare July 26, 2026 00:13
@kang-heewon

Copy link
Copy Markdown
Member Author

@coderabbitai resolve

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Comments resolved and changes approved.

@kang-heewon
kang-heewon force-pushed the issue-1515-typed-meters branch 3 times, most recently from b22e019 to 5cef491 Compare July 26, 2026 01:28

@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: 12

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/docs/src/content/docs/api/metering-drizzle/src/classes/UsageEnvelopeConfigurationProblem.md`:
- Line 8: Update the source TSDoc for UsageEnvelopeConfigurationProblem to
describe it as the concrete Problem representing a missing usage-envelope
mapping, rather than a base abstract error class. Regenerate the TypeDoc API
documentation and validate the generated output with pnpm docs:api:check; do not
edit the generated Markdown directly.

In
`@packages/docs/src/content/docs/api/metering-drizzle/src/functions/removeUsageEnvelopeFieldsPostgres.md`:
- Around line 8-18: Update the source TSDoc for both
removeUsageEnvelopeFieldsPostgres and removeUsageEnvelopeFieldsSqlite to
explicitly warn that deleting the event_id and dimensions columns causes
irreversible data loss, and advise backing up because rollback is unavailable.
Regenerate the TypeDoc API output rather than editing generated Markdown
directly; the PostgreSQL site at
packages/docs/src/content/docs/api/metering-drizzle/src/functions/removeUsageEnvelopeFieldsPostgres.md
lines 8-18 and SQLite site at
packages/docs/src/content/docs/api/metering-drizzle/src/functions/removeUsageEnvelopeFieldsSqlite.md
lines 8-23 should both receive the generated warning. Validate with pnpm
docs:api:check.

In `@packages/metering-core/src/index.ts`:
- Around line 466-467: Move the type-only export of MeteredMetadata,
MeteredOptions, and MeteredRefOptions from the current location near
UsageAggregator to the final type-export block after line 521 in index.ts. Keep
the export unchanged and ensure all type exports remain grouped last.

In `@packages/metering-core/src/libs/decorators/Metered.ts`:
- Around line 91-108: The `@Metered`<Meter> JSDoc example should also demonstrate
eventIdExtractor and dimensionsExtractor alongside the existing meter
configuration and valueExtractor usage. Update the example in Metered.ts to show
how billing-required/typed meters extract event IDs and dimensions, then
regenerate or update the corresponding Metered.md documentation.

In `@packages/metering-core/src/libs/MeterRef.ts`:
- Around line 86-123: Update validateDimensionValues and the descriptor handling
in dimension.enum and normalizeDimensions to validate every value as a string,
finite number, or boolean, reject empty arrays and invalid runtime values with
InvalidMeterDimensionProblem, and require kind === "enum" for descriptors. Apply
the same validation to both direct enum creation and schema normalization paths,
preserving only validated enum descriptors; add regression tests covering both
paths.

In `@packages/metering-core/src/tests/MeteringService.spec.ts`:
- Around line 8-12: Reorder the imports in MeteringService.spec.ts so the value
imports from MeterRef and the problem modules remain together first, followed by
a separate type-only import section containing MeterRecordInput.

In `@packages/metering-core/src/tests/MeterRefTypes.spec.ts`:
- Around line 6-36: Rename the module-level constants aiTokens, localCalls,
billableCalls, and regionalCalls to AI_TOKENS, LOCAL_CALLS, BILLABLE_CALLS, and
REGIONAL_CALLS respectively, and update every reference to these symbols in
MeterRefTypes.spec.ts.

In `@packages/metering-drizzle/README.md`:
- Around line 79-86: README의 기존 테이블 업그레이드 예제에서 선언되지 않은 sqliteClient를 제거하고, 앞서
선언된 호환 가능한 클라이언트를 사용하거나 MeteringMigrationClient를 실제로 구성하는 코드로 교체하세요.
addUsageEnvelopeFieldsSqlite 호출이 예제만으로 실행 가능하도록 관련 import와 변수 선언을 일관되게 맞추세요.

In `@packages/metering-drizzle/src/libs/DrizzleMeterRepository.ts`:
- Around line 225-229: Update DrizzleMeterRepository.encodeJsonColumn to pass
JSON values through for every supported Drizzle JSON column type, including
PgJson and MySqlJson, rather than only PgJsonb; retain serializeJson for
non-JSON columns to prevent double encoding.

In `@packages/metering-drizzle/src/libs/schema.ts`:
- Around line 38-39: Update the schema and its migration to add a partial index
on (tenant_id, event_id) for rows where event_id is not null, supporting
reconciliation lookups while preserving the existing unique index.

In `@packages/metering-drizzle/src/migrations/addUsageEnvelopeFields.ts`:
- Around line 9-19: Update addUsageEnvelopeFieldsPostgres and
removeUsageEnvelopeFieldsPostgres to execute both column operations through the
same transaction-aware migration flow used by runSqliteMigration. Extract and
reuse that transaction branching logic via runMigration, preserving the existing
operation order and fallback behavior when no transaction is available.
- Around line 44-53: Update the JSDoc for the exported
removeUsageEnvelopeFieldsSqlite function to document that its SQLite ALTER TABLE
DROP COLUMN operations require SQLite 3.35.0 or later.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a7872741-7c61-42fa-8311-013265c993af

📥 Commits

Reviewing files that changed from the base of the PR and between 8316ee3 and 5cef491.

⛔ Files ignored due to path filters (1)
  • packages/problems-core/src/generated/problem-code-registry.ts is excluded by !**/generated/**
📒 Files selected for processing (57)
  • .changeset/typed-billable-meters.md
  • docs/problem-code-registry.json
  • packages/docs/src/content/docs/api/metering-core/src/classes/InvalidMeterDimensionProblem.md
  • packages/docs/src/content/docs/api/metering-core/src/classes/InvalidUsageEnvelopeProblem.md
  • packages/docs/src/content/docs/api/metering-core/src/classes/MeteringService.md
  • packages/docs/src/content/docs/api/metering-core/src/functions/Metered.md
  • packages/docs/src/content/docs/api/metering-core/src/functions/defineMeter.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/CountMeterRef.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/EnumDimension.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterAggregation.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterBillingIntent.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDefinitionOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDimensionSchema.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDimensionValue.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterRecordInput.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterRef.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredMetadata.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredRefOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/RecordOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/UsageRecord.md
  • packages/docs/src/content/docs/api/metering-core/src/variables/dimension.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/classes/UsageEnvelopeConfigurationProblem.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/addUsageEnvelopeFieldsPostgres.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/addUsageEnvelopeFieldsSqlite.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/removeUsageEnvelopeFieldsPostgres.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/removeUsageEnvelopeFieldsSqlite.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/type-aliases/MeteringMigrationClient.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/type-aliases/UsageRecordTable.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/variables/usageRecordsPg.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/variables/usageRecordsSqlite.md
  • packages/docs/src/content/docs/api/problems-core/src/classes/Problem.md
  • packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md
  • packages/docs/src/content/docs/en/reference/problem-recovery-cookbook.md
  • packages/metering-core/README.md
  • packages/metering-core/src/index.ts
  • packages/metering-core/src/libs/MeterRef.ts
  • packages/metering-core/src/libs/MeteringService.ts
  • packages/metering-core/src/libs/RedisUsageStorage.ts
  • packages/metering-core/src/libs/decorators/Metered.ts
  • packages/metering-core/src/libs/problems/InvalidMeterDimensionProblem.ts
  • packages/metering-core/src/libs/problems/InvalidUsageEnvelopeProblem.ts
  • packages/metering-core/src/libs/types.ts
  • packages/metering-core/src/tests/MeterRef.spec.ts
  • packages/metering-core/src/tests/MeterRefTypes.spec.ts
  • packages/metering-core/src/tests/MeteringService.spec.ts
  • packages/metering-core/src/tests/RedisUsageStorage.spec.ts
  • packages/metering-core/src/tests/decorators/Metered.spec.ts
  • packages/metering-drizzle/README.md
  • packages/metering-drizzle/src/index.ts
  • packages/metering-drizzle/src/libs/DrizzleMeterRepository.ts
  • packages/metering-drizzle/src/libs/index.ts
  • packages/metering-drizzle/src/libs/problems/UsageEnvelopeConfigurationProblem.ts
  • packages/metering-drizzle/src/libs/schema.ts
  • packages/metering-drizzle/src/migrations/addUsageEnvelopeFields.ts
  • packages/metering-drizzle/src/tests/DrizzleMeterRepository.spec.ts
  • public-api-surface.snapshot.json

Comment thread packages/metering-core/src/index.ts Outdated
Comment thread packages/metering-core/src/libs/decorators/Metered.ts
Comment thread packages/metering-core/src/libs/MeterRef.ts Outdated
Comment thread packages/metering-drizzle/README.md
Comment thread packages/metering-drizzle/src/libs/DrizzleMeterRepository.ts
Comment thread packages/metering-drizzle/src/libs/schema.ts
Comment thread packages/metering-drizzle/src/migrations/addUsageEnvelopeFields.ts
Comment thread packages/metering-drizzle/src/migrations/addUsageEnvelopeFields.ts
@kang-heewon
kang-heewon force-pushed the issue-1515-typed-meters branch from 66e327e to 2d362d9 Compare July 26, 2026 04:29

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/docs/src/content/docs/api/metering-core/src/functions/defineMeter.md`:
- Around line 26-28: Update the source TypeDoc input or type definition for
Dimensions/EnumDimension so the generated contract represents a readonly tuple
containing at least one MeterDimensionValue, rather than exactly two. Do not
edit the generated documentation directly; regenerate or validate the output
with pnpm docs:api:api:check.

In `@packages/metering-core/README.md`:
- Around line 113-114: Update the README’s problem-type list near the existing
public API summary to include InvalidMeterDimensionProblem,
InvalidUsageEnvelopeProblem, and UsageEnvelopeConfigurationProblem, keeping the
documented public API aligned with the newly exposed types.

In `@packages/metering-core/src/index.ts`:
- Around line 482-492: Move the type-only export block for CountMeterRef,
EnumDimension, MeterAggregation, MeterBillingIntent, MeterDefinitionOptions,
MeterDimensionSchema, MeterDimensionValue, MeterRecordInput, and MeterRef from
its current position before the UsageAggregator runtime export to the file’s
final type-export section. Keep the symbols and source module unchanged, and
preserve the barrel ordering with all type definitions grouped last.

In `@packages/metering-core/src/libs/decorators/Metered.ts`:
- Around line 184-187: Metered 데코레이터에서 dimensionsExtractor 호출을 originalMethod 실행
전의 try 블록 밖에서 제거하고, 계량 record가 수행되는 try 경로 내부로 이동하세요. eventId 추출과 billing 검증의 사전
수행은 유지하되, billing이 required가 아닌 미터에서 dimensionsExtractor가 예외를 발생시켜도
originalMethod가 실행되고 기존 fail-safe catch가 처리하도록 하세요.

In `@packages/metering-core/src/tests/decorators/Metered.spec.ts`:
- Around line 106-130: Add a runtime test alongside the existing
eventIdExtractor test in Metered.spec.ts using a typed meter with declared
dimensions and a dimensionsExtractor. Invoke the decorated method with dimension
data, then assert mockService.record receives the same meter and an input whose
dimensions contain the extracted values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2350acca-ed2f-4ab2-b28d-8bf8234af477

📥 Commits

Reviewing files that changed from the base of the PR and between 5cef491 and 2d362d9.

⛔ Files ignored due to path filters (1)
  • packages/problems-core/src/generated/problem-code-registry.ts is excluded by !**/generated/**
📒 Files selected for processing (57)
  • .changeset/typed-billable-meters.md
  • docs/problem-code-registry.json
  • packages/docs/src/content/docs/api/metering-core/src/classes/InvalidMeterDimensionProblem.md
  • packages/docs/src/content/docs/api/metering-core/src/classes/InvalidUsageEnvelopeProblem.md
  • packages/docs/src/content/docs/api/metering-core/src/classes/MeteringService.md
  • packages/docs/src/content/docs/api/metering-core/src/functions/Metered.md
  • packages/docs/src/content/docs/api/metering-core/src/functions/defineMeter.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/CountMeterRef.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/EnumDimension.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterAggregation.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterBillingIntent.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDefinitionOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDimensionSchema.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDimensionValue.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterRecordInput.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterRef.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredMetadata.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredRefOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/RecordOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/UsageRecord.md
  • packages/docs/src/content/docs/api/metering-core/src/variables/dimension.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/classes/UsageEnvelopeConfigurationProblem.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/addUsageEnvelopeFieldsPostgres.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/addUsageEnvelopeFieldsSqlite.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/removeUsageEnvelopeFieldsPostgres.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/removeUsageEnvelopeFieldsSqlite.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/type-aliases/MeteringMigrationClient.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/type-aliases/UsageRecordTable.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/variables/usageRecordsPg.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/variables/usageRecordsSqlite.md
  • packages/docs/src/content/docs/api/problems-core/src/classes/Problem.md
  • packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md
  • packages/docs/src/content/docs/en/reference/problem-recovery-cookbook.md
  • packages/metering-core/README.md
  • packages/metering-core/src/index.ts
  • packages/metering-core/src/libs/MeterRef.ts
  • packages/metering-core/src/libs/MeteringService.ts
  • packages/metering-core/src/libs/RedisUsageStorage.ts
  • packages/metering-core/src/libs/decorators/Metered.ts
  • packages/metering-core/src/libs/problems/InvalidMeterDimensionProblem.ts
  • packages/metering-core/src/libs/problems/InvalidUsageEnvelopeProblem.ts
  • packages/metering-core/src/libs/types.ts
  • packages/metering-core/src/tests/MeterRef.spec.ts
  • packages/metering-core/src/tests/MeterRefTypes.spec.ts
  • packages/metering-core/src/tests/MeteringService.spec.ts
  • packages/metering-core/src/tests/RedisUsageStorage.spec.ts
  • packages/metering-core/src/tests/decorators/Metered.spec.ts
  • packages/metering-drizzle/README.md
  • packages/metering-drizzle/src/index.ts
  • packages/metering-drizzle/src/libs/DrizzleMeterRepository.ts
  • packages/metering-drizzle/src/libs/index.ts
  • packages/metering-drizzle/src/libs/problems/UsageEnvelopeConfigurationProblem.ts
  • packages/metering-drizzle/src/libs/schema.ts
  • packages/metering-drizzle/src/migrations/addUsageEnvelopeFields.ts
  • packages/metering-drizzle/src/tests/DrizzleMeterRepository.spec.ts
  • public-api-surface.snapshot.json

Comment thread packages/docs/src/content/docs/api/metering-core/src/functions/defineMeter.md Outdated
Comment thread packages/metering-core/README.md
Comment thread packages/metering-core/src/index.ts Outdated
Comment thread packages/metering-core/src/libs/decorators/Metered.ts Outdated
Comment thread packages/metering-core/src/tests/decorators/Metered.spec.ts
@kang-heewon
kang-heewon force-pushed the issue-1515-typed-meters branch from 9180267 to 0c20711 Compare July 26, 2026 08:15

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/docs/src/content/docs/api/metering-core/src/variables/dimension.md`:
- Around line 10-20: Update the source TSDoc example for defineMeter to
demonstrate actual dimension usage by adding a dimensions property whose value
uses dimension.enum(...). Do not edit the generated Markdown under
packages/docs/src/content/docs/api/ directly; regenerate the API documentation
after updating the TSDoc.

In `@packages/metering-core/src/libs/decorators/Metered.ts`:
- Around line 169-199: Update the eventIdExtractor flow in the descriptor.value
wrapper so pre-execution extraction and validation occur only when
metadata.meter.billing is "required". For non-required meters, defer
eventIdExtractor(args) until the existing recording try block, preserving
fail-safe execution of originalMethod and the current required-meter validation
behavior; add the suggested regression coverage if appropriate.

In `@packages/metering-drizzle/src/libs/DrizzleMeterRepository.ts`:
- Around line 1-9: DrizzleMeterRepository의 import 블록을 가이드 순서에 맞게 재정렬하세요. 외부 패키지인
drizzle-orm 계열을 `@croco/`* 및 상대 경로 내부 import보다 앞 그룹으로 분리하고, runtime import와
type-only import도 각각 구분해 일관된 그룹을 유지하세요.

In `@packages/metering-drizzle/src/migrations/addUsageEnvelopeFields.ts`:
- Around line 9-19: Document in the README or JSDoc for
addUsageEnvelopeFieldsPostgres that the current transactional index creation can
block writes on large usage_records tables, and provide an operational note to
create usage_records_event_id_idx separately with CREATE INDEX CONCURRENTLY
outside a transaction when needed. Keep the migration’s existing column and
index behavior unchanged.

In `@packages/metering-drizzle/src/tests/DrizzleMeterRepository.spec.ts`:
- Around line 968-983: Update the PostgreSQL upgrade statement assertions in the
“should expose PostgreSQL-specific upgrade statements” test to normalize
whitespace and indentation before comparison, so formatting changes in the
migration template do not break the test while preserving validation of the SQL
content.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ed6ad4e3-3c0d-492c-bdde-d1687457fa36

📥 Commits

Reviewing files that changed from the base of the PR and between 2d362d9 and 0c20711.

⛔ Files ignored due to path filters (1)
  • packages/problems-core/src/generated/problem-code-registry.ts is excluded by !**/generated/**
📒 Files selected for processing (58)
  • .changeset/typed-billable-meters.md
  • docs/problem-code-registry.json
  • packages/docs/src/content/docs/api/metering-core/src/classes/InvalidMeterDimensionProblem.md
  • packages/docs/src/content/docs/api/metering-core/src/classes/InvalidUsageEnvelopeProblem.md
  • packages/docs/src/content/docs/api/metering-core/src/classes/MeteringService.md
  • packages/docs/src/content/docs/api/metering-core/src/functions/Metered.md
  • packages/docs/src/content/docs/api/metering-core/src/functions/defineMeter.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/CountMeterRef.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/EnumDimension.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterAggregation.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterBillingIntent.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDefinitionOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDimensionSchema.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDimensionValue.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterRecordInput.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterRef.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredMetadata.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredRefOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/NonEmptyMeterDimensionValues.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/RecordOptions.md
  • packages/docs/src/content/docs/api/metering-core/src/type-aliases/UsageRecord.md
  • packages/docs/src/content/docs/api/metering-core/src/variables/dimension.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/classes/UsageEnvelopeConfigurationProblem.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/addUsageEnvelopeFieldsPostgres.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/addUsageEnvelopeFieldsSqlite.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/removeUsageEnvelopeFieldsPostgres.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/functions/removeUsageEnvelopeFieldsSqlite.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/type-aliases/MeteringMigrationClient.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/type-aliases/UsageRecordTable.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/variables/usageRecordsPg.md
  • packages/docs/src/content/docs/api/metering-drizzle/src/variables/usageRecordsSqlite.md
  • packages/docs/src/content/docs/api/problems-core/src/classes/Problem.md
  • packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md
  • packages/docs/src/content/docs/en/reference/problem-recovery-cookbook.md
  • packages/metering-core/README.md
  • packages/metering-core/src/index.ts
  • packages/metering-core/src/libs/MeterRef.ts
  • packages/metering-core/src/libs/MeteringService.ts
  • packages/metering-core/src/libs/RedisUsageStorage.ts
  • packages/metering-core/src/libs/decorators/Metered.ts
  • packages/metering-core/src/libs/problems/InvalidMeterDimensionProblem.ts
  • packages/metering-core/src/libs/problems/InvalidUsageEnvelopeProblem.ts
  • packages/metering-core/src/libs/types.ts
  • packages/metering-core/src/tests/MeterRef.spec.ts
  • packages/metering-core/src/tests/MeterRefTypes.spec.ts
  • packages/metering-core/src/tests/MeteringService.spec.ts
  • packages/metering-core/src/tests/RedisUsageStorage.spec.ts
  • packages/metering-core/src/tests/decorators/Metered.spec.ts
  • packages/metering-drizzle/README.md
  • packages/metering-drizzle/src/index.ts
  • packages/metering-drizzle/src/libs/DrizzleMeterRepository.ts
  • packages/metering-drizzle/src/libs/index.ts
  • packages/metering-drizzle/src/libs/problems/UsageEnvelopeConfigurationProblem.ts
  • packages/metering-drizzle/src/libs/schema.ts
  • packages/metering-drizzle/src/migrations/addUsageEnvelopeFields.ts
  • packages/metering-drizzle/src/tests/DrizzleMeterRepository.spec.ts
  • public-api-surface.snapshot.json

Comment thread packages/metering-core/src/libs/decorators/Metered.ts
Comment thread packages/metering-drizzle/src/libs/DrizzleMeterRepository.ts Outdated
Comment thread packages/metering-drizzle/src/migrations/addUsageEnvelopeFields.ts
Comment thread packages/metering-drizzle/src/tests/DrizzleMeterRepository.spec.ts
@kang-heewon
kang-heewon force-pushed the issue-1515-typed-meters branch from f0aac88 to 8bf3a49 Compare July 26, 2026 08:47
@kang-heewon
kang-heewon force-pushed the issue-1515-typed-meters branch from d89fdd0 to b1c922d Compare July 26, 2026 09:50
@kang-heewon
kang-heewon merged commit c80ce21 into trunk Jul 26, 2026
10 checks passed
@kang-heewon
kang-heewon deleted the issue-1515-typed-meters branch July 26, 2026 11:58
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.

[metering-core] Define typed billable meters and usage envelopes

1 participant