Loading workspace insights... Statistics interval
7 days30 daysLatest CI Pipeline Executions
22c9b42b feat(fal): surface billed cost as result.usage.unitsBilled (#723)
* feat(fal): surface billed cost as result.usage.unitsBilled
The fal adapters discarded fal's response headers, so the actual billed
cost of a generation was unrecoverable through the SDK. fal returns the
real billed quantity in the `x-fal-billable-units` header on the result
fetch; this surfaces it as `result.usage.unitsBilled` so consumers can
compute exact media-generation cost without wrapping `fetch` themselves.
- `TokenUsage` gains an optional `unitsBilled` (a bare count of priced
units, sibling to `durationSeconds`; the unit name itself is provider
-defined and looked up via the pricing API, not carried here).
- A `config.fetch` wrapper reads `x-fal-billable-units` off every fal
response, keyed by `x-fal-request-id` (the same value the client
surfaces as `Result.requestId`), so the adapter's lookup always
matches the fetch the units came from. `config.fetch` is used rather
than `responseHandler` because the queue ops clobber a global handler.
- All five fal media adapters (image, audio, video, speech,
transcription) populate `result.usage.unitsBilled` when fal reports it.
- `VideoUrlResult` gains a `usage` slot; `getVideoJobStatus` now emits
the `video:usage` event and returns `usage` on completion.
Closes #722
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* ci: apply automated fixes
* feat(examples): show fal unitsBilled in ts-react-media
Surface the new `result.usage.unitsBilled` in the media example so the
billed quantity is visible after a generation — a caption under each
generated image/video ("Billed N fal units"). Verified against the live
fal API: a fal-ai/flux/schnell generation reports unitsBilled: 1.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(examples): use a runtime-valid size for grok-imagine-image
fal's generated `size`/`resolution` type for `xai/grok-imagine-image`
offers `16:9_1K` / `16:9_4K`, but the live API rejects those resolutions
("Input should be '1k' or '2k'") — the vendor enum is out of sync with
the API. `'16:9_4K'` therefore type-checked but 422'd at runtime. Pass
`aspect_ratio: '16:9'` via modelOptions instead and let the endpoint
default the resolution; verified against the live fal API.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(fal): inject fetch instead of overriding the global
Address CodeRabbit + review feedback: dependency-inject the underlying
fetch rather than mutating globals.
- `createBillingFetch(baseFetch = globalThis.fetch)` now takes the fetch to
delegate to, and `FalClientConfig` gains an optional `fetch` override that
`configureFalClient` wraps for usage capture.
- The E2E route passes a per-request redirecting `fetch` via
`falImage(model, { fetch })` instead of swapping `globalThis.fetch` —
removing the concurrency race CodeRabbit flagged (no global mutation, no
try/finally restore).
- `billing.test.ts` injects a fake fetch directly instead of
`vi.stubGlobal('fetch')`.
- Changeset: reword "billed cost" → "billed units" to match the surfaced
`usage.unitsBilled` field.
Verified: full `pnpm test:pr` green, fal E2E spec green, and a live
fal-ai/flux/schnell call still reports unitsBilled via the default
(no-override) path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* ci: apply automated fixes
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> 22c9b42b feat(fal): surface billed cost as result.usage.unitsBilled (#723)
* feat(fal): surface billed cost as result.usage.unitsBilled
The fal adapters discarded fal's response headers, so the actual billed
cost of a generation was unrecoverable through the SDK. fal returns the
real billed quantity in the `x-fal-billable-units` header on the result
fetch; this surfaces it as `result.usage.unitsBilled` so consumers can
compute exact media-generation cost without wrapping `fetch` themselves.
- `TokenUsage` gains an optional `unitsBilled` (a bare count of priced
units, sibling to `durationSeconds`; the unit name itself is provider
-defined and looked up via the pricing API, not carried here).
- A `config.fetch` wrapper reads `x-fal-billable-units` off every fal
response, keyed by `x-fal-request-id` (the same value the client
surfaces as `Result.requestId`), so the adapter's lookup always
matches the fetch the units came from. `config.fetch` is used rather
than `responseHandler` because the queue ops clobber a global handler.
- All five fal media adapters (image, audio, video, speech,
transcription) populate `result.usage.unitsBilled` when fal reports it.
- `VideoUrlResult` gains a `usage` slot; `getVideoJobStatus` now emits
the `video:usage` event and returns `usage` on completion.
Closes #722
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* ci: apply automated fixes
* feat(examples): show fal unitsBilled in ts-react-media
Surface the new `result.usage.unitsBilled` in the media example so the
billed quantity is visible after a generation — a caption under each
generated image/video ("Billed N fal units"). Verified against the live
fal API: a fal-ai/flux/schnell generation reports unitsBilled: 1.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(examples): use a runtime-valid size for grok-imagine-image
fal's generated `size`/`resolution` type for `xai/grok-imagine-image`
offers `16:9_1K` / `16:9_4K`, but the live API rejects those resolutions
("Input should be '1k' or '2k'") — the vendor enum is out of sync with
the API. `'16:9_4K'` therefore type-checked but 422'd at runtime. Pass
`aspect_ratio: '16:9'` via modelOptions instead and let the endpoint
default the resolution; verified against the live fal API.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(fal): inject fetch instead of overriding the global
Address CodeRabbit + review feedback: dependency-inject the underlying
fetch rather than mutating globals.
- `createBillingFetch(baseFetch = globalThis.fetch)` now takes the fetch to
delegate to, and `FalClientConfig` gains an optional `fetch` override that
`configureFalClient` wraps for usage capture.
- The E2E route passes a per-request redirecting `fetch` via
`falImage(model, { fetch })` instead of swapping `globalThis.fetch` —
removing the concurrency race CodeRabbit flagged (no global mutation, no
try/finally restore).
- `billing.test.ts` injects a fake fetch directly instead of
`vi.stubGlobal('fetch')`.
- Changeset: reword "billed cost" → "billed units" to match the surfaced
`usage.unitsBilled` field.
Verified: full `pnpm test:pr` green, fal E2E spec green, and a live
fal-ai/flux/schnell call still reports unitsBilled via the default
(no-override) path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* ci: apply automated fixes
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> 22c9b42b feat(fal): surface billed cost as result.usage.unitsBilled (#723)
* feat(fal): surface billed cost as result.usage.unitsBilled
The fal adapters discarded fal's response headers, so the actual billed
cost of a generation was unrecoverable through the SDK. fal returns the
real billed quantity in the `x-fal-billable-units` header on the result
fetch; this surfaces it as `result.usage.unitsBilled` so consumers can
compute exact media-generation cost without wrapping `fetch` themselves.
- `TokenUsage` gains an optional `unitsBilled` (a bare count of priced
units, sibling to `durationSeconds`; the unit name itself is provider
-defined and looked up via the pricing API, not carried here).
- A `config.fetch` wrapper reads `x-fal-billable-units` off every fal
response, keyed by `x-fal-request-id` (the same value the client
surfaces as `Result.requestId`), so the adapter's lookup always
matches the fetch the units came from. `config.fetch` is used rather
than `responseHandler` because the queue ops clobber a global handler.
- All five fal media adapters (image, audio, video, speech,
transcription) populate `result.usage.unitsBilled` when fal reports it.
- `VideoUrlResult` gains a `usage` slot; `getVideoJobStatus` now emits
the `video:usage` event and returns `usage` on completion.
Closes #722
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* ci: apply automated fixes
* feat(examples): show fal unitsBilled in ts-react-media
Surface the new `result.usage.unitsBilled` in the media example so the
billed quantity is visible after a generation — a caption under each
generated image/video ("Billed N fal units"). Verified against the live
fal API: a fal-ai/flux/schnell generation reports unitsBilled: 1.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(examples): use a runtime-valid size for grok-imagine-image
fal's generated `size`/`resolution` type for `xai/grok-imagine-image`
offers `16:9_1K` / `16:9_4K`, but the live API rejects those resolutions
("Input should be '1k' or '2k'") — the vendor enum is out of sync with
the API. `'16:9_4K'` therefore type-checked but 422'd at runtime. Pass
`aspect_ratio: '16:9'` via modelOptions instead and let the endpoint
default the resolution; verified against the live fal API.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(fal): inject fetch instead of overriding the global
Address CodeRabbit + review feedback: dependency-inject the underlying
fetch rather than mutating globals.
- `createBillingFetch(baseFetch = globalThis.fetch)` now takes the fetch to
delegate to, and `FalClientConfig` gains an optional `fetch` override that
`configureFalClient` wraps for usage capture.
- The E2E route passes a per-request redirecting `fetch` via
`falImage(model, { fetch })` instead of swapping `globalThis.fetch` —
removing the concurrency race CodeRabbit flagged (no global mutation, no
try/finally restore).
- `billing.test.ts` injects a fake fetch directly instead of
`vi.stubGlobal('fetch')`.
- Changeset: reword "billed cost" → "billed units" to match the surfaced
`usage.unitsBilled` field.
Verified: full `pnpm test:pr` green, fal E2E spec green, and a live
fal-ai/flux/schnell call still reports unitsBilled via the default
(no-override) path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* ci: apply automated fixes
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>