From 218c345ebb7f303ef0dda4bd71432304674287e0 Mon Sep 17 00:00:00 2001 From: "fern-api[bot]" <115122769+fern-api[bot]@users.noreply.github.com> Date: Sat, 5 Sep 2026 06:37:36 +0000 Subject: [PATCH 1/2] [fern-generated] Update SDK Generated by Fern CLI Version: unknown Generators: - fernapi/fern-typescript-node-sdk: 3.90.0 --- .fern/metadata.json | 8 +- conformance/SPEC.md | 446 ------- conformance/vectors/check-flow.json | 527 --------- conformance/vectors/crash-windows.json | 271 ----- conformance/vectors/expiry.json | 198 ---- conformance/vectors/lease-lifecycle.json | 447 ------- conformance/vectors/lease-manager.json | 417 ------- .../vectors/reservation-lifecycle.json | 353 ------ conformance/vectors/track-settle.json | 194 --- package.json | 5 +- reference.md | 1047 +++++++++++++++-- src/BaseClient.ts | 4 +- src/api/errors/PaymentRequiredError.ts | 24 + src/api/errors/index.ts | 1 + .../UpdateOnboardingStateRequestBody.ts | 1 + src/api/resources/billing/client/Client.ts | 301 +++++ .../ListCompanyBillingProfilesRequest.ts | 23 + .../UpdateCompanyBillingProfileRequestBody.ts | 18 + .../billing/client/requests/index.ts | 2 + .../types/ListCompanyBillingProfilesParams.ts | 16 + .../ListCompanyBillingProfilesResponse.ts | 9 + .../UpdateCompanyBillingProfileResponse.ts | 9 + src/api/resources/billing/types/index.ts | 3 + src/api/resources/credits/client/Client.ts | 896 ++++++++++++++ .../CountCreditSpendPoliciesRequest.ts | 27 + .../CreateCreditSpendPolicyRequestBody.ts | 19 + .../ListCreditSpendPoliciesRequest.ts | 27 + .../UpdateCreditSpendPolicyRequestBody.ts | 10 + .../credits/client/requests/index.ts | 4 + .../types/CountCreditSpendPoliciesParams.ts | 18 + .../types/CountCreditSpendPoliciesResponse.ts | 9 + .../types/CreateCreditSpendPolicyResponse.ts | 9 + .../types/DeleteCreditSpendPolicyResponse.ts | 9 + .../types/GetCreditSpendPolicyResponse.ts | 9 + .../types/ListCreditSpendPoliciesParams.ts | 18 + .../types/ListCreditSpendPoliciesResponse.ts | 9 + .../types/UpdateCreditSpendPolicyResponse.ts | 9 + src/api/resources/credits/types/index.ts | 8 + src/api/resources/events/client/Client.ts | 382 ++++++ ...psertOtlpEnvironmentSettingsRequestBody.ts | 15 + .../resources/events/client/requests/index.ts | 1 + .../DeleteOtlpEnvironmentSettingsResponse.ts | 9 + .../GetOtlpEnvironmentSettingsResponse.ts | 9 + .../UpsertOtlpEnvironmentSettingsResponse.ts | 9 + src/api/resources/events/types/index.ts | 3 + .../integrationsapi/client/Client.ts | 646 ++++++++++ .../ClaimStripeSandboxKeysRequestBody.ts | 11 + .../InstallStripeSandboxRequestBody.ts | 14 + .../integrationsapi/client/requests/index.ts | 2 + .../types/ClaimStripeSandboxKeysResponse.ts | 9 + .../GetStripeSandboxClaimLinkResponse.ts | 9 + .../types/GetStripeSandboxKeysResponse.ts | 9 + .../InstallStripeClaimableSandboxResponse.ts | 9 + .../ListStripeSandboxCountriesResponse.ts | 9 + .../resources/integrationsapi/types/index.ts | 5 + .../ClaimedStripeSandboxKeysResponseData.ts | 7 + .../CompanyBillingProfileResponseData.ts | 20 + src/api/types/CompanyDetailResponseData.ts | 2 + src/api/types/CompanyOverrideResponseData.ts | 2 + .../types/CreditSpendPolicyResponseData.ts | 15 + src/api/types/CreditSpendPolicyScope.ts | 8 + src/api/types/EventBodyInference.ts | 6 +- src/api/types/GetOnboardingStateResp.ts | 1 + .../OtlpEnvironmentSettingsResponseData.ts | 12 + .../types/RuleConditionDetailResponseData.ts | 1 + .../RuleConditionPlanVersionResponseData.ts | 10 + src/api/types/StripeIntegrationConfig.ts | 6 + src/api/types/StripeSandboxClaimLink.ts | 8 + .../StripeSandboxCountriesResponseData.ts | 5 + .../types/StripeSandboxInstallResponseData.ts | 13 + .../types/StripeSandboxKeysResponseData.ts | 7 + src/api/types/index.ts | 10 + .../UpdateOnboardingStateRequestBody.ts | 2 + .../UpdateCompanyBillingProfileRequestBody.ts | 30 + .../billing/client/requests/index.ts | 1 + .../types/ListCompanyBillingProfilesParams.ts | 27 + .../ListCompanyBillingProfilesResponse.ts | 22 + .../UpdateCompanyBillingProfileResponse.ts | 21 + .../resources/billing/types/index.ts | 3 + .../CreateCreditSpendPolicyRequestBody.ts | 26 + .../UpdateCreditSpendPolicyRequestBody.ts | 20 + .../credits/client/requests/index.ts | 2 + .../types/CountCreditSpendPoliciesParams.ts | 31 + .../types/CountCreditSpendPoliciesResponse.ts | 22 + .../types/CreateCreditSpendPolicyResponse.ts | 21 + .../types/DeleteCreditSpendPolicyResponse.ts | 21 + .../types/GetCreditSpendPolicyResponse.ts | 21 + .../types/ListCreditSpendPoliciesParams.ts | 31 + .../types/ListCreditSpendPoliciesResponse.ts | 22 + .../types/UpdateCreditSpendPolicyResponse.ts | 21 + .../resources/credits/types/index.ts | 8 + ...psertOtlpEnvironmentSettingsRequestBody.ts | 26 + .../resources/events/client/requests/index.ts | 1 + .../DeleteOtlpEnvironmentSettingsResponse.ts | 21 + .../GetOtlpEnvironmentSettingsResponse.ts | 21 + .../UpsertOtlpEnvironmentSettingsResponse.ts | 21 + .../resources/events/types/index.ts | 3 + .../ClaimStripeSandboxKeysRequestBody.ts | 18 + .../InstallStripeSandboxRequestBody.ts | 24 + .../integrationsapi/client/requests/index.ts | 2 + .../types/ClaimStripeSandboxKeysResponse.ts | 21 + .../GetStripeSandboxClaimLinkResponse.ts | 21 + .../types/GetStripeSandboxKeysResponse.ts | 21 + .../InstallStripeClaimableSandboxResponse.ts | 21 + .../ListStripeSandboxCountriesResponse.ts | 21 + .../resources/integrationsapi/types/index.ts | 5 + .../ClaimedStripeSandboxKeysResponseData.ts | 22 + .../CompanyBillingProfileResponseData.ts | 47 + .../types/CompanyDetailResponseData.ts | 8 + .../types/CompanyOverrideResponseData.ts | 5 + .../types/CreditSpendPolicyResponseData.ts | 35 + .../types/CreditSpendPolicyScope.ts | 14 + src/serialization/types/EventBodyInference.ts | 5 + .../types/GetOnboardingStateResp.ts | 2 + .../OtlpEnvironmentSettingsResponseData.ts | 32 + .../types/RuleConditionDetailResponseData.ts | 6 + .../RuleConditionPlanVersionResponseData.ts | 25 + .../types/StripeIntegrationConfig.ts | 12 + .../types/StripeSandboxClaimLink.ts | 24 + .../StripeSandboxCountriesResponseData.ts | 18 + .../types/StripeSandboxInstallResponseData.ts | 32 + .../types/StripeSandboxKeysResponseData.ts | 22 + src/serialization/types/index.ts | 10 + tests/conformance/runner.test.ts | 720 ------------ tests/races/harness.ts | 676 ----------- tests/races/prng.ts | 50 - tests/races/races.test.ts | 311 ----- tests/races/scripted-server.ts | 118 -- tests/wire/accounts.test.ts | 4 + tests/wire/billing.test.ts | 304 +++++ tests/wire/checkout.test.ts | 144 +++ tests/wire/companies.test.ts | 380 ++++++ tests/wire/components.test.ts | 48 + tests/wire/credits.test.ts | 920 ++++++++++++++- tests/wire/entitlements.test.ts | 654 +++++++++- tests/wire/events.test.ts | 331 ++++++ tests/wire/integrationsapi.test.ts | 661 +++++++++++ tests/wire/plans.test.ts | 106 ++ yarn.lock | 70 +- 139 files changed, 8195 insertions(+), 4909 deletions(-) delete mode 100644 conformance/SPEC.md delete mode 100644 conformance/vectors/check-flow.json delete mode 100644 conformance/vectors/crash-windows.json delete mode 100644 conformance/vectors/expiry.json delete mode 100644 conformance/vectors/lease-lifecycle.json delete mode 100644 conformance/vectors/lease-manager.json delete mode 100644 conformance/vectors/reservation-lifecycle.json delete mode 100644 conformance/vectors/track-settle.json create mode 100644 src/api/errors/PaymentRequiredError.ts create mode 100644 src/api/resources/billing/client/requests/ListCompanyBillingProfilesRequest.ts create mode 100644 src/api/resources/billing/client/requests/UpdateCompanyBillingProfileRequestBody.ts create mode 100644 src/api/resources/billing/types/ListCompanyBillingProfilesParams.ts create mode 100644 src/api/resources/billing/types/ListCompanyBillingProfilesResponse.ts create mode 100644 src/api/resources/billing/types/UpdateCompanyBillingProfileResponse.ts create mode 100644 src/api/resources/credits/client/requests/CountCreditSpendPoliciesRequest.ts create mode 100644 src/api/resources/credits/client/requests/CreateCreditSpendPolicyRequestBody.ts create mode 100644 src/api/resources/credits/client/requests/ListCreditSpendPoliciesRequest.ts create mode 100644 src/api/resources/credits/client/requests/UpdateCreditSpendPolicyRequestBody.ts create mode 100644 src/api/resources/credits/types/CountCreditSpendPoliciesParams.ts create mode 100644 src/api/resources/credits/types/CountCreditSpendPoliciesResponse.ts create mode 100644 src/api/resources/credits/types/CreateCreditSpendPolicyResponse.ts create mode 100644 src/api/resources/credits/types/DeleteCreditSpendPolicyResponse.ts create mode 100644 src/api/resources/credits/types/GetCreditSpendPolicyResponse.ts create mode 100644 src/api/resources/credits/types/ListCreditSpendPoliciesParams.ts create mode 100644 src/api/resources/credits/types/ListCreditSpendPoliciesResponse.ts create mode 100644 src/api/resources/credits/types/UpdateCreditSpendPolicyResponse.ts create mode 100644 src/api/resources/events/client/requests/UpsertOtlpEnvironmentSettingsRequestBody.ts create mode 100644 src/api/resources/events/types/DeleteOtlpEnvironmentSettingsResponse.ts create mode 100644 src/api/resources/events/types/GetOtlpEnvironmentSettingsResponse.ts create mode 100644 src/api/resources/events/types/UpsertOtlpEnvironmentSettingsResponse.ts create mode 100644 src/api/resources/integrationsapi/client/requests/ClaimStripeSandboxKeysRequestBody.ts create mode 100644 src/api/resources/integrationsapi/client/requests/InstallStripeSandboxRequestBody.ts create mode 100644 src/api/resources/integrationsapi/types/ClaimStripeSandboxKeysResponse.ts create mode 100644 src/api/resources/integrationsapi/types/GetStripeSandboxClaimLinkResponse.ts create mode 100644 src/api/resources/integrationsapi/types/GetStripeSandboxKeysResponse.ts create mode 100644 src/api/resources/integrationsapi/types/InstallStripeClaimableSandboxResponse.ts create mode 100644 src/api/resources/integrationsapi/types/ListStripeSandboxCountriesResponse.ts create mode 100644 src/api/types/ClaimedStripeSandboxKeysResponseData.ts create mode 100644 src/api/types/CompanyBillingProfileResponseData.ts create mode 100644 src/api/types/CreditSpendPolicyResponseData.ts create mode 100644 src/api/types/CreditSpendPolicyScope.ts create mode 100644 src/api/types/OtlpEnvironmentSettingsResponseData.ts create mode 100644 src/api/types/RuleConditionPlanVersionResponseData.ts create mode 100644 src/api/types/StripeSandboxClaimLink.ts create mode 100644 src/api/types/StripeSandboxCountriesResponseData.ts create mode 100644 src/api/types/StripeSandboxInstallResponseData.ts create mode 100644 src/api/types/StripeSandboxKeysResponseData.ts create mode 100644 src/serialization/resources/billing/client/requests/UpdateCompanyBillingProfileRequestBody.ts create mode 100644 src/serialization/resources/billing/types/ListCompanyBillingProfilesParams.ts create mode 100644 src/serialization/resources/billing/types/ListCompanyBillingProfilesResponse.ts create mode 100644 src/serialization/resources/billing/types/UpdateCompanyBillingProfileResponse.ts create mode 100644 src/serialization/resources/credits/client/requests/CreateCreditSpendPolicyRequestBody.ts create mode 100644 src/serialization/resources/credits/client/requests/UpdateCreditSpendPolicyRequestBody.ts create mode 100644 src/serialization/resources/credits/types/CountCreditSpendPoliciesParams.ts create mode 100644 src/serialization/resources/credits/types/CountCreditSpendPoliciesResponse.ts create mode 100644 src/serialization/resources/credits/types/CreateCreditSpendPolicyResponse.ts create mode 100644 src/serialization/resources/credits/types/DeleteCreditSpendPolicyResponse.ts create mode 100644 src/serialization/resources/credits/types/GetCreditSpendPolicyResponse.ts create mode 100644 src/serialization/resources/credits/types/ListCreditSpendPoliciesParams.ts create mode 100644 src/serialization/resources/credits/types/ListCreditSpendPoliciesResponse.ts create mode 100644 src/serialization/resources/credits/types/UpdateCreditSpendPolicyResponse.ts create mode 100644 src/serialization/resources/events/client/requests/UpsertOtlpEnvironmentSettingsRequestBody.ts create mode 100644 src/serialization/resources/events/types/DeleteOtlpEnvironmentSettingsResponse.ts create mode 100644 src/serialization/resources/events/types/GetOtlpEnvironmentSettingsResponse.ts create mode 100644 src/serialization/resources/events/types/UpsertOtlpEnvironmentSettingsResponse.ts create mode 100644 src/serialization/resources/integrationsapi/client/requests/ClaimStripeSandboxKeysRequestBody.ts create mode 100644 src/serialization/resources/integrationsapi/client/requests/InstallStripeSandboxRequestBody.ts create mode 100644 src/serialization/resources/integrationsapi/types/ClaimStripeSandboxKeysResponse.ts create mode 100644 src/serialization/resources/integrationsapi/types/GetStripeSandboxClaimLinkResponse.ts create mode 100644 src/serialization/resources/integrationsapi/types/GetStripeSandboxKeysResponse.ts create mode 100644 src/serialization/resources/integrationsapi/types/InstallStripeClaimableSandboxResponse.ts create mode 100644 src/serialization/resources/integrationsapi/types/ListStripeSandboxCountriesResponse.ts create mode 100644 src/serialization/types/ClaimedStripeSandboxKeysResponseData.ts create mode 100644 src/serialization/types/CompanyBillingProfileResponseData.ts create mode 100644 src/serialization/types/CreditSpendPolicyResponseData.ts create mode 100644 src/serialization/types/CreditSpendPolicyScope.ts create mode 100644 src/serialization/types/OtlpEnvironmentSettingsResponseData.ts create mode 100644 src/serialization/types/RuleConditionPlanVersionResponseData.ts create mode 100644 src/serialization/types/StripeSandboxClaimLink.ts create mode 100644 src/serialization/types/StripeSandboxCountriesResponseData.ts create mode 100644 src/serialization/types/StripeSandboxInstallResponseData.ts create mode 100644 src/serialization/types/StripeSandboxKeysResponseData.ts delete mode 100644 tests/conformance/runner.test.ts delete mode 100644 tests/races/harness.ts delete mode 100644 tests/races/prng.ts delete mode 100644 tests/races/races.test.ts delete mode 100644 tests/races/scripted-server.ts diff --git a/.fern/metadata.json b/.fern/metadata.json index c82cc117..c50fd4be 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -1,7 +1,7 @@ { "cliVersion": "5.50.0", "generatorName": "fernapi/fern-typescript-node-sdk", - "generatorVersion": "3.88.3", + "generatorVersion": "3.90.0", "generatorConfig": { "allowCustomFetcher": true, "includeApiReference": true, @@ -53,10 +53,10 @@ ] } }, - "originGitCommit": "686551a0297d2f37075b3586b030ff32be5c94f7", + "originGitCommit": "31f498c0a9babdc0eec5ae88e1212a254b2f2561", "originGitCommitIsDirty": false, "invokedBy": "ci", - "requestedVersion": "1.5.11", + "requestedVersion": "1.5.12", "ciProvider": "github", - "sdkVersion": "1.5.11" + "sdkVersion": "1.5.12" } diff --git a/conformance/SPEC.md b/conformance/SPEC.md deleted file mode 100644 index 6191f101..00000000 --- a/conformance/SPEC.md +++ /dev/null @@ -1,446 +0,0 @@ -# Credit lease & reservation semantics — conformance spec - -This document specifies the client-side credit lease/reservation semantics implemented by the -Schematic Node SDK (the reference implementation), in enough detail to reimplement them in another -language without reading the Node source. The machine-readable test vectors in -`conformance/vectors/*.json` pin the observable behavior; this spec explains the model, the -configuration knobs, and the invariants that cannot be expressed as deterministic vectors. - -Where this document and the vectors disagree, the vectors win — they are generated from the -reference implementation's behavior. - -- [Vector format](#vector-format) -- [Model overview](#model-overview) -- [State](#state) -- [Store operations](#store-operations) -- [Lease manager](#lease-manager) -- [Check flow](#check-flow) -- [Track / settle flow](#track--settle-flow) -- [Configuration knobs](#configuration-knobs) -- [Bounded-leak contract](#bounded-leak-contract) -- [Invariants not expressible as vectors](#invariants-not-expressible-as-vectors) - -## Vector format - -Each file in `conformance/vectors/` is a JSON document: - -```json -{ - "category": "reservation_lifecycle", - "vectors": [ - { - "name": "unique_snake_case_name", - "description": "What this vector pins and why.", - "backends": ["in_memory", "redis"], - "given": { - "config": { "lease_duration_ms": 300000, "reservation_ttl_ms": 60000, "lease_size": 1000, "low_water_mark": 0.25 }, - "leases": [ { "lease_id": "lse_1", "company_id": "co_1", "credit_type_id": "ct_1", "granted_amount": 1000, "expires_at_ms": 60000 } ] - }, - "operations": [ - { "op": "try_reserve", "company_id": "co_1", "credit_type_id": "ct_1", "credits": 100, "expect": { "balance": 900 } } - ] - } - ] -} -``` - -Rules: - -- All keys are `snake_case`. Vectors are plain JSON — no language-specific types. -- **Virtual clock.** The run starts at a fixed virtual instant `t0`. Every `*_at_ms` field is an - offset in milliseconds from `t0` (an absolute position on the virtual timeline, not relative to - the current operation). The `advance_clock` operation moves the clock forward; nothing else does. - Runners must execute vectors against a controllable clock (no wall time). -- `backends` restricts which store backends the vector runs against; when omitted, the vector must - pass against every backend the SDK ships (in-memory and Redis for Node). -- `given.leases` are installed via the store's `replace` operation at `t0` (each install must - return "written"). -- Assertions are attached per-operation via `expect`. Final-state assertions are expressed as - trailing read operations (`get_lease`, `reserved_credits`, `reservation_count`). -- `expect.balance` / `expect.consumed` use JSON `null` for the "no / refused" result. -- Reservation ids created by `check` operations are random; the vector names them via - `save_reservation_as` and later operations reference them with `handle`. - -### Operations - -Store-level (exercise the lease store and reservation store directly): - -| op | fields | expect | -| --- | --- | --- | -| `advance_clock` | `ms` | — | -| `replace_lease` | `lease_id`, `company_id`, `credit_type_id`, `granted_amount`, `expires_at_ms` | `written` (bool) | -| `drop_lease` | `company_id`, `credit_type_id` | — | -| `try_reserve` | `company_id`, `credit_type_id`, `credits` | `balance` (post-debit number, or `null`) | -| `refund_lease` | `company_id`, `credit_type_id`, `credits`, `pin_lease_id`? | — | -| `extend_lease` | `company_id`, `credit_type_id`, `granted_total`, `expires_at_ms`?, `pin_lease_id`? | — | -| `get_lease` | `company_id`, `credit_type_id` | `exists`, `lease_id`?, `granted_amount`?, `local_remaining_credits`? | -| `add_reservation` | `id`, `lease_id`, `company_id`, `credit_type_id`, `event_subtype`, `quantity_reserved`, `credits_reserved`, `consumption_rate`, `expires_at_ms` | — | -| `consume_reservation` | `id` or `handle`, `credits`, `crash_before_refund`? (bool, one-shot) | `consumed` (number or `null`), `throws`? | -| `get_reservation` | `id` or `handle` | `exists` | -| `reserved_credits` | `company_id`, `credit_type_id` | `total` | -| `reservation_count` | — | `count` | -| `sweep_expired` | — | `swept` | - -Manager-level (exercise the lease manager with a scripted wire client): - -| op | fields | expect | -| --- | --- | --- | -| `acquire_if_needed` | `company_id`, `credit_type_id`, `server`? ( `{ "lease": {...} }` or `{ "error": "..." }` ), `install_during_wire`? (lease installed into the store while the wire call is in flight, emulating a sibling pod winning the race) | `lease_id` (or `null`), `wire_acquires` (cumulative count), `last_acquire_requested_amount`?, `released_lease_ids` (cumulative) | -| `maybe_extend` | `company_id`, `credit_type_id`, `required_credits`?, `server`? ( `{ "lease": { "granted_total", "expires_at_ms" } }` or `{ "error": "..." }` ) | `wire_extends` (cumulative count), `last_extend_additional_amount`?, `last_extend_lease_id`? | -| `release_all_local_leases` | — (in-memory backend only) | `released_lease_ids`, `remaining_slots` | - -Flow-level (exercise the full check/track orchestration with a scripted rules engine): - -| op | fields | expect | -| --- | --- | --- | -| `check` | `flag_key`, `company` (`{ id, credit_balances }`), `usage`, `event_subtype`?, `on_acquire_failure`?, `engine` (array of scripted engine results, consumed in call order), `server`? (as above), `save_reservation_as`? | `allowed`, `reason`?, `err`?, `has_reservation`, `reservation`? (field subset), `fallback_called`?, `engine_calls`? (per-call `{ credit_balance, credit_cost?, event_usage? }`; `credit_balance` may be the string `"max_safe_integer"`) | -| `track` | `handle`, `actual_quantity` | `settled_locally`, `track` (`{ event, quantity, lease_id }`) | - -A scripted engine result is `{ "value": bool, "reason"?: string, "entitlement"?: { "value_type", -"credit_id"?, "consumption_rate"?, "event_subtype"?, "feature_id"?, "feature_key"? } }`. The engine -is an oracle: the vectors pin the *orchestration around* the rules engine (what it is called with, -and what the SDK does with its answer), not the engine itself — the engine is shared WASM across -SDKs and has its own tests. - -## Model overview - -Credit-metered features are gated client-side without a wire call per check. The SDK: - -1. **Leases** a tranche of credits from the server per `(company_id, credit_type_id)`. The server - pre-debits the company balance by the granted amount; the SDK tracks a local view of how much - of the tranche remains un-reserved (`local_remaining_credits`). -2. **Reserves** `usage x consumption_rate` credits from the lease at `check()` time, atomically - (check-and-debit). A successful, engine-approved check returns a *reservation handle*. -3. **Settles** the reservation at `track()` time with the actual usage: the actually-consumed - credits stay debited, the unspent slice is refunded to the lease, and a Track event bills the - server (the server is the source of truth for real consumption). - -Everything client-side is *local bookkeeping against the leased tranche*. The server reconciles: -an expired lease's unspent remainder is refunded to the company balance server-side, and Track -events (keyed by `lease_id`) drive the authoritative consumption. - -Leases and reservations both expire: - -- A **lease** past its expiry must be treated as *released* — its local balance is stale (the - server already refunded the remainder) and must never serve another reserve or be extended. -- A **reservation** past its TTL is swept: removed from the table and its full hold refunded to - the lease. Work that finishes after the sweep still bills the server (recovery emit) but does - not re-debit the local lease. - -## State - -**Lease slot** — at most one lease per `(company_id, credit_type_id)` key: - -| field | meaning | -| --- | --- | -| `lease_id` | Server-issued id. | -| `granted_amount` | Server-authoritative total granted to this lease (grows on extend). | -| `local_remaining_credits` | Local view: granted minus outstanding holds/consumption. Initialized to `granted_amount` on install. | -| `expires_at` | Expiry instant. Past it the lease is dead (see above). | - -**Reservation** — keyed by a unique id: - -| field | meaning | -| --- | --- | -| `id` | Unique (UUID in Node). | -| `lease_id` | The lease the hold was carved from. Pins refunds. | -| `company_id`, `credit_type_id` | Slot key. | -| `event_subtype` | Event the settle will bill as. | -| `quantity_reserved` | Caller-declared usage (event units). | -| `credits_reserved` | `quantity_reserved x consumption_rate`. | -| `consumption_rate` | Rate at reservation time. | -| `expires_at` | Reservation TTL deadline (sweep target). | -| `eval_ctx` | Company/user keys used at check time; threaded onto the Track event. | - -## Store operations - -These are the primitives both store backends (per-process in-memory; shared Redis) must implement -with identical observable semantics. Each mutation must be atomic per slot/reservation (see -[Invariants](#invariants-not-expressible-as-vectors)). - -### `replace(lease)` — install-if-not-live - -Install a fresh lease with `local_remaining_credits = granted_amount`, **only if** the slot is -empty or the existing lease is expired *and carries a different `lease_id`*. If a *live* lease -occupies the slot — even with a different `lease_id` (a sibling pod won the race) — leave it -untouched (its already-debited balance wins) and report "kept". If an *expired* lease with the -**same** `lease_id` occupies the slot (a stale acquire response for a lease the idempotent server -also handed to a racing sibling, which may since have extended it), do not rewrite it either: -rewriting would reset `local_remaining_credits` to the full grant and erase debits whose -reservations are still open. Reconcile it like `extend` instead — granted to the incoming total -(lower/equal totals are no-ops), expiry only forward, balance untouched — and report "kept". -Returns written/kept so the caller can run the redundant-lease release logic (see manager). - -### `try_reserve(company, credit, credits)` — atomic check-and-debit - -- Reject (return `null`, touch nothing) if: no lease in the slot; the lease is **expired**; the - remaining balance is `< credits`; or `credits` is not a finite non-negative number (NaN must - never reach the arithmetic — it slips through every comparison and would poison the balance - into approving everything). -- Otherwise debit and return the **post-debit balance** (so the caller can derive the pre-debit - figure as `returned + credits` without a racy follow-up read). -- Reserving down to exactly 0 is allowed. - -### `refund(company, credit, credits, pin_lease_id?)` - -Add credits back to `local_remaining_credits`, **clamped at `granted_amount`**. No-op if -`credits <= 0` or no lease is in the slot. When `pin_lease_id` is given, the refund applies -**only if** the slot still holds that lease: a hold carved out of expired lease A must never -inflate successor lease B — A's remainder (including this slice) was already refunded to the -company balance server-side when A expired, so crediting B would double-count. - -### `extend(company, credit, granted_total, new_expires_at?, pin_lease_id?)` — reconcile to total - -After a remote extend, reconcile the slot to the **server-authoritative total**: - -- Compute `delta = granted_total - stored granted_amount` **atomically against the currently - stored total** — never from a caller-held pre-wire-call read (two pods extending concurrently - from the same stale read would each apply a delta and mint phantom credits). If `delta > 0`, - set `granted_amount = granted_total` and add `delta` to `local_remaining_credits`. If - `delta <= 0` (a total a sibling already applied, or a stale lower total) it is a **no-op** — - applies converge in any order. -- Expiry only ever moves **forward**: `new_expires_at` is applied only if later than the stored - expiry, so an out-of-order apply cannot shorten a lease a sibling just extended. -- When `pin_lease_id` is given and the slot holds a different lease, drop the whole extend - (credits and expiry): the server granted the extension to the pinned lease; crediting a - successor would mint credits the server refunds with the pinned lease at its expiry. -- No-op if the slot is empty. - -### `drop(company, credit)` - -Remove the slot entry (after a remote release). Plain delete. - -### Reservation table: `add`, `get`, `consume`, `reserved_credits`, `sweep_expired` - -- `add(reservation)` — register. Idempotent on id. `add` does NOT debit the lease; the debit - already happened in `try_reserve` (see [ordering](#bounded-leak-contract)). -- `consume(id, credits_consumed)` — **exactly-once claim**: atomically remove the reservation - from the table; if it was already gone (swept, or consumed by a racing caller) return `null` - and touch nothing. On a successful claim, clamp `credits_consumed` to - `[0, credits_reserved]`, refund `credits_reserved - clamped` to the lease (pinned to the - reservation's `lease_id`), and return the clamped figure. The claim and the refund are two - steps; the claim is the arbiter (see bounded-leak contract). -- `reserved_credits(company, credit)` — sum of `credits_reserved` across open reservations for - the slot. A reservation counts iff it is still in the table, so - `local_remaining_credits + reserved_credits` stays exact between operations. -- `sweep_expired(now)` — remove every reservation with `expires_at <= now` and refund its full - hold to its lease (pinned to its `lease_id`; a stale-lease hold is dropped, not refunded). - Returns the number swept. Runs on a background interval (`sweep_interval_ms`) in production; - vectors call it explicitly. - -## Lease manager - -Owns the lease lifecycle against the server wire API (`acquire`, `extend`, `release`). - -### Acquire (`acquire_if_needed`) - -- If the slot holds a **live** lease, return it — no wire call. -- Otherwise call the server: `requested_amount = lease_size`, `expires_at = now + - lease_duration_ms`. An expired local entry is left in place for `replace` to overwrite - atomically (deleting it first would open a race window against sibling pods; every reader - re-guards on expiry anyway). -- On response, `replace` the slot. If `replace` kept an existing lease (a sibling won, or the - slot's expired row was reconciled in place): - - If the installed lease has a **different id** than the one the server handed us, ours is a - redundant hold nobody will draw on — release it (fire-and-forget; a failed release falls - back to server-side lease expiry). - - If the ids are the **same** (the server is idempotent for an active slot and handed the - racing acquire the sibling's lease back), release **nothing** — releasing would pull the - shared lease out from under every sibling. - - If the slot reads empty (expired in the gap), also release nothing. - - Either way, return whatever the slot now holds. -- Wire or store failure: return "no lease" (never throw) — the caller routes it through - fail-open/fail-closed. -- Per-process single-flight per slot: concurrent callers share one in-flight wire call - (best-effort; duplicates are absorbed by the idempotent server + `replace`). - -### Extend (`maybe_extend`) - -Triggered when EITHER: - -- `local_remaining_credits / max(granted_amount, 1) <= low_water_mark` (steady-state refresh), or -- the caller passes `required_credits` and `local_remaining_credits < required_credits` (a check - just failed a reserve of that size — extend opportunistically). - -Rules: - -- **Never extend an expired lease** — the server treats it as released; the right move is a fresh - acquire on the next check. -- Wire body: `additional_amount = max(lease_size, required_credits - local_remaining_credits)`. - Sizing to the shortfall matters: a single check needing more than `remaining + lease_size` - would otherwise fail its post-extend retry forever regardless of server balance. - `expires_at = now + lease_duration_ms`. -- On response, reconcile via the store's `extend` with the server's **total** and new expiry, - **pinned** to the extended lease's id. -- Failures resolve to "no lease" without throwing (often fire-and-forget). -- Per-process single-flight per slot, kept separate from acquire's (an in-flight extend must not - satisfy an acquire, or vice versa). - -### Release on close (`release_all_local_leases`) - -Only for a **per-process (in-memory) store**, whose leases are exclusively this process's: -release every live lease over the wire (returning the unspent remainder to the company balance -immediately) and drop it locally; **skip expired** leases (already swept server-side). A shared -(Redis) store must never do this — sibling pods still draw on those leases. Best-effort: -failures fall back to server-side expiry. - -## Check flow - -`check(eval_ctx, flag_key, { usage, event_subtype?, on_acquire_failure?, ... })` — the -lease-gated feature check. Fallback = the plain (non-lease) flag check, which has its own -degradation story; when the flow "falls back", no reservation is issued and no lease state is -touched beyond what already happened. - -Guards, in order: - -1. `usage` missing → plain check (lease path not requested). -2. `usage` not a finite non-negative number → resolve **statically** by `on_acquire_failure` - (deny for fail-closed; blanket allow for fail-open, reason `invalid_usage`). The value must - never reach the stores. -3. `usage == 0` → nothing to reserve; fall back to the plain check (no 0-credit reservation). -4. No datastream / cached flag / resolvable company (or named user) → fall back. - -Then: - -5. **Entitlement probe.** Run the rules engine once against the company's *real* balance — no - substitution, no credit-cost preflight (a preflight against the lease-depleted server balance - could fail the credit condition and hide the entitlement being probed for). Read the matched - entitlement's shape: - - Not credit-metered (`value_type != "credit"`: boolean/override grant, numeric allocation, - unlimited, or not entitled) → **fall back**, no lease traffic at all. - - Credit entitlement missing `credit_id`, a positive `consumption_rate`, or a resolvable - `event_subtype` (caller's explicit subtype wins over the entitlement's) → fall back. - - Probe error → fall back (it is a resolution step, not the gate). -6. `credit_cost = usage x consumption_rate`. -7. **Acquire** a lease for `(company, credit_id)`. Failure → [failure handling](#failure-handling) - with reason `lease_acquire_failed`. -8. **Reserve** `credit_cost` via `try_reserve`. On refusal, opportunistically - `maybe_extend(required_credits = credit_cost)` (awaited) and retry the reserve **once**. - Still refused → failure handling, reason `insufficient_lease_balance`. Store error → - failure handling, reason `lease_store_error`. -9. **Record the reservation** (TTL = `reservation_ttl_ms` from now) — *after* the debit, *before* - the engine gate. If persisting fails, undo the debit (claim-and-refund; direct refund if - nothing persisted; both pinned to the lease) and go to failure handling - (`lease_store_error`). If even the undo fails, accept the bounded leak. -10. **Engine gate.** Re-run the engine against a company snapshot whose - `credit_balances[credit_id]` is substituted with the **pre-reservation** local balance - (post-debit balance returned by `try_reserve` + `credit_cost` — exact as of the debit, no - read race), passing `credit_cost = { credit_id: credit_cost }` so the engine evaluates - `pre_reservation - credit_cost >= 0` — the same arithmetic `try_reserve` just enforced, plus - every non-credit rule (plan targeting, overrides). - - Engine **allows** → keep the hold; return `{ allowed: true, reservation }`. Fire-and-forget - a watermark-driven `maybe_extend`. - - Engine **denies** → cancel the reservation (claim + full refund) and return - `{ allowed: false }` with the engine's reason. - - Engine **errors** → cancel the reservation and resolve **statically** by mode (the engine - itself is down, so no fail-open re-evaluation is possible). - -### Failure handling - -Every can't-gate outcome (acquire failed, store unreachable, lease exhausted) funnels through the -configured `on_acquire_failure` mode (default **fail-closed**): - -- **fail-closed** → `{ allowed: false }`, reason = the failure reason. No reservation. -- **fail-open** → *err on the side of assuming the credits are there*, **not** blanket allow: - re-run the engine with the credit balance substituted to an effectively unlimited value - (`MAX_SAFE_INTEGER` in Node) and the caller's usage preflight threaded through. Plan - targeting, overrides, and every non-credit condition still apply — a company that is not - entitled stays **denied** even with the lease backend down. No reservation is issued either - way; `err` carries the failure reason. Only if that evaluation itself errors does the SDK - fall back to a blanket allow. - -## Track / settle flow - -`track_with_reservation(reservation, actual_quantity)` settles a reservation: - -1. `credits = actual_quantity x reservation.consumption_rate`. -2. `consume(reservation.id, credits)`: - - **Settled locally** (claim succeeded): the clamped consumed slice stays debited; the unspent - slice is refunded to the lease (pinned). - - **Not settled** (`null`: already swept after TTL, already consumed, or store unreachable): - local lease state is untouched — if the sweeper already refunded the full hold, nothing - re-debits the consumed slice, so the local balance reads **high** until the lease rolls - over. This is why `reservation_ttl_ms` should exceed the longest expected gap between - `check()` and `track_with_reservation()`. -3. Either way, emit the Track event built from the **caller-held handle** (not the store): - `event = event_subtype`, `quantity = actual_quantity` (the *unclamped* actual — the server is - the source of truth for real consumption; only local bookkeeping clamps to the reserved - amount), `lease_id = reservation.lease_id` (routes the server-side consumption through the - lease's sub-ledger instead of double-debiting the pre-debited grant), plus the reservation's - `eval_ctx` company/user and any caller traits. -4. The Track carries a deterministic idempotency key derived from the reservation id - (`"lease-reservation:" + reservation.id` in Node); the server dedupes by it for 24h, so a - recovery emit racing the normal emit, or an accidental double settle, collapses to one billed - event across pods and restarts. -5. Guard: a non-finite or negative `actual_quantity` skips the settle entirely (no store call, no - event) — the untouched reservation expires at its TTL and the sweeper refunds the full hold. - -## Configuration knobs - -| knob (vector key) | Node name | default | meaning | -| --- | --- | --- | --- | -| `lease_duration_ms` | `defaultLeaseDuration` | 300 000 (5 min) | Lease lifetime requested at acquire/extend (`expires_at = now + duration`). | -| `reservation_ttl_ms` | `defaultReservationTTL` | 60 000 (60 s) | Reservation lifetime; the sweep deadline. Size above the longest expected check→track gap. | -| `lease_size` | `defaultLeaseSize` | 10 000 | Credits requested per acquire, and the minimum extend tranche. | -| `low_water_mark` | `lowWaterMark` | 0.25 | Remaining/granted ratio at or below which a background extend is kicked off. | -| `sweep_interval_ms` | `sweepIntervalMs` | 1 000 | Expired-reservation sweep cadence. | -| — | `onAcquireFailure` | `fail-closed` | Per-check failure mode (see check flow). | - -Per-credit-type overrides of the first four are supported (keyed by credit type id); resolution is -override → client config → default. - -## Bounded-leak contract - -The flow deliberately orders its two-step transitions so that a process crash between steps leaks -*locally held credits* (which the server reclaims at lease expiry) rather than enabling a -double-spend. The invariant direction is always: **the debit/claim is durable first; the -record/refund may be lost.** - -| # | crash window | what leaks | bound | reclaimed by | must NOT happen | -| --- | --- | --- | --- | --- | --- | -| 1 | after `try_reserve` (debit), before `add` (record) | the debited hold — invisible to the reservation table, so the sweeper can never refund it | `credits_reserved` of that one check | lease expiry: the expired balance is never served again, and the server refunds the whole grant; the successor lease installs at full grant | a reservation record without a debit (a later consume would refund credits never held → double-spend). Vectors pin that the debit lands strictly before the record. | -| 2 | inside `consume`: after the claim, before the refund | the unspent slice of that reservation | `credits_reserved` of that one reservation | lease expiry (same mechanism) | a double refund: the claim is exactly-once, so a retried settle or a sweeper finds nothing to claim and refunds nothing | -| 3 | (Redis only) after the claim, before index cleanup | nothing (bookkeeping only): the per-slot reserved-credits index transiently over-counts | one index field | the sweeper reconciles the orphaned index entry — **without refunding** (without the claimed record, exactly-once cannot be arbitrated across racing sweepers) | a refund driven by an index entry alone | - -Additional pinned properties: - -- A leak never survives its lease: after lease expiry the stale balance is refused - (`try_reserve → null`) and a successor lease restores the full grant. -- A retried check after a window-1 crash settles independently: its own slice refunds exactly - once; the leaked slice never refunds. -- A late retried settle after a window-2 crash (even after a successor lease is installed) - refunds nothing into the successor. - -## Invariants not expressible as vectors - -These hold in the reference implementation but need concurrency, wall clocks, or non-JSON values -to demonstrate; ports must uphold them and should test them natively. - -1. **Per-slot atomicity.** `replace`, `try_reserve`, `refund`, `extend` are atomic per lease - slot; `consume`'s claim is atomic per reservation. In-memory: per-key mutual exclusion. Redis: - single-key Lua scripts (single-key keeps them Redis-Cluster-safe; the refund to the lease hash - is deliberately a separate single-key step, never a multi-key script — see leak window 2/3). -2. **Server-clock expiry (shared backend).** With a shared store, lease expiry must be decided - against the *store's* clock (Redis `TIME`), not the calling process's — pods with skewed - clocks must agree on liveness. Backend rows carry a TTL grace window past `expires_at` - (60 s lease / 30 s reservation in Node) so the sweeper can still read them; expired-but-not- - evicted rows must still refuse reserves. -3. **NaN/precision guards.** Non-finite or negative amounts are rejected at every boundary - (`usage`, `try_reserve`, `actual_quantity`) — JSON cannot encode NaN, so vectors only cover - the negative case. Fractional credit amounts are legal throughout (rates like 0.1); Redis - stores balances as strings to avoid integer truncation. -4. **Single-flight.** Per-process, per-slot single-flight for acquire and for extend, tracked - separately. Best-effort only: duplicate wire calls are safe (idempotent server + keep-first - `replace` + reconcile-to-total `extend`). -5. **Concurrent cross-pod extends converge.** Two pods extending from the same stale read must - not double-count — guaranteed by reconcile-to-total computed inside the store (the sequential - out-of-order-totals vector pins the arithmetic; the concurrent schedule needs a race). -6. **Idempotent billing.** The Track idempotency key is deterministic from the reservation id; - the server dedupes for 24h. Double settles and recovery emits collapse to one billed event. -7. **Background sweep loop.** `start_sweep`/`stop` run `sweep_expired` on an interval; timers - must not keep the process alive. Vectors call `sweep_expired` explicitly instead. -8. **Fire-and-forget never rejects.** `acquire_if_needed`, `maybe_extend`, and release paths - resolve (to "no lease") on failure rather than rejecting — they are often unawaited. -9. **Offline/unconfigured degradation.** Lease config absent → `check` is a plain flag check; - `track_with_reservation` on an unconfigured client still emits the billing event with the - `lease_id` and idempotency key intact. diff --git a/conformance/vectors/check-flow.json b/conformance/vectors/check-flow.json deleted file mode 100644 index eff99903..00000000 --- a/conformance/vectors/check-flow.json +++ /dev/null @@ -1,527 +0,0 @@ -{ - "category": "check_flow", - "vectors": [ - { - "name": "check_happy_path_gates_on_pre_reservation_balance", - "description": "A lease-bearing check: probe against the real balance (no substitution, no credit cost), reserve usage x rate from the lease, then gate the engine on the PRE-reservation local balance with credit_cost — the same arithmetic the atomic reserve just enforced. The hold sticks only because the engine allowed.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": { "ct_1": 5000 } }, - "usage": 10, - "event_subtype": "inference_tokens", - "save_reservation_as": "r1", - "engine": [ - { - "value": true, - "reason": "probe", - "entitlement": { - "value_type": "credit", - "credit_id": "ct_1", - "consumption_rate": 10, - "event_subtype": "inference_tokens" - } - }, - { "value": true, "reason": "ok" } - ], - "expect": { - "allowed": true, - "has_reservation": true, - "reservation": { - "lease_id": "lse_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 10, - "credits_reserved": 100, - "consumption_rate": 10 - }, - "engine_calls": [{ "credit_balance": 5000 }, { "credit_balance": 1000, "credit_cost": 100 }] - } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 900 } - }, - { "op": "reserved_credits", "company_id": "co_1", "credit_type_id": "ct_1", "expect": { "total": 100 } } - ] - }, - { - "name": "check_denied_by_engine_cancels_the_hold", - "description": "When the gate evaluation denies, the reservation made before the eval is cancelled: claimed and fully refunded, leaving no hold and no reservation.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": { "ct_1": 5000 } }, - "usage": 10, - "event_subtype": "inference_tokens", - "engine": [ - { - "value": true, - "reason": "probe", - "entitlement": { - "value_type": "credit", - "credit_id": "ct_1", - "consumption_rate": 10, - "event_subtype": "inference_tokens" - } - }, - { "value": false, "reason": "denied_by_targeting" } - ], - "expect": { "allowed": false, "reason": "denied_by_targeting", "has_reservation": false } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 1000 } - }, - { "op": "reserved_credits", "company_id": "co_1", "credit_type_id": "ct_1", "expect": { "total": 0 } }, - { "op": "reservation_count", "expect": { "count": 0 } } - ] - }, - { - "name": "check_acquire_failure_fail_closed_denies", - "description": "fail-closed (the default): when no lease can be acquired the check denies outright with the failure reason; no reservation is issued.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - } - }, - "operations": [ - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": { "ct_1": 5000 } }, - "usage": 10, - "event_subtype": "inference_tokens", - "on_acquire_failure": "fail-closed", - "server": { "acquire": { "error": "wire down" } }, - "engine": [ - { - "value": true, - "reason": "probe", - "entitlement": { - "value_type": "credit", - "credit_id": "ct_1", - "consumption_rate": 10, - "event_subtype": "inference_tokens" - } - } - ], - "expect": { - "allowed": false, - "reason": "lease_acquire_failed", - "err": "lease_acquire_failed", - "has_reservation": false - } - }, - { "op": "reservation_count", "expect": { "count": 0 } } - ] - }, - { - "name": "check_acquire_failure_fail_open_reevaluates", - "description": "fail-open is NOT blanket allow: the engine re-runs with the credit balance substituted to an effectively unlimited value and the caller's usage preflight threaded through, so non-credit rules still apply. Here they pass, so the check allows — with the failure recorded in err and no reservation.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - } - }, - "operations": [ - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": { "ct_1": 5000 } }, - "usage": 10, - "event_subtype": "inference_tokens", - "on_acquire_failure": "fail-open", - "server": { "acquire": { "error": "wire down" } }, - "engine": [ - { - "value": true, - "reason": "probe", - "entitlement": { - "value_type": "credit", - "credit_id": "ct_1", - "consumption_rate": 10, - "event_subtype": "inference_tokens" - } - }, - { "value": true, "reason": "evaluated" } - ], - "expect": { - "allowed": true, - "reason": "evaluated (lease_acquire_failed_fail_open)", - "err": "lease_acquire_failed", - "has_reservation": false, - "engine_calls": [ - { "credit_balance": 5000 }, - { - "credit_balance": "max_safe_integer", - "event_usage": { "event_subtype": "inference_tokens", "quantity": 10 } - } - ] - } - }, - { "op": "reservation_count", "expect": { "count": 0 } } - ] - }, - { - "name": "check_fail_open_still_denies_when_rules_deny", - "description": "fail-open with a denying rules evaluation stays denied: substituting an unlimited balance only bypasses the credit gate, never plan targeting or overrides.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - } - }, - "operations": [ - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": { "ct_1": 5000 } }, - "usage": 10, - "event_subtype": "inference_tokens", - "on_acquire_failure": "fail-open", - "server": { "acquire": { "error": "wire down" } }, - "engine": [ - { - "value": true, - "reason": "probe", - "entitlement": { - "value_type": "credit", - "credit_id": "ct_1", - "consumption_rate": 10, - "event_subtype": "inference_tokens" - } - }, - { "value": false, "reason": "not_targeted" } - ], - "expect": { - "allowed": false, - "reason": "not_targeted (lease_acquire_failed_fail_open)", - "err": "lease_acquire_failed", - "has_reservation": false - } - } - ] - }, - { - "name": "check_insufficient_lease_extends_and_retries", - "description": "A reserve refusal triggers an awaited opportunistic extend sized to cover the request (required_credits = credit_cost), then exactly one reserve retry. On success the check proceeds normally, gating on the post-extend pre-reservation balance.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 950, - "expect": { "balance": 50 } - }, - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": { "ct_1": 5000 } }, - "usage": 10, - "event_subtype": "inference_tokens", - "server": { "extend": { "lease": { "granted_total": 2000, "expires_at_ms": 600000 } } }, - "save_reservation_as": "r1", - "engine": [ - { - "value": true, - "reason": "probe", - "entitlement": { - "value_type": "credit", - "credit_id": "ct_1", - "consumption_rate": 10, - "event_subtype": "inference_tokens" - } - }, - { "value": true, "reason": "ok" } - ], - "expect": { - "allowed": true, - "has_reservation": true, - "wire_extends": 1, - "last_extend_additional_amount": 1000, - "engine_calls": [{ "credit_balance": 5000 }, { "credit_balance": 1050, "credit_cost": 100 }] - } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "granted_amount": 2000, "local_remaining_credits": 950 } - } - ] - }, - { - "name": "check_insufficient_lease_after_failed_extend_resolves_by_mode", - "description": "When the opportunistic extend fails and the retry is still refused, the check resolves through the failure mode (fail-closed here) with reason insufficient_lease_balance, leaving the lease balance untouched.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 950, - "expect": { "balance": 50 } - }, - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": { "ct_1": 5000 } }, - "usage": 10, - "event_subtype": "inference_tokens", - "on_acquire_failure": "fail-closed", - "server": { "extend": { "error": "wire down" } }, - "engine": [ - { - "value": true, - "reason": "probe", - "entitlement": { - "value_type": "credit", - "credit_id": "ct_1", - "consumption_rate": 10, - "event_subtype": "inference_tokens" - } - } - ], - "expect": { - "allowed": false, - "reason": "insufficient_lease_balance", - "err": "insufficient_lease_balance", - "has_reservation": false - } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 50 } - }, - { "op": "reservation_count", "expect": { "count": 0 } } - ] - }, - { - "name": "check_falls_back_without_usable_credit_entitlement", - "description": "A non-credit matched entitlement (boolean/override/numeric/unlimited/not entitled) or an incomplete credit entitlement (no positive consumption rate) defers to the plain check: no lease traffic, no reservation.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - } - }, - "operations": [ - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": {} }, - "usage": 10, - "event_subtype": "inference_tokens", - "engine": [{ "value": true, "reason": "probe", "entitlement": { "value_type": "boolean" } }], - "expect": { "fallback_called": true, "reason": "fallback", "has_reservation": false } - }, - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": { "ct_1": 5000 } }, - "usage": 10, - "event_subtype": "inference_tokens", - "engine": [ - { - "value": true, - "reason": "probe", - "entitlement": { - "value_type": "credit", - "credit_id": "ct_1", - "consumption_rate": 0, - "event_subtype": "inference_tokens" - } - } - ], - "expect": { "fallback_called": true, "reason": "fallback", "has_reservation": false } - }, - { "op": "reservation_count", "expect": { "count": 0 } } - ] - }, - { - "name": "check_zero_usage_falls_back", - "description": "usage = 0 means nothing to reserve: the check defers to the plain (preflight-threaded) check instead of issuing a no-op 0-credit reservation.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": { "ct_1": 5000 } }, - "usage": 0, - "event_subtype": "inference_tokens", - "engine": [], - "expect": { "fallback_called": true, "reason": "fallback", "has_reservation": false } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 1000 } - } - ] - }, - { - "name": "check_invalid_usage_resolves_statically_by_mode", - "description": "A negative (or non-finite) usage must never reach the stores; the check resolves statically by mode without any engine evaluation: deny for fail-closed, blanket allow for fail-open, reason invalid_usage either way.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": { "ct_1": 5000 } }, - "usage": -5, - "event_subtype": "inference_tokens", - "on_acquire_failure": "fail-closed", - "engine": [], - "expect": { - "allowed": false, - "reason": "invalid_usage", - "err": "invalid_usage", - "has_reservation": false, - "engine_calls": [] - } - }, - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": { "ct_1": 5000 } }, - "usage": -5, - "event_subtype": "inference_tokens", - "on_acquire_failure": "fail-open", - "engine": [], - "expect": { - "allowed": true, - "reason": "invalid_usage_fail_open", - "err": "invalid_usage", - "has_reservation": false, - "engine_calls": [] - } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 1000 } - } - ] - } - ] -} diff --git a/conformance/vectors/crash-windows.json b/conformance/vectors/crash-windows.json deleted file mode 100644 index c8ee05b9..00000000 --- a/conformance/vectors/crash-windows.json +++ /dev/null @@ -1,271 +0,0 @@ -{ - "category": "crash_window", - "vectors": [ - { - "name": "debit_without_record_leaks_bounded", - "description": "Crash window 1 (debit-then-add): the atomic debit landed but the reservation record never did. The leak is exactly the reserved amount; the sweeper can never refund a hold that was never recorded.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { "op": "reserved_credits", "company_id": "co_1", "credit_type_id": "ct_1", "expect": { "total": 0 } }, - { "op": "advance_clock", "ms": 55000 }, - { "op": "sweep_expired", "expect": { "swept": 0 } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 900 } - } - ] - }, - { - "name": "debit_leak_reclaimed_at_lease_expiry", - "description": "Crash window 1 recovery: the leaked balance is never served after lease expiry, and the successor lease installs at the full grant — the leak does not outlive the lease.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { "op": "advance_clock", "ms": 60001 }, - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 1, - "expect": { "balance": null } - }, - { - "op": "replace_lease", - "lease_id": "lse_2", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 180000, - "expect": { "written": true } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 1000 } - } - ] - }, - { - "name": "retried_check_after_debit_leak_settles_once", - "description": "A retry after a window-1 crash is a fresh check with a fresh reservation: its unspent slice refunds exactly once; the leaked slice never refunds — not on a repeat consume, not on a sweep.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 3600000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 800 } - }, - { - "op": "add_reservation", - "id": "res_retry", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 10, - "credits_reserved": 100, - "consumption_rate": 10, - "expires_at_ms": 60000 - }, - { "op": "consume_reservation", "id": "res_retry", "credits": 40, "expect": { "consumed": 40 } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 860 } - }, - { "op": "consume_reservation", "id": "res_retry", "credits": 40, "expect": { "consumed": null } }, - { "op": "advance_clock", "ms": 70000 }, - { "op": "sweep_expired", "expect": { "swept": 0 } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 860 } - } - ] - }, - { - "name": "crash_before_refund_claim_is_durable", - "description": "Crash window 2 (consume-then-refund): the claim survives the crash, so the reservation is gone everywhere and nothing can double-spend; the unspent slice's refund is lost, bounded by credits_reserved. A retried settle neither re-claims nor double-refunds, and the sweeper cannot refund a claimed reservation.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 3600000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { - "op": "add_reservation", - "id": "res_1", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 10, - "credits_reserved": 100, - "consumption_rate": 10, - "expires_at_ms": 60000 - }, - { - "op": "consume_reservation", - "id": "res_1", - "credits": 30, - "crash_before_refund": true, - "expect": { "throws": true } - }, - { "op": "get_reservation", "id": "res_1", "expect": { "exists": false } }, - { "op": "reserved_credits", "company_id": "co_1", "credit_type_id": "ct_1", "expect": { "total": 0 } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 900 } - }, - { "op": "consume_reservation", "id": "res_1", "credits": 30, "expect": { "consumed": null } }, - { "op": "advance_clock", "ms": 70000 }, - { "op": "sweep_expired", "expect": { "swept": 0 } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 900 } - } - ] - }, - { - "name": "crash_before_refund_reclaimed_at_lease_expiry", - "description": "Crash window 2 recovery: after the lease expires and a successor takes the slot at full grant, a very late retried settle of the crashed reservation must not leak the lost refund into the successor.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { - "op": "add_reservation", - "id": "res_1", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 10, - "credits_reserved": 100, - "consumption_rate": 10, - "expires_at_ms": 60000 - }, - { - "op": "consume_reservation", - "id": "res_1", - "credits": 30, - "crash_before_refund": true, - "expect": { "throws": true } - }, - { "op": "advance_clock", "ms": 60001 }, - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 1, - "expect": { "balance": null } - }, - { - "op": "replace_lease", - "lease_id": "lse_2", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 180000, - "expect": { "written": true } - }, - { "op": "consume_reservation", "id": "res_1", "credits": 0, "expect": { "consumed": null } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "lease_id": "lse_2", "local_remaining_credits": 1000 } - } - ] - } - ] -} diff --git a/conformance/vectors/expiry.json b/conformance/vectors/expiry.json deleted file mode 100644 index e1f7e2cc..00000000 --- a/conformance/vectors/expiry.json +++ /dev/null @@ -1,198 +0,0 @@ -{ - "category": "expiry", - "vectors": [ - { - "name": "expired_lease_never_serves_reserves", - "description": "Past its expiry a lease's balance is stale (the server refunded the grant): reserves are refused even with ample local balance.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { "op": "advance_clock", "ms": 60001 }, - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 1, - "expect": { "balance": null } - } - ] - }, - { - "name": "successor_after_expiry_restores_full_grant", - "description": "A successor lease installed over an expired slot starts at its full grant — nothing from the expired lease (debits or leaks) carries over.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 700, - "expect": { "balance": 300 } - }, - { "op": "advance_clock", "ms": 60001 }, - { - "op": "replace_lease", - "lease_id": "lse_2", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 180000, - "expect": { "written": true } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "lease_id": "lse_2", "local_remaining_credits": 1000 } - } - ] - }, - { - "name": "sweep_refunds_expired_holds_only", - "description": "The sweeper refunds an expired reservation's full hold to its lease and leaves live reservations untouched.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 300, - "expect": { "balance": 700 } - }, - { - "op": "add_reservation", - "id": "res_short", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 10, - "credits_reserved": 100, - "consumption_rate": 10, - "expires_at_ms": 10000 - }, - { - "op": "add_reservation", - "id": "res_long", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 20, - "credits_reserved": 200, - "consumption_rate": 10, - "expires_at_ms": 200000 - }, - { "op": "sweep_expired", "expect": { "swept": 0 } }, - { "op": "advance_clock", "ms": 10001 }, - { "op": "sweep_expired", "expect": { "swept": 1 } }, - { "op": "get_reservation", "id": "res_short", "expect": { "exists": false } }, - { "op": "get_reservation", "id": "res_long", "expect": { "exists": true } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 800 } - }, - { "op": "reserved_credits", "company_id": "co_1", "credit_type_id": "ct_1", "expect": { "total": 200 } } - ] - }, - { - "name": "sweep_of_stale_lease_hold_does_not_inflate_successor", - "description": "Sweeping (or consuming) a reservation carved from an expired lease refunds nothing into the successor lease occupying the slot: the hold is pinned to its originating lease_id.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { - "op": "add_reservation", - "id": "res_stale", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 10, - "credits_reserved": 100, - "consumption_rate": 10, - "expires_at_ms": 90000 - }, - { "op": "advance_clock", "ms": 60001 }, - { - "op": "replace_lease", - "lease_id": "lse_2", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000, - "expect": { "written": true } - }, - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 200, - "expect": { "balance": 800 } - }, - { "op": "advance_clock", "ms": 30000 }, - { "op": "sweep_expired", "expect": { "swept": 1 } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "lease_id": "lse_2", "local_remaining_credits": 800 } - } - ] - } - ] -} diff --git a/conformance/vectors/lease-lifecycle.json b/conformance/vectors/lease-lifecycle.json deleted file mode 100644 index 085b5faa..00000000 --- a/conformance/vectors/lease-lifecycle.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "category": "lease_lifecycle", - "vectors": [ - { - "name": "replace_installs_full_grant", - "description": "A fresh install initializes local_remaining_credits to the full granted amount.", - "operations": [ - { - "op": "replace_lease", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000, - "expect": { "written": true } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { - "exists": true, - "lease_id": "lse_1", - "granted_amount": 1000, - "local_remaining_credits": 1000 - } - } - ] - }, - { - "name": "replace_keeps_live_lease_even_with_different_id", - "description": "A live lease occupying the slot wins over any replace — even one carrying a different lease_id (a sibling raced this acquire). Its already-debited balance is preserved.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 400, - "expect": { "balance": 600 } - }, - { - "op": "replace_lease", - "lease_id": "lse_2", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 5000, - "expires_at_ms": 120000, - "expect": { "written": false } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { - "exists": true, - "lease_id": "lse_1", - "granted_amount": 1000, - "local_remaining_credits": 600 - } - } - ] - }, - { - "name": "replace_reconciles_expired_slot_with_same_id", - "description": "A stale acquire response for the SAME lease landing over its own expired local row must not reinstall it: that would reset local_remaining_credits and erase debits whose reservations are still open. The row is reconciled like an extend (granted to total, expiry forward, balance untouched) and reported as kept.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 400, - "expect": { "balance": 600 } - }, - { "op": "advance_clock", "ms": 60001 }, - { - "op": "replace_lease", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1500, - "expires_at_ms": 120000, - "expect": { "written": false } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { - "exists": true, - "lease_id": "lse_1", - "granted_amount": 1500, - "local_remaining_credits": 1100 - } - }, - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 1000 } - } - ] - }, - { - "name": "replace_overwrites_expired_lease", - "description": "An expired lease does not block the slot: replace overwrites it atomically and restores the full new grant.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 400, - "expect": { "balance": 600 } - }, - { "op": "advance_clock", "ms": 60001 }, - { - "op": "replace_lease", - "lease_id": "lse_2", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 180000, - "expect": { "written": true } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "lease_id": "lse_2", "local_remaining_credits": 1000 } - } - ] - }, - { - "name": "try_reserve_insufficient_and_boundary", - "description": "A reserve larger than the remaining balance is refused and touches nothing; reserving down to exactly zero is allowed; negative amounts are always refused.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 100, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 101, - "expect": { "balance": null } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 100 } - }, - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": -1, - "expect": { "balance": null } - }, - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 0 } - }, - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 1, - "expect": { "balance": null } - }, - { - "op": "try_reserve", - "company_id": "co_9", - "credit_type_id": "ct_1", - "credits": 1, - "expect": { "balance": null } - } - ] - }, - { - "name": "refund_clamped_at_granted_amount", - "description": "A refund can never push the local balance above the granted amount.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { "op": "refund_lease", "company_id": "co_1", "credit_type_id": "ct_1", "credits": 500 }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 1000 } - } - ] - }, - { - "name": "refund_pinned_to_lease_id_dropped_on_successor", - "description": "A refund pinned to an expired lease's id must not inflate the successor lease occupying the slot — the expired lease's remainder was already returned to the company balance server-side. An unpinned refund still applies.", - "given": { - "leases": [ - { - "lease_id": "lse_2", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 200, - "expect": { "balance": 800 } - }, - { - "op": "refund_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "pin_lease_id": "lse_1" - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 800 } - }, - { - "op": "refund_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "pin_lease_id": "lse_2" - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 900 } - } - ] - }, - { - "name": "extend_reconciles_to_total_and_converges", - "description": "Extend applies the server-authoritative TOTAL: the delta is computed against the stored total, so a repeated or stale-lower total is a no-op and out-of-order applies converge without minting credits.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 800, - "expect": { "balance": 200 } - }, - { - "op": "extend_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_total": 3000, - "expires_at_ms": 300000 - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "granted_amount": 3000, "local_remaining_credits": 2200 } - }, - { - "op": "extend_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_total": 3000, - "expires_at_ms": 300000 - }, - { - "op": "extend_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_total": 2000, - "expires_at_ms": 300000 - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "granted_amount": 3000, "local_remaining_credits": 2200 } - } - ] - }, - { - "name": "extend_expiry_only_moves_forward", - "description": "An extend carrying an earlier expiry must not shorten the lease: after an extend to a later expiry, a stale out-of-order apply with an earlier expiry leaves the lease live past that earlier instant.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "extend_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_total": 2000, - "expires_at_ms": 120000 - }, - { - "op": "extend_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_total": 2000, - "expires_at_ms": 30000 - }, - { "op": "advance_clock", "ms": 90000 }, - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 1900 } - } - ] - }, - { - "name": "extend_pinned_to_lease_id_dropped_on_successor", - "description": "An extend pinned to a lease the slot no longer holds is dropped entirely — crediting the successor would mint credits the server granted to the expired lease.", - "given": { - "leases": [ - { - "lease_id": "lse_2", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "extend_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_total": 5000, - "expires_at_ms": 600000, - "pin_lease_id": "lse_1" - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "granted_amount": 1000, "local_remaining_credits": 1000 } - }, - { - "op": "extend_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_total": 2000, - "expires_at_ms": 600000, - "pin_lease_id": "lse_2" - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "granted_amount": 2000, "local_remaining_credits": 2000 } - } - ] - } - ] -} diff --git a/conformance/vectors/lease-manager.json b/conformance/vectors/lease-manager.json deleted file mode 100644 index 79ab1afa..00000000 --- a/conformance/vectors/lease-manager.json +++ /dev/null @@ -1,417 +0,0 @@ -{ - "category": "lease_manager", - "vectors": [ - { - "name": "acquire_installs_tranche_and_reuses_live_lease", - "description": "First acquire requests lease_size from the server and installs the response at full grant; a second acquire while the lease is live makes no wire call.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - } - }, - "operations": [ - { - "op": "acquire_if_needed", - "company_id": "co_1", - "credit_type_id": "ct_1", - "server": { - "lease": { "lease_id": "lse_1", "granted_amount": 1000, "expires_at_ms": 300000 } - }, - "expect": { - "lease_id": "lse_1", - "wire_acquires": 1, - "last_acquire_requested_amount": 1000, - "released_lease_ids": [] - } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "lease_id": "lse_1", "local_remaining_credits": 1000 } - }, - { - "op": "acquire_if_needed", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "lease_id": "lse_1", "wire_acquires": 1 } - } - ] - }, - { - "name": "acquire_replaces_expired_slot_without_release", - "description": "An expired slot triggers a fresh acquire that supplants the stale entry in place; the redundant-lease release path must not fire (replace wrote, it did not keep a live lease).", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_stale", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { "op": "advance_clock", "ms": 60001 }, - { - "op": "acquire_if_needed", - "company_id": "co_1", - "credit_type_id": "ct_1", - "server": { - "lease": { "lease_id": "lse_fresh", "granted_amount": 1000, "expires_at_ms": 360000 } - }, - "expect": { "lease_id": "lse_fresh", "wire_acquires": 1, "released_lease_ids": [] } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "lease_id": "lse_fresh", "local_remaining_credits": 1000 } - } - ] - }, - { - "name": "lost_acquire_race_different_id_releases_redundant_lease", - "description": "A sibling installs a live lease while this acquire's wire call is in flight. The installed lease (with its debited balance) wins; the lease the server minted for the loser is redundant and gets released so it is not orphaned against the company balance.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - } - }, - "operations": [ - { - "op": "acquire_if_needed", - "company_id": "co_1", - "credit_type_id": "ct_1", - "server": { - "lease": { "lease_id": "lse_loser", "granted_amount": 1000, "expires_at_ms": 300000 } - }, - "install_during_wire": { - "lease_id": "lse_winner", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - }, - "expect": { "lease_id": "lse_winner", "wire_acquires": 1, "released_lease_ids": ["lse_loser"] } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "lease_id": "lse_winner" } - } - ] - }, - { - "name": "lost_acquire_race_same_id_releases_nothing", - "description": "The server is idempotent for an active slot: a racing acquire is handed back the SAME lease the sibling installed. There is nothing to release — releasing would pull the shared lease out from under every sibling.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - } - }, - "operations": [ - { - "op": "acquire_if_needed", - "company_id": "co_1", - "credit_type_id": "ct_1", - "server": { - "lease": { "lease_id": "lse_shared", "granted_amount": 1000, "expires_at_ms": 300000 } - }, - "install_during_wire": { - "lease_id": "lse_shared", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - }, - "expect": { "lease_id": "lse_shared", "wire_acquires": 1, "released_lease_ids": [] } - } - ] - }, - { - "name": "extend_triggered_at_low_water_mark_requests_tranche", - "description": "At or below the low-water-mark ratio a steady-state extend fires, requesting the configured tranche (lease_size) and reconciling the local row to the server total.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 800, - "expect": { "balance": 200 } - }, - { - "op": "maybe_extend", - "company_id": "co_1", - "credit_type_id": "ct_1", - "server": { "lease": { "granted_total": 2000, "expires_at_ms": 600000 } }, - "expect": { - "wire_extends": 1, - "last_extend_additional_amount": 1000, - "last_extend_lease_id": "lse_1" - } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "granted_amount": 2000, "local_remaining_credits": 1200 } - } - ] - }, - { - "name": "extend_triggered_by_required_credits_above_watermark", - "description": "Above the watermark no steady-state extend fires; a required_credits hint larger than the local remaining triggers one anyway (a check just failed a reserve of that size).", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { - "op": "maybe_extend", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "wire_extends": 0 } - }, - { - "op": "maybe_extend", - "company_id": "co_1", - "credit_type_id": "ct_1", - "required_credits": 1500, - "server": { "lease": { "granted_total": 2000, "expires_at_ms": 600000 } }, - "expect": { "wire_extends": 1, "last_extend_additional_amount": 1000 } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "granted_amount": 2000, "local_remaining_credits": 1900 } - } - ] - }, - { - "name": "extend_sized_to_shortfall_when_larger_than_tranche", - "description": "additional_amount = max(lease_size, required_credits - local_remaining): a single request larger than remaining + tranche must extend by the shortfall, or its post-extend retry would fail forever regardless of server balance.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { - "op": "maybe_extend", - "company_id": "co_1", - "credit_type_id": "ct_1", - "required_credits": 5000, - "server": { "lease": { "granted_total": 5100, "expires_at_ms": 600000 } }, - "expect": { "wire_extends": 1, "last_extend_additional_amount": 4100 } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "granted_amount": 5100, "local_remaining_credits": 5000 } - } - ] - }, - { - "name": "never_extend_an_expired_lease", - "description": "An expired lease is released as far as the server is concerned — the only correct move is a fresh acquire, never an extend, no matter how depleted the balance.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_old", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 900, - "expect": { "balance": 100 } - }, - { "op": "advance_clock", "ms": 60001 }, - { - "op": "maybe_extend", - "company_id": "co_1", - "credit_type_id": "ct_1", - "required_credits": 1500, - "expect": { "wire_extends": 0 } - } - ] - }, - { - "name": "wire_failures_resolve_to_no_lease_without_state_changes", - "description": "A failed acquire yields no lease and installs nothing; a failed extend leaves the local row untouched. Neither throws (both are routed through fail-open/fail-closed by callers).", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - } - }, - "operations": [ - { - "op": "acquire_if_needed", - "company_id": "co_1", - "credit_type_id": "ct_1", - "server": { "error": "wire down" }, - "expect": { "lease_id": null, "wire_acquires": 1 } - }, - { "op": "get_lease", "company_id": "co_1", "credit_type_id": "ct_1", "expect": { "exists": false } }, - { - "op": "replace_lease", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000, - "expect": { "written": true } - }, - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 800, - "expect": { "balance": 200 } - }, - { - "op": "maybe_extend", - "company_id": "co_1", - "credit_type_id": "ct_1", - "server": { "error": "wire down" }, - "expect": { "wire_extends": 1 } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "granted_amount": 1000, "local_remaining_credits": 200 } - } - ] - }, - { - "name": "release_all_releases_live_and_skips_expired", - "description": "On close, a per-process store releases its live leases over the wire (returning remainders immediately) and drops them locally; expired leases are skipped — the server already swept them. Only valid for an exclusively-owned (in-memory) store; a shared backend must never enumerate-and-release.", - "backends": ["in_memory"], - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_live", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - }, - { - "lease_id": "lse_expired", - "company_id": "co_2", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 30000 - } - ] - }, - "operations": [ - { "op": "advance_clock", "ms": 30001 }, - { - "op": "release_all_local_leases", - "expect": { "released_lease_ids": ["lse_live"] } - }, - { "op": "get_lease", "company_id": "co_1", "credit_type_id": "ct_1", "expect": { "exists": false } } - ] - } - ] -} diff --git a/conformance/vectors/reservation-lifecycle.json b/conformance/vectors/reservation-lifecycle.json deleted file mode 100644 index eea6b50e..00000000 --- a/conformance/vectors/reservation-lifecycle.json +++ /dev/null @@ -1,353 +0,0 @@ -{ - "category": "reservation_lifecycle", - "vectors": [ - { - "name": "consume_exact_usage_no_refund", - "description": "Consuming exactly the reserved amount removes the reservation and refunds nothing.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { - "op": "add_reservation", - "id": "res_1", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 10, - "credits_reserved": 100, - "consumption_rate": 10, - "expires_at_ms": 60000 - }, - { "op": "consume_reservation", "id": "res_1", "credits": 100, "expect": { "consumed": 100 } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 900 } - }, - { "op": "get_reservation", "id": "res_1", "expect": { "exists": false } } - ] - }, - { - "name": "consume_under_reserved_refunds_unspent", - "description": "Consuming less than reserved refunds the unspent slice to the lease in the same step.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { - "op": "add_reservation", - "id": "res_1", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 10, - "credits_reserved": 100, - "consumption_rate": 10, - "expires_at_ms": 60000 - }, - { "op": "consume_reservation", "id": "res_1", "credits": 30, "expect": { "consumed": 30 } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 970 } - } - ] - }, - { - "name": "consume_over_reserved_clamps_to_hold", - "description": "Local consumption is clamped to credits_reserved: over-use consumes the full hold, refunds nothing, and never debits the lease beyond the reservation. (The billed Track quantity is NOT clamped — see track-settle vectors.)", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { - "op": "add_reservation", - "id": "res_1", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 10, - "credits_reserved": 100, - "consumption_rate": 10, - "expires_at_ms": 60000 - }, - { "op": "consume_reservation", "id": "res_1", "credits": 999, "expect": { "consumed": 100 } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 900 } - } - ] - }, - { - "name": "consume_zero_cancels_with_full_refund", - "description": "Consuming 0 credits acts as a cancel: the full hold is refunded. Negative consumption clamps to 0 the same way.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { - "op": "add_reservation", - "id": "res_1", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 10, - "credits_reserved": 100, - "consumption_rate": 10, - "expires_at_ms": 60000 - }, - { "op": "consume_reservation", "id": "res_1", "credits": 0, "expect": { "consumed": 0 } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 1000 } - } - ] - }, - { - "name": "consume_is_exactly_once", - "description": "A missing reservation and a second consume of the same id both return null and refund nothing — the claim is the exactly-once arbiter.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { "op": "consume_reservation", "id": "res_missing", "credits": 10, "expect": { "consumed": null } }, - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 100, - "expect": { "balance": 900 } - }, - { - "op": "add_reservation", - "id": "res_1", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 10, - "credits_reserved": 100, - "consumption_rate": 10, - "expires_at_ms": 60000 - }, - { "op": "consume_reservation", "id": "res_1", "credits": 30, "expect": { "consumed": 30 } }, - { "op": "consume_reservation", "id": "res_1", "credits": 30, "expect": { "consumed": null } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 970 } - } - ] - }, - { - "name": "reserved_credits_sums_open_holds_per_slot", - "description": "reserved_credits sums credits_reserved across open reservations for the exact (company, credit) slot only, and a hold stops counting the moment it is consumed.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 350, - "expect": { "balance": 650 } - }, - { - "op": "add_reservation", - "id": "res_1", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 10, - "credits_reserved": 100, - "consumption_rate": 10, - "expires_at_ms": 60000 - }, - { - "op": "add_reservation", - "id": "res_2", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 25, - "credits_reserved": 250, - "consumption_rate": 10, - "expires_at_ms": 60000 - }, - { - "op": "add_reservation", - "id": "res_other_credit", - "lease_id": "lse_9", - "company_id": "co_1", - "credit_type_id": "ct_2", - "event_subtype": "inference_tokens", - "quantity_reserved": 99, - "credits_reserved": 999, - "consumption_rate": 10, - "expires_at_ms": 60000 - }, - { - "op": "add_reservation", - "id": "res_other_company", - "lease_id": "lse_8", - "company_id": "co_2", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 99, - "credits_reserved": 999, - "consumption_rate": 10, - "expires_at_ms": 60000 - }, - { - "op": "reserved_credits", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "total": 350 } - }, - { - "op": "reserved_credits", - "company_id": "co_1", - "credit_type_id": "ct_2", - "expect": { "total": 999 } - }, - { "op": "reserved_credits", "company_id": "co_9", "credit_type_id": "ct_1", "expect": { "total": 0 } }, - { "op": "consume_reservation", "id": "res_1", "credits": 40, "expect": { "consumed": 40 } }, - { "op": "reserved_credits", "company_id": "co_1", "credit_type_id": "ct_1", "expect": { "total": 250 } } - ] - }, - { - "name": "fractional_credit_amounts_are_exact", - "description": "Fractional consumption rates produce fractional holds; reserve, consume, and refund arithmetic must not truncate.", - "given": { - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 10, - "expires_at_ms": 60000 - } - ] - }, - "operations": [ - { - "op": "try_reserve", - "company_id": "co_1", - "credit_type_id": "ct_1", - "credits": 2.5, - "expect": { "balance": 7.5 } - }, - { - "op": "add_reservation", - "id": "res_1", - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "event_subtype": "inference_tokens", - "quantity_reserved": 25, - "credits_reserved": 2.5, - "consumption_rate": 0.1, - "expires_at_ms": 60000 - }, - { "op": "consume_reservation", "id": "res_1", "credits": 1.5, "expect": { "consumed": 1.5 } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 8.5 } - } - ] - } - ] -} diff --git a/conformance/vectors/track-settle.json b/conformance/vectors/track-settle.json deleted file mode 100644 index 1da71a09..00000000 --- a/conformance/vectors/track-settle.json +++ /dev/null @@ -1,194 +0,0 @@ -{ - "category": "track_settle", - "vectors": [ - { - "name": "track_underuse_settles_and_refunds_unspent", - "description": "Settling with less than the reserved usage consumes actual x rate, refunds the unspent slice to the lease, and emits a Track billing the ACTUAL quantity keyed to the lease.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": { "ct_1": 5000 } }, - "usage": 10, - "event_subtype": "inference_tokens", - "save_reservation_as": "r1", - "engine": [ - { - "value": true, - "reason": "probe", - "entitlement": { - "value_type": "credit", - "credit_id": "ct_1", - "consumption_rate": 10, - "event_subtype": "inference_tokens" - } - }, - { "value": true, "reason": "ok" } - ], - "expect": { "allowed": true, "has_reservation": true } - }, - { - "op": "track", - "handle": "r1", - "actual_quantity": 4, - "expect": { - "settled_locally": true, - "track": { "event": "inference_tokens", "quantity": 4, "lease_id": "lse_1" } - } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 960 } - }, - { "op": "reserved_credits", "company_id": "co_1", "credit_type_id": "ct_1", "expect": { "total": 0 } } - ] - }, - { - "name": "track_overuse_bills_actual_but_clamps_local_debit", - "description": "Actual usage above the reservation: the LOCAL settle clamps consumption to the reserved hold (the lease is never debited past the reservation), but the Track event bills the unclamped actual quantity — the server is the source of truth for real consumption.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": { "ct_1": 5000 } }, - "usage": 10, - "event_subtype": "inference_tokens", - "save_reservation_as": "r1", - "engine": [ - { - "value": true, - "reason": "probe", - "entitlement": { - "value_type": "credit", - "credit_id": "ct_1", - "consumption_rate": 10, - "event_subtype": "inference_tokens" - } - }, - { "value": true, "reason": "ok" } - ], - "expect": { "allowed": true, "has_reservation": true } - }, - { - "op": "track", - "handle": "r1", - "actual_quantity": 25, - "expect": { - "settled_locally": true, - "track": { "event": "inference_tokens", "quantity": 25, "lease_id": "lse_1" } - } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 900 } - } - ] - }, - { - "name": "track_after_sweep_is_a_recovery_emit", - "description": "Work outliving the reservation TTL: the sweeper already refunded the full hold, so the late settle does not touch the lease (the local balance reads high until rollover) — but the Track is still emitted so the server bills the actual usage. Server-side idempotency (a deterministic key derived from the reservation id) is what keeps a racing normal emit from double-billing.", - "given": { - "config": { - "lease_duration_ms": 300000, - "reservation_ttl_ms": 60000, - "lease_size": 1000, - "low_water_mark": 0.25 - }, - "leases": [ - { - "lease_id": "lse_1", - "company_id": "co_1", - "credit_type_id": "ct_1", - "granted_amount": 1000, - "expires_at_ms": 300000 - } - ] - }, - "operations": [ - { - "op": "check", - "flag_key": "inference", - "company": { "id": "co_1", "credit_balances": { "ct_1": 5000 } }, - "usage": 10, - "event_subtype": "inference_tokens", - "save_reservation_as": "r1", - "engine": [ - { - "value": true, - "reason": "probe", - "entitlement": { - "value_type": "credit", - "credit_id": "ct_1", - "consumption_rate": 10, - "event_subtype": "inference_tokens" - } - }, - { "value": true, "reason": "ok" } - ], - "expect": { "allowed": true, "has_reservation": true } - }, - { "op": "advance_clock", "ms": 60001 }, - { "op": "sweep_expired", "expect": { "swept": 1 } }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 1000 } - }, - { - "op": "track", - "handle": "r1", - "actual_quantity": 4, - "expect": { - "settled_locally": false, - "track": { "event": "inference_tokens", "quantity": 4, "lease_id": "lse_1" } - } - }, - { - "op": "get_lease", - "company_id": "co_1", - "credit_type_id": "ct_1", - "expect": { "exists": true, "local_remaining_credits": 1000 } - } - ] - } - ] -} diff --git a/package.json b/package.json index 84df190d..d779590c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@schematichq/schematic-typescript-node", - "version": "1.5.11", + "version": "1.5.12", "private": false, "repository": { "type": "git", @@ -57,9 +57,6 @@ "crypto": false, "timers": false }, - "resolutions": { - "undici": "7.29.0" - }, "packageManager": "yarn@1.22.22", "engines": { "node": ">=18.0.0" diff --git a/reference.md b/reference.md index 95eb181f..26f221a5 100644 --- a/reference.md +++ b/reference.md @@ -2382,6 +2382,120 @@ await client.billing.countBillingProducts({ + + + + +
client.billing.listCompanyBillingProfiles({ ...params }) -> Schematic.ListCompanyBillingProfilesResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.billing.listCompanyBillingProfiles({ + companyId: "company_id", + isDefault: true, + providerType: "metronome", + limit: 1000000, + offset: 1000000 +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Schematic.ListCompanyBillingProfilesRequest` + +
+
+ +
+
+ +**requestOptions:** `BillingClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.billing.updateCompanyBillingProfile(billing_profile_id, { ...params }) -> Schematic.UpdateCompanyBillingProfileResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.billing.updateCompanyBillingProfile("billing_profile_id", { + collectionMethod: "charge_automatically" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**billing_profile_id:** `string` — billing_profile_id + +
+
+ +
+
+ +**request:** `Schematic.UpdateCompanyBillingProfileRequestBody` + +
+
+ +
+
+ +**requestOptions:** `BillingClient.RequestOptions` + +
+
+
+
+ +
@@ -3991,7 +4105,7 @@ await client.credits.countBillingPlanCreditGrants({ -
client.credits.listCreditEventLedger({ ...params }) -> Schematic.ListCreditEventLedgerResponse +
client.credits.listCreditSpendPolicies({ ...params }) -> Schematic.ListCreditSpendPoliciesResponse
@@ -4004,13 +4118,12 @@ await client.credits.countBillingPlanCreditGrants({
```typescript -await client.credits.listCreditEventLedger({ +await client.credits.listCreditSpendPolicies({ billingCreditId: "billing_credit_id", companyId: "company_id", - endTime: "end_time", - eventType: "grant", - featureId: "feature_id", - startTime: "start_time", + scopeType: "company", + userId: "user_id", + userIds: ["user_ids"], limit: 1000000, offset: 1000000 }); @@ -4029,7 +4142,7 @@ await client.credits.listCreditEventLedger({
-**request:** `Schematic.ListCreditEventLedgerRequest` +**request:** `Schematic.ListCreditSpendPoliciesRequest`
@@ -4049,7 +4162,7 @@ await client.credits.listCreditEventLedger({
-
client.credits.countCreditEventLedger({ ...params }) -> Schematic.CountCreditEventLedgerResponse +
client.credits.createCreditSpendPolicy({ ...params }) -> Schematic.CreateCreditSpendPolicyResponse
@@ -4062,15 +4175,9 @@ await client.credits.listCreditEventLedger({
```typescript -await client.credits.countCreditEventLedger({ +await client.credits.createCreditSpendPolicy({ billingCreditId: "billing_credit_id", - companyId: "company_id", - endTime: "end_time", - eventType: "grant", - featureId: "feature_id", - startTime: "start_time", - limit: 1000000, - offset: 1000000 + maxPerDraw: 1.1 }); ``` @@ -4087,7 +4194,7 @@ await client.credits.countCreditEventLedger({
-**request:** `Schematic.CountCreditEventLedgerRequest` +**request:** `Schematic.CreateCreditSpendPolicyRequestBody`
@@ -4107,8 +4214,7 @@ await client.credits.countCreditEventLedger({
-## catalogs -
client.catalogs.listCatalogs({ ...params }) -> Schematic.ListCatalogsResponse +
client.credits.getCreditSpendPolicy(spend_policy_id) -> Schematic.GetCreditSpendPolicyResponse
@@ -4121,12 +4227,7 @@ await client.credits.countCreditEventLedger({
```typescript -await client.catalogs.listCatalogs({ - isDefault: true, - q: "q", - limit: 1000000, - offset: 1000000 -}); +await client.credits.getCreditSpendPolicy("spend_policy_id"); ```
@@ -4142,7 +4243,7 @@ await client.catalogs.listCatalogs({
-**request:** `Schematic.ListCatalogsRequest` +**spend_policy_id:** `string` — spend_policy_id
@@ -4150,7 +4251,7 @@ await client.catalogs.listCatalogs({
-**requestOptions:** `CatalogsClient.RequestOptions` +**requestOptions:** `CreditsClient.RequestOptions`
@@ -4162,7 +4263,7 @@ await client.catalogs.listCatalogs({
-
client.catalogs.createCatalog({ ...params }) -> Schematic.CreateCatalogResponse +
client.credits.updateCreditSpendPolicy(spend_policy_id, { ...params }) -> Schematic.UpdateCreditSpendPolicyResponse
@@ -4175,9 +4276,7 @@ await client.catalogs.listCatalogs({
```typescript -await client.catalogs.createCatalog({ - name: "name" -}); +await client.credits.updateCreditSpendPolicy("spend_policy_id"); ```
@@ -4193,7 +4292,7 @@ await client.catalogs.createCatalog({
-**request:** `Schematic.CreateCatalogRequestBody` +**spend_policy_id:** `string` — spend_policy_id
@@ -4201,7 +4300,15 @@ await client.catalogs.createCatalog({
-**requestOptions:** `CatalogsClient.RequestOptions` +**request:** `Schematic.UpdateCreditSpendPolicyRequestBody` + +
+
+ +
+
+ +**requestOptions:** `CreditsClient.RequestOptions`
@@ -4213,7 +4320,7 @@ await client.catalogs.createCatalog({
-
client.catalogs.getCatalog(catalog_id) -> Schematic.GetCatalogResponse +
client.credits.deleteCreditSpendPolicy(spend_policy_id) -> Schematic.DeleteCreditSpendPolicyResponse
@@ -4226,7 +4333,7 @@ await client.catalogs.createCatalog({
```typescript -await client.catalogs.getCatalog("catalog_id"); +await client.credits.deleteCreditSpendPolicy("spend_policy_id"); ```
@@ -4242,7 +4349,7 @@ await client.catalogs.getCatalog("catalog_id");
-**catalog_id:** `string` — catalog_id +**spend_policy_id:** `string` — spend_policy_id
@@ -4250,7 +4357,7 @@ await client.catalogs.getCatalog("catalog_id");
-**requestOptions:** `CatalogsClient.RequestOptions` +**requestOptions:** `CreditsClient.RequestOptions`
@@ -4262,7 +4369,7 @@ await client.catalogs.getCatalog("catalog_id");
-
client.catalogs.updateCatalog(catalog_id, { ...params }) -> Schematic.UpdateCatalogResponse +
client.credits.countCreditSpendPolicies({ ...params }) -> Schematic.CountCreditSpendPoliciesResponse
@@ -4275,7 +4382,15 @@ await client.catalogs.getCatalog("catalog_id");
```typescript -await client.catalogs.updateCatalog("catalog_id"); +await client.credits.countCreditSpendPolicies({ + billingCreditId: "billing_credit_id", + companyId: "company_id", + scopeType: "company", + userId: "user_id", + userIds: ["user_ids"], + limit: 1000000, + offset: 1000000 +}); ```
@@ -4291,15 +4406,7 @@ await client.catalogs.updateCatalog("catalog_id");
-**catalog_id:** `string` — catalog_id - -
-
- -
-
- -**request:** `Schematic.UpdateCatalogRequestBody` +**request:** `Schematic.CountCreditSpendPoliciesRequest`
@@ -4307,7 +4414,7 @@ await client.catalogs.updateCatalog("catalog_id");
-**requestOptions:** `CatalogsClient.RequestOptions` +**requestOptions:** `CreditsClient.RequestOptions`
@@ -4319,7 +4426,7 @@ await client.catalogs.updateCatalog("catalog_id");
-
client.catalogs.deleteCatalog(catalog_id) -> Schematic.DeleteCatalogResponse +
client.credits.listCreditEventLedger({ ...params }) -> Schematic.ListCreditEventLedgerResponse
@@ -4332,7 +4439,16 @@ await client.catalogs.updateCatalog("catalog_id");
```typescript -await client.catalogs.deleteCatalog("catalog_id"); +await client.credits.listCreditEventLedger({ + billingCreditId: "billing_credit_id", + companyId: "company_id", + endTime: "end_time", + eventType: "grant", + featureId: "feature_id", + startTime: "start_time", + limit: 1000000, + offset: 1000000 +}); ```
@@ -4348,7 +4464,7 @@ await client.catalogs.deleteCatalog("catalog_id");
-**catalog_id:** `string` — catalog_id +**request:** `Schematic.ListCreditEventLedgerRequest`
@@ -4356,7 +4472,7 @@ await client.catalogs.deleteCatalog("catalog_id");
-**requestOptions:** `CatalogsClient.RequestOptions` +**requestOptions:** `CreditsClient.RequestOptions`
@@ -4368,7 +4484,7 @@ await client.catalogs.deleteCatalog("catalog_id");
-
client.catalogs.getConfiguration(catalog_id) -> Schematic.GetConfigurationResponse +
client.credits.countCreditEventLedger({ ...params }) -> Schematic.CountCreditEventLedgerResponse
@@ -4381,7 +4497,16 @@ await client.catalogs.deleteCatalog("catalog_id");
```typescript -await client.catalogs.getConfiguration("catalog_id"); +await client.credits.countCreditEventLedger({ + billingCreditId: "billing_credit_id", + companyId: "company_id", + endTime: "end_time", + eventType: "grant", + featureId: "feature_id", + startTime: "start_time", + limit: 1000000, + offset: 1000000 +}); ```
@@ -4397,7 +4522,7 @@ await client.catalogs.getConfiguration("catalog_id");
-**catalog_id:** `string` — catalog_id +**request:** `Schematic.CountCreditEventLedgerRequest`
@@ -4405,7 +4530,7 @@ await client.catalogs.getConfiguration("catalog_id");
-**requestOptions:** `CatalogsClient.RequestOptions` +**requestOptions:** `CreditsClient.RequestOptions`
@@ -4417,7 +4542,8 @@ await client.catalogs.getConfiguration("catalog_id");
-
client.catalogs.updateConfiguration(catalog_id, { ...params }) -> Schematic.UpdateConfigurationResponse +## catalogs +
client.catalogs.listCatalogs({ ...params }) -> Schematic.ListCatalogsResponse
@@ -4430,7 +4556,12 @@ await client.catalogs.getConfiguration("catalog_id");
```typescript -await client.catalogs.updateConfiguration("catalog_id"); +await client.catalogs.listCatalogs({ + isDefault: true, + q: "q", + limit: 1000000, + offset: 1000000 +}); ```
@@ -4446,15 +4577,7 @@ await client.catalogs.updateConfiguration("catalog_id");
-**catalog_id:** `string` — catalog_id - -
-
- -
-
- -**request:** `Schematic.UpdateCatalogConfigurationRequestBody` +**request:** `Schematic.ListCatalogsRequest`
@@ -4474,7 +4597,7 @@ await client.catalogs.updateConfiguration("catalog_id");
-
client.catalogs.getCreditBundlesInCatalog(catalog_id) -> Schematic.GetCreditBundlesInCatalogResponse +
client.catalogs.createCatalog({ ...params }) -> Schematic.CreateCatalogResponse
@@ -4487,7 +4610,9 @@ await client.catalogs.updateConfiguration("catalog_id");
```typescript -await client.catalogs.getCreditBundlesInCatalog("catalog_id"); +await client.catalogs.createCatalog({ + name: "name" +}); ```
@@ -4503,7 +4628,7 @@ await client.catalogs.getCreditBundlesInCatalog("catalog_id");
-**catalog_id:** `string` — catalog_id +**request:** `Schematic.CreateCatalogRequestBody`
@@ -4523,7 +4648,7 @@ await client.catalogs.getCreditBundlesInCatalog("catalog_id");
-
client.catalogs.addCreditBundle(catalog_id, credit_bundle_id) -> void +
client.catalogs.getCatalog(catalog_id) -> Schematic.GetCatalogResponse
@@ -4536,7 +4661,7 @@ await client.catalogs.getCreditBundlesInCatalog("catalog_id");
```typescript -await client.catalogs.addCreditBundle("catalog_id", "credit_bundle_id"); +await client.catalogs.getCatalog("catalog_id"); ```
@@ -4560,14 +4685,6 @@ await client.catalogs.addCreditBundle("catalog_id", "credit_bundle_id");
-**credit_bundle_id:** `string` — credit_bundle_id - -
-
- -
-
- **requestOptions:** `CatalogsClient.RequestOptions`
@@ -4580,7 +4697,7 @@ await client.catalogs.addCreditBundle("catalog_id", "credit_bundle_id");
-
client.catalogs.removeCreditBundle(catalog_id, credit_bundle_id) -> void +
client.catalogs.updateCatalog(catalog_id, { ...params }) -> Schematic.UpdateCatalogResponse
@@ -4593,7 +4710,7 @@ await client.catalogs.addCreditBundle("catalog_id", "credit_bundle_id");
```typescript -await client.catalogs.removeCreditBundle("catalog_id", "credit_bundle_id"); +await client.catalogs.updateCatalog("catalog_id"); ```
@@ -4617,7 +4734,7 @@ await client.catalogs.removeCreditBundle("catalog_id", "credit_bundle_id");
-**credit_bundle_id:** `string` — credit_bundle_id +**request:** `Schematic.UpdateCatalogRequestBody`
@@ -4637,7 +4754,7 @@ await client.catalogs.removeCreditBundle("catalog_id", "credit_bundle_id");
-
client.catalogs.getDerivedFeatures(catalog_id) -> Schematic.GetDerivedFeaturesResponse +
client.catalogs.deleteCatalog(catalog_id) -> Schematic.DeleteCatalogResponse
@@ -4650,7 +4767,325 @@ await client.catalogs.removeCreditBundle("catalog_id", "credit_bundle_id");
```typescript -await client.catalogs.getDerivedFeatures("catalog_id"); +await client.catalogs.deleteCatalog("catalog_id"); + +``` +
+
+ + + +#### ⚙️ Parameters + +
+
+ +
+
+ +**catalog_id:** `string` — catalog_id + +
+
+ +
+
+ +**requestOptions:** `CatalogsClient.RequestOptions` + +
+
+
+
+ + + + +
+ +
client.catalogs.getConfiguration(catalog_id) -> Schematic.GetConfigurationResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.catalogs.getConfiguration("catalog_id"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**catalog_id:** `string` — catalog_id + +
+
+ +
+
+ +**requestOptions:** `CatalogsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.catalogs.updateConfiguration(catalog_id, { ...params }) -> Schematic.UpdateConfigurationResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.catalogs.updateConfiguration("catalog_id"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**catalog_id:** `string` — catalog_id + +
+
+ +
+
+ +**request:** `Schematic.UpdateCatalogConfigurationRequestBody` + +
+
+ +
+
+ +**requestOptions:** `CatalogsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.catalogs.getCreditBundlesInCatalog(catalog_id) -> Schematic.GetCreditBundlesInCatalogResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.catalogs.getCreditBundlesInCatalog("catalog_id"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**catalog_id:** `string` — catalog_id + +
+
+ +
+
+ +**requestOptions:** `CatalogsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.catalogs.addCreditBundle(catalog_id, credit_bundle_id) -> void +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.catalogs.addCreditBundle("catalog_id", "credit_bundle_id"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**catalog_id:** `string` — catalog_id + +
+
+ +
+
+ +**credit_bundle_id:** `string` — credit_bundle_id + +
+
+ +
+
+ +**requestOptions:** `CatalogsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.catalogs.removeCreditBundle(catalog_id, credit_bundle_id) -> void +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.catalogs.removeCreditBundle("catalog_id", "credit_bundle_id"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**catalog_id:** `string` — catalog_id + +
+
+ +
+
+ +**credit_bundle_id:** `string` — credit_bundle_id + +
+
+ +
+
+ +**requestOptions:** `CatalogsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.catalogs.getDerivedFeatures(catalog_id) -> Schematic.GetDerivedFeaturesResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.catalogs.getDerivedFeatures("catalog_id"); ```
@@ -11008,7 +11443,170 @@ await client.events.createEventBatch({
-
client.events.getEventSummaries({ ...params }) -> Schematic.GetEventSummariesResponse +
client.events.getEventSummaries({ ...params }) -> Schematic.GetEventSummariesResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.events.getEventSummaries({ + q: "q", + eventSubtypes: ["event_subtypes"], + limit: 1000000, + offset: 1000000 +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Schematic.GetEventSummariesRequest` + +
+
+ +
+
+ +**requestOptions:** `EventsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.events.listEvents({ ...params }) -> Schematic.ListEventsResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.events.listEvents({ + companyId: "company_id", + eventSubtype: "event_subtype", + eventTypes: ["flag_check"], + flagId: "flag_id", + idempotencyKey: "idempotency_key", + userId: "user_id", + limit: 1000000, + offset: 1000000 +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Schematic.ListEventsRequest` + +
+
+ +
+
+ +**requestOptions:** `EventsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.events.createEvent({ ...params }) -> Schematic.CreateEventResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.events.createEvent({ + eventType: "flag_check" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Schematic.CreateEventRequestBody` + +
+
+ +
+
+ +**requestOptions:** `EventsClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.events.getEvent(event_id) -> Schematic.GetEventResponse
@@ -11021,12 +11619,7 @@ await client.events.createEventBatch({
```typescript -await client.events.getEventSummaries({ - q: "q", - eventSubtypes: ["event_subtypes"], - limit: 1000000, - offset: 1000000 -}); +await client.events.getEvent("event_id"); ```
@@ -11042,7 +11635,7 @@ await client.events.getEventSummaries({
-**request:** `Schematic.GetEventSummariesRequest` +**event_id:** `string` — event_id
@@ -11062,7 +11655,7 @@ await client.events.getEventSummaries({
-
client.events.listEvents({ ...params }) -> Schematic.ListEventsResponse +
client.events.getOtlpEnvironmentSettings() -> Schematic.GetOtlpEnvironmentSettingsResponse
@@ -11075,16 +11668,7 @@ await client.events.getEventSummaries({
```typescript -await client.events.listEvents({ - companyId: "company_id", - eventSubtype: "event_subtype", - eventTypes: ["flag_check"], - flagId: "flag_id", - idempotencyKey: "idempotency_key", - userId: "user_id", - limit: 1000000, - offset: 1000000 -}); +await client.events.getOtlpEnvironmentSettings(); ```
@@ -11100,14 +11684,6 @@ await client.events.listEvents({
-**request:** `Schematic.ListEventsRequest` - -
-
- -
-
- **requestOptions:** `EventsClient.RequestOptions`
@@ -11120,7 +11696,7 @@ await client.events.listEvents({
-
client.events.createEvent({ ...params }) -> Schematic.CreateEventResponse +
client.events.upsertOtlpEnvironmentSettings({ ...params }) -> Schematic.UpsertOtlpEnvironmentSettingsResponse
@@ -11133,8 +11709,8 @@ await client.events.listEvents({
```typescript -await client.events.createEvent({ - eventType: "flag_check" +await client.events.upsertOtlpEnvironmentSettings({ + toolEventsEnabled: true }); ``` @@ -11151,7 +11727,7 @@ await client.events.createEvent({
-**request:** `Schematic.CreateEventRequestBody` +**request:** `Schematic.UpsertOtlpEnvironmentSettingsRequestBody`
@@ -11171,7 +11747,7 @@ await client.events.createEvent({
-
client.events.getEvent(event_id) -> Schematic.GetEventResponse +
client.events.deleteOtlpEnvironmentSettings() -> Schematic.DeleteOtlpEnvironmentSettingsResponse
@@ -11184,7 +11760,7 @@ await client.events.createEvent({
```typescript -await client.events.getEvent("event_id"); +await client.events.deleteOtlpEnvironmentSettings(); ```
@@ -11200,14 +11776,6 @@ await client.events.getEvent("event_id");
-**event_id:** `string` — event_id - -
-
- -
-
- **requestOptions:** `EventsClient.RequestOptions`
@@ -12803,6 +13371,139 @@ await client.integrationsapi.loadSampleDataSet();
+ +
+
+ +
client.integrationsapi.getStripeSandboxClaimLink() -> Schematic.GetStripeSandboxClaimLinkResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.integrationsapi.getStripeSandboxClaimLink(); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**requestOptions:** `IntegrationsapiClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.integrationsapi.getStripeSandboxKeys() -> Schematic.GetStripeSandboxKeysResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.integrationsapi.getStripeSandboxKeys(); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**requestOptions:** `IntegrationsapiClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.integrationsapi.claimStripeSandboxKeys({ ...params }) -> Schematic.ClaimStripeSandboxKeysResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.integrationsapi.claimStripeSandboxKeys({ + token: "token" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Schematic.ClaimStripeSandboxKeysRequestBody` + +
+
+ +
+
+ +**requestOptions:** `IntegrationsapiClient.RequestOptions` + +
+
+
+
+ +
@@ -12905,6 +13606,98 @@ await client.integrationsapi.installStripe({ + + +
+ +
client.integrationsapi.installStripeClaimableSandbox({ ...params }) -> Schematic.InstallStripeClaimableSandboxResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.integrationsapi.installStripeClaimableSandbox({ + email: "email" +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Schematic.InstallStripeSandboxRequestBody` + +
+
+ +
+
+ +**requestOptions:** `IntegrationsapiClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.integrationsapi.listStripeSandboxCountries() -> Schematic.ListStripeSandboxCountriesResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.integrationsapi.listStripeSandboxCountries(); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**requestOptions:** `IntegrationsapiClient.RequestOptions` + +
+
+
+
+ +
diff --git a/src/BaseClient.ts b/src/BaseClient.ts index 243ba69d..906e05ac 100644 --- a/src/BaseClient.ts +++ b/src/BaseClient.ts @@ -66,8 +66,8 @@ export function normalizeClientOptions { + return core.HttpResponsePromise.fromPromise(this.__listCompanyBillingProfiles(request, requestOptions)); + } + + private async __listCompanyBillingProfiles( + request: Schematic.ListCompanyBillingProfilesRequest = {}, + requestOptions?: BillingClient.RequestOptions, + ): Promise> { + const { companyId, isDefault, providerType, limit, offset } = request; + const _queryParams: Record = { + company_id: companyId, + is_default: isDefault, + provider_type: + providerType != null + ? serializers.BillingProviderType.jsonOrThrow(providerType, { unrecognizedObjectKeys: "strip" }) + : undefined, + limit, + offset, + }; + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + "billing/profiles", + ), + method: "GET", + headers: _headers, + queryString: core.url + .queryBuilder() + .addMany(_queryParams) + .mergeAdditional(requestOptions?.queryParams) + .build(), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.ListCompanyBillingProfilesResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Schematic.BadRequestError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/billing/profiles"); + } + + /** + * @param {string} billing_profile_id - billing_profile_id + * @param {Schematic.UpdateCompanyBillingProfileRequestBody} request + * @param {BillingClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.BadRequestError} + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.billing.updateCompanyBillingProfile("billing_profile_id", { + * collectionMethod: "charge_automatically" + * }) + */ + public updateCompanyBillingProfile( + billing_profile_id: string, + request: Schematic.UpdateCompanyBillingProfileRequestBody, + requestOptions?: BillingClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise( + this.__updateCompanyBillingProfile(billing_profile_id, request, requestOptions), + ); + } + + private async __updateCompanyBillingProfile( + billing_profile_id: string, + request: Schematic.UpdateCompanyBillingProfileRequestBody, + requestOptions?: BillingClient.RequestOptions, + ): Promise> { + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + `billing/profiles/${core.url.encodePathParam(billing_profile_id)}`, + ), + method: "PUT", + headers: _headers, + contentType: "application/json", + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + requestType: "json", + body: mergeAdditionalBodyParameters( + serializers.UpdateCompanyBillingProfileRequestBody.jsonOrThrow(request, { + unrecognizedObjectKeys: "strip", + }), + requestOptions?.additionalBodyParameters, + ), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.UpdateCompanyBillingProfileResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Schematic.BadRequestError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError( + _response.error, + _response.rawResponse, + "PUT", + "/billing/profiles/{billing_profile_id}", + ); + } + /** * @param {Schematic.CreateBillingSubscriptionRequestBody} request * @param {BillingClient.RequestOptions} requestOptions - Request-specific configuration. diff --git a/src/api/resources/billing/client/requests/ListCompanyBillingProfilesRequest.ts b/src/api/resources/billing/client/requests/ListCompanyBillingProfilesRequest.ts new file mode 100644 index 00000000..56e8f42c --- /dev/null +++ b/src/api/resources/billing/client/requests/ListCompanyBillingProfilesRequest.ts @@ -0,0 +1,23 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../index"; + +/** + * @example + * { + * companyId: "company_id", + * isDefault: true, + * providerType: "metronome", + * limit: 1000000, + * offset: 1000000 + * } + */ +export interface ListCompanyBillingProfilesRequest { + companyId?: string; + isDefault?: boolean; + providerType?: Schematic.BillingProviderType; + /** Page limit (default 100) */ + limit?: number; + /** Page offset (default 0) */ + offset?: number; +} diff --git a/src/api/resources/billing/client/requests/UpdateCompanyBillingProfileRequestBody.ts b/src/api/resources/billing/client/requests/UpdateCompanyBillingProfileRequestBody.ts new file mode 100644 index 00000000..690249ec --- /dev/null +++ b/src/api/resources/billing/client/requests/UpdateCompanyBillingProfileRequestBody.ts @@ -0,0 +1,18 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../index"; + +/** + * @example + * { + * collectionMethod: "charge_automatically" + * } + */ +export interface UpdateCompanyBillingProfileRequestBody { + collectionMethod: Schematic.BillingCollectionMethod; + daysUntilDue?: number; + isDefault?: boolean; + name?: string; + paymentMethodId?: string; + prorationBehavior?: Schematic.ProrationBehavior; +} diff --git a/src/api/resources/billing/client/requests/index.ts b/src/api/resources/billing/client/requests/index.ts index fc3aa928..9ebade65 100644 --- a/src/api/resources/billing/client/requests/index.ts +++ b/src/api/resources/billing/client/requests/index.ts @@ -11,8 +11,10 @@ export type { CreatePaymentMethodRequestBody } from "./CreatePaymentMethodReques export type { ListBillingPricesRequest } from "./ListBillingPricesRequest"; export type { ListBillingProductPricesRequest } from "./ListBillingProductPricesRequest"; export type { ListBillingProductsRequest } from "./ListBillingProductsRequest"; +export type { ListCompanyBillingProfilesRequest } from "./ListCompanyBillingProfilesRequest"; export type { ListCouponsRequest } from "./ListCouponsRequest"; export type { ListCustomersWithSubscriptionsRequest } from "./ListCustomersWithSubscriptionsRequest"; export type { ListInvoicesRequest } from "./ListInvoicesRequest"; export type { ListMetersRequest } from "./ListMetersRequest"; export type { ListPaymentMethodsRequest } from "./ListPaymentMethodsRequest"; +export type { UpdateCompanyBillingProfileRequestBody } from "./UpdateCompanyBillingProfileRequestBody"; diff --git a/src/api/resources/billing/types/ListCompanyBillingProfilesParams.ts b/src/api/resources/billing/types/ListCompanyBillingProfilesParams.ts new file mode 100644 index 00000000..b17a1b1a --- /dev/null +++ b/src/api/resources/billing/types/ListCompanyBillingProfilesParams.ts @@ -0,0 +1,16 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +/** + * Input parameters + */ +export interface ListCompanyBillingProfilesParams { + companyId?: string; + isDefault?: boolean; + /** Page limit (default 100) */ + limit?: number; + /** Page offset (default 0) */ + offset?: number; + providerType?: Schematic.BillingProviderType; +} diff --git a/src/api/resources/billing/types/ListCompanyBillingProfilesResponse.ts b/src/api/resources/billing/types/ListCompanyBillingProfilesResponse.ts new file mode 100644 index 00000000..63ae1bab --- /dev/null +++ b/src/api/resources/billing/types/ListCompanyBillingProfilesResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface ListCompanyBillingProfilesResponse { + data: Schematic.CompanyBillingProfileResponseData[]; + /** Input parameters */ + params: Schematic.ListCompanyBillingProfilesParams; +} diff --git a/src/api/resources/billing/types/UpdateCompanyBillingProfileResponse.ts b/src/api/resources/billing/types/UpdateCompanyBillingProfileResponse.ts new file mode 100644 index 00000000..c047c38b --- /dev/null +++ b/src/api/resources/billing/types/UpdateCompanyBillingProfileResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface UpdateCompanyBillingProfileResponse { + data: Schematic.CompanyBillingProfileResponseData; + /** Input parameters */ + params: Record; +} diff --git a/src/api/resources/billing/types/index.ts b/src/api/resources/billing/types/index.ts index 7e9332c9..5fa2d7b3 100644 --- a/src/api/resources/billing/types/index.ts +++ b/src/api/resources/billing/types/index.ts @@ -14,6 +14,8 @@ export * from "./ListBillingProductPricesParams"; export * from "./ListBillingProductPricesResponse"; export * from "./ListBillingProductsParams"; export * from "./ListBillingProductsResponse"; +export * from "./ListCompanyBillingProfilesParams"; +export * from "./ListCompanyBillingProfilesResponse"; export * from "./ListCouponsParams"; export * from "./ListCouponsResponse"; export * from "./ListCustomersWithSubscriptionsParams"; @@ -24,6 +26,7 @@ export * from "./ListMetersParams"; export * from "./ListMetersResponse"; export * from "./ListPaymentMethodsParams"; export * from "./ListPaymentMethodsResponse"; +export * from "./UpdateCompanyBillingProfileResponse"; export * from "./UpsertBillingCouponResponse"; export * from "./UpsertBillingCustomerResponse"; export * from "./UpsertBillingMeterResponse"; diff --git a/src/api/resources/credits/client/Client.ts b/src/api/resources/credits/client/Client.ts index 7428e3ad..53f1f50a 100644 --- a/src/api/resources/credits/client/Client.ts +++ b/src/api/resources/credits/client/Client.ts @@ -2764,6 +2764,7 @@ export class CreditsClient { * * @throws {@link Schematic.BadRequestError} * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.PaymentRequiredError} * @throws {@link Schematic.ForbiddenError} * @throws {@link Schematic.NotFoundError} * @throws {@link Schematic.InternalServerError} @@ -2853,6 +2854,17 @@ export class CreditsClient { }), _response.rawResponse, ); + case 402: + throw new Schematic.PaymentRequiredError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); case 403: throw new Schematic.ForbiddenError( serializers.ApiError.parseOrThrow(_response.error.body, { @@ -2905,6 +2917,7 @@ export class CreditsClient { * * @throws {@link Schematic.BadRequestError} * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.PaymentRequiredError} * @throws {@link Schematic.ForbiddenError} * @throws {@link Schematic.NotFoundError} * @throws {@link Schematic.InternalServerError} @@ -2994,6 +3007,17 @@ export class CreditsClient { }), _response.rawResponse, ); + case 402: + throw new Schematic.PaymentRequiredError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); case 403: throw new Schematic.ForbiddenError( serializers.ApiError.parseOrThrow(_response.error.body, { @@ -4073,6 +4097,878 @@ export class CreditsClient { ); } + /** + * @param {Schematic.ListCreditSpendPoliciesRequest} request + * @param {CreditsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.BadRequestError} + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.credits.listCreditSpendPolicies({ + * billingCreditId: "billing_credit_id", + * companyId: "company_id", + * scopeType: "company", + * userId: "user_id", + * userIds: ["user_ids"], + * limit: 1000000, + * offset: 1000000 + * }) + */ + public listCreditSpendPolicies( + request: Schematic.ListCreditSpendPoliciesRequest = {}, + requestOptions?: CreditsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__listCreditSpendPolicies(request, requestOptions)); + } + + private async __listCreditSpendPolicies( + request: Schematic.ListCreditSpendPoliciesRequest = {}, + requestOptions?: CreditsClient.RequestOptions, + ): Promise> { + const { billingCreditId, companyId, scopeType, userId, userIds, limit, offset } = request; + const _queryParams: Record = { + billing_credit_id: billingCreditId, + company_id: companyId, + scope_type: + scopeType != null + ? serializers.CreditSpendPolicyScope.jsonOrThrow(scopeType, { unrecognizedObjectKeys: "strip" }) + : undefined, + user_id: userId, + user_ids: userIds, + limit, + offset, + }; + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + "billing/credits/spend-policies", + ), + method: "GET", + headers: _headers, + queryString: core.url + .queryBuilder() + .addMany(_queryParams) + .mergeAdditional(requestOptions?.queryParams) + .build(), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.ListCreditSpendPoliciesResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Schematic.BadRequestError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError( + _response.error, + _response.rawResponse, + "GET", + "/billing/credits/spend-policies", + ); + } + + /** + * @param {Schematic.CreateCreditSpendPolicyRequestBody} request + * @param {CreditsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.BadRequestError} + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.credits.createCreditSpendPolicy({ + * billingCreditId: "billing_credit_id", + * maxPerDraw: 1.1 + * }) + */ + public createCreditSpendPolicy( + request: Schematic.CreateCreditSpendPolicyRequestBody, + requestOptions?: CreditsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__createCreditSpendPolicy(request, requestOptions)); + } + + private async __createCreditSpendPolicy( + request: Schematic.CreateCreditSpendPolicyRequestBody, + requestOptions?: CreditsClient.RequestOptions, + ): Promise> { + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + "billing/credits/spend-policies", + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + requestType: "json", + body: mergeAdditionalBodyParameters( + serializers.CreateCreditSpendPolicyRequestBody.jsonOrThrow(request, { + unrecognizedObjectKeys: "strip", + }), + requestOptions?.additionalBodyParameters, + ), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.CreateCreditSpendPolicyResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Schematic.BadRequestError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError( + _response.error, + _response.rawResponse, + "POST", + "/billing/credits/spend-policies", + ); + } + + /** + * @param {string} spend_policy_id - spend_policy_id + * @param {CreditsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.credits.getCreditSpendPolicy("spend_policy_id") + */ + public getCreditSpendPolicy( + spend_policy_id: string, + requestOptions?: CreditsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__getCreditSpendPolicy(spend_policy_id, requestOptions)); + } + + private async __getCreditSpendPolicy( + spend_policy_id: string, + requestOptions?: CreditsClient.RequestOptions, + ): Promise> { + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + `billing/credits/spend-policies/${core.url.encodePathParam(spend_policy_id)}`, + ), + method: "GET", + headers: _headers, + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.GetCreditSpendPolicyResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError( + _response.error, + _response.rawResponse, + "GET", + "/billing/credits/spend-policies/{spend_policy_id}", + ); + } + + /** + * @param {string} spend_policy_id - spend_policy_id + * @param {Schematic.UpdateCreditSpendPolicyRequestBody} request + * @param {CreditsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.BadRequestError} + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.credits.updateCreditSpendPolicy("spend_policy_id") + */ + public updateCreditSpendPolicy( + spend_policy_id: string, + request: Schematic.UpdateCreditSpendPolicyRequestBody = {}, + requestOptions?: CreditsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise( + this.__updateCreditSpendPolicy(spend_policy_id, request, requestOptions), + ); + } + + private async __updateCreditSpendPolicy( + spend_policy_id: string, + request: Schematic.UpdateCreditSpendPolicyRequestBody = {}, + requestOptions?: CreditsClient.RequestOptions, + ): Promise> { + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + `billing/credits/spend-policies/${core.url.encodePathParam(spend_policy_id)}`, + ), + method: "PUT", + headers: _headers, + contentType: "application/json", + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + requestType: "json", + body: mergeAdditionalBodyParameters( + serializers.UpdateCreditSpendPolicyRequestBody.jsonOrThrow(request, { + unrecognizedObjectKeys: "strip", + }), + requestOptions?.additionalBodyParameters, + ), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.UpdateCreditSpendPolicyResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Schematic.BadRequestError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError( + _response.error, + _response.rawResponse, + "PUT", + "/billing/credits/spend-policies/{spend_policy_id}", + ); + } + + /** + * @param {string} spend_policy_id - spend_policy_id + * @param {CreditsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.BadRequestError} + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.credits.deleteCreditSpendPolicy("spend_policy_id") + */ + public deleteCreditSpendPolicy( + spend_policy_id: string, + requestOptions?: CreditsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__deleteCreditSpendPolicy(spend_policy_id, requestOptions)); + } + + private async __deleteCreditSpendPolicy( + spend_policy_id: string, + requestOptions?: CreditsClient.RequestOptions, + ): Promise> { + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + `billing/credits/spend-policies/${core.url.encodePathParam(spend_policy_id)}`, + ), + method: "DELETE", + headers: _headers, + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.DeleteCreditSpendPolicyResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Schematic.BadRequestError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError( + _response.error, + _response.rawResponse, + "DELETE", + "/billing/credits/spend-policies/{spend_policy_id}", + ); + } + + /** + * @param {Schematic.CountCreditSpendPoliciesRequest} request + * @param {CreditsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.BadRequestError} + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.credits.countCreditSpendPolicies({ + * billingCreditId: "billing_credit_id", + * companyId: "company_id", + * scopeType: "company", + * userId: "user_id", + * userIds: ["user_ids"], + * limit: 1000000, + * offset: 1000000 + * }) + */ + public countCreditSpendPolicies( + request: Schematic.CountCreditSpendPoliciesRequest = {}, + requestOptions?: CreditsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__countCreditSpendPolicies(request, requestOptions)); + } + + private async __countCreditSpendPolicies( + request: Schematic.CountCreditSpendPoliciesRequest = {}, + requestOptions?: CreditsClient.RequestOptions, + ): Promise> { + const { billingCreditId, companyId, scopeType, userId, userIds, limit, offset } = request; + const _queryParams: Record = { + billing_credit_id: billingCreditId, + company_id: companyId, + scope_type: + scopeType != null + ? serializers.CreditSpendPolicyScope.jsonOrThrow(scopeType, { unrecognizedObjectKeys: "strip" }) + : undefined, + user_id: userId, + user_ids: userIds, + limit, + offset, + }; + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + "billing/credits/spend-policies/count", + ), + method: "GET", + headers: _headers, + queryString: core.url + .queryBuilder() + .addMany(_queryParams) + .mergeAdditional(requestOptions?.queryParams) + .build(), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.CountCreditSpendPoliciesResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Schematic.BadRequestError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError( + _response.error, + _response.rawResponse, + "GET", + "/billing/credits/spend-policies/count", + ); + } + /** * @param {Schematic.ListCreditEventLedgerRequest} request * @param {CreditsClient.RequestOptions} requestOptions - Request-specific configuration. diff --git a/src/api/resources/credits/client/requests/CountCreditSpendPoliciesRequest.ts b/src/api/resources/credits/client/requests/CountCreditSpendPoliciesRequest.ts new file mode 100644 index 00000000..82a6de7d --- /dev/null +++ b/src/api/resources/credits/client/requests/CountCreditSpendPoliciesRequest.ts @@ -0,0 +1,27 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../index"; + +/** + * @example + * { + * billingCreditId: "billing_credit_id", + * companyId: "company_id", + * scopeType: "company", + * userId: "user_id", + * userIds: ["user_ids"], + * limit: 1000000, + * offset: 1000000 + * } + */ +export interface CountCreditSpendPoliciesRequest { + billingCreditId?: string; + companyId?: string; + scopeType?: Schematic.CreditSpendPolicyScope; + userId?: string; + userIds?: string | string[]; + /** Page limit (default 100) */ + limit?: number; + /** Page offset (default 0) */ + offset?: number; +} diff --git a/src/api/resources/credits/client/requests/CreateCreditSpendPolicyRequestBody.ts b/src/api/resources/credits/client/requests/CreateCreditSpendPolicyRequestBody.ts new file mode 100644 index 00000000..60a28c83 --- /dev/null +++ b/src/api/resources/credits/client/requests/CreateCreditSpendPolicyRequestBody.ts @@ -0,0 +1,19 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * { + * billingCreditId: "billing_credit_id", + * maxPerDraw: 1.1 + * } + */ +export interface CreateCreditSpendPolicyRequestBody { + billingCreditId: string; + /** The company the cap applies to. Set exactly one of company_id and user_id. */ + companyId?: string; + label?: string; + /** The largest number of credits a single draw may spend. */ + maxPerDraw: number; + /** The user the cap applies to. Set exactly one of company_id and user_id. */ + userId?: string; +} diff --git a/src/api/resources/credits/client/requests/ListCreditSpendPoliciesRequest.ts b/src/api/resources/credits/client/requests/ListCreditSpendPoliciesRequest.ts new file mode 100644 index 00000000..19f11ae6 --- /dev/null +++ b/src/api/resources/credits/client/requests/ListCreditSpendPoliciesRequest.ts @@ -0,0 +1,27 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../index"; + +/** + * @example + * { + * billingCreditId: "billing_credit_id", + * companyId: "company_id", + * scopeType: "company", + * userId: "user_id", + * userIds: ["user_ids"], + * limit: 1000000, + * offset: 1000000 + * } + */ +export interface ListCreditSpendPoliciesRequest { + billingCreditId?: string; + companyId?: string; + scopeType?: Schematic.CreditSpendPolicyScope; + userId?: string; + userIds?: string | string[]; + /** Page limit (default 100) */ + limit?: number; + /** Page offset (default 0) */ + offset?: number; +} diff --git a/src/api/resources/credits/client/requests/UpdateCreditSpendPolicyRequestBody.ts b/src/api/resources/credits/client/requests/UpdateCreditSpendPolicyRequestBody.ts new file mode 100644 index 00000000..243af906 --- /dev/null +++ b/src/api/resources/credits/client/requests/UpdateCreditSpendPolicyRequestBody.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * {} + */ +export interface UpdateCreditSpendPolicyRequestBody { + label?: string; + maxPerDraw?: number; +} diff --git a/src/api/resources/credits/client/requests/index.ts b/src/api/resources/credits/client/requests/index.ts index 3c019166..3da0aed6 100644 --- a/src/api/resources/credits/client/requests/index.ts +++ b/src/api/resources/credits/client/requests/index.ts @@ -5,9 +5,11 @@ export type { CountBillingPlanCreditGrantsRequest } from "./CountBillingPlanCred export type { CountCompanyGrantsRequest } from "./CountCompanyGrantsRequest"; export type { CountCreditBundlesRequest } from "./CountCreditBundlesRequest"; export type { CountCreditEventLedgerRequest } from "./CountCreditEventLedgerRequest"; +export type { CountCreditSpendPoliciesRequest } from "./CountCreditSpendPoliciesRequest"; export type { CreateBillingCreditRequestBody } from "./CreateBillingCreditRequestBody"; export type { CreateCompanyCreditGrant } from "./CreateCompanyCreditGrant"; export type { CreateCreditBundleRequestBody } from "./CreateCreditBundleRequestBody"; +export type { CreateCreditSpendPolicyRequestBody } from "./CreateCreditSpendPolicyRequestBody"; export type { DeleteBillingPlanCreditGrantRequest } from "./DeleteBillingPlanCreditGrantRequest"; export type { ExtendCreditLeaseRequestBody } from "./ExtendCreditLeaseRequestBody"; export type { ListBillingCreditsRequest } from "./ListBillingCreditsRequest"; @@ -16,7 +18,9 @@ export type { ListCompanyCreditBalancesRequest } from "./ListCompanyCreditBalanc export type { ListCompanyGrantsRequest } from "./ListCompanyGrantsRequest"; export type { ListCreditBundlesRequest } from "./ListCreditBundlesRequest"; export type { ListCreditEventLedgerRequest } from "./ListCreditEventLedgerRequest"; +export type { ListCreditSpendPoliciesRequest } from "./ListCreditSpendPoliciesRequest"; export type { ListGrantsForCreditRequest } from "./ListGrantsForCreditRequest"; export type { UpdateBillingCreditRequestBody } from "./UpdateBillingCreditRequestBody"; export type { UpdateCreditBundleDetailsRequestBody } from "./UpdateCreditBundleDetailsRequestBody"; +export type { UpdateCreditSpendPolicyRequestBody } from "./UpdateCreditSpendPolicyRequestBody"; export type { ZeroOutGrantRequestBody } from "./ZeroOutGrantRequestBody"; diff --git a/src/api/resources/credits/types/CountCreditSpendPoliciesParams.ts b/src/api/resources/credits/types/CountCreditSpendPoliciesParams.ts new file mode 100644 index 00000000..f69267d2 --- /dev/null +++ b/src/api/resources/credits/types/CountCreditSpendPoliciesParams.ts @@ -0,0 +1,18 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +/** + * Input parameters + */ +export interface CountCreditSpendPoliciesParams { + billingCreditId?: string; + companyId?: string; + /** Page limit (default 100) */ + limit?: number; + /** Page offset (default 0) */ + offset?: number; + scopeType?: Schematic.CreditSpendPolicyScope; + userId?: string; + userIds?: string[]; +} diff --git a/src/api/resources/credits/types/CountCreditSpendPoliciesResponse.ts b/src/api/resources/credits/types/CountCreditSpendPoliciesResponse.ts new file mode 100644 index 00000000..7fc50bdc --- /dev/null +++ b/src/api/resources/credits/types/CountCreditSpendPoliciesResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface CountCreditSpendPoliciesResponse { + data: Schematic.CountResponse; + /** Input parameters */ + params: Schematic.CountCreditSpendPoliciesParams; +} diff --git a/src/api/resources/credits/types/CreateCreditSpendPolicyResponse.ts b/src/api/resources/credits/types/CreateCreditSpendPolicyResponse.ts new file mode 100644 index 00000000..f7f21416 --- /dev/null +++ b/src/api/resources/credits/types/CreateCreditSpendPolicyResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface CreateCreditSpendPolicyResponse { + data: Schematic.CreditSpendPolicyResponseData; + /** Input parameters */ + params: Record; +} diff --git a/src/api/resources/credits/types/DeleteCreditSpendPolicyResponse.ts b/src/api/resources/credits/types/DeleteCreditSpendPolicyResponse.ts new file mode 100644 index 00000000..4ae4b8e4 --- /dev/null +++ b/src/api/resources/credits/types/DeleteCreditSpendPolicyResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface DeleteCreditSpendPolicyResponse { + data: Schematic.DeleteResponse; + /** Input parameters */ + params: Record; +} diff --git a/src/api/resources/credits/types/GetCreditSpendPolicyResponse.ts b/src/api/resources/credits/types/GetCreditSpendPolicyResponse.ts new file mode 100644 index 00000000..f03ff954 --- /dev/null +++ b/src/api/resources/credits/types/GetCreditSpendPolicyResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface GetCreditSpendPolicyResponse { + data: Schematic.CreditSpendPolicyResponseData; + /** Input parameters */ + params: Record; +} diff --git a/src/api/resources/credits/types/ListCreditSpendPoliciesParams.ts b/src/api/resources/credits/types/ListCreditSpendPoliciesParams.ts new file mode 100644 index 00000000..862184b3 --- /dev/null +++ b/src/api/resources/credits/types/ListCreditSpendPoliciesParams.ts @@ -0,0 +1,18 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +/** + * Input parameters + */ +export interface ListCreditSpendPoliciesParams { + billingCreditId?: string; + companyId?: string; + /** Page limit (default 100) */ + limit?: number; + /** Page offset (default 0) */ + offset?: number; + scopeType?: Schematic.CreditSpendPolicyScope; + userId?: string; + userIds?: string[]; +} diff --git a/src/api/resources/credits/types/ListCreditSpendPoliciesResponse.ts b/src/api/resources/credits/types/ListCreditSpendPoliciesResponse.ts new file mode 100644 index 00000000..2b91160b --- /dev/null +++ b/src/api/resources/credits/types/ListCreditSpendPoliciesResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface ListCreditSpendPoliciesResponse { + data: Schematic.CreditSpendPolicyResponseData[]; + /** Input parameters */ + params: Schematic.ListCreditSpendPoliciesParams; +} diff --git a/src/api/resources/credits/types/UpdateCreditSpendPolicyResponse.ts b/src/api/resources/credits/types/UpdateCreditSpendPolicyResponse.ts new file mode 100644 index 00000000..1b3e908c --- /dev/null +++ b/src/api/resources/credits/types/UpdateCreditSpendPolicyResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface UpdateCreditSpendPolicyResponse { + data: Schematic.CreditSpendPolicyResponseData; + /** Input parameters */ + params: Record; +} diff --git a/src/api/resources/credits/types/index.ts b/src/api/resources/credits/types/index.ts index 2e92a33a..f55d471c 100644 --- a/src/api/resources/credits/types/index.ts +++ b/src/api/resources/credits/types/index.ts @@ -11,14 +11,19 @@ export * from "./CountCreditBundlesParams"; export * from "./CountCreditBundlesResponse"; export * from "./CountCreditEventLedgerParams"; export * from "./CountCreditEventLedgerResponse"; +export * from "./CountCreditSpendPoliciesParams"; +export * from "./CountCreditSpendPoliciesResponse"; export * from "./CreateBillingCreditResponse"; export * from "./CreateBillingPlanCreditGrantResponse"; export * from "./CreateCreditBundleResponse"; +export * from "./CreateCreditSpendPolicyResponse"; export * from "./DeleteBillingPlanCreditGrantParams"; export * from "./DeleteBillingPlanCreditGrantResponse"; export * from "./DeleteCreditBundleResponse"; +export * from "./DeleteCreditSpendPolicyResponse"; export * from "./ExtendCreditLeaseResponse"; export * from "./GetCreditBundleResponse"; +export * from "./GetCreditSpendPolicyResponse"; export * from "./GetSingleBillingCreditResponse"; export * from "./GetSingleBillingPlanCreditGrantResponse"; export * from "./GrantBillingCreditsToCompanyResponse"; @@ -34,6 +39,8 @@ export * from "./ListCreditBundlesParams"; export * from "./ListCreditBundlesResponse"; export * from "./ListCreditEventLedgerParams"; export * from "./ListCreditEventLedgerResponse"; +export * from "./ListCreditSpendPoliciesParams"; +export * from "./ListCreditSpendPoliciesResponse"; export * from "./ListGrantsForCreditParams"; export * from "./ListGrantsForCreditResponse"; export * from "./ReleaseCreditLeaseResponse"; @@ -41,4 +48,5 @@ export * from "./SoftDeleteBillingCreditResponse"; export * from "./UpdateBillingCreditResponse"; export * from "./UpdateBillingPlanCreditGrantResponse"; export * from "./UpdateCreditBundleDetailsResponse"; +export * from "./UpdateCreditSpendPolicyResponse"; export * from "./ZeroOutGrantResponse"; diff --git a/src/api/resources/events/client/Client.ts b/src/api/resources/events/client/Client.ts index 8ab61512..71a9bccd 100644 --- a/src/api/resources/events/client/Client.ts +++ b/src/api/resources/events/client/Client.ts @@ -724,6 +724,388 @@ export class EventsClient { return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/events/{event_id}"); } + /** + * @param {EventsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.events.getOtlpEnvironmentSettings() + */ + public getOtlpEnvironmentSettings( + requestOptions?: EventsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__getOtlpEnvironmentSettings(requestOptions)); + } + + private async __getOtlpEnvironmentSettings( + requestOptions?: EventsClient.RequestOptions, + ): Promise> { + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + "otlp/settings", + ), + method: "GET", + headers: _headers, + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.GetOtlpEnvironmentSettingsResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/otlp/settings"); + } + + /** + * @param {Schematic.UpsertOtlpEnvironmentSettingsRequestBody} request + * @param {EventsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.BadRequestError} + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.events.upsertOtlpEnvironmentSettings({ + * toolEventsEnabled: true + * }) + */ + public upsertOtlpEnvironmentSettings( + request: Schematic.UpsertOtlpEnvironmentSettingsRequestBody, + requestOptions?: EventsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__upsertOtlpEnvironmentSettings(request, requestOptions)); + } + + private async __upsertOtlpEnvironmentSettings( + request: Schematic.UpsertOtlpEnvironmentSettingsRequestBody, + requestOptions?: EventsClient.RequestOptions, + ): Promise> { + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + "otlp/settings", + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + requestType: "json", + body: mergeAdditionalBodyParameters( + serializers.UpsertOtlpEnvironmentSettingsRequestBody.jsonOrThrow(request, { + unrecognizedObjectKeys: "strip", + }), + requestOptions?.additionalBodyParameters, + ), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.UpsertOtlpEnvironmentSettingsResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Schematic.BadRequestError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/otlp/settings"); + } + + /** + * @param {EventsClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.BadRequestError} + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.events.deleteOtlpEnvironmentSettings() + */ + public deleteOtlpEnvironmentSettings( + requestOptions?: EventsClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__deleteOtlpEnvironmentSettings(requestOptions)); + } + + private async __deleteOtlpEnvironmentSettings( + requestOptions?: EventsClient.RequestOptions, + ): Promise> { + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + "otlp/settings", + ), + method: "DELETE", + headers: _headers, + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.DeleteOtlpEnvironmentSettingsResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Schematic.BadRequestError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError(_response.error, _response.rawResponse, "DELETE", "/otlp/settings"); + } + /** * @param {EventsClient.RequestOptions} requestOptions - Request-specific configuration. * diff --git a/src/api/resources/events/client/requests/UpsertOtlpEnvironmentSettingsRequestBody.ts b/src/api/resources/events/client/requests/UpsertOtlpEnvironmentSettingsRequestBody.ts new file mode 100644 index 00000000..1e19c220 --- /dev/null +++ b/src/api/resources/events/client/requests/UpsertOtlpEnvironmentSettingsRequestBody.ts @@ -0,0 +1,15 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * { + * toolEventsEnabled: true + * } + */ +export interface UpsertOtlpEnvironmentSettingsRequestBody { + companyAttribute?: string; + companyKey?: string; + toolEventsEnabled: boolean; + userAttribute?: string; + userKey?: string; +} diff --git a/src/api/resources/events/client/requests/index.ts b/src/api/resources/events/client/requests/index.ts index 5a36c08e..2a53be06 100644 --- a/src/api/resources/events/client/requests/index.ts +++ b/src/api/resources/events/client/requests/index.ts @@ -1,3 +1,4 @@ export type { CreateEventBatchRequestBody } from "./CreateEventBatchRequestBody"; export type { GetEventSummariesRequest } from "./GetEventSummariesRequest"; export type { ListEventsRequest } from "./ListEventsRequest"; +export type { UpsertOtlpEnvironmentSettingsRequestBody } from "./UpsertOtlpEnvironmentSettingsRequestBody"; diff --git a/src/api/resources/events/types/DeleteOtlpEnvironmentSettingsResponse.ts b/src/api/resources/events/types/DeleteOtlpEnvironmentSettingsResponse.ts new file mode 100644 index 00000000..329f8016 --- /dev/null +++ b/src/api/resources/events/types/DeleteOtlpEnvironmentSettingsResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface DeleteOtlpEnvironmentSettingsResponse { + data: Schematic.DeleteResponse; + /** Input parameters */ + params: Record; +} diff --git a/src/api/resources/events/types/GetOtlpEnvironmentSettingsResponse.ts b/src/api/resources/events/types/GetOtlpEnvironmentSettingsResponse.ts new file mode 100644 index 00000000..91c48f48 --- /dev/null +++ b/src/api/resources/events/types/GetOtlpEnvironmentSettingsResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface GetOtlpEnvironmentSettingsResponse { + data: Schematic.OtlpEnvironmentSettingsResponseData; + /** Input parameters */ + params: Record; +} diff --git a/src/api/resources/events/types/UpsertOtlpEnvironmentSettingsResponse.ts b/src/api/resources/events/types/UpsertOtlpEnvironmentSettingsResponse.ts new file mode 100644 index 00000000..e7b47969 --- /dev/null +++ b/src/api/resources/events/types/UpsertOtlpEnvironmentSettingsResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface UpsertOtlpEnvironmentSettingsResponse { + data: Schematic.OtlpEnvironmentSettingsResponseData; + /** Input parameters */ + params: Record; +} diff --git a/src/api/resources/events/types/index.ts b/src/api/resources/events/types/index.ts index 421f16fb..3ed83d82 100644 --- a/src/api/resources/events/types/index.ts +++ b/src/api/resources/events/types/index.ts @@ -1,8 +1,11 @@ export * from "./CreateEventBatchResponse"; export * from "./CreateEventResponse"; +export * from "./DeleteOtlpEnvironmentSettingsResponse"; export * from "./GetEventResponse"; export * from "./GetEventSummariesParams"; export * from "./GetEventSummariesResponse"; +export * from "./GetOtlpEnvironmentSettingsResponse"; export * from "./GetSegmentIntegrationStatusResponse"; export * from "./ListEventsParams"; export * from "./ListEventsResponse"; +export * from "./UpsertOtlpEnvironmentSettingsResponse"; diff --git a/src/api/resources/integrationsapi/client/Client.ts b/src/api/resources/integrationsapi/client/Client.ts index 5143f235..e22d0317 100644 --- a/src/api/resources/integrationsapi/client/Client.ts +++ b/src/api/resources/integrationsapi/client/Client.ts @@ -829,6 +829,389 @@ export class IntegrationsapiClient { ); } + /** + * @param {IntegrationsapiClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.integrationsapi.getStripeSandboxClaimLink() + */ + public getStripeSandboxClaimLink( + requestOptions?: IntegrationsapiClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__getStripeSandboxClaimLink(requestOptions)); + } + + private async __getStripeSandboxClaimLink( + requestOptions?: IntegrationsapiClient.RequestOptions, + ): Promise> { + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + "integrations/stripe/sandbox/claim-link", + ), + method: "GET", + headers: _headers, + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.GetStripeSandboxClaimLinkResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError( + _response.error, + _response.rawResponse, + "GET", + "/integrations/stripe/sandbox/claim-link", + ); + } + + /** + * @param {IntegrationsapiClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.integrationsapi.getStripeSandboxKeys() + */ + public getStripeSandboxKeys( + requestOptions?: IntegrationsapiClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__getStripeSandboxKeys(requestOptions)); + } + + private async __getStripeSandboxKeys( + requestOptions?: IntegrationsapiClient.RequestOptions, + ): Promise> { + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + "integrations/stripe/sandbox/keys", + ), + method: "GET", + headers: _headers, + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.GetStripeSandboxKeysResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError( + _response.error, + _response.rawResponse, + "GET", + "/integrations/stripe/sandbox/keys", + ); + } + + /** + * @param {Schematic.ClaimStripeSandboxKeysRequestBody} request + * @param {IntegrationsapiClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.BadRequestError} + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.integrationsapi.claimStripeSandboxKeys({ + * token: "token" + * }) + */ + public claimStripeSandboxKeys( + request: Schematic.ClaimStripeSandboxKeysRequestBody, + requestOptions?: IntegrationsapiClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__claimStripeSandboxKeys(request, requestOptions)); + } + + private async __claimStripeSandboxKeys( + request: Schematic.ClaimStripeSandboxKeysRequestBody, + requestOptions?: IntegrationsapiClient.RequestOptions, + ): Promise> { + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + "integrations/stripe/sandbox/keys/claim", + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + requestType: "json", + body: mergeAdditionalBodyParameters( + serializers.ClaimStripeSandboxKeysRequestBody.jsonOrThrow(request, { unrecognizedObjectKeys: "strip" }), + requestOptions?.additionalBodyParameters, + ), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.ClaimStripeSandboxKeysResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Schematic.BadRequestError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError( + _response.error, + _response.rawResponse, + "POST", + "/integrations/stripe/sandbox/keys/claim", + ); + } + /** * @param {Schematic.InstallIntegrationRequestBody} request * @param {IntegrationsapiClient.RequestOptions} requestOptions - Request-specific configuration. @@ -1115,6 +1498,269 @@ export class IntegrationsapiClient { ); } + /** + * @param {Schematic.InstallStripeSandboxRequestBody} request + * @param {IntegrationsapiClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.BadRequestError} + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.integrationsapi.installStripeClaimableSandbox({ + * email: "email" + * }) + */ + public installStripeClaimableSandbox( + request: Schematic.InstallStripeSandboxRequestBody, + requestOptions?: IntegrationsapiClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__installStripeClaimableSandbox(request, requestOptions)); + } + + private async __installStripeClaimableSandbox( + request: Schematic.InstallStripeSandboxRequestBody, + requestOptions?: IntegrationsapiClient.RequestOptions, + ): Promise> { + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + "integrations/stripe/v2/sandbox", + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + requestType: "json", + body: mergeAdditionalBodyParameters( + serializers.InstallStripeSandboxRequestBody.jsonOrThrow(request, { unrecognizedObjectKeys: "strip" }), + requestOptions?.additionalBodyParameters, + ), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.InstallStripeClaimableSandboxResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Schematic.BadRequestError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError( + _response.error, + _response.rawResponse, + "POST", + "/integrations/stripe/v2/sandbox", + ); + } + + /** + * @param {IntegrationsapiClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Schematic.UnauthorizedError} + * @throws {@link Schematic.ForbiddenError} + * @throws {@link Schematic.NotFoundError} + * @throws {@link Schematic.InternalServerError} + * @throws {@link errors.SchematicError} + * @throws {@link errors.SchematicTimeoutError} + * + * @example + * await client.integrationsapi.listStripeSandboxCountries() + */ + public listStripeSandboxCountries( + requestOptions?: IntegrationsapiClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__listStripeSandboxCountries(requestOptions)); + } + + private async __listStripeSandboxCountries( + requestOptions?: IntegrationsapiClient.RequestOptions, + ): Promise> { + const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest(); + const _headers: core.Fetcher.Args["headers"] = mergeHeaders( + _authRequest.headers, + this._options?.headers, + requestOptions?.headers, + ); + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.SchematicEnvironment.Default, + "integrations/stripe/v2/sandbox-countries", + ), + method: "GET", + headers: _headers, + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { + data: serializers.ListStripeSandboxCountriesResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + rawResponse: _response.rawResponse, + }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 401: + throw new Schematic.UnauthorizedError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 403: + throw new Schematic.ForbiddenError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 404: + throw new Schematic.NotFoundError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + case 500: + throw new Schematic.InternalServerError( + serializers.ApiError.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }), + _response.rawResponse, + ); + default: + throw new errors.SchematicError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError( + _response.error, + _response.rawResponse, + "GET", + "/integrations/stripe/v2/sandbox-countries", + ); + } + /** * @param {string} integration_id - integration_id * @param {IntegrationsapiClient.RequestOptions} requestOptions - Request-specific configuration. diff --git a/src/api/resources/integrationsapi/client/requests/ClaimStripeSandboxKeysRequestBody.ts b/src/api/resources/integrationsapi/client/requests/ClaimStripeSandboxKeysRequestBody.ts new file mode 100644 index 00000000..2dbe821d --- /dev/null +++ b/src/api/resources/integrationsapi/client/requests/ClaimStripeSandboxKeysRequestBody.ts @@ -0,0 +1,11 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * { + * token: "token" + * } + */ +export interface ClaimStripeSandboxKeysRequestBody { + token: string; +} diff --git a/src/api/resources/integrationsapi/client/requests/InstallStripeSandboxRequestBody.ts b/src/api/resources/integrationsapi/client/requests/InstallStripeSandboxRequestBody.ts new file mode 100644 index 00000000..7bcde347 --- /dev/null +++ b/src/api/resources/integrationsapi/client/requests/InstallStripeSandboxRequestBody.ts @@ -0,0 +1,14 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * { + * email: "email" + * } + */ +export interface InstallStripeSandboxRequestBody { + country?: string; + email: string; + name?: string; + seedSampleData?: boolean; +} diff --git a/src/api/resources/integrationsapi/client/requests/index.ts b/src/api/resources/integrationsapi/client/requests/index.ts index c4031dc4..eba3e6b5 100644 --- a/src/api/resources/integrationsapi/client/requests/index.ts +++ b/src/api/resources/integrationsapi/client/requests/index.ts @@ -1,2 +1,4 @@ +export type { ClaimStripeSandboxKeysRequestBody } from "./ClaimStripeSandboxKeysRequestBody"; +export type { InstallStripeSandboxRequestBody } from "./InstallStripeSandboxRequestBody"; export type { ListIntegrationsRequest } from "./ListIntegrationsRequest"; export type { StartDataImportRequestBody } from "./StartDataImportRequestBody"; diff --git a/src/api/resources/integrationsapi/types/ClaimStripeSandboxKeysResponse.ts b/src/api/resources/integrationsapi/types/ClaimStripeSandboxKeysResponse.ts new file mode 100644 index 00000000..04e8c07f --- /dev/null +++ b/src/api/resources/integrationsapi/types/ClaimStripeSandboxKeysResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface ClaimStripeSandboxKeysResponse { + data: Schematic.ClaimedStripeSandboxKeysResponseData; + /** Input parameters */ + params: Record; +} diff --git a/src/api/resources/integrationsapi/types/GetStripeSandboxClaimLinkResponse.ts b/src/api/resources/integrationsapi/types/GetStripeSandboxClaimLinkResponse.ts new file mode 100644 index 00000000..b8403e32 --- /dev/null +++ b/src/api/resources/integrationsapi/types/GetStripeSandboxClaimLinkResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface GetStripeSandboxClaimLinkResponse { + data: Schematic.StripeSandboxClaimLink; + /** Input parameters */ + params: Record; +} diff --git a/src/api/resources/integrationsapi/types/GetStripeSandboxKeysResponse.ts b/src/api/resources/integrationsapi/types/GetStripeSandboxKeysResponse.ts new file mode 100644 index 00000000..5a061ef2 --- /dev/null +++ b/src/api/resources/integrationsapi/types/GetStripeSandboxKeysResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface GetStripeSandboxKeysResponse { + data: Schematic.ClaimedStripeSandboxKeysResponseData; + /** Input parameters */ + params: Record; +} diff --git a/src/api/resources/integrationsapi/types/InstallStripeClaimableSandboxResponse.ts b/src/api/resources/integrationsapi/types/InstallStripeClaimableSandboxResponse.ts new file mode 100644 index 00000000..06dff8dc --- /dev/null +++ b/src/api/resources/integrationsapi/types/InstallStripeClaimableSandboxResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface InstallStripeClaimableSandboxResponse { + data: Schematic.StripeSandboxInstallResponseData; + /** Input parameters */ + params: Record; +} diff --git a/src/api/resources/integrationsapi/types/ListStripeSandboxCountriesResponse.ts b/src/api/resources/integrationsapi/types/ListStripeSandboxCountriesResponse.ts new file mode 100644 index 00000000..31739cae --- /dev/null +++ b/src/api/resources/integrationsapi/types/ListStripeSandboxCountriesResponse.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../index"; + +export interface ListStripeSandboxCountriesResponse { + data: Schematic.StripeSandboxCountriesResponseData; + /** Input parameters */ + params: Record; +} diff --git a/src/api/resources/integrationsapi/types/index.ts b/src/api/resources/integrationsapi/types/index.ts index 3c4b71a4..3835c1ba 100644 --- a/src/api/resources/integrationsapi/types/index.ts +++ b/src/api/resources/integrationsapi/types/index.ts @@ -1,9 +1,14 @@ export * from "./AssumeStripeInstalledResponse"; +export * from "./ClaimStripeSandboxKeysResponse"; export * from "./GetIntegrationWebhookUrlResponse"; +export * from "./GetStripeSandboxClaimLinkResponse"; +export * from "./GetStripeSandboxKeysResponse"; export * from "./InstallIntegrationResponse"; +export * from "./InstallStripeClaimableSandboxResponse"; export * from "./InstallStripeResponse"; export * from "./ListIntegrationsParams"; export * from "./ListIntegrationsResponse"; +export * from "./ListStripeSandboxCountriesResponse"; export * from "./LoadSampleDataSetResponse"; export * from "./RunIntegrationResponse"; export * from "./StartDataImportResponse"; diff --git a/src/api/types/ClaimedStripeSandboxKeysResponseData.ts b/src/api/types/ClaimedStripeSandboxKeysResponseData.ts new file mode 100644 index 00000000..90342d33 --- /dev/null +++ b/src/api/types/ClaimedStripeSandboxKeysResponseData.ts @@ -0,0 +1,7 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface ClaimedStripeSandboxKeysResponseData { + publishable: string; + sandboxId: string; + secret: string; +} diff --git a/src/api/types/CompanyBillingProfileResponseData.ts b/src/api/types/CompanyBillingProfileResponseData.ts new file mode 100644 index 00000000..61f81774 --- /dev/null +++ b/src/api/types/CompanyBillingProfileResponseData.ts @@ -0,0 +1,20 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../index"; + +export interface CompanyBillingProfileResponseData { + accountId: string; + billingCustomerId?: string; + collectionMethod: Schematic.BillingCollectionMethod; + companyId: string; + createdAt: Date; + daysUntilDue?: number; + environmentId: string; + id: string; + isDefault: boolean; + name?: string; + paymentMethodId?: string; + prorationBehavior?: Schematic.ProrationBehavior; + providerType: Schematic.BillingProviderType; + updatedAt: Date; +} diff --git a/src/api/types/CompanyDetailResponseData.ts b/src/api/types/CompanyDetailResponseData.ts index aaec8c3d..7c12b495 100644 --- a/src/api/types/CompanyDetailResponseData.ts +++ b/src/api/types/CompanyDetailResponseData.ts @@ -5,6 +5,8 @@ import type * as Schematic from "../index"; export interface CompanyDetailResponseData { addOns: Schematic.CompanyPlanWithBillingSubView[]; billingCreditBalances?: Record; + billingProfile?: Schematic.CompanyBillingProfileResponseData; + billingProfiles?: Schematic.CompanyBillingProfileResponseData[]; billingSubscription?: Schematic.BillingSubscriptionView; billingSubscriptions: Schematic.BillingSubscriptionView[]; createdAt: Date; diff --git a/src/api/types/CompanyOverrideResponseData.ts b/src/api/types/CompanyOverrideResponseData.ts index ad78e24a..924d4fb0 100644 --- a/src/api/types/CompanyOverrideResponseData.ts +++ b/src/api/types/CompanyOverrideResponseData.ts @@ -19,6 +19,8 @@ export interface CompanyOverrideResponseData { ruleIdUsageExceeded?: string; updatedAt: Date; valueBool?: boolean; + valueCredit?: Schematic.BillingCreditResponseData; + valueCreditId?: string; valueNumeric?: number; valueTrait?: Schematic.EntityTraitDefinitionResponseData; valueTraitId?: string; diff --git a/src/api/types/CreditSpendPolicyResponseData.ts b/src/api/types/CreditSpendPolicyResponseData.ts new file mode 100644 index 00000000..b30575a1 --- /dev/null +++ b/src/api/types/CreditSpendPolicyResponseData.ts @@ -0,0 +1,15 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../index"; + +export interface CreditSpendPolicyResponseData { + billingCreditId: string; + companyId?: string; + createdAt: Date; + id: string; + label?: string; + maxPerDraw?: number; + scopeType: Schematic.CreditSpendPolicyScope; + updatedAt: Date; + userId?: string; +} diff --git a/src/api/types/CreditSpendPolicyScope.ts b/src/api/types/CreditSpendPolicyScope.ts new file mode 100644 index 00000000..16ab934d --- /dev/null +++ b/src/api/types/CreditSpendPolicyScope.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export const CreditSpendPolicyScope = { + Company: "company", + User: "user", + Group: "group", +} as const; +export type CreditSpendPolicyScope = (typeof CreditSpendPolicyScope)[keyof typeof CreditSpendPolicyScope]; diff --git a/src/api/types/EventBodyInference.ts b/src/api/types/EventBodyInference.ts index 13546c06..ed70210d 100644 --- a/src/api/types/EventBodyInference.ts +++ b/src/api/types/EventBodyInference.ts @@ -1,7 +1,9 @@ // This file was auto-generated by Fern from our API Definition. export interface EventBodyInference { - /** Number of input tokens served from cache */ + /** Number of input tokens written to a prompt cache; a subset of input_tokens */ + cacheCreationInputTokens?: number; + /** Number of input tokens served from cache; a subset of input_tokens */ cachedInputTokens?: number; /** Key-value pairs to identify the company associated with the inference event */ company: Record; @@ -11,7 +13,7 @@ export interface EventBodyInference { currency?: string; /** Optional track event name to fan out for usage-based billing */ event?: string; - /** Number of input tokens for the inference request */ + /** Total number of input tokens for the inference request, including those served from and written to a prompt cache */ inputTokens: number; /** The inference operation; defaults to 'chat' */ operation?: string; diff --git a/src/api/types/GetOnboardingStateResp.ts b/src/api/types/GetOnboardingStateResp.ts index 96aedc54..31249da0 100644 --- a/src/api/types/GetOnboardingStateResp.ts +++ b/src/api/types/GetOnboardingStateResp.ts @@ -4,6 +4,7 @@ import type * as Schematic from "../index"; export interface GetOnboardingStateResp { agentConnectedAt?: Date; + country?: string; dismissedAt?: Date; environmentId?: string; milestones: Schematic.OnboardingMilestoneView[]; diff --git a/src/api/types/OtlpEnvironmentSettingsResponseData.ts b/src/api/types/OtlpEnvironmentSettingsResponseData.ts new file mode 100644 index 00000000..5320255d --- /dev/null +++ b/src/api/types/OtlpEnvironmentSettingsResponseData.ts @@ -0,0 +1,12 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface OtlpEnvironmentSettingsResponseData { + companyAttribute?: string; + companyKey?: string; + createdAt: Date; + environmentId: string; + toolEventsEnabled: boolean; + updatedAt: Date; + userAttribute?: string; + userKey?: string; +} diff --git a/src/api/types/RuleConditionDetailResponseData.ts b/src/api/types/RuleConditionDetailResponseData.ts index 73053ae3..950eb7f5 100644 --- a/src/api/types/RuleConditionDetailResponseData.ts +++ b/src/api/types/RuleConditionDetailResponseData.ts @@ -16,6 +16,7 @@ export interface RuleConditionDetailResponseData { metricPeriodMonthReset?: Schematic.MetricPeriodMonthReset; metricValue?: number; operator: Schematic.ComparableOperator; + planVersions?: Schematic.RuleConditionPlanVersionResponseData[]; resourceIds: string[]; resources: Schematic.PreviewObjectResponseData[]; ruleId: string; diff --git a/src/api/types/RuleConditionPlanVersionResponseData.ts b/src/api/types/RuleConditionPlanVersionResponseData.ts new file mode 100644 index 00000000..bc96054b --- /dev/null +++ b/src/api/types/RuleConditionPlanVersionResponseData.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../index"; + +export interface RuleConditionPlanVersionResponseData { + id: string; + name: string; + status: Schematic.PlanVersionStatus; + version: number; +} diff --git a/src/api/types/StripeIntegrationConfig.ts b/src/api/types/StripeIntegrationConfig.ts index 9092df41..e9a30de9 100644 --- a/src/api/types/StripeIntegrationConfig.ts +++ b/src/api/types/StripeIntegrationConfig.ts @@ -5,6 +5,12 @@ export interface StripeIntegrationConfig { accountId?: string; /** Display name of the connected Stripe account */ accountName?: string; + /** When Stripe deletes the sandbox if nobody claims it, 60 days from creation; absent on sandboxes created before it was recorded */ + claimableSandboxExpiresAt?: Date; + /** Stripe claimable sandbox this connection was provisioned from; absent for an OAuth connect */ + claimableSandboxId?: string; + /** Stripe's claim status for the sandbox: unclaimed, claimed, or live */ + claimableSandboxStatus?: string; /** When importing Stripe customers, only update existing companies, do not create new companies */ companyUpdateOnly?: boolean; /** Whether the integration is connected to a Stripe sandbox account */ diff --git a/src/api/types/StripeSandboxClaimLink.ts b/src/api/types/StripeSandboxClaimLink.ts new file mode 100644 index 00000000..da3a12fe --- /dev/null +++ b/src/api/types/StripeSandboxClaimLink.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface StripeSandboxClaimLink { + claimUrl: string; + expiresAt?: Date; + sandboxId: string; + status: string; +} diff --git a/src/api/types/StripeSandboxCountriesResponseData.ts b/src/api/types/StripeSandboxCountriesResponseData.ts new file mode 100644 index 00000000..aceb61f7 --- /dev/null +++ b/src/api/types/StripeSandboxCountriesResponseData.ts @@ -0,0 +1,5 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface StripeSandboxCountriesResponseData { + countries: string[]; +} diff --git a/src/api/types/StripeSandboxInstallResponseData.ts b/src/api/types/StripeSandboxInstallResponseData.ts new file mode 100644 index 00000000..5a8d30de --- /dev/null +++ b/src/api/types/StripeSandboxInstallResponseData.ts @@ -0,0 +1,13 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../index"; + +export interface StripeSandboxInstallResponseData { + apiKeys?: Schematic.StripeSandboxKeysResponseData; + claimUrl: string; + claimUrlExpiresAt?: Date; + expiresAt?: Date; + install: Schematic.IntegrationInstallResponseData; + sandboxId: string; + stripeAccountId: string; +} diff --git a/src/api/types/StripeSandboxKeysResponseData.ts b/src/api/types/StripeSandboxKeysResponseData.ts new file mode 100644 index 00000000..da5879e4 --- /dev/null +++ b/src/api/types/StripeSandboxKeysResponseData.ts @@ -0,0 +1,7 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface StripeSandboxKeysResponseData { + mcp: string; + publishable: string; + secret: string; +} diff --git a/src/api/types/index.ts b/src/api/types/index.ts index 6e7d3cb9..f54b90e5 100644 --- a/src/api/types/index.ts +++ b/src/api/types/index.ts @@ -89,6 +89,7 @@ export * from "./CheckoutFieldValue"; export * from "./CheckoutFieldWithValue"; export * from "./CheckoutSettingsResponseData"; export * from "./CheckoutSubscription"; +export * from "./ClaimedStripeSandboxKeysResponseData"; export * from "./ClerkIntegrationConfig"; export * from "./CompanyBillingAddressView"; export * from "./CompanyBillingCheckoutSettings"; @@ -96,6 +97,7 @@ export * from "./CompanyBillingDetailsResponseData"; export * from "./CompanyBillingDetailsView"; export * from "./CompanyBillingEntityResponseData"; export * from "./CompanyBillingEntitySubscriptionResponseData"; +export * from "./CompanyBillingProfileResponseData"; export * from "./CompanyCreditBalance"; export * from "./CompanyCreditBalanceResponseData"; export * from "./CompanyDetailResponseData"; @@ -165,6 +167,8 @@ export * from "./CreditGrantDetail"; export * from "./CreditGrantExpiryRequestBody"; export * from "./CreditGrantSortOrder"; export * from "./CreditLeaseResponseData"; +export * from "./CreditSpendPolicyResponseData"; +export * from "./CreditSpendPolicyScope"; export * from "./CreditsAutoTopupCompanySummary"; export * from "./CreditsAutoTopupCreditSummary"; export * from "./CreditsAutoTopupHardFailure"; @@ -293,6 +297,7 @@ export * from "./OnboardingStripeImport"; export * from "./OnboardingTrack"; export * from "./OrbIntegrationConfig"; export * from "./OrderedPlansInGroup"; +export * from "./OtlpEnvironmentSettingsResponseData"; export * from "./PaymentMethodRequestBody"; export * from "./PaymentMethodResponseData"; export * from "./PendingMigrationResponseData"; @@ -357,6 +362,7 @@ export * from "./Rule"; export * from "./RuleConditionDetailResponseData"; export * from "./RuleConditionGroupDetailResponseData"; export * from "./RuleConditionGroupResponseData"; +export * from "./RuleConditionPlanVersionResponseData"; export * from "./RuleConditionResponseData"; export * from "./RuleDetailResponseData"; export * from "./RuleResponseData"; @@ -394,6 +400,10 @@ export * from "./SkippedEntitlementResponseData"; export * from "./SortDirection"; export * from "./StripeEmbedInfo"; export * from "./StripeIntegrationConfig"; +export * from "./StripeSandboxClaimLink"; +export * from "./StripeSandboxCountriesResponseData"; +export * from "./StripeSandboxInstallResponseData"; +export * from "./StripeSandboxKeysResponseData"; export * from "./SubscriptionStatus"; export * from "./SubscriptionTraitUpdate"; export * from "./SubscriptionType"; diff --git a/src/serialization/resources/accounts/client/requests/UpdateOnboardingStateRequestBody.ts b/src/serialization/resources/accounts/client/requests/UpdateOnboardingStateRequestBody.ts index abaae39d..fa20843a 100644 --- a/src/serialization/resources/accounts/client/requests/UpdateOnboardingStateRequestBody.ts +++ b/src/serialization/resources/accounts/client/requests/UpdateOnboardingStateRequestBody.ts @@ -10,6 +10,7 @@ export const UpdateOnboardingStateRequestBody: core.serialization.Schema< serializers.UpdateOnboardingStateRequestBody.Raw, Schematic.UpdateOnboardingStateRequestBody > = core.serialization.object({ + country: core.serialization.string().optional(), dismissed: core.serialization.boolean().optional(), path: OnboardingPath.optional(), pricingPageUrl: core.serialization.property("pricing_page_url", core.serialization.string().optional()), @@ -19,6 +20,7 @@ export const UpdateOnboardingStateRequestBody: core.serialization.Schema< export declare namespace UpdateOnboardingStateRequestBody { export interface Raw { + country?: string | null; dismissed?: boolean | null; path?: OnboardingPath.Raw | null; pricing_page_url?: string | null; diff --git a/src/serialization/resources/billing/client/requests/UpdateCompanyBillingProfileRequestBody.ts b/src/serialization/resources/billing/client/requests/UpdateCompanyBillingProfileRequestBody.ts new file mode 100644 index 00000000..b11634ec --- /dev/null +++ b/src/serialization/resources/billing/client/requests/UpdateCompanyBillingProfileRequestBody.ts @@ -0,0 +1,30 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../../api/index"; +import * as core from "../../../../../core"; +import type * as serializers from "../../../../index"; +import { BillingCollectionMethod } from "../../../../types/BillingCollectionMethod"; +import { ProrationBehavior } from "../../../../types/ProrationBehavior"; + +export const UpdateCompanyBillingProfileRequestBody: core.serialization.Schema< + serializers.UpdateCompanyBillingProfileRequestBody.Raw, + Schematic.UpdateCompanyBillingProfileRequestBody +> = core.serialization.object({ + collectionMethod: core.serialization.property("collection_method", BillingCollectionMethod), + daysUntilDue: core.serialization.property("days_until_due", core.serialization.number().optional()), + isDefault: core.serialization.property("is_default", core.serialization.boolean().optional()), + name: core.serialization.string().optional(), + paymentMethodId: core.serialization.property("payment_method_id", core.serialization.string().optional()), + prorationBehavior: core.serialization.property("proration_behavior", ProrationBehavior.optional()), +}); + +export declare namespace UpdateCompanyBillingProfileRequestBody { + export interface Raw { + collection_method: BillingCollectionMethod.Raw; + days_until_due?: number | null; + is_default?: boolean | null; + name?: string | null; + payment_method_id?: string | null; + proration_behavior?: ProrationBehavior.Raw | null; + } +} diff --git a/src/serialization/resources/billing/client/requests/index.ts b/src/serialization/resources/billing/client/requests/index.ts index ae39129e..2e05f983 100644 --- a/src/serialization/resources/billing/client/requests/index.ts +++ b/src/serialization/resources/billing/client/requests/index.ts @@ -6,3 +6,4 @@ export { CreateCouponRequestBody } from "./CreateCouponRequestBody"; export { CreateInvoiceRequestBody } from "./CreateInvoiceRequestBody"; export { CreateMeterRequestBody } from "./CreateMeterRequestBody"; export { CreatePaymentMethodRequestBody } from "./CreatePaymentMethodRequestBody"; +export { UpdateCompanyBillingProfileRequestBody } from "./UpdateCompanyBillingProfileRequestBody"; diff --git a/src/serialization/resources/billing/types/ListCompanyBillingProfilesParams.ts b/src/serialization/resources/billing/types/ListCompanyBillingProfilesParams.ts new file mode 100644 index 00000000..f4a414ae --- /dev/null +++ b/src/serialization/resources/billing/types/ListCompanyBillingProfilesParams.ts @@ -0,0 +1,27 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { BillingProviderType } from "../../../types/BillingProviderType"; + +export const ListCompanyBillingProfilesParams: core.serialization.ObjectSchema< + serializers.ListCompanyBillingProfilesParams.Raw, + Schematic.ListCompanyBillingProfilesParams +> = core.serialization.object({ + companyId: core.serialization.property("company_id", core.serialization.string().optional()), + isDefault: core.serialization.property("is_default", core.serialization.boolean().optional()), + limit: core.serialization.number().optional(), + offset: core.serialization.number().optional(), + providerType: core.serialization.property("provider_type", BillingProviderType.optional()), +}); + +export declare namespace ListCompanyBillingProfilesParams { + export interface Raw { + company_id?: string | null; + is_default?: boolean | null; + limit?: number | null; + offset?: number | null; + provider_type?: BillingProviderType.Raw | null; + } +} diff --git a/src/serialization/resources/billing/types/ListCompanyBillingProfilesResponse.ts b/src/serialization/resources/billing/types/ListCompanyBillingProfilesResponse.ts new file mode 100644 index 00000000..eee33642 --- /dev/null +++ b/src/serialization/resources/billing/types/ListCompanyBillingProfilesResponse.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { CompanyBillingProfileResponseData } from "../../../types/CompanyBillingProfileResponseData"; +import { ListCompanyBillingProfilesParams } from "./ListCompanyBillingProfilesParams"; + +export const ListCompanyBillingProfilesResponse: core.serialization.ObjectSchema< + serializers.ListCompanyBillingProfilesResponse.Raw, + Schematic.ListCompanyBillingProfilesResponse +> = core.serialization.object({ + data: core.serialization.list(CompanyBillingProfileResponseData), + params: ListCompanyBillingProfilesParams, +}); + +export declare namespace ListCompanyBillingProfilesResponse { + export interface Raw { + data: CompanyBillingProfileResponseData.Raw[]; + params: ListCompanyBillingProfilesParams.Raw; + } +} diff --git a/src/serialization/resources/billing/types/UpdateCompanyBillingProfileResponse.ts b/src/serialization/resources/billing/types/UpdateCompanyBillingProfileResponse.ts new file mode 100644 index 00000000..4f8f88fc --- /dev/null +++ b/src/serialization/resources/billing/types/UpdateCompanyBillingProfileResponse.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { CompanyBillingProfileResponseData } from "../../../types/CompanyBillingProfileResponseData"; + +export const UpdateCompanyBillingProfileResponse: core.serialization.ObjectSchema< + serializers.UpdateCompanyBillingProfileResponse.Raw, + Schematic.UpdateCompanyBillingProfileResponse +> = core.serialization.object({ + data: CompanyBillingProfileResponseData, + params: core.serialization.record(core.serialization.string(), core.serialization.unknown()), +}); + +export declare namespace UpdateCompanyBillingProfileResponse { + export interface Raw { + data: CompanyBillingProfileResponseData.Raw; + params: Record; + } +} diff --git a/src/serialization/resources/billing/types/index.ts b/src/serialization/resources/billing/types/index.ts index 7e9332c9..5fa2d7b3 100644 --- a/src/serialization/resources/billing/types/index.ts +++ b/src/serialization/resources/billing/types/index.ts @@ -14,6 +14,8 @@ export * from "./ListBillingProductPricesParams"; export * from "./ListBillingProductPricesResponse"; export * from "./ListBillingProductsParams"; export * from "./ListBillingProductsResponse"; +export * from "./ListCompanyBillingProfilesParams"; +export * from "./ListCompanyBillingProfilesResponse"; export * from "./ListCouponsParams"; export * from "./ListCouponsResponse"; export * from "./ListCustomersWithSubscriptionsParams"; @@ -24,6 +26,7 @@ export * from "./ListMetersParams"; export * from "./ListMetersResponse"; export * from "./ListPaymentMethodsParams"; export * from "./ListPaymentMethodsResponse"; +export * from "./UpdateCompanyBillingProfileResponse"; export * from "./UpsertBillingCouponResponse"; export * from "./UpsertBillingCustomerResponse"; export * from "./UpsertBillingMeterResponse"; diff --git a/src/serialization/resources/credits/client/requests/CreateCreditSpendPolicyRequestBody.ts b/src/serialization/resources/credits/client/requests/CreateCreditSpendPolicyRequestBody.ts new file mode 100644 index 00000000..1e39f973 --- /dev/null +++ b/src/serialization/resources/credits/client/requests/CreateCreditSpendPolicyRequestBody.ts @@ -0,0 +1,26 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../../api/index"; +import * as core from "../../../../../core"; +import type * as serializers from "../../../../index"; + +export const CreateCreditSpendPolicyRequestBody: core.serialization.Schema< + serializers.CreateCreditSpendPolicyRequestBody.Raw, + Schematic.CreateCreditSpendPolicyRequestBody +> = core.serialization.object({ + billingCreditId: core.serialization.property("billing_credit_id", core.serialization.string()), + companyId: core.serialization.property("company_id", core.serialization.string().optional()), + label: core.serialization.string().optional(), + maxPerDraw: core.serialization.property("max_per_draw", core.serialization.number()), + userId: core.serialization.property("user_id", core.serialization.string().optional()), +}); + +export declare namespace CreateCreditSpendPolicyRequestBody { + export interface Raw { + billing_credit_id: string; + company_id?: string | null; + label?: string | null; + max_per_draw: number; + user_id?: string | null; + } +} diff --git a/src/serialization/resources/credits/client/requests/UpdateCreditSpendPolicyRequestBody.ts b/src/serialization/resources/credits/client/requests/UpdateCreditSpendPolicyRequestBody.ts new file mode 100644 index 00000000..45d76ca8 --- /dev/null +++ b/src/serialization/resources/credits/client/requests/UpdateCreditSpendPolicyRequestBody.ts @@ -0,0 +1,20 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../../api/index"; +import * as core from "../../../../../core"; +import type * as serializers from "../../../../index"; + +export const UpdateCreditSpendPolicyRequestBody: core.serialization.Schema< + serializers.UpdateCreditSpendPolicyRequestBody.Raw, + Schematic.UpdateCreditSpendPolicyRequestBody +> = core.serialization.object({ + label: core.serialization.string().optional(), + maxPerDraw: core.serialization.property("max_per_draw", core.serialization.number().optional()), +}); + +export declare namespace UpdateCreditSpendPolicyRequestBody { + export interface Raw { + label?: string | null; + max_per_draw?: number | null; + } +} diff --git a/src/serialization/resources/credits/client/requests/index.ts b/src/serialization/resources/credits/client/requests/index.ts index 010270c7..d71ca06d 100644 --- a/src/serialization/resources/credits/client/requests/index.ts +++ b/src/serialization/resources/credits/client/requests/index.ts @@ -2,7 +2,9 @@ export { AcquireCreditLeaseRequestBody } from "./AcquireCreditLeaseRequestBody"; export { CreateBillingCreditRequestBody } from "./CreateBillingCreditRequestBody"; export { CreateCompanyCreditGrant } from "./CreateCompanyCreditGrant"; export { CreateCreditBundleRequestBody } from "./CreateCreditBundleRequestBody"; +export { CreateCreditSpendPolicyRequestBody } from "./CreateCreditSpendPolicyRequestBody"; export { ExtendCreditLeaseRequestBody } from "./ExtendCreditLeaseRequestBody"; export { UpdateBillingCreditRequestBody } from "./UpdateBillingCreditRequestBody"; export { UpdateCreditBundleDetailsRequestBody } from "./UpdateCreditBundleDetailsRequestBody"; +export { UpdateCreditSpendPolicyRequestBody } from "./UpdateCreditSpendPolicyRequestBody"; export { ZeroOutGrantRequestBody } from "./ZeroOutGrantRequestBody"; diff --git a/src/serialization/resources/credits/types/CountCreditSpendPoliciesParams.ts b/src/serialization/resources/credits/types/CountCreditSpendPoliciesParams.ts new file mode 100644 index 00000000..0fee30f2 --- /dev/null +++ b/src/serialization/resources/credits/types/CountCreditSpendPoliciesParams.ts @@ -0,0 +1,31 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { CreditSpendPolicyScope } from "../../../types/CreditSpendPolicyScope"; + +export const CountCreditSpendPoliciesParams: core.serialization.ObjectSchema< + serializers.CountCreditSpendPoliciesParams.Raw, + Schematic.CountCreditSpendPoliciesParams +> = core.serialization.object({ + billingCreditId: core.serialization.property("billing_credit_id", core.serialization.string().optional()), + companyId: core.serialization.property("company_id", core.serialization.string().optional()), + limit: core.serialization.number().optional(), + offset: core.serialization.number().optional(), + scopeType: core.serialization.property("scope_type", CreditSpendPolicyScope.optional()), + userId: core.serialization.property("user_id", core.serialization.string().optional()), + userIds: core.serialization.property("user_ids", core.serialization.list(core.serialization.string()).optional()), +}); + +export declare namespace CountCreditSpendPoliciesParams { + export interface Raw { + billing_credit_id?: string | null; + company_id?: string | null; + limit?: number | null; + offset?: number | null; + scope_type?: CreditSpendPolicyScope.Raw | null; + user_id?: string | null; + user_ids?: string[] | null; + } +} diff --git a/src/serialization/resources/credits/types/CountCreditSpendPoliciesResponse.ts b/src/serialization/resources/credits/types/CountCreditSpendPoliciesResponse.ts new file mode 100644 index 00000000..1c4acb21 --- /dev/null +++ b/src/serialization/resources/credits/types/CountCreditSpendPoliciesResponse.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { CountResponse } from "../../../types/CountResponse"; +import { CountCreditSpendPoliciesParams } from "./CountCreditSpendPoliciesParams"; + +export const CountCreditSpendPoliciesResponse: core.serialization.ObjectSchema< + serializers.CountCreditSpendPoliciesResponse.Raw, + Schematic.CountCreditSpendPoliciesResponse +> = core.serialization.object({ + data: CountResponse, + params: CountCreditSpendPoliciesParams, +}); + +export declare namespace CountCreditSpendPoliciesResponse { + export interface Raw { + data: CountResponse.Raw; + params: CountCreditSpendPoliciesParams.Raw; + } +} diff --git a/src/serialization/resources/credits/types/CreateCreditSpendPolicyResponse.ts b/src/serialization/resources/credits/types/CreateCreditSpendPolicyResponse.ts new file mode 100644 index 00000000..ceb25da9 --- /dev/null +++ b/src/serialization/resources/credits/types/CreateCreditSpendPolicyResponse.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { CreditSpendPolicyResponseData } from "../../../types/CreditSpendPolicyResponseData"; + +export const CreateCreditSpendPolicyResponse: core.serialization.ObjectSchema< + serializers.CreateCreditSpendPolicyResponse.Raw, + Schematic.CreateCreditSpendPolicyResponse +> = core.serialization.object({ + data: CreditSpendPolicyResponseData, + params: core.serialization.record(core.serialization.string(), core.serialization.unknown()), +}); + +export declare namespace CreateCreditSpendPolicyResponse { + export interface Raw { + data: CreditSpendPolicyResponseData.Raw; + params: Record; + } +} diff --git a/src/serialization/resources/credits/types/DeleteCreditSpendPolicyResponse.ts b/src/serialization/resources/credits/types/DeleteCreditSpendPolicyResponse.ts new file mode 100644 index 00000000..3da848fd --- /dev/null +++ b/src/serialization/resources/credits/types/DeleteCreditSpendPolicyResponse.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { DeleteResponse } from "../../../types/DeleteResponse"; + +export const DeleteCreditSpendPolicyResponse: core.serialization.ObjectSchema< + serializers.DeleteCreditSpendPolicyResponse.Raw, + Schematic.DeleteCreditSpendPolicyResponse +> = core.serialization.object({ + data: DeleteResponse, + params: core.serialization.record(core.serialization.string(), core.serialization.unknown()), +}); + +export declare namespace DeleteCreditSpendPolicyResponse { + export interface Raw { + data: DeleteResponse.Raw; + params: Record; + } +} diff --git a/src/serialization/resources/credits/types/GetCreditSpendPolicyResponse.ts b/src/serialization/resources/credits/types/GetCreditSpendPolicyResponse.ts new file mode 100644 index 00000000..ca226f6b --- /dev/null +++ b/src/serialization/resources/credits/types/GetCreditSpendPolicyResponse.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { CreditSpendPolicyResponseData } from "../../../types/CreditSpendPolicyResponseData"; + +export const GetCreditSpendPolicyResponse: core.serialization.ObjectSchema< + serializers.GetCreditSpendPolicyResponse.Raw, + Schematic.GetCreditSpendPolicyResponse +> = core.serialization.object({ + data: CreditSpendPolicyResponseData, + params: core.serialization.record(core.serialization.string(), core.serialization.unknown()), +}); + +export declare namespace GetCreditSpendPolicyResponse { + export interface Raw { + data: CreditSpendPolicyResponseData.Raw; + params: Record; + } +} diff --git a/src/serialization/resources/credits/types/ListCreditSpendPoliciesParams.ts b/src/serialization/resources/credits/types/ListCreditSpendPoliciesParams.ts new file mode 100644 index 00000000..d4e3047d --- /dev/null +++ b/src/serialization/resources/credits/types/ListCreditSpendPoliciesParams.ts @@ -0,0 +1,31 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { CreditSpendPolicyScope } from "../../../types/CreditSpendPolicyScope"; + +export const ListCreditSpendPoliciesParams: core.serialization.ObjectSchema< + serializers.ListCreditSpendPoliciesParams.Raw, + Schematic.ListCreditSpendPoliciesParams +> = core.serialization.object({ + billingCreditId: core.serialization.property("billing_credit_id", core.serialization.string().optional()), + companyId: core.serialization.property("company_id", core.serialization.string().optional()), + limit: core.serialization.number().optional(), + offset: core.serialization.number().optional(), + scopeType: core.serialization.property("scope_type", CreditSpendPolicyScope.optional()), + userId: core.serialization.property("user_id", core.serialization.string().optional()), + userIds: core.serialization.property("user_ids", core.serialization.list(core.serialization.string()).optional()), +}); + +export declare namespace ListCreditSpendPoliciesParams { + export interface Raw { + billing_credit_id?: string | null; + company_id?: string | null; + limit?: number | null; + offset?: number | null; + scope_type?: CreditSpendPolicyScope.Raw | null; + user_id?: string | null; + user_ids?: string[] | null; + } +} diff --git a/src/serialization/resources/credits/types/ListCreditSpendPoliciesResponse.ts b/src/serialization/resources/credits/types/ListCreditSpendPoliciesResponse.ts new file mode 100644 index 00000000..9fe19495 --- /dev/null +++ b/src/serialization/resources/credits/types/ListCreditSpendPoliciesResponse.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { CreditSpendPolicyResponseData } from "../../../types/CreditSpendPolicyResponseData"; +import { ListCreditSpendPoliciesParams } from "./ListCreditSpendPoliciesParams"; + +export const ListCreditSpendPoliciesResponse: core.serialization.ObjectSchema< + serializers.ListCreditSpendPoliciesResponse.Raw, + Schematic.ListCreditSpendPoliciesResponse +> = core.serialization.object({ + data: core.serialization.list(CreditSpendPolicyResponseData), + params: ListCreditSpendPoliciesParams, +}); + +export declare namespace ListCreditSpendPoliciesResponse { + export interface Raw { + data: CreditSpendPolicyResponseData.Raw[]; + params: ListCreditSpendPoliciesParams.Raw; + } +} diff --git a/src/serialization/resources/credits/types/UpdateCreditSpendPolicyResponse.ts b/src/serialization/resources/credits/types/UpdateCreditSpendPolicyResponse.ts new file mode 100644 index 00000000..b27c0631 --- /dev/null +++ b/src/serialization/resources/credits/types/UpdateCreditSpendPolicyResponse.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { CreditSpendPolicyResponseData } from "../../../types/CreditSpendPolicyResponseData"; + +export const UpdateCreditSpendPolicyResponse: core.serialization.ObjectSchema< + serializers.UpdateCreditSpendPolicyResponse.Raw, + Schematic.UpdateCreditSpendPolicyResponse +> = core.serialization.object({ + data: CreditSpendPolicyResponseData, + params: core.serialization.record(core.serialization.string(), core.serialization.unknown()), +}); + +export declare namespace UpdateCreditSpendPolicyResponse { + export interface Raw { + data: CreditSpendPolicyResponseData.Raw; + params: Record; + } +} diff --git a/src/serialization/resources/credits/types/index.ts b/src/serialization/resources/credits/types/index.ts index 2e92a33a..f55d471c 100644 --- a/src/serialization/resources/credits/types/index.ts +++ b/src/serialization/resources/credits/types/index.ts @@ -11,14 +11,19 @@ export * from "./CountCreditBundlesParams"; export * from "./CountCreditBundlesResponse"; export * from "./CountCreditEventLedgerParams"; export * from "./CountCreditEventLedgerResponse"; +export * from "./CountCreditSpendPoliciesParams"; +export * from "./CountCreditSpendPoliciesResponse"; export * from "./CreateBillingCreditResponse"; export * from "./CreateBillingPlanCreditGrantResponse"; export * from "./CreateCreditBundleResponse"; +export * from "./CreateCreditSpendPolicyResponse"; export * from "./DeleteBillingPlanCreditGrantParams"; export * from "./DeleteBillingPlanCreditGrantResponse"; export * from "./DeleteCreditBundleResponse"; +export * from "./DeleteCreditSpendPolicyResponse"; export * from "./ExtendCreditLeaseResponse"; export * from "./GetCreditBundleResponse"; +export * from "./GetCreditSpendPolicyResponse"; export * from "./GetSingleBillingCreditResponse"; export * from "./GetSingleBillingPlanCreditGrantResponse"; export * from "./GrantBillingCreditsToCompanyResponse"; @@ -34,6 +39,8 @@ export * from "./ListCreditBundlesParams"; export * from "./ListCreditBundlesResponse"; export * from "./ListCreditEventLedgerParams"; export * from "./ListCreditEventLedgerResponse"; +export * from "./ListCreditSpendPoliciesParams"; +export * from "./ListCreditSpendPoliciesResponse"; export * from "./ListGrantsForCreditParams"; export * from "./ListGrantsForCreditResponse"; export * from "./ReleaseCreditLeaseResponse"; @@ -41,4 +48,5 @@ export * from "./SoftDeleteBillingCreditResponse"; export * from "./UpdateBillingCreditResponse"; export * from "./UpdateBillingPlanCreditGrantResponse"; export * from "./UpdateCreditBundleDetailsResponse"; +export * from "./UpdateCreditSpendPolicyResponse"; export * from "./ZeroOutGrantResponse"; diff --git a/src/serialization/resources/events/client/requests/UpsertOtlpEnvironmentSettingsRequestBody.ts b/src/serialization/resources/events/client/requests/UpsertOtlpEnvironmentSettingsRequestBody.ts new file mode 100644 index 00000000..bf0ebc8c --- /dev/null +++ b/src/serialization/resources/events/client/requests/UpsertOtlpEnvironmentSettingsRequestBody.ts @@ -0,0 +1,26 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../../api/index"; +import * as core from "../../../../../core"; +import type * as serializers from "../../../../index"; + +export const UpsertOtlpEnvironmentSettingsRequestBody: core.serialization.Schema< + serializers.UpsertOtlpEnvironmentSettingsRequestBody.Raw, + Schematic.UpsertOtlpEnvironmentSettingsRequestBody +> = core.serialization.object({ + companyAttribute: core.serialization.property("company_attribute", core.serialization.string().optional()), + companyKey: core.serialization.property("company_key", core.serialization.string().optional()), + toolEventsEnabled: core.serialization.property("tool_events_enabled", core.serialization.boolean()), + userAttribute: core.serialization.property("user_attribute", core.serialization.string().optional()), + userKey: core.serialization.property("user_key", core.serialization.string().optional()), +}); + +export declare namespace UpsertOtlpEnvironmentSettingsRequestBody { + export interface Raw { + company_attribute?: string | null; + company_key?: string | null; + tool_events_enabled: boolean; + user_attribute?: string | null; + user_key?: string | null; + } +} diff --git a/src/serialization/resources/events/client/requests/index.ts b/src/serialization/resources/events/client/requests/index.ts index b63138cc..e8553efa 100644 --- a/src/serialization/resources/events/client/requests/index.ts +++ b/src/serialization/resources/events/client/requests/index.ts @@ -1 +1,2 @@ export { CreateEventBatchRequestBody } from "./CreateEventBatchRequestBody"; +export { UpsertOtlpEnvironmentSettingsRequestBody } from "./UpsertOtlpEnvironmentSettingsRequestBody"; diff --git a/src/serialization/resources/events/types/DeleteOtlpEnvironmentSettingsResponse.ts b/src/serialization/resources/events/types/DeleteOtlpEnvironmentSettingsResponse.ts new file mode 100644 index 00000000..355c3ce4 --- /dev/null +++ b/src/serialization/resources/events/types/DeleteOtlpEnvironmentSettingsResponse.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { DeleteResponse } from "../../../types/DeleteResponse"; + +export const DeleteOtlpEnvironmentSettingsResponse: core.serialization.ObjectSchema< + serializers.DeleteOtlpEnvironmentSettingsResponse.Raw, + Schematic.DeleteOtlpEnvironmentSettingsResponse +> = core.serialization.object({ + data: DeleteResponse, + params: core.serialization.record(core.serialization.string(), core.serialization.unknown()), +}); + +export declare namespace DeleteOtlpEnvironmentSettingsResponse { + export interface Raw { + data: DeleteResponse.Raw; + params: Record; + } +} diff --git a/src/serialization/resources/events/types/GetOtlpEnvironmentSettingsResponse.ts b/src/serialization/resources/events/types/GetOtlpEnvironmentSettingsResponse.ts new file mode 100644 index 00000000..a4463f35 --- /dev/null +++ b/src/serialization/resources/events/types/GetOtlpEnvironmentSettingsResponse.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { OtlpEnvironmentSettingsResponseData } from "../../../types/OtlpEnvironmentSettingsResponseData"; + +export const GetOtlpEnvironmentSettingsResponse: core.serialization.ObjectSchema< + serializers.GetOtlpEnvironmentSettingsResponse.Raw, + Schematic.GetOtlpEnvironmentSettingsResponse +> = core.serialization.object({ + data: OtlpEnvironmentSettingsResponseData, + params: core.serialization.record(core.serialization.string(), core.serialization.unknown()), +}); + +export declare namespace GetOtlpEnvironmentSettingsResponse { + export interface Raw { + data: OtlpEnvironmentSettingsResponseData.Raw; + params: Record; + } +} diff --git a/src/serialization/resources/events/types/UpsertOtlpEnvironmentSettingsResponse.ts b/src/serialization/resources/events/types/UpsertOtlpEnvironmentSettingsResponse.ts new file mode 100644 index 00000000..510d9573 --- /dev/null +++ b/src/serialization/resources/events/types/UpsertOtlpEnvironmentSettingsResponse.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { OtlpEnvironmentSettingsResponseData } from "../../../types/OtlpEnvironmentSettingsResponseData"; + +export const UpsertOtlpEnvironmentSettingsResponse: core.serialization.ObjectSchema< + serializers.UpsertOtlpEnvironmentSettingsResponse.Raw, + Schematic.UpsertOtlpEnvironmentSettingsResponse +> = core.serialization.object({ + data: OtlpEnvironmentSettingsResponseData, + params: core.serialization.record(core.serialization.string(), core.serialization.unknown()), +}); + +export declare namespace UpsertOtlpEnvironmentSettingsResponse { + export interface Raw { + data: OtlpEnvironmentSettingsResponseData.Raw; + params: Record; + } +} diff --git a/src/serialization/resources/events/types/index.ts b/src/serialization/resources/events/types/index.ts index 421f16fb..3ed83d82 100644 --- a/src/serialization/resources/events/types/index.ts +++ b/src/serialization/resources/events/types/index.ts @@ -1,8 +1,11 @@ export * from "./CreateEventBatchResponse"; export * from "./CreateEventResponse"; +export * from "./DeleteOtlpEnvironmentSettingsResponse"; export * from "./GetEventResponse"; export * from "./GetEventSummariesParams"; export * from "./GetEventSummariesResponse"; +export * from "./GetOtlpEnvironmentSettingsResponse"; export * from "./GetSegmentIntegrationStatusResponse"; export * from "./ListEventsParams"; export * from "./ListEventsResponse"; +export * from "./UpsertOtlpEnvironmentSettingsResponse"; diff --git a/src/serialization/resources/integrationsapi/client/requests/ClaimStripeSandboxKeysRequestBody.ts b/src/serialization/resources/integrationsapi/client/requests/ClaimStripeSandboxKeysRequestBody.ts new file mode 100644 index 00000000..98c493c2 --- /dev/null +++ b/src/serialization/resources/integrationsapi/client/requests/ClaimStripeSandboxKeysRequestBody.ts @@ -0,0 +1,18 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../../api/index"; +import * as core from "../../../../../core"; +import type * as serializers from "../../../../index"; + +export const ClaimStripeSandboxKeysRequestBody: core.serialization.Schema< + serializers.ClaimStripeSandboxKeysRequestBody.Raw, + Schematic.ClaimStripeSandboxKeysRequestBody +> = core.serialization.object({ + token: core.serialization.string(), +}); + +export declare namespace ClaimStripeSandboxKeysRequestBody { + export interface Raw { + token: string; + } +} diff --git a/src/serialization/resources/integrationsapi/client/requests/InstallStripeSandboxRequestBody.ts b/src/serialization/resources/integrationsapi/client/requests/InstallStripeSandboxRequestBody.ts new file mode 100644 index 00000000..563586c8 --- /dev/null +++ b/src/serialization/resources/integrationsapi/client/requests/InstallStripeSandboxRequestBody.ts @@ -0,0 +1,24 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../../api/index"; +import * as core from "../../../../../core"; +import type * as serializers from "../../../../index"; + +export const InstallStripeSandboxRequestBody: core.serialization.Schema< + serializers.InstallStripeSandboxRequestBody.Raw, + Schematic.InstallStripeSandboxRequestBody +> = core.serialization.object({ + country: core.serialization.string().optional(), + email: core.serialization.string(), + name: core.serialization.string().optional(), + seedSampleData: core.serialization.property("seed_sample_data", core.serialization.boolean().optional()), +}); + +export declare namespace InstallStripeSandboxRequestBody { + export interface Raw { + country?: string | null; + email: string; + name?: string | null; + seed_sample_data?: boolean | null; + } +} diff --git a/src/serialization/resources/integrationsapi/client/requests/index.ts b/src/serialization/resources/integrationsapi/client/requests/index.ts index 3c15e6ae..aff599c3 100644 --- a/src/serialization/resources/integrationsapi/client/requests/index.ts +++ b/src/serialization/resources/integrationsapi/client/requests/index.ts @@ -1 +1,3 @@ +export { ClaimStripeSandboxKeysRequestBody } from "./ClaimStripeSandboxKeysRequestBody"; +export { InstallStripeSandboxRequestBody } from "./InstallStripeSandboxRequestBody"; export { StartDataImportRequestBody } from "./StartDataImportRequestBody"; diff --git a/src/serialization/resources/integrationsapi/types/ClaimStripeSandboxKeysResponse.ts b/src/serialization/resources/integrationsapi/types/ClaimStripeSandboxKeysResponse.ts new file mode 100644 index 00000000..ced992b4 --- /dev/null +++ b/src/serialization/resources/integrationsapi/types/ClaimStripeSandboxKeysResponse.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { ClaimedStripeSandboxKeysResponseData } from "../../../types/ClaimedStripeSandboxKeysResponseData"; + +export const ClaimStripeSandboxKeysResponse: core.serialization.ObjectSchema< + serializers.ClaimStripeSandboxKeysResponse.Raw, + Schematic.ClaimStripeSandboxKeysResponse +> = core.serialization.object({ + data: ClaimedStripeSandboxKeysResponseData, + params: core.serialization.record(core.serialization.string(), core.serialization.unknown()), +}); + +export declare namespace ClaimStripeSandboxKeysResponse { + export interface Raw { + data: ClaimedStripeSandboxKeysResponseData.Raw; + params: Record; + } +} diff --git a/src/serialization/resources/integrationsapi/types/GetStripeSandboxClaimLinkResponse.ts b/src/serialization/resources/integrationsapi/types/GetStripeSandboxClaimLinkResponse.ts new file mode 100644 index 00000000..57ffffc7 --- /dev/null +++ b/src/serialization/resources/integrationsapi/types/GetStripeSandboxClaimLinkResponse.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { StripeSandboxClaimLink } from "../../../types/StripeSandboxClaimLink"; + +export const GetStripeSandboxClaimLinkResponse: core.serialization.ObjectSchema< + serializers.GetStripeSandboxClaimLinkResponse.Raw, + Schematic.GetStripeSandboxClaimLinkResponse +> = core.serialization.object({ + data: StripeSandboxClaimLink, + params: core.serialization.record(core.serialization.string(), core.serialization.unknown()), +}); + +export declare namespace GetStripeSandboxClaimLinkResponse { + export interface Raw { + data: StripeSandboxClaimLink.Raw; + params: Record; + } +} diff --git a/src/serialization/resources/integrationsapi/types/GetStripeSandboxKeysResponse.ts b/src/serialization/resources/integrationsapi/types/GetStripeSandboxKeysResponse.ts new file mode 100644 index 00000000..ef0c212f --- /dev/null +++ b/src/serialization/resources/integrationsapi/types/GetStripeSandboxKeysResponse.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { ClaimedStripeSandboxKeysResponseData } from "../../../types/ClaimedStripeSandboxKeysResponseData"; + +export const GetStripeSandboxKeysResponse: core.serialization.ObjectSchema< + serializers.GetStripeSandboxKeysResponse.Raw, + Schematic.GetStripeSandboxKeysResponse +> = core.serialization.object({ + data: ClaimedStripeSandboxKeysResponseData, + params: core.serialization.record(core.serialization.string(), core.serialization.unknown()), +}); + +export declare namespace GetStripeSandboxKeysResponse { + export interface Raw { + data: ClaimedStripeSandboxKeysResponseData.Raw; + params: Record; + } +} diff --git a/src/serialization/resources/integrationsapi/types/InstallStripeClaimableSandboxResponse.ts b/src/serialization/resources/integrationsapi/types/InstallStripeClaimableSandboxResponse.ts new file mode 100644 index 00000000..a9b5f7d4 --- /dev/null +++ b/src/serialization/resources/integrationsapi/types/InstallStripeClaimableSandboxResponse.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { StripeSandboxInstallResponseData } from "../../../types/StripeSandboxInstallResponseData"; + +export const InstallStripeClaimableSandboxResponse: core.serialization.ObjectSchema< + serializers.InstallStripeClaimableSandboxResponse.Raw, + Schematic.InstallStripeClaimableSandboxResponse +> = core.serialization.object({ + data: StripeSandboxInstallResponseData, + params: core.serialization.record(core.serialization.string(), core.serialization.unknown()), +}); + +export declare namespace InstallStripeClaimableSandboxResponse { + export interface Raw { + data: StripeSandboxInstallResponseData.Raw; + params: Record; + } +} diff --git a/src/serialization/resources/integrationsapi/types/ListStripeSandboxCountriesResponse.ts b/src/serialization/resources/integrationsapi/types/ListStripeSandboxCountriesResponse.ts new file mode 100644 index 00000000..dacacd18 --- /dev/null +++ b/src/serialization/resources/integrationsapi/types/ListStripeSandboxCountriesResponse.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../../../api/index"; +import * as core from "../../../../core"; +import type * as serializers from "../../../index"; +import { StripeSandboxCountriesResponseData } from "../../../types/StripeSandboxCountriesResponseData"; + +export const ListStripeSandboxCountriesResponse: core.serialization.ObjectSchema< + serializers.ListStripeSandboxCountriesResponse.Raw, + Schematic.ListStripeSandboxCountriesResponse +> = core.serialization.object({ + data: StripeSandboxCountriesResponseData, + params: core.serialization.record(core.serialization.string(), core.serialization.unknown()), +}); + +export declare namespace ListStripeSandboxCountriesResponse { + export interface Raw { + data: StripeSandboxCountriesResponseData.Raw; + params: Record; + } +} diff --git a/src/serialization/resources/integrationsapi/types/index.ts b/src/serialization/resources/integrationsapi/types/index.ts index 3c4b71a4..3835c1ba 100644 --- a/src/serialization/resources/integrationsapi/types/index.ts +++ b/src/serialization/resources/integrationsapi/types/index.ts @@ -1,9 +1,14 @@ export * from "./AssumeStripeInstalledResponse"; +export * from "./ClaimStripeSandboxKeysResponse"; export * from "./GetIntegrationWebhookUrlResponse"; +export * from "./GetStripeSandboxClaimLinkResponse"; +export * from "./GetStripeSandboxKeysResponse"; export * from "./InstallIntegrationResponse"; +export * from "./InstallStripeClaimableSandboxResponse"; export * from "./InstallStripeResponse"; export * from "./ListIntegrationsParams"; export * from "./ListIntegrationsResponse"; +export * from "./ListStripeSandboxCountriesResponse"; export * from "./LoadSampleDataSetResponse"; export * from "./RunIntegrationResponse"; export * from "./StartDataImportResponse"; diff --git a/src/serialization/types/ClaimedStripeSandboxKeysResponseData.ts b/src/serialization/types/ClaimedStripeSandboxKeysResponseData.ts new file mode 100644 index 00000000..83eebeff --- /dev/null +++ b/src/serialization/types/ClaimedStripeSandboxKeysResponseData.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../api/index"; +import * as core from "../../core"; +import type * as serializers from "../index"; + +export const ClaimedStripeSandboxKeysResponseData: core.serialization.ObjectSchema< + serializers.ClaimedStripeSandboxKeysResponseData.Raw, + Schematic.ClaimedStripeSandboxKeysResponseData +> = core.serialization.object({ + publishable: core.serialization.string(), + sandboxId: core.serialization.property("sandbox_id", core.serialization.string()), + secret: core.serialization.string(), +}); + +export declare namespace ClaimedStripeSandboxKeysResponseData { + export interface Raw { + publishable: string; + sandbox_id: string; + secret: string; + } +} diff --git a/src/serialization/types/CompanyBillingProfileResponseData.ts b/src/serialization/types/CompanyBillingProfileResponseData.ts new file mode 100644 index 00000000..0a2e15f4 --- /dev/null +++ b/src/serialization/types/CompanyBillingProfileResponseData.ts @@ -0,0 +1,47 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../api/index"; +import * as core from "../../core"; +import type * as serializers from "../index"; +import { BillingCollectionMethod } from "./BillingCollectionMethod"; +import { BillingProviderType } from "./BillingProviderType"; +import { ProrationBehavior } from "./ProrationBehavior"; + +export const CompanyBillingProfileResponseData: core.serialization.ObjectSchema< + serializers.CompanyBillingProfileResponseData.Raw, + Schematic.CompanyBillingProfileResponseData +> = core.serialization.object({ + accountId: core.serialization.property("account_id", core.serialization.string()), + billingCustomerId: core.serialization.property("billing_customer_id", core.serialization.string().optional()), + collectionMethod: core.serialization.property("collection_method", BillingCollectionMethod), + companyId: core.serialization.property("company_id", core.serialization.string()), + createdAt: core.serialization.property("created_at", core.serialization.date()), + daysUntilDue: core.serialization.property("days_until_due", core.serialization.number().optional()), + environmentId: core.serialization.property("environment_id", core.serialization.string()), + id: core.serialization.string(), + isDefault: core.serialization.property("is_default", core.serialization.boolean()), + name: core.serialization.string().optional(), + paymentMethodId: core.serialization.property("payment_method_id", core.serialization.string().optional()), + prorationBehavior: core.serialization.property("proration_behavior", ProrationBehavior.optional()), + providerType: core.serialization.property("provider_type", BillingProviderType), + updatedAt: core.serialization.property("updated_at", core.serialization.date()), +}); + +export declare namespace CompanyBillingProfileResponseData { + export interface Raw { + account_id: string; + billing_customer_id?: string | null; + collection_method: BillingCollectionMethod.Raw; + company_id: string; + created_at: string; + days_until_due?: number | null; + environment_id: string; + id: string; + is_default: boolean; + name?: string | null; + payment_method_id?: string | null; + proration_behavior?: ProrationBehavior.Raw | null; + provider_type: BillingProviderType.Raw; + updated_at: string; + } +} diff --git a/src/serialization/types/CompanyDetailResponseData.ts b/src/serialization/types/CompanyDetailResponseData.ts index 5483195e..ab368c46 100644 --- a/src/serialization/types/CompanyDetailResponseData.ts +++ b/src/serialization/types/CompanyDetailResponseData.ts @@ -4,6 +4,7 @@ import type * as Schematic from "../../api/index"; import * as core from "../../core"; import type * as serializers from "../index"; import { BillingSubscriptionView } from "./BillingSubscriptionView"; +import { CompanyBillingProfileResponseData } from "./CompanyBillingProfileResponseData"; import { CompanyEventPeriodMetricsResponseData } from "./CompanyEventPeriodMetricsResponseData"; import { CompanyPlanWithBillingSubView } from "./CompanyPlanWithBillingSubView"; import { CustomPlanBillingResponseData } from "./CustomPlanBillingResponseData"; @@ -25,6 +26,11 @@ export const CompanyDetailResponseData: core.serialization.ObjectSchema< "billing_credit_balances", core.serialization.record(core.serialization.string(), core.serialization.number()).optional(), ), + billingProfile: core.serialization.property("billing_profile", CompanyBillingProfileResponseData.optional()), + billingProfiles: core.serialization.property( + "billing_profiles", + core.serialization.list(CompanyBillingProfileResponseData).optional(), + ), billingSubscription: core.serialization.property("billing_subscription", BillingSubscriptionView.optional()), billingSubscriptions: core.serialization.property( "billing_subscriptions", @@ -60,6 +66,8 @@ export declare namespace CompanyDetailResponseData { export interface Raw { add_ons: CompanyPlanWithBillingSubView.Raw[]; billing_credit_balances?: Record | null; + billing_profile?: CompanyBillingProfileResponseData.Raw | null; + billing_profiles?: CompanyBillingProfileResponseData.Raw[] | null; billing_subscription?: BillingSubscriptionView.Raw | null; billing_subscriptions: BillingSubscriptionView.Raw[]; created_at: string; diff --git a/src/serialization/types/CompanyOverrideResponseData.ts b/src/serialization/types/CompanyOverrideResponseData.ts index bdc4c395..95856238 100644 --- a/src/serialization/types/CompanyOverrideResponseData.ts +++ b/src/serialization/types/CompanyOverrideResponseData.ts @@ -3,6 +3,7 @@ import type * as Schematic from "../../api/index"; import * as core from "../../core"; import type * as serializers from "../index"; +import { BillingCreditResponseData } from "./BillingCreditResponseData"; import { CompanyDetailResponseData } from "./CompanyDetailResponseData"; import { CompanyOverrideNoteResponseData } from "./CompanyOverrideNoteResponseData"; import { EntitlementValueType } from "./EntitlementValueType"; @@ -31,6 +32,8 @@ export const CompanyOverrideResponseData: core.serialization.ObjectSchema< ruleIdUsageExceeded: core.serialization.property("rule_id_usage_exceeded", core.serialization.string().optional()), updatedAt: core.serialization.property("updated_at", core.serialization.date()), valueBool: core.serialization.property("value_bool", core.serialization.boolean().optional()), + valueCredit: core.serialization.property("value_credit", BillingCreditResponseData.optional()), + valueCreditId: core.serialization.property("value_credit_id", core.serialization.string().optional()), valueNumeric: core.serialization.property("value_numeric", core.serialization.number().optional()), valueTrait: core.serialization.property("value_trait", EntityTraitDefinitionResponseData.optional()), valueTraitId: core.serialization.property("value_trait_id", core.serialization.string().optional()), @@ -55,6 +58,8 @@ export declare namespace CompanyOverrideResponseData { rule_id_usage_exceeded?: string | null; updated_at: string; value_bool?: boolean | null; + value_credit?: BillingCreditResponseData.Raw | null; + value_credit_id?: string | null; value_numeric?: number | null; value_trait?: EntityTraitDefinitionResponseData.Raw | null; value_trait_id?: string | null; diff --git a/src/serialization/types/CreditSpendPolicyResponseData.ts b/src/serialization/types/CreditSpendPolicyResponseData.ts new file mode 100644 index 00000000..9f1bc294 --- /dev/null +++ b/src/serialization/types/CreditSpendPolicyResponseData.ts @@ -0,0 +1,35 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../api/index"; +import * as core from "../../core"; +import type * as serializers from "../index"; +import { CreditSpendPolicyScope } from "./CreditSpendPolicyScope"; + +export const CreditSpendPolicyResponseData: core.serialization.ObjectSchema< + serializers.CreditSpendPolicyResponseData.Raw, + Schematic.CreditSpendPolicyResponseData +> = core.serialization.object({ + billingCreditId: core.serialization.property("billing_credit_id", core.serialization.string()), + companyId: core.serialization.property("company_id", core.serialization.string().optional()), + createdAt: core.serialization.property("created_at", core.serialization.date()), + id: core.serialization.string(), + label: core.serialization.string().optional(), + maxPerDraw: core.serialization.property("max_per_draw", core.serialization.number().optional()), + scopeType: core.serialization.property("scope_type", CreditSpendPolicyScope), + updatedAt: core.serialization.property("updated_at", core.serialization.date()), + userId: core.serialization.property("user_id", core.serialization.string().optional()), +}); + +export declare namespace CreditSpendPolicyResponseData { + export interface Raw { + billing_credit_id: string; + company_id?: string | null; + created_at: string; + id: string; + label?: string | null; + max_per_draw?: number | null; + scope_type: CreditSpendPolicyScope.Raw; + updated_at: string; + user_id?: string | null; + } +} diff --git a/src/serialization/types/CreditSpendPolicyScope.ts b/src/serialization/types/CreditSpendPolicyScope.ts new file mode 100644 index 00000000..4be0f45a --- /dev/null +++ b/src/serialization/types/CreditSpendPolicyScope.ts @@ -0,0 +1,14 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../api/index"; +import * as core from "../../core"; +import type * as serializers from "../index"; + +export const CreditSpendPolicyScope: core.serialization.Schema< + serializers.CreditSpendPolicyScope.Raw, + Schematic.CreditSpendPolicyScope +> = core.serialization.enum_(["company", "user", "group"]); + +export declare namespace CreditSpendPolicyScope { + export type Raw = "company" | "user" | "group"; +} diff --git a/src/serialization/types/EventBodyInference.ts b/src/serialization/types/EventBodyInference.ts index 898174a7..5ec6b863 100644 --- a/src/serialization/types/EventBodyInference.ts +++ b/src/serialization/types/EventBodyInference.ts @@ -8,6 +8,10 @@ export const EventBodyInference: core.serialization.ObjectSchema< serializers.EventBodyInference.Raw, Schematic.EventBodyInference > = core.serialization.object({ + cacheCreationInputTokens: core.serialization.property( + "cache_creation_input_tokens", + core.serialization.number().optional(), + ), cachedInputTokens: core.serialization.property("cached_input_tokens", core.serialization.number().optional()), company: core.serialization.record(core.serialization.string(), core.serialization.string()), cost: core.serialization.string().optional(), @@ -26,6 +30,7 @@ export const EventBodyInference: core.serialization.ObjectSchema< export declare namespace EventBodyInference { export interface Raw { + cache_creation_input_tokens?: number | null; cached_input_tokens?: number | null; company: Record; cost?: string | null; diff --git a/src/serialization/types/GetOnboardingStateResp.ts b/src/serialization/types/GetOnboardingStateResp.ts index cae18d26..9c69b39d 100644 --- a/src/serialization/types/GetOnboardingStateResp.ts +++ b/src/serialization/types/GetOnboardingStateResp.ts @@ -15,6 +15,7 @@ export const GetOnboardingStateResp: core.serialization.ObjectSchema< Schematic.GetOnboardingStateResp > = core.serialization.object({ agentConnectedAt: core.serialization.property("agent_connected_at", core.serialization.date().optional()), + country: core.serialization.string().optional(), dismissedAt: core.serialization.property("dismissed_at", core.serialization.date().optional()), environmentId: core.serialization.property("environment_id", core.serialization.string().optional()), milestones: core.serialization.list(OnboardingMilestoneView), @@ -30,6 +31,7 @@ export const GetOnboardingStateResp: core.serialization.ObjectSchema< export declare namespace GetOnboardingStateResp { export interface Raw { agent_connected_at?: string | null; + country?: string | null; dismissed_at?: string | null; environment_id?: string | null; milestones: OnboardingMilestoneView.Raw[]; diff --git a/src/serialization/types/OtlpEnvironmentSettingsResponseData.ts b/src/serialization/types/OtlpEnvironmentSettingsResponseData.ts new file mode 100644 index 00000000..68645de9 --- /dev/null +++ b/src/serialization/types/OtlpEnvironmentSettingsResponseData.ts @@ -0,0 +1,32 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../api/index"; +import * as core from "../../core"; +import type * as serializers from "../index"; + +export const OtlpEnvironmentSettingsResponseData: core.serialization.ObjectSchema< + serializers.OtlpEnvironmentSettingsResponseData.Raw, + Schematic.OtlpEnvironmentSettingsResponseData +> = core.serialization.object({ + companyAttribute: core.serialization.property("company_attribute", core.serialization.string().optional()), + companyKey: core.serialization.property("company_key", core.serialization.string().optional()), + createdAt: core.serialization.property("created_at", core.serialization.date()), + environmentId: core.serialization.property("environment_id", core.serialization.string()), + toolEventsEnabled: core.serialization.property("tool_events_enabled", core.serialization.boolean()), + updatedAt: core.serialization.property("updated_at", core.serialization.date()), + userAttribute: core.serialization.property("user_attribute", core.serialization.string().optional()), + userKey: core.serialization.property("user_key", core.serialization.string().optional()), +}); + +export declare namespace OtlpEnvironmentSettingsResponseData { + export interface Raw { + company_attribute?: string | null; + company_key?: string | null; + created_at: string; + environment_id: string; + tool_events_enabled: boolean; + updated_at: string; + user_attribute?: string | null; + user_key?: string | null; + } +} diff --git a/src/serialization/types/RuleConditionDetailResponseData.ts b/src/serialization/types/RuleConditionDetailResponseData.ts index 7424c50a..56d878c0 100644 --- a/src/serialization/types/RuleConditionDetailResponseData.ts +++ b/src/serialization/types/RuleConditionDetailResponseData.ts @@ -10,6 +10,7 @@ import { EntityType } from "./EntityType"; import { MetricPeriod } from "./MetricPeriod"; import { MetricPeriodMonthReset } from "./MetricPeriodMonthReset"; import { PreviewObjectResponseData } from "./PreviewObjectResponseData"; +import { RuleConditionPlanVersionResponseData } from "./RuleConditionPlanVersionResponseData"; export const RuleConditionDetailResponseData: core.serialization.ObjectSchema< serializers.RuleConditionDetailResponseData.Raw, @@ -28,6 +29,10 @@ export const RuleConditionDetailResponseData: core.serialization.ObjectSchema< metricPeriodMonthReset: core.serialization.property("metric_period_month_reset", MetricPeriodMonthReset.optional()), metricValue: core.serialization.property("metric_value", core.serialization.number().optional()), operator: ComparableOperator, + planVersions: core.serialization.property( + "plan_versions", + core.serialization.list(RuleConditionPlanVersionResponseData).optional(), + ), resourceIds: core.serialization.property("resource_ids", core.serialization.list(core.serialization.string())), resources: core.serialization.list(PreviewObjectResponseData), ruleId: core.serialization.property("rule_id", core.serialization.string()), @@ -53,6 +58,7 @@ export declare namespace RuleConditionDetailResponseData { metric_period_month_reset?: MetricPeriodMonthReset.Raw | null; metric_value?: number | null; operator: ComparableOperator.Raw; + plan_versions?: RuleConditionPlanVersionResponseData.Raw[] | null; resource_ids: string[]; resources: PreviewObjectResponseData.Raw[]; rule_id: string; diff --git a/src/serialization/types/RuleConditionPlanVersionResponseData.ts b/src/serialization/types/RuleConditionPlanVersionResponseData.ts new file mode 100644 index 00000000..5bf073f6 --- /dev/null +++ b/src/serialization/types/RuleConditionPlanVersionResponseData.ts @@ -0,0 +1,25 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../api/index"; +import * as core from "../../core"; +import type * as serializers from "../index"; +import { PlanVersionStatus } from "./PlanVersionStatus"; + +export const RuleConditionPlanVersionResponseData: core.serialization.ObjectSchema< + serializers.RuleConditionPlanVersionResponseData.Raw, + Schematic.RuleConditionPlanVersionResponseData +> = core.serialization.object({ + id: core.serialization.string(), + name: core.serialization.string(), + status: PlanVersionStatus, + version: core.serialization.number(), +}); + +export declare namespace RuleConditionPlanVersionResponseData { + export interface Raw { + id: string; + name: string; + status: PlanVersionStatus.Raw; + version: number; + } +} diff --git a/src/serialization/types/StripeIntegrationConfig.ts b/src/serialization/types/StripeIntegrationConfig.ts index 52ae8ce7..ebe29be8 100644 --- a/src/serialization/types/StripeIntegrationConfig.ts +++ b/src/serialization/types/StripeIntegrationConfig.ts @@ -10,6 +10,15 @@ export const StripeIntegrationConfig: core.serialization.ObjectSchema< > = core.serialization.object({ accountId: core.serialization.property("account_id", core.serialization.string().optional()), accountName: core.serialization.property("account_name", core.serialization.string().optional()), + claimableSandboxExpiresAt: core.serialization.property( + "claimable_sandbox_expires_at", + core.serialization.date().optional(), + ), + claimableSandboxId: core.serialization.property("claimable_sandbox_id", core.serialization.string().optional()), + claimableSandboxStatus: core.serialization.property( + "claimable_sandbox_status", + core.serialization.string().optional(), + ), companyUpdateOnly: core.serialization.property("company_update_only", core.serialization.boolean().optional()), isSandbox: core.serialization.property("is_sandbox", core.serialization.boolean()), liveMode: core.serialization.property("live_mode", core.serialization.boolean()), @@ -21,6 +30,9 @@ export declare namespace StripeIntegrationConfig { export interface Raw { account_id?: string | null; account_name?: string | null; + claimable_sandbox_expires_at?: string | null; + claimable_sandbox_id?: string | null; + claimable_sandbox_status?: string | null; company_update_only?: boolean | null; is_sandbox: boolean; live_mode: boolean; diff --git a/src/serialization/types/StripeSandboxClaimLink.ts b/src/serialization/types/StripeSandboxClaimLink.ts new file mode 100644 index 00000000..13e25639 --- /dev/null +++ b/src/serialization/types/StripeSandboxClaimLink.ts @@ -0,0 +1,24 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../api/index"; +import * as core from "../../core"; +import type * as serializers from "../index"; + +export const StripeSandboxClaimLink: core.serialization.ObjectSchema< + serializers.StripeSandboxClaimLink.Raw, + Schematic.StripeSandboxClaimLink +> = core.serialization.object({ + claimUrl: core.serialization.property("claim_url", core.serialization.string()), + expiresAt: core.serialization.property("expires_at", core.serialization.date().optional()), + sandboxId: core.serialization.property("sandbox_id", core.serialization.string()), + status: core.serialization.string(), +}); + +export declare namespace StripeSandboxClaimLink { + export interface Raw { + claim_url: string; + expires_at?: string | null; + sandbox_id: string; + status: string; + } +} diff --git a/src/serialization/types/StripeSandboxCountriesResponseData.ts b/src/serialization/types/StripeSandboxCountriesResponseData.ts new file mode 100644 index 00000000..7b92e46f --- /dev/null +++ b/src/serialization/types/StripeSandboxCountriesResponseData.ts @@ -0,0 +1,18 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../api/index"; +import * as core from "../../core"; +import type * as serializers from "../index"; + +export const StripeSandboxCountriesResponseData: core.serialization.ObjectSchema< + serializers.StripeSandboxCountriesResponseData.Raw, + Schematic.StripeSandboxCountriesResponseData +> = core.serialization.object({ + countries: core.serialization.list(core.serialization.string()), +}); + +export declare namespace StripeSandboxCountriesResponseData { + export interface Raw { + countries: string[]; + } +} diff --git a/src/serialization/types/StripeSandboxInstallResponseData.ts b/src/serialization/types/StripeSandboxInstallResponseData.ts new file mode 100644 index 00000000..e8cd2a99 --- /dev/null +++ b/src/serialization/types/StripeSandboxInstallResponseData.ts @@ -0,0 +1,32 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../api/index"; +import * as core from "../../core"; +import type * as serializers from "../index"; +import { IntegrationInstallResponseData } from "./IntegrationInstallResponseData"; +import { StripeSandboxKeysResponseData } from "./StripeSandboxKeysResponseData"; + +export const StripeSandboxInstallResponseData: core.serialization.ObjectSchema< + serializers.StripeSandboxInstallResponseData.Raw, + Schematic.StripeSandboxInstallResponseData +> = core.serialization.object({ + apiKeys: core.serialization.property("api_keys", StripeSandboxKeysResponseData.optional()), + claimUrl: core.serialization.property("claim_url", core.serialization.string()), + claimUrlExpiresAt: core.serialization.property("claim_url_expires_at", core.serialization.date().optional()), + expiresAt: core.serialization.property("expires_at", core.serialization.date().optional()), + install: IntegrationInstallResponseData, + sandboxId: core.serialization.property("sandbox_id", core.serialization.string()), + stripeAccountId: core.serialization.property("stripe_account_id", core.serialization.string()), +}); + +export declare namespace StripeSandboxInstallResponseData { + export interface Raw { + api_keys?: StripeSandboxKeysResponseData.Raw | null; + claim_url: string; + claim_url_expires_at?: string | null; + expires_at?: string | null; + install: IntegrationInstallResponseData.Raw; + sandbox_id: string; + stripe_account_id: string; + } +} diff --git a/src/serialization/types/StripeSandboxKeysResponseData.ts b/src/serialization/types/StripeSandboxKeysResponseData.ts new file mode 100644 index 00000000..9bfcd7f7 --- /dev/null +++ b/src/serialization/types/StripeSandboxKeysResponseData.ts @@ -0,0 +1,22 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as Schematic from "../../api/index"; +import * as core from "../../core"; +import type * as serializers from "../index"; + +export const StripeSandboxKeysResponseData: core.serialization.ObjectSchema< + serializers.StripeSandboxKeysResponseData.Raw, + Schematic.StripeSandboxKeysResponseData +> = core.serialization.object({ + mcp: core.serialization.string(), + publishable: core.serialization.string(), + secret: core.serialization.string(), +}); + +export declare namespace StripeSandboxKeysResponseData { + export interface Raw { + mcp: string; + publishable: string; + secret: string; + } +} diff --git a/src/serialization/types/index.ts b/src/serialization/types/index.ts index 6e7d3cb9..f54b90e5 100644 --- a/src/serialization/types/index.ts +++ b/src/serialization/types/index.ts @@ -89,6 +89,7 @@ export * from "./CheckoutFieldValue"; export * from "./CheckoutFieldWithValue"; export * from "./CheckoutSettingsResponseData"; export * from "./CheckoutSubscription"; +export * from "./ClaimedStripeSandboxKeysResponseData"; export * from "./ClerkIntegrationConfig"; export * from "./CompanyBillingAddressView"; export * from "./CompanyBillingCheckoutSettings"; @@ -96,6 +97,7 @@ export * from "./CompanyBillingDetailsResponseData"; export * from "./CompanyBillingDetailsView"; export * from "./CompanyBillingEntityResponseData"; export * from "./CompanyBillingEntitySubscriptionResponseData"; +export * from "./CompanyBillingProfileResponseData"; export * from "./CompanyCreditBalance"; export * from "./CompanyCreditBalanceResponseData"; export * from "./CompanyDetailResponseData"; @@ -165,6 +167,8 @@ export * from "./CreditGrantDetail"; export * from "./CreditGrantExpiryRequestBody"; export * from "./CreditGrantSortOrder"; export * from "./CreditLeaseResponseData"; +export * from "./CreditSpendPolicyResponseData"; +export * from "./CreditSpendPolicyScope"; export * from "./CreditsAutoTopupCompanySummary"; export * from "./CreditsAutoTopupCreditSummary"; export * from "./CreditsAutoTopupHardFailure"; @@ -293,6 +297,7 @@ export * from "./OnboardingStripeImport"; export * from "./OnboardingTrack"; export * from "./OrbIntegrationConfig"; export * from "./OrderedPlansInGroup"; +export * from "./OtlpEnvironmentSettingsResponseData"; export * from "./PaymentMethodRequestBody"; export * from "./PaymentMethodResponseData"; export * from "./PendingMigrationResponseData"; @@ -357,6 +362,7 @@ export * from "./Rule"; export * from "./RuleConditionDetailResponseData"; export * from "./RuleConditionGroupDetailResponseData"; export * from "./RuleConditionGroupResponseData"; +export * from "./RuleConditionPlanVersionResponseData"; export * from "./RuleConditionResponseData"; export * from "./RuleDetailResponseData"; export * from "./RuleResponseData"; @@ -394,6 +400,10 @@ export * from "./SkippedEntitlementResponseData"; export * from "./SortDirection"; export * from "./StripeEmbedInfo"; export * from "./StripeIntegrationConfig"; +export * from "./StripeSandboxClaimLink"; +export * from "./StripeSandboxCountriesResponseData"; +export * from "./StripeSandboxInstallResponseData"; +export * from "./StripeSandboxKeysResponseData"; export * from "./SubscriptionStatus"; export * from "./SubscriptionTraitUpdate"; export * from "./SubscriptionType"; diff --git a/tests/conformance/runner.test.ts b/tests/conformance/runner.test.ts deleted file mode 100644 index 3a29a886..00000000 --- a/tests/conformance/runner.test.ts +++ /dev/null @@ -1,720 +0,0 @@ -/** - * Executes the language-agnostic conformance vectors in `conformance/vectors/` - * against the reference implementation, on both store backends. The vector - * schema and the semantics they pin are documented in `conformance/SPEC.md`; - * ports of the lease/reservation system reimplement this runner (it is the - * only language-specific piece) and must pass the same vectors. - */ -import * as fs from "fs"; -import * as path from "path"; - -import type * as api from "../../src/api"; -import type { CreditsClient } from "../../src/api/resources/credits/client/Client"; -import { type CreditCheckDeps, checkWithLease } from "../../src/credits/check"; -import { CreditLeaseManager } from "../../src/credits/lease-manager"; -import { type ILeaseStore, LeaseStore } from "../../src/credits/lease-store"; -import { RedisLeaseStore } from "../../src/credits/redis-lease-store"; -import { RedisReservationStore } from "../../src/credits/redis-reservation-store"; -import { type IReservationStore, ReservationStore } from "../../src/credits/reservation-store"; -import { consumeReservationAndBuildEvent } from "../../src/credits/track"; -import type { CheckOptions, CheckResult, OnAcquireFailure, Reservation } from "../../src/credits/types"; -import type { DataStreamClient } from "../../src/datastream"; -import type { Logger } from "../../src/logger"; -import { makeFakeRedis } from "../unit/credits/fake-redis"; - -// --------------------------------------------------------------------------- -// Vector schema (see conformance/SPEC.md — keys are snake_case JSON). - -interface LeaseSpec { - lease_id: string; - company_id: string; - credit_type_id: string; - granted_amount: number; - expires_at_ms: number; -} - -interface ConfigSpec { - lease_duration_ms?: number; - reservation_ttl_ms?: number; - lease_size?: number; - low_water_mark?: number; -} - -interface ServerLeaseSpec { - lease_id?: string; - granted_amount?: number; - granted_total?: number; - expires_at_ms: number; -} - -type ServerScript = { lease: ServerLeaseSpec; error?: undefined } | { error: string; lease?: undefined }; - -interface EngineEntitlementSpec { - value_type: string; - credit_id?: string; - consumption_rate?: number; - event_subtype?: string; -} - -interface EngineResultSpec { - value: boolean; - reason?: string; - entitlement?: EngineEntitlementSpec; -} - -interface EngineCallExpect { - credit_balance?: number | "max_safe_integer"; - credit_cost?: number; - event_usage?: { event_subtype: string; quantity: number }; - usage?: number; -} - -interface OpExpect { - written?: boolean; - balance?: number | null; - consumed?: number | null; - throws?: boolean; - exists?: boolean; - lease_id?: string | null; - granted_amount?: number; - local_remaining_credits?: number; - total?: number; - count?: number; - swept?: number; - wire_acquires?: number; - last_acquire_requested_amount?: number; - released_lease_ids?: string[]; - wire_extends?: number; - last_extend_additional_amount?: number; - last_extend_lease_id?: string; - allowed?: boolean; - reason?: string; - err?: string; - has_reservation?: boolean; - reservation?: { - lease_id?: string; - credit_type_id?: string; - event_subtype?: string; - quantity_reserved?: number; - credits_reserved?: number; - consumption_rate?: number; - }; - engine_calls?: EngineCallExpect[]; - fallback_called?: boolean; - settled_locally?: boolean; - track?: { event?: string; quantity?: number; lease_id?: string }; -} - -interface Operation { - op: string; - expect?: OpExpect; - // advance_clock - ms?: number; - // lease / reservation store ops - lease_id?: string; - company_id?: string; - credit_type_id?: string; - granted_amount?: number; - expires_at_ms?: number; - credits?: number; - pin_lease_id?: string; - granted_total?: number; - id?: string; - handle?: string; - event_subtype?: string; - quantity_reserved?: number; - credits_reserved?: number; - consumption_rate?: number; - crash_before_refund?: boolean; - // manager ops - required_credits?: number; - server?: ServerScript | { acquire?: ServerScript; extend?: ServerScript }; - install_during_wire?: LeaseSpec; - // check / track ops - flag_key?: string; - company?: { id: string; credit_balances?: Record }; - usage?: number; - on_acquire_failure?: string; - engine?: EngineResultSpec[]; - save_reservation_as?: string; - actual_quantity?: number; -} - -interface Vector { - name: string; - description: string; - backends?: string[]; - given?: { config?: ConfigSpec; leases?: LeaseSpec[] }; - operations: Operation[]; -} - -interface VectorDoc { - category: string; - vectors: Vector[]; -} - -const VECTORS_DIR = path.join(__dirname, "..", "..", "conformance", "vectors"); -const documents: VectorDoc[] = fs - .readdirSync(VECTORS_DIR) - .filter((f) => f.endsWith(".json")) - .sort() - .map((f) => JSON.parse(fs.readFileSync(path.join(VECTORS_DIR, f), "utf8")) as VectorDoc); - -// --------------------------------------------------------------------------- -// Backends. The crash hook interposes on the lease store the RESERVATION -// store refunds through (the consume-then-refund window); every other path -// uses the raw store. One-shot: it disarms itself when it fires. - -interface Stores { - leases: ILeaseStore; - reservations: IReservationStore; - armCrash: () => void; -} - -function crashableRefund(target: ILeaseStore): { store: ILeaseStore; arm: () => void } { - let armed = false; - return { - arm: () => { - armed = true; - }, - store: { - get: (companyId, creditTypeId) => target.get(companyId, creditTypeId), - replace: (entry) => target.replace(entry), - extend: (companyId, creditTypeId, grantedAmount, newExpiresAt, leaseId) => - target.extend(companyId, creditTypeId, grantedAmount, newExpiresAt, leaseId), - drop: (companyId, creditTypeId) => target.drop(companyId, creditTypeId), - tryReserve: (companyId, creditTypeId, credits) => target.tryReserve(companyId, creditTypeId, credits), - refund: (companyId, creditTypeId, credits, leaseId) => { - if (armed) { - armed = false; - throw new Error("simulated crash before refund"); - } - return target.refund(companyId, creditTypeId, credits, leaseId); - }, - }, - }; -} - -const backends: Array<["in_memory" | "redis", () => Stores]> = [ - [ - "in_memory", - () => { - const leases = new LeaseStore(); - const crash = crashableRefund(leases); - return { leases, reservations: new ReservationStore(crash.store, 60_000), armCrash: crash.arm }; - }, - ], - [ - "redis", - () => { - const client = makeFakeRedis(); - const leases = new RedisLeaseStore({ client }); - const crash = crashableRefund(leases); - return { - leases, - reservations: new RedisReservationStore({ client, leaseStore: crash.store, sweepIntervalMs: 60_000 }), - armCrash: crash.arm, - }; - }, - ], -]; - -// --------------------------------------------------------------------------- -// Harness - -const T0 = new Date("2026-01-01T00:00:00Z").getTime(); - -const silentLogger: Logger = { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} }; - -// Let floating fire-and-forget promise chains (background extend, redundant -// release) settle. Only microtasks are involved — no timers. -async function drain(): Promise { - for (let i = 0; i < 20; i++) { - await Promise.resolve(); - } -} - -interface RecordedEngineCall { - creditBalances: Record | undefined; - creditCost: Record | undefined; - eventUsage: { eventSubtype: string; quantity: number } | undefined; - usage: number | undefined; -} - -class Harness { - readonly handles = new Map(); - readonly acquireResponses: ServerScript[] = []; - readonly extendResponses: ServerScript[] = []; - readonly acquireCalls: api.AcquireCreditLeaseRequestBody[] = []; - readonly extendCalls: Array<{ leaseId: string; body: api.ExtendCreditLeaseRequestBody }> = []; - readonly releaseCalls: string[] = []; - installDuringWire: LeaseSpec | undefined; - readonly manager: CreditLeaseManager; - private elapsed = 0; - - constructor( - readonly stores: Stores, - config: ConfigSpec, - ) { - const creditsClient = { - acquireCreditLease: async (body: api.AcquireCreditLeaseRequestBody) => { - this.acquireCalls.push(body); - const install = this.installDuringWire; - if (install) { - this.installDuringWire = undefined; - await this.stores.leases.replace({ - leaseId: install.lease_id, - companyId: install.company_id, - creditTypeId: install.credit_type_id, - grantedAmount: install.granted_amount, - expiresAt: this.atMs(install.expires_at_ms), - }); - } - const scripted = this.acquireResponses.shift(); - if (!scripted || scripted.error !== undefined || !scripted.lease) { - throw new Error(scripted?.error ?? "unscripted acquire wire call"); - } - const lease = scripted.lease; - return { - data: { - id: lease.lease_id ?? "lse_unnamed", - companyId: body.companyId, - creditTypeId: body.creditTypeId, - grantedAmount: lease.granted_amount ?? 0, - expiresAt: this.atMs(lease.expires_at_ms), - createdAt: this.atMs(0), - updatedAt: this.atMs(0), - }, - params: {}, - }; - }, - extendCreditLease: async (leaseId: string, body: api.ExtendCreditLeaseRequestBody) => { - this.extendCalls.push({ leaseId, body }); - const scripted = this.extendResponses.shift(); - if (!scripted || scripted.error !== undefined || !scripted.lease) { - throw new Error(scripted?.error ?? "unscripted extend wire call"); - } - const lease = scripted.lease; - return { - data: { - id: leaseId, - companyId: "co_wire", - creditTypeId: "ct_wire", - grantedAmount: lease.granted_total ?? 0, - expiresAt: this.atMs(lease.expires_at_ms), - createdAt: this.atMs(0), - updatedAt: this.atMs(0), - }, - params: {}, - }; - }, - releaseCreditLease: async (leaseId: string) => { - this.releaseCalls.push(leaseId); - return { data: {}, params: {} }; - }, - } as unknown as CreditsClient; - this.manager = new CreditLeaseManager({ - creditsClient, - leaseStore: stores.leases, - logger: silentLogger, - config: { - defaultLeaseDuration: config.lease_duration_ms, - defaultReservationTTL: config.reservation_ttl_ms, - defaultLeaseSize: config.lease_size, - lowWaterMark: config.low_water_mark, - }, - }); - } - - atMs(offset: number): Date { - return new Date(T0 + offset); - } - - advance(ms: number): void { - this.elapsed += ms; - jest.setSystemTime(T0 + this.elapsed); - } - - setServer(server: Operation["server"]): void { - if (!server) return; - if ("lease" in server || "error" in server) { - // Manager ops script a single call directly. - return; - } - if (server.acquire) this.acquireResponses.push(server.acquire); - if (server.extend) this.extendResponses.push(server.extend); - } - - resolveReservation(op: Operation): string { - if (op.handle !== undefined) { - const reservation = this.handles.get(op.handle); - if (!reservation) throw new Error(`unknown reservation handle: ${op.handle}`); - return reservation.id; - } - if (op.id === undefined) throw new Error(`op ${op.op} needs an id or handle`); - return op.id; - } -} - -function mapEntitlement(spec: EngineEntitlementSpec, flagKey: string) { - return { - featureId: "feat_1", - featureKey: flagKey, - valueType: spec.value_type, - creditId: spec.credit_id, - consumptionRate: spec.consumption_rate, - eventSubtype: spec.event_subtype, - }; -} - -async function runCheck( - h: Harness, - op: Operation, -): Promise<{ result: CheckResult; engineCalls: RecordedEngineCall[]; fallbackCalled: boolean }> { - const flagKey = op.flag_key ?? "flag"; - const company = op.company ?? { id: "co_1" }; - const engineResults = [...(op.engine ?? [])]; - const engineCalls: RecordedEngineCall[] = []; - const engine = { - checkFlagWithOptions: async ( - _flag: unknown, - evalCompany: { creditBalances?: Record }, - _user: unknown, - options: { - creditCost?: Record; - eventUsage?: { eventSubtype: string; quantity: number }; - usage?: number; - } | null, - ) => { - engineCalls.push({ - creditBalances: evalCompany.creditBalances, - creditCost: options?.creditCost, - eventUsage: options?.eventUsage, - usage: options?.usage, - }); - const scripted = engineResults.shift(); - if (!scripted) throw new Error(`unscripted engine call in check op for flag ${flagKey}`); - return { - value: scripted.value, - reason: scripted.reason, - flagKey, - flagId: "flag_1", - entitlement: scripted.entitlement ? mapEntitlement(scripted.entitlement, flagKey) : undefined, - }; - }, - }; - const datastream = { - getFlag: async () => ({ id: "flag_1", key: flagKey }), - getCompany: async () => ({ id: company.id, creditBalances: company.credit_balances ?? {} }), - getUser: async () => null, - getRulesEngine: () => engine, - } as unknown as DataStreamClient; - - h.setServer(op.server); - - let fallbackCalled = false; - const fallback = async (): Promise => { - fallbackCalled = true; - return { allowed: true, value: true, reason: "fallback", flagKey }; - }; - - const deps: CreditCheckDeps = { - leaseStore: h.stores.leases, - reservations: h.stores.reservations, - manager: h.manager, - datastream, - logger: silentLogger, - enqueueFlagCheckEvent: () => {}, - }; - const options: CheckOptions = { - usage: op.usage, - eventSubtype: op.event_subtype, - onAcquireFailure: op.on_acquire_failure as OnAcquireFailure | undefined, - }; - const result = await checkWithLease(deps, flagKey, { company: { id: company.id } }, options, fallback); - await drain(); - return { result, engineCalls, fallbackCalled }; -} - -function assertEngineCalls(recorded: RecordedEngineCall[], expected: EngineCallExpect[], creditId: string | undefined) { - expect(recorded).toHaveLength(expected.length); - expected.forEach((want, i) => { - const got = recorded[i]; - if (want.credit_balance !== undefined) { - const wantBalance = - want.credit_balance === "max_safe_integer" ? Number.MAX_SAFE_INTEGER : want.credit_balance; - expect(creditId).toBeDefined(); - expect(got.creditBalances?.[creditId as string]).toBe(wantBalance); - } - if (want.credit_cost !== undefined) { - expect(got.creditCost?.[creditId as string]).toBe(want.credit_cost); - } - if (want.event_usage !== undefined) { - expect(got.eventUsage).toEqual({ - eventSubtype: want.event_usage.event_subtype, - quantity: want.event_usage.quantity, - }); - } - if (want.usage !== undefined) { - expect(got.usage).toBe(want.usage); - } - }); -} - -async function runVector(vector: Vector, makeStores: () => Stores): Promise { - const stores = makeStores(); - const h = new Harness(stores, vector.given?.config ?? {}); - try { - for (const lease of vector.given?.leases ?? []) { - expect( - await stores.leases.replace({ - leaseId: lease.lease_id, - companyId: lease.company_id, - creditTypeId: lease.credit_type_id, - grantedAmount: lease.granted_amount, - expiresAt: h.atMs(lease.expires_at_ms), - }), - ).toBe(true); - } - - for (const op of vector.operations) { - const exp = op.expect ?? {}; - switch (op.op) { - case "advance_clock": { - h.advance(op.ms ?? 0); - break; - } - case "replace_lease": { - const written = await stores.leases.replace({ - leaseId: op.lease_id as string, - companyId: op.company_id as string, - creditTypeId: op.credit_type_id as string, - grantedAmount: op.granted_amount as number, - expiresAt: h.atMs(op.expires_at_ms as number), - }); - if (exp.written !== undefined) expect(written).toBe(exp.written); - break; - } - case "drop_lease": { - await stores.leases.drop(op.company_id as string, op.credit_type_id as string); - break; - } - case "try_reserve": { - const balance = await stores.leases.tryReserve( - op.company_id as string, - op.credit_type_id as string, - op.credits as number, - ); - if ("balance" in exp) expect(balance).toBe(exp.balance); - break; - } - case "refund_lease": { - await stores.leases.refund( - op.company_id as string, - op.credit_type_id as string, - op.credits as number, - op.pin_lease_id, - ); - break; - } - case "extend_lease": { - await stores.leases.extend( - op.company_id as string, - op.credit_type_id as string, - op.granted_total as number, - op.expires_at_ms !== undefined ? h.atMs(op.expires_at_ms) : undefined, - op.pin_lease_id, - ); - break; - } - case "get_lease": { - const entry = await stores.leases.get(op.company_id as string, op.credit_type_id as string); - if (exp.exists !== undefined) expect(entry !== undefined).toBe(exp.exists); - if (exp.lease_id !== undefined) expect(entry?.leaseId).toBe(exp.lease_id); - if (exp.granted_amount !== undefined) expect(entry?.grantedAmount).toBe(exp.granted_amount); - if (exp.local_remaining_credits !== undefined) { - expect(entry?.localRemainingCredits).toBe(exp.local_remaining_credits); - } - break; - } - case "add_reservation": { - await stores.reservations.add({ - id: op.id as string, - leaseId: op.lease_id as string, - companyId: op.company_id as string, - creditTypeId: op.credit_type_id as string, - eventSubtype: op.event_subtype as string, - quantityReserved: op.quantity_reserved as number, - creditsReserved: op.credits_reserved as number, - consumptionRate: op.consumption_rate as number, - expiresAt: h.atMs(op.expires_at_ms as number), - evalCtx: { company: { id: op.company_id as string } }, - }); - break; - } - case "consume_reservation": { - const id = h.resolveReservation(op); - if (op.crash_before_refund) { - stores.armCrash(); - await expect(stores.reservations.consume(id, op.credits as number)).rejects.toThrow( - "simulated crash before refund", - ); - expect(exp.throws).toBe(true); - } else { - const consumed = await stores.reservations.consume(id, op.credits as number); - if ("consumed" in exp) expect(consumed).toBe(exp.consumed); - } - break; - } - case "get_reservation": { - const reservation = await stores.reservations.get(h.resolveReservation(op)); - if (exp.exists !== undefined) expect(reservation !== undefined).toBe(exp.exists); - break; - } - case "reserved_credits": { - const total = await stores.reservations.reservedCredits( - op.company_id as string, - op.credit_type_id as string, - ); - expect(total).toBe(exp.total); - break; - } - case "reservation_count": { - expect(await stores.reservations.size()).toBe(exp.count); - break; - } - case "sweep_expired": { - const swept = await stores.reservations.sweepExpired(new Date()); - if (exp.swept !== undefined) expect(swept).toBe(exp.swept); - break; - } - case "acquire_if_needed": { - if (op.server) h.acquireResponses.push(op.server as ServerScript); - if (op.install_during_wire) h.installDuringWire = op.install_during_wire; - const entry = await h.manager.acquireIfNeeded(op.company_id as string, op.credit_type_id as string); - await drain(); - if ("lease_id" in exp) expect(entry?.leaseId ?? null).toBe(exp.lease_id); - if (exp.wire_acquires !== undefined) expect(h.acquireCalls).toHaveLength(exp.wire_acquires); - if (exp.last_acquire_requested_amount !== undefined) { - expect(h.acquireCalls[h.acquireCalls.length - 1]?.requestedAmount).toBe( - exp.last_acquire_requested_amount, - ); - } - if (exp.released_lease_ids !== undefined) expect(h.releaseCalls).toEqual(exp.released_lease_ids); - break; - } - case "maybe_extend": { - if (op.server) h.extendResponses.push(op.server as ServerScript); - await h.manager.maybeExtendInBackground( - op.company_id as string, - op.credit_type_id as string, - op.required_credits, - ); - await drain(); - if (exp.wire_extends !== undefined) expect(h.extendCalls).toHaveLength(exp.wire_extends); - if (exp.last_extend_additional_amount !== undefined) { - expect(h.extendCalls[h.extendCalls.length - 1]?.body.additionalAmount).toBe( - exp.last_extend_additional_amount, - ); - } - if (exp.last_extend_lease_id !== undefined) { - expect(h.extendCalls[h.extendCalls.length - 1]?.leaseId).toBe(exp.last_extend_lease_id); - } - break; - } - case "release_all_local_leases": { - await h.manager.releaseAllLocalLeases(); - if (exp.released_lease_ids !== undefined) expect(h.releaseCalls).toEqual(exp.released_lease_ids); - break; - } - case "check": { - const { result, engineCalls, fallbackCalled } = await runCheck(h, op); - if (exp.allowed !== undefined) expect(result.allowed).toBe(exp.allowed); - if (exp.reason !== undefined) expect(result.reason).toBe(exp.reason); - if (exp.err !== undefined) expect(result.err).toBe(exp.err); - if (exp.has_reservation !== undefined) { - expect(result.reservation !== undefined).toBe(exp.has_reservation); - } - if (exp.fallback_called !== undefined) expect(fallbackCalled).toBe(exp.fallback_called); - if (exp.reservation) { - const r = result.reservation; - expect(r).toBeDefined(); - if (exp.reservation.lease_id !== undefined) expect(r?.leaseId).toBe(exp.reservation.lease_id); - if (exp.reservation.credit_type_id !== undefined) { - expect(r?.creditTypeId).toBe(exp.reservation.credit_type_id); - } - if (exp.reservation.event_subtype !== undefined) { - expect(r?.eventSubtype).toBe(exp.reservation.event_subtype); - } - if (exp.reservation.quantity_reserved !== undefined) { - expect(r?.quantityReserved).toBe(exp.reservation.quantity_reserved); - } - if (exp.reservation.credits_reserved !== undefined) { - expect(r?.creditsReserved).toBe(exp.reservation.credits_reserved); - } - if (exp.reservation.consumption_rate !== undefined) { - expect(r?.consumptionRate).toBe(exp.reservation.consumption_rate); - } - } - if (exp.engine_calls !== undefined) { - const creditId = - op.engine?.find((e) => e.entitlement?.credit_id)?.entitlement?.credit_id ?? - Object.keys(op.company?.credit_balances ?? {})[0]; - assertEngineCalls(engineCalls, exp.engine_calls, creditId); - } - if (exp.wire_extends !== undefined) expect(h.extendCalls).toHaveLength(exp.wire_extends); - if (exp.last_extend_additional_amount !== undefined) { - expect(h.extendCalls[h.extendCalls.length - 1]?.body.additionalAmount).toBe( - exp.last_extend_additional_amount, - ); - } - if (op.save_reservation_as && result.reservation) { - h.handles.set(op.save_reservation_as, result.reservation); - } - break; - } - case "track": { - const reservation = h.handles.get(op.handle as string); - if (!reservation) throw new Error(`unknown reservation handle: ${op.handle}`); - const { track, settledLocally } = await consumeReservationAndBuildEvent( - stores.reservations, - reservation, - op.actual_quantity as number, - ); - if (exp.settled_locally !== undefined) expect(settledLocally).toBe(exp.settled_locally); - if (exp.track) { - if (exp.track.event !== undefined) expect(track.event).toBe(exp.track.event); - if (exp.track.quantity !== undefined) expect(track.quantity).toBe(exp.track.quantity); - if (exp.track.lease_id !== undefined) expect(track.leaseId).toBe(exp.track.lease_id); - } - break; - } - default: - throw new Error(`unknown conformance op: ${op.op}`); - } - } - } finally { - stores.reservations.stop(); - } -} - -describe.each(backends)("credit lease conformance — %s", (backendName, makeStores) => { - beforeEach(() => { - jest.useFakeTimers(); - jest.setSystemTime(T0); - }); - afterEach(() => { - jest.useRealTimers(); - }); - - for (const doc of documents) { - describe(doc.category, () => { - for (const vector of doc.vectors) { - if (vector.backends && !vector.backends.includes(backendName)) continue; - it(vector.name, async () => { - await runVector(vector, makeStores); - }); - } - }); - } -}); diff --git a/tests/races/harness.ts b/tests/races/harness.ts deleted file mode 100644 index 14b3d14b..00000000 --- a/tests/races/harness.ts +++ /dev/null @@ -1,676 +0,0 @@ -/** - * Seeded randomized race harness for the lease/reservation stores. - * - * The conformance suite pins sequential semantics with deterministic vectors; - * the truly concurrent interleavings (single-flight, extend-vs-expiry, - * release-vs-sweeper, replace-vs-reserve) are prose invariants there. This - * harness exercises exactly those: per seed it spawns N async workers sharing - * a small set of (company, creditType) slots, each running a randomized op - * sequence against the store API with seeded micro-yields injected between - * store calls so the event-loop interleaving varies by seed. At quiescence it - * asserts the prose invariants (conservation, bounded leak, expiry - * monotonicity, pinned refunds/extends, exactly-once claims). - * - * Determinism: everything (op choice, amounts, yields, virtual-clock - * advances) draws from PRNGs derived from the seed, ids are counters, and the - * only awaited primitives are microtasks and `setImmediate` — whose relative - * ordering Node schedules deterministically — so a seed replays the exact - * schedule. `RACE_SEED=` re-runs one seed; `RACE_ITERATIONS=` scales the - * batch. - */ -import type { ILeaseStore } from "../../src/credits/lease-store"; -import { LeaseStore } from "../../src/credits/lease-store"; -import { RedisLeaseStore } from "../../src/credits/redis-lease-store"; -import { RedisReservationStore } from "../../src/credits/redis-reservation-store"; -import type { IReservationStore } from "../../src/credits/reservation-store"; -import { ReservationStore } from "../../src/credits/reservation-store"; -import type { Reservation } from "../../src/credits/types"; -import { makeFakeRedis } from "../unit/credits/fake-redis"; -import { deriveSeed, Rng } from "./prng"; - -const EPS = 1e-9; - -export interface Slot { - companyId: string; - creditTypeId: string; -} - -export function slotKeyOf(slot: Slot): string { - return `${slot.companyId}:${slot.creditTypeId}`; -} - -// --------------------------------------------------------------------------- -// Virtual clock -// -// Both stores (and fake-redis's TTL eviction) decide expiry via `Date.now()`, -// so overriding it gives the harness full, deterministic control of the -// timeline — clock advances are ordinary synchronous ops workers race against -// reserves/extends/sweeps. (The real Redis store reads the *server* clock via -// TIME; fake-redis emulates that with `Date.now()`, which this override also -// controls. The opt-in real-Redis integration suite is where server-clock -// authority itself is exercised.) -// --------------------------------------------------------------------------- - -export interface VirtualClock { - now(): number; - advance(ms: number): void; - uninstall(): void; -} - -const CLOCK_EPOCH_MS = 1_700_000_000_000; - -export function installVirtualClock(): VirtualClock { - const realNow = Date.now; - let current = CLOCK_EPOCH_MS; - Date.now = () => current; - return { - now: () => current, - advance: (ms: number) => { - current += ms; - }, - uninstall: () => { - Date.now = realNow; - }, - }; -} - -// --------------------------------------------------------------------------- -// Interleaving control -// --------------------------------------------------------------------------- - -/** - * Seeded micro-yield: 0-3 awaits, each either a microtask or a macrotask - * (`setImmediate`). Workers call this between store operations so the - * interleaving of their op sequences varies by seed. `setTimeout(0)` is - * deliberately excluded — its ordering relative to `setImmediate` is not - * deterministic in Node, which would break seed replay. - */ -export async function jitter(rng: Rng): Promise { - const yields = rng.int(4); - for (let i = 0; i < yields; i++) { - if (rng.chance(0.5)) { - await Promise.resolve(); - } else { - await new Promise((resolve) => setImmediate(resolve)); - } - } -} - -/** Drain pending microtasks/immediates (e.g. fire-and-forget releases) before verifying. */ -export async function settle(rounds = 25): Promise { - for (let i = 0; i < rounds; i++) { - await new Promise((resolve) => setImmediate(resolve)); - } -} - -/** - * Credit amounts are multiples of 0.25: fractional (exercising the Redis - * string-balance encoding) but exactly representable in binary, so the - * conservation sums below can be compared exactly. - */ -export function quarters(rng: Rng, maxQuarters: number, minQuarters = 1): number { - return rng.intBetween(minQuarters, maxQuarters) * 0.25; -} - -// --------------------------------------------------------------------------- -// Backends -// --------------------------------------------------------------------------- - -export interface StorePair { - leases: ILeaseStore; - reservations: IReservationStore; -} - -export interface Backend { - name: string; - make(): StorePair; -} - -// The sweep interval is irrelevant here (workers call `sweepExpired` -// explicitly, racing it against consumes); set it long so a stray -// `startSweep` could never fire mid-run. -export const backends: Backend[] = [ - { - name: "in-memory", - make: () => { - const leases = new LeaseStore(); - return { leases, reservations: new ReservationStore(leases, 60_000) }; - }, - }, - { - name: "redis (fake)", - make: () => { - const client = makeFakeRedis(); - const leases = new RedisLeaseStore({ client }); - return { - leases, - reservations: new RedisReservationStore({ client, leaseStore: leases, sweepIntervalMs: 60_000 }), - }; - }, - }, -]; - -// --------------------------------------------------------------------------- -// Model: what the harness knows it asked the stores to do -// --------------------------------------------------------------------------- - -export interface OpenReservation { - slotKey: string; - leaseId: string; - credits: number; -} - -export class RaceModel { - /** Leases whose `replace` returned written=true, keyed by lease id (ids are never reused). */ - installs = new Map(); - /** Every store `extend` issued, with its pin. Pins are only ever ids observed live in the slot. */ - extendsIssued: Array<{ pinLeaseId: string; total: number; expiresAtMs: number }> = []; - /** Reservations recorded via `add` and not yet claimed by a non-null `consume` this run. */ - open = new Map(); - /** Per-slot credits actually consumed (sum of non-null `consume` returns). */ - consumed = new Map(); - /** Per-slot credits deliberately leaked via simulated window-1 crashes (debit without record). */ - leaked = new Map(); - /** Per-reservation count of non-null `consume` returns (must be <= 1). */ - claims = new Map(); - /** Op-time violations (non-racy assertions checked inline). */ - violations: string[] = []; - - addTo(map: Map, key: string, credits: number): void { - map.set(key, (map.get(key) ?? 0) + credits); - } -} - -export interface RaceCtx { - seed: number; - clock: VirtualClock; - leases: ILeaseStore; - reservations: IReservationStore; - slots: Slot[]; - model: RaceModel; - nextId(prefix: string): string; -} - -export function makeReservation( - ctx: RaceCtx, - slot: Slot, - leaseId: string, - credits: number, - ttlMs: number, -): Reservation { - return { - id: ctx.nextId("res"), - leaseId, - companyId: slot.companyId, - creditTypeId: slot.creditTypeId, - eventSubtype: "inference_tokens", - quantityReserved: credits, - creditsReserved: credits, - consumptionRate: 1, - expiresAt: new Date(ctx.clock.now() + ttlMs), - evalCtx: { company: { id: slot.companyId } }, - }; -} - -// --------------------------------------------------------------------------- -// Shared ops -// --------------------------------------------------------------------------- - -export interface WeightedOp { - weight: number; - run(rng: Rng): Promise; -} - -export interface ReserveOpts { - /** Probability of simulating a window-1 crash (debit lands, record never written). */ - crashChance?: number; - /** Reservation TTL range [min, max] ms. */ - ttlMs: [number, number]; - /** Max reserve size in quarter-credits. */ - maxQuarters: number; -} - -/** - * The check-flow shape: observe the lease (skipping expired ones, like the - * manager does), debit via `try_reserve`, then record the reservation pinned - * to the OBSERVED lease id — deliberately leaving seeded yield points where - * expiry, a successor `replace`, or a sweep can interleave. - */ -export function reserveOp(ctx: RaceCtx, opts: ReserveOpts): WeightedOp { - return { - weight: 4, - run: async (rng) => { - const slot = rng.pick(ctx.slots); - const entry = await ctx.leases.get(slot.companyId, slot.creditTypeId); - if (!entry || entry.expiresAt.getTime() <= ctx.clock.now()) return; - const credits = quarters(rng, opts.maxQuarters); - await jitter(rng); - const post = await ctx.leases.tryReserve(slot.companyId, slot.creditTypeId, credits); - if (post === null) return; - if (post < -EPS) { - ctx.model.violations.push( - `tryReserve(${credits}) on ${slotKeyOf(slot)} returned a negative balance ${post}`, - ); - } - await jitter(rng); - if (opts.crashChance && rng.chance(opts.crashChance)) { - // Simulated window-1 crash: the debit landed but the record is - // never written. The sweeper can never refund it; conservation - // accounts for it via the leak budget. - ctx.model.addTo(ctx.model.leaked, slotKeyOf(slot), credits); - return; - } - const reservation = makeReservation(ctx, slot, entry.leaseId, credits, rng.intBetween(...opts.ttlMs)); - await ctx.reservations.add(reservation); - ctx.model.open.set(reservation.id, { slotKey: slotKeyOf(slot), leaseId: entry.leaseId, credits }); - }, - }; -} - -/** Settle a random open reservation — racing other consumers and the sweeper. */ -export function consumeOp(ctx: RaceCtx): WeightedOp { - return { - weight: 3, - run: async (rng) => { - const ids = Array.from(ctx.model.open.keys()); - if (ids.length === 0) return; - const id = rng.pick(ids); - const open = ctx.model.open.get(id); - if (!open) return; - const roll = rng.next(); - let requested: number; - if (roll < 0.15) { - requested = open.credits + quarters(rng, 20); // over-consume: clamps to reserved - } else if (roll < 0.25) { - requested = -quarters(rng, 8); // negative: clamps to 0, full refund - } else { - requested = quarters(rng, Math.max(1, Math.round(open.credits * 4)), 0); - } - await jitter(rng); - const consumed = await ctx.reservations.consume(id, requested); - if (consumed === null) return; // lost the claim race (sweeper or another consumer) - if (consumed < -EPS || consumed > open.credits + EPS) { - ctx.model.violations.push( - `consume(${id}, ${requested}) returned ${consumed}, outside [0, ${open.credits}]`, - ); - } - ctx.model.claims.set(id, (ctx.model.claims.get(id) ?? 0) + 1); - ctx.model.addTo(ctx.model.consumed, open.slotKey, consumed); - ctx.model.open.delete(id); - }, - }; -} - -/** Run the expired-reservation sweeper — racing settles on the same reservations. */ -export function sweepOp(ctx: RaceCtx): WeightedOp { - return { - weight: 2, - run: async (rng) => { - await jitter(rng); - await ctx.reservations.sweepExpired(new Date(ctx.clock.now())); - }, - }; -} - -/** - * Advance the virtual clock. Bounded to 300ms per op so a run's total advance - * stays well under the stores' TTL grace windows (30s reservation / 60s - * lease): rows must never TTL-evict un-swept mid-run, which would look like a - * lost refund to the conservation check. - */ -export function advanceOp(ctx: RaceCtx, weight = 2): WeightedOp { - return { - weight, - run: async (rng) => { - ctx.clock.advance(rng.intBetween(50, 300)); - }, - }; -} - -/** Non-finite/negative debits must be rejected without touching the balance. */ -export function invalidReserveOp(ctx: RaceCtx): WeightedOp { - return { - weight: 1, - run: async (rng) => { - const slot = rng.pick(ctx.slots); - const bad = rng.pick([Number.NaN, -3, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY]); - const result = await ctx.leases.tryReserve(slot.companyId, slot.creditTypeId, bad); - if (result !== null) { - ctx.model.violations.push(`tryReserve(${bad}) on ${slotKeyOf(slot)} returned ${result}, not null`); - } - }, - }; -} - -/** - * The manager's extend shape: observe the lease (skipping expired ones), - * then reconcile the store to a server-authoritative total pinned to the - * observed lease id — racing expiry and successor installs. - */ -export function extendObservedOp(ctx: RaceCtx, durationMs: [number, number]): WeightedOp { - return { - weight: 3, - run: async (rng) => { - const slot = rng.pick(ctx.slots); - const entry = await ctx.leases.get(slot.companyId, slot.creditTypeId); - if (!entry || entry.expiresAt.getTime() <= ctx.clock.now()) return; - // Mix of higher totals (real extends) and stale/lower totals - // (out-of-order applies that must converge as no-ops). - const total = entry.grantedAmount + rng.pick([-50, -0.25, 25, 100, 250.5]); - const expiresAtMs = ctx.clock.now() + rng.intBetween(...durationMs); - await jitter(rng); - await ctx.leases.extend(slot.companyId, slot.creditTypeId, total, new Date(expiresAtMs), entry.leaseId); - ctx.model.extendsIssued.push({ pinLeaseId: entry.leaseId, total, expiresAtMs }); - }, - }; -} - -export interface ReplaceOpts { - /** Lease duration range, or "immortal" for a lease that can never expire mid-run. */ - durationMs: [number, number] | "immortal"; - grantedQuarters: [number, number]; - weight?: number; - /** Only attempt the replace when the observed slot is empty/expired (the manager's shape). */ - onlyIfDead?: boolean; -} - -/** Install a fresh lease — racing sibling installs (keep-first) and in-flight reserves. */ -export function replaceFreshOp(ctx: RaceCtx, opts: ReplaceOpts): WeightedOp { - return { - weight: opts.weight ?? 2, - run: async (rng) => { - const slot = rng.pick(ctx.slots); - if (opts.onlyIfDead) { - const current = await ctx.leases.get(slot.companyId, slot.creditTypeId); - if (current && current.expiresAt.getTime() > ctx.clock.now()) return; - await jitter(rng); - } - const granted = quarters(rng, opts.grantedQuarters[1], opts.grantedQuarters[0]); - const expiresAtMs = - opts.durationMs === "immortal" - ? ctx.clock.now() + 10 * 365 * 24 * 60 * 60 * 1000 - : ctx.clock.now() + rng.intBetween(...opts.durationMs); - const leaseId = ctx.nextId("lse"); - const wrote = await ctx.leases.replace({ - leaseId, - companyId: slot.companyId, - creditTypeId: slot.creditTypeId, - grantedAmount: granted, - expiresAt: new Date(expiresAtMs), - }); - if (wrote) { - ctx.model.installs.set(leaseId, { slotKey: slotKeyOf(slot), granted, expiresAtMs }); - } - }, - }; -} - -/** - * Prove the expiry guard: observe the lease, synchronously advance the clock - * just past its expiry, and immediately probe `try_reserve`. The advance and - * the call have no yield between them, so any debit happens at - * `clock >= advancedTo`. If the probe succeeds and the slot still holds the - * SAME lease with an expiry `<= advancedTo`, the debit provably landed on an - * expired lease (ids are never reused and expiry only moves forward, so a - * live-at-debit lease would read a later expiry afterwards) — a - * server-side double-spend the local ledger alone cannot see. A success where - * the slot moved on to a live successor is legitimate (the debit hit the - * successor); it is accounted as an unrecorded hold, like a window-1 crash. - */ -export function expiredProbeOp(ctx: RaceCtx, weight = 2): WeightedOp { - return { - weight, - run: async (rng) => { - const slot = rng.pick(ctx.slots); - const before = await ctx.leases.get(slot.companyId, slot.creditTypeId); - if (!before) return; - const advancedTo = Math.max(ctx.clock.now(), before.expiresAt.getTime() + 1); - ctx.clock.advance(advancedTo - ctx.clock.now()); - const credits = 0.25; - const post = await ctx.leases.tryReserve(slot.companyId, slot.creditTypeId, credits); - if (post === null) return; - const after = await ctx.leases.get(slot.companyId, slot.creditTypeId); - if (after && after.leaseId === before.leaseId && after.expiresAt.getTime() <= advancedTo) { - ctx.model.violations.push( - `${slotKeyOf(slot)}: tryReserve succeeded against expired lease ${before.leaseId} ` + - `(expiry ${after.expiresAt.getTime()} <= clock ${advancedTo}; ` + - `the server already refunded this balance — serving it double-spends)`, - ); - return; - } - // Legitimate: the debit landed on a live successor. Nothing records - // this hold, so account it like a window-1 crash leak. - ctx.model.addTo(ctx.model.leaked, slotKeyOf(slot), credits); - }, - }; -} - -/** Drop the slot (remote release) — racing everything else. */ -export function dropOp(ctx: RaceCtx, weight = 1): WeightedOp { - return { - weight, - run: async (rng) => { - const slot = rng.pick(ctx.slots); - await jitter(rng); - await ctx.leases.drop(slot.companyId, slot.creditTypeId); - }, - }; -} - -// --------------------------------------------------------------------------- -// Invariant verification (at quiescence) -// --------------------------------------------------------------------------- - -export interface VerifyOpts { - /** - * Exact conservation: granted == remaining + open holds + consumed + - * crash-leaked, per slot. Only sound when the scenario guarantees a single - * never-expiring lease per slot (attribution of debits is then exact); it - * catches both double-refunds and lost refunds. - */ - conservation?: boolean; - /** - * Assert the exact final granted/expiry of the surviving lease from the - * model (install + pinned extends). Sound whenever the harness only pins - * extends to observed-live lease ids (ids are never reused, so a lease - * still installed at quiescence was installed continuously since its - * `replace` — every extend pinned to it applied). Off for manager-driven - * scenarios where installs happen inside the manager. - */ - exactLeaseState?: boolean; - /** Require every slot to still hold a known lease (single-immortal-lease scenarios). */ - requireLease?: boolean; -} - -export async function verifyInvariants(ctx: RaceCtx, opts: VerifyOpts): Promise { - const violations: string[] = [...ctx.model.violations]; - - // Reconcile the model's open reservations against the store: ones the - // sweeper claimed are gone (their hold refunded to the lease); ones still - // present are open holds. - const presentBySlot = new Map(); - for (const [id, open] of ctx.model.open) { - const inStore = await ctx.reservations.get(id); - if (!inStore) continue; // swept: full hold refunded (pinned), counts as consumed 0 - const list = presentBySlot.get(open.slotKey) ?? []; - list.push(open); - presentBySlot.set(open.slotKey, list); - } - - for (const slot of ctx.slots) { - const key = slotKeyOf(slot); - const present = presentBySlot.get(key) ?? []; - const presentSum = present.reduce((sum, r) => sum + r.credits, 0); - - // The reserved-credits index (a separate structure in the Redis store) - // must agree exactly with the reservations actually present. - const reservedTotal = await ctx.reservations.reservedCredits(slot.companyId, slot.creditTypeId); - if (Math.abs(reservedTotal - presentSum) > EPS) { - violations.push( - `${key}: reservedCredits reports ${reservedTotal} but open reservations sum to ${presentSum}`, - ); - } - - const entry = await ctx.leases.get(slot.companyId, slot.creditTypeId); - if (!entry) { - if (opts.requireLease) violations.push(`${key}: expected the immortal lease to survive, slot is empty`); - continue; - } - - const remaining = entry.localRemainingCredits; - const granted = entry.grantedAmount; - if (remaining < -EPS) violations.push(`${key}: negative balance ${remaining} on lease ${entry.leaseId}`); - if (remaining > granted + EPS) { - violations.push(`${key}: balance ${remaining} exceeds granted ${granted} on lease ${entry.leaseId}`); - } - - // No double-spend: credits held by open reservations pinned to the - // live lease were debited from it, so remaining + holds can never - // exceed granted. A double-refund or a refund crossing lease - // generations (a broken pin) pushes this over. - const pinnedOpen = present.filter((r) => r.leaseId === entry.leaseId).reduce((sum, r) => sum + r.credits, 0); - if (remaining + pinnedOpen > granted + EPS) { - violations.push( - `${key}: remaining ${remaining} + pinned open holds ${pinnedOpen} exceeds granted ${granted} ` + - `on lease ${entry.leaseId} (credits were minted)`, - ); - } - - const install = ctx.model.installs.get(entry.leaseId); - if (opts.exactLeaseState) { - if (!install) { - violations.push(`${key}: slot holds lease ${entry.leaseId} the harness never installed`); - } else { - const pinnedExtends = ctx.model.extendsIssued.filter((e) => e.pinLeaseId === entry.leaseId); - const expectedGranted = Math.max(install.granted, ...pinnedExtends.map((e) => e.total)); - const expectedExpiry = Math.max(install.expiresAtMs, ...pinnedExtends.map((e) => e.expiresAtMs)); - if (Math.abs(granted - expectedGranted) > EPS) { - violations.push( - `${key}: lease ${entry.leaseId} granted ${granted}, expected ${expectedGranted} ` + - `(install ${install.granted} + ${pinnedExtends.length} pinned extends; ` + - `an unpinned/stale extend leaked through)`, - ); - } - if (entry.expiresAt.getTime() !== expectedExpiry) { - violations.push( - `${key}: lease ${entry.leaseId} expiry ${entry.expiresAt.getTime()}, expected ${expectedExpiry} ` + - `(expiry must equal the max of install + pinned extend expiries — it only moves forward)`, - ); - } - } - } - - if (opts.conservation) { - const consumed = ctx.model.consumed.get(key) ?? 0; - const leaked = ctx.model.leaked.get(key) ?? 0; - const accounted = remaining + presentSum + consumed + leaked; - if (Math.abs(accounted - granted) > EPS) { - violations.push( - `${key}: conservation broken on lease ${entry.leaseId}: remaining ${remaining} + ` + - `open holds ${presentSum} + consumed ${consumed} + crash-leaked ${leaked} ` + - `= ${accounted}, expected granted ${granted} ` + - `(${accounted > granted ? "double refund" : "lost refund"})`, - ); - } - } - } - - for (const [id, count] of ctx.model.claims) { - if (count > 1) violations.push(`reservation ${id} was claimed ${count} times (consume must be exactly-once)`); - } - - return violations; -} - -// --------------------------------------------------------------------------- -// Runner -// --------------------------------------------------------------------------- - -export interface ScenarioRun { - ops: WeightedOp[]; - verify(): Promise; -} - -export interface RaceScenario { - name: string; - slots: Slot[]; - build(ctx: RaceCtx): Promise; -} - -function pickWeighted(ops: WeightedOp[], rng: Rng): WeightedOp { - const total = ops.reduce((sum, op) => sum + op.weight, 0); - let roll = rng.next() * total; - for (const op of ops) { - roll -= op.weight; - if (roll < 0) return op; - } - return ops[ops.length - 1]; -} - -export async function runScenario(scenario: RaceScenario, backend: Backend, seed: number): Promise { - const rng = new Rng(deriveSeed(seed, 0)); - const clock = installVirtualClock(); - try { - const { leases, reservations } = backend.make(); - let idCounter = 0; - const ctx: RaceCtx = { - seed, - clock, - leases, - reservations, - slots: scenario.slots, - model: new RaceModel(), - nextId: (prefix: string) => `${prefix}_${seed}_${++idCounter}`, - }; - const { ops, verify } = await scenario.build(ctx); - - const workerCount = rng.intBetween(3, 6); - const opsPerWorker = rng.intBetween(6, 12); - await Promise.all( - Array.from({ length: workerCount }, (_, workerIndex) => { - const workerRng = new Rng(deriveSeed(seed, workerIndex + 1)); - return (async () => { - for (let i = 0; i < opsPerWorker; i++) { - await jitter(workerRng); - await pickWeighted(ops, workerRng).run(workerRng); - } - })(); - }), - ); - - // Quiescence: all workers idle; drain anything fire-and-forget, then - // run one final sweep. The sweep reconciles reservation rows the - // backend TTL-evicted after large clock jumps (their per-slot index - // fields would otherwise read as reserved-credits drift) — the same - // reconciliation the production sweep loop performs. - await settle(); - await reservations.sweepExpired(new Date(clock.now())); - - const violations = await verify(); - if (violations.length > 0) { - throw new Error( - `Race invariant violated (scenario="${scenario.name}", backend="${backend.name}", seed=${seed}, ` + - `workers=${workerCount}, opsPerWorker=${opsPerWorker})\n` + - `Replay exactly this schedule with: RACE_SEED=${seed} yarn test tests/races\n` + - violations.map((v) => ` - ${v}`).join("\n"), - ); - } - } finally { - clock.uninstall(); - } -} - -/** Seeds for this run: `RACE_SEED` replays one; `RACE_ITERATIONS` scales the batch. */ -export function seedBatch(defaultIterations: number): number[] { - const single = process.env.RACE_SEED; - if (single !== undefined && single !== "") { - const seed = Number(single); - if (!Number.isInteger(seed)) throw new Error(`RACE_SEED must be an integer, got "${single}"`); - return [seed]; - } - const iterations = Number(process.env.RACE_ITERATIONS ?? defaultIterations); - if (!Number.isInteger(iterations) || iterations < 1) { - throw new Error(`RACE_ITERATIONS must be a positive integer, got "${process.env.RACE_ITERATIONS}"`); - } - return Array.from({ length: iterations }, (_, i) => i + 1); -} diff --git a/tests/races/prng.ts b/tests/races/prng.ts deleted file mode 100644 index 666904e2..00000000 --- a/tests/races/prng.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Seeded PRNG (mulberry32) for the race harness. Every random choice in a run - * — op selection, amounts, TTLs, and the micro-yields that vary event-loop - * interleaving — draws from an `Rng` derived from the run's seed, so a failing - * schedule replays exactly under `RACE_SEED=`. - */ -export class Rng { - private state: number; - - constructor(seed: number) { - this.state = seed >>> 0; - // mulberry32 degenerates on a zero state; nudge to a fixed constant so - // seed 0 is still a valid, distinct stream. - if (this.state === 0) this.state = 0x9e3779b9; - } - - /** Uniform float in [0, 1). */ - next(): number { - this.state = (this.state + 0x6d2b79f5) >>> 0; - let t = this.state; - t = Math.imul(t ^ (t >>> 15), t | 1); - t ^= t + Math.imul(t ^ (t >>> 7), t | 61); - return ((t ^ (t >>> 14)) >>> 0) / 4294967296; - } - - /** Uniform integer in [0, maxExclusive). */ - int(maxExclusive: number): number { - return Math.floor(this.next() * maxExclusive); - } - - /** Uniform integer in [min, max] (inclusive). */ - intBetween(min: number, max: number): number { - return min + this.int(max - min + 1); - } - - pick(items: readonly T[]): T { - return items[this.int(items.length)]; - } - - chance(probability: number): boolean { - return this.next() < probability; - } -} - -/** Deterministically derive a child seed (e.g. per worker) from a run seed. */ -export function deriveSeed(seed: number, salt: number): number { - let h = (Math.imul(seed, 0x9e3779b1) ^ Math.imul(salt + 1, 0x85ebca6b)) >>> 0; - h = Math.imul(h ^ (h >>> 13), 0xc2b2ae35) >>> 0; - return h; -} diff --git a/tests/races/races.test.ts b/tests/races/races.test.ts deleted file mode 100644 index 5a65d7bd..00000000 --- a/tests/races/races.test.ts +++ /dev/null @@ -1,311 +0,0 @@ -/** - * Seeded concurrency race tests for the lease/reservation stores (and the - * lease manager on top of them). Each scenario targets one of the race pairs - * the conformance spec can only state as prose invariants: - * - * - concurrent acquires (replace) on one slot: keep-first, single live lease - * - extend racing lease expiry and successor installs: pinned extends never - * credit a successor; expiry only moves forward - * - settle (consume) racing the sweeper: exactly-once claims, no double or - * lost refunds - * - successor replace racing try_reserve: expired balances are never served - * - manager acquire/extend single-flight over a shared store: the installed - * lease is never released out from under siblings; extends never mint - * phantom credits - * - mixed chaos across slots: all of the above at once, plus drops and - * simulated window-1 crashes (bounded leak) - * - * Every run is deterministic per seed. A failure prints the seed; replay it - * with `RACE_SEED= yarn test tests/races`. `RACE_ITERATIONS=` scales - * the batch (default 40 per scenario/backend). - */ -import { CreditLeaseManager } from "../../src/credits/lease-manager"; -import type { Logger } from "../../src/logger"; - -import type { RaceCtx, RaceScenario, Slot, WeightedOp } from "./harness"; -import { - advanceOp, - backends, - consumeOp, - dropOp, - expiredProbeOp, - extendObservedOp, - invalidReserveOp, - quarters, - replaceFreshOp, - reserveOp, - runScenario, - seedBatch, - slotKeyOf, - sweepOp, - verifyInvariants, -} from "./harness"; -import { deriveSeed, Rng } from "./prng"; -import { ScriptedCreditsServer } from "./scripted-server"; - -const seeds = seedBatch(40); - -jest.setTimeout(600_000); - -const oneSlot: Slot[] = [{ companyId: "co_1", creditTypeId: "ct_1" }]; -const twoSlots: Slot[] = [ - { companyId: "co_1", creditTypeId: "ct_1" }, - { companyId: "co_1", creditTypeId: "ct_2" }, -]; - -const silentLogger: Logger = { error() {}, warn() {}, info() {}, debug() {} }; - -async function installLease(ctx: RaceCtx, slot: Slot, granted: number, expiresAtMs: number): Promise { - const leaseId = ctx.nextId("lse"); - const wrote = await ctx.leases.replace({ - leaseId, - companyId: slot.companyId, - creditTypeId: slot.creditTypeId, - grantedAmount: granted, - expiresAt: new Date(expiresAtMs), - }); - if (!wrote) throw new Error(`setup: failed to install lease for ${slotKeyOf(slot)}`); - ctx.model.installs.set(leaseId, { slotKey: slotKeyOf(slot), granted, expiresAtMs }); - return leaseId; -} - -const scenarios: RaceScenario[] = [ - { - // Documented gap: single-flight / concurrent acquires. All installs - // use a lease that can never expire, so exactly one concurrent - // `replace` may win the slot; the losers must keep the winner's - // already-debited balance intact (conservation stays exact). - name: "concurrent acquires (replace) on one slot", - slots: oneSlot, - async build(ctx) { - return { - ops: [ - replaceFreshOp(ctx, { durationMs: "immortal", grantedQuarters: [2000, 4000], weight: 3 }), - reserveOp(ctx, { ttlMs: [100, 800], maxQuarters: 100 }), - consumeOp(ctx), - sweepOp(ctx), - advanceOp(ctx), - invalidReserveOp(ctx), - ], - verify: async () => { - const violations = await verifyInvariants(ctx, { conservation: true, exactLeaseState: true }); - if (ctx.model.installs.size > 1) { - violations.push( - `${ctx.model.installs.size} concurrent replaces reported written=true for one live slot`, - ); - } - return violations; - }, - }; - }, - }, - { - // Documented gap: extend racing expiry. A short-lived lease is - // extended (pinned) while the clock races past its expiry and - // successors install over it. A pinned extend must never credit a - // successor, and a lease's final granted/expiry must equal exactly - // what its install plus its own pinned extends produced. - name: "extend racing expiry and successor installs", - slots: oneSlot, - async build(ctx) { - const setupRng = new Rng(deriveSeed(ctx.seed, 101)); - await installLease( - ctx, - ctx.slots[0], - quarters(setupRng, 2000, 800), - ctx.clock.now() + setupRng.intBetween(300, 1200), - ); - return { - ops: [ - advanceOp(ctx, 3), - extendObservedOp(ctx, [300, 1500]), - replaceFreshOp(ctx, { durationMs: [300, 1500], grantedQuarters: [800, 2000], onlyIfDead: true }), - reserveOp(ctx, { ttlMs: [100, 700], maxQuarters: 60 }), - consumeOp(ctx), - sweepOp(ctx), - expiredProbeOp(ctx), - ], - verify: () => verifyInvariants(ctx, { exactLeaseState: true }), - }; - }, - }, - { - // Documented gap: release (settle) racing the sweeper. One immortal - // lease; short-TTL reservations are settled by racing consumers while - // sweeps and clock advances fire concurrently, with occasional - // simulated window-1 crashes (debit without record). Conservation is - // exact: every credit is remaining, held, consumed, or accounted to - // the crash-leak budget — a double refund (sweeper + settle both - // winning a claim) or a lost refund breaks the equality. - name: "settle (consume) racing the sweeper", - slots: oneSlot, - async build(ctx) { - const setupRng = new Rng(deriveSeed(ctx.seed, 202)); - await installLease( - ctx, - ctx.slots[0], - quarters(setupRng, 1600, 1000), - ctx.clock.now() + 10 * 365 * 24 * 60 * 60 * 1000, - ); - return { - ops: [ - reserveOp(ctx, { ttlMs: [100, 700], maxQuarters: 400, crashChance: 0.1 }), - { ...consumeOp(ctx), weight: 4 }, - { ...sweepOp(ctx), weight: 3 }, - advanceOp(ctx, 3), - extendObservedOp(ctx, [300, 1500]), - invalidReserveOp(ctx), - ], - verify: () => verifyInvariants(ctx, { conservation: true, exactLeaseState: true, requireLease: true }), - }; - }, - }, - { - // Documented gap: replace racing try_reserve. Leases churn quickly - // (short durations, aggressive clock advances) while reserves are in - // flight, so debits race successor installs. A reserve must never be - // served by an expired balance and never mint credits on a successor. - name: "successor replace racing try_reserve", - slots: oneSlot, - async build(ctx) { - const setupRng = new Rng(deriveSeed(ctx.seed, 303)); - await installLease( - ctx, - ctx.slots[0], - quarters(setupRng, 1200, 400), - ctx.clock.now() + setupRng.intBetween(200, 1000), - ); - return { - ops: [ - replaceFreshOp(ctx, { - durationMs: [200, 1000], - grantedQuarters: [400, 1200], - onlyIfDead: true, - weight: 3, - }), - { ...reserveOp(ctx, { ttlMs: [100, 600], maxQuarters: 40 }), weight: 5 }, - consumeOp(ctx), - { ...sweepOp(ctx), weight: 1 }, - advanceOp(ctx, 3), - expiredProbeOp(ctx), - ], - verify: () => verifyInvariants(ctx, { exactLeaseState: true }), - }; - }, - }, - { - // Everything at once, across two slots: acquires, pinned extends, - // reserves, settles, sweeps, drops, clock advances, and window-1 - // crashes, all interleaved by seed. - name: "mixed chaos across slots", - slots: twoSlots, - async build(ctx) { - return { - ops: [ - replaceFreshOp(ctx, { durationMs: [200, 1200], grantedQuarters: [400, 1600], weight: 3 }), - extendObservedOp(ctx, [300, 1500]), - reserveOp(ctx, { ttlMs: [100, 700], maxQuarters: 60, crashChance: 0.1 }), - consumeOp(ctx), - sweepOp(ctx), - advanceOp(ctx, 3), - dropOp(ctx), - invalidReserveOp(ctx), - expiredProbeOp(ctx, 1), - ], - verify: () => verifyInvariants(ctx, { exactLeaseState: true }), - }; - }, - }, - { - // Documented gap: per-slot single-flight and the redundant-release - // rules, driven through the real CreditLeaseManager. Two managers - // ("pods") share one store and one scripted wire server whose calls - // carry seeded latency, so acquire responses race sibling installs - // and extend responses race expiry. The lease actually installed must - // never be released server-side, and the local view must never exceed - // the server-authoritative total. - name: "manager acquire/extend single-flight over a shared store", - slots: oneSlot, - async build(ctx) { - const buildRng = new Rng(deriveSeed(ctx.seed, 404)); - const server = new ScriptedCreditsServer(ctx.clock, new Rng(deriveSeed(ctx.seed, 405))); - const leaseDuration = buildRng.intBetween(800, 2500); - const managers = [0, 1].map( - () => - new CreditLeaseManager({ - creditsClient: server.client(), - leaseStore: ctx.leases, - logger: silentLogger, - config: { - defaultLeaseDuration: leaseDuration, - defaultReservationTTL: 60_000, - defaultLeaseSize: 500, - lowWaterMark: 0.25, - }, - }), - ); - const slot = ctx.slots[0]; - const ops: WeightedOp[] = [ - { - weight: 4, - run: async (rng) => { - await managers[rng.int(managers.length)].acquireIfNeeded(slot.companyId, slot.creditTypeId); - }, - }, - { - weight: 3, - run: async (rng) => { - const required = rng.chance(0.5) ? quarters(rng, 2400) : undefined; - await managers[rng.int(managers.length)].maybeExtendInBackground( - slot.companyId, - slot.creditTypeId, - required, - ); - }, - }, - reserveOp(ctx, { ttlMs: [100, 800], maxQuarters: 300 }), - consumeOp(ctx), - sweepOp(ctx), - advanceOp(ctx, 3), - expiredProbeOp(ctx, 1), - ]; - return { - ops, - verify: async () => { - const violations = await verifyInvariants(ctx, {}); - const entry = await ctx.leases.get(slot.companyId, slot.creditTypeId); - if (entry && entry.expiresAt.getTime() > ctx.clock.now()) { - if (server.released.has(entry.leaseId)) { - violations.push( - `live installed lease ${entry.leaseId} was released server-side ` + - `(a redundant-release pulled the shared lease out from under siblings)`, - ); - } - const srv = server.leasesById.get(entry.leaseId); - if (!srv) { - violations.push(`installed lease ${entry.leaseId} is unknown to the server`); - } else if (entry.grantedAmount > srv.granted + 1e-9) { - violations.push( - `local granted ${entry.grantedAmount} exceeds server-authoritative total ` + - `${srv.granted} for ${entry.leaseId} (phantom extend credits)`, - ); - } - } - return violations; - }, - }; - }, - }, -]; - -describe("lease/reservation concurrency race harness", () => { - for (const scenario of scenarios) { - for (const backend of backends) { - test(`${scenario.name} [${backend.name}] — ${seeds.length} seeded schedule(s)`, async () => { - for (const seed of seeds) { - await runScenario(scenario, backend, seed); - } - }); - } - } -}); diff --git a/tests/races/scripted-server.ts b/tests/races/scripted-server.ts deleted file mode 100644 index a4ad2807..00000000 --- a/tests/races/scripted-server.ts +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Deterministic in-process stand-in for the credits wire API, used by the - * manager-level race scenario. Mirrors the server contract the SDK relies on: - * - * - `acquire` is transactional and idempotent for an active slot: while a - * live, unreleased lease exists for (company, creditType) every acquire is - * handed that lease back; a fresh lease is minted only when the slot is - * free. The check-and-mint is atomic (no awaits inside), like the real - * server's transaction. - * - `extend` grows the lease's authoritative total and returns it; extending - * a released/expired lease errors. - * - `release` marks the lease released and frees the slot. - * - * Seeded jitter at the entry and exit of every call simulates wire latency, - * opening the windows (acquire response racing a sibling's install, extend - * response landing after expiry) the lease manager has to survive. - */ -import type { CreditsClient } from "../../src/api/resources/credits/client/Client"; - -import type { VirtualClock } from "./harness"; -import { jitter } from "./harness"; -import type { Rng } from "./prng"; - -interface ServerLease { - id: string; - companyId: string; - creditTypeId: string; - granted: number; - expiresAtMs: number; -} - -export class ScriptedCreditsServer { - readonly leasesById = new Map(); - readonly released = new Set(); - private readonly activeBySlot = new Map(); - private seq = 0; - - constructor( - private readonly clock: VirtualClock, - private readonly rng: Rng, - ) {} - - private activeLease(slotKey: string): ServerLease | undefined { - const id = this.activeBySlot.get(slotKey); - if (!id) return undefined; - const lease = this.leasesById.get(id); - if (!lease || this.released.has(id) || lease.expiresAtMs <= this.clock.now()) return undefined; - return lease; - } - - private toData(lease: ServerLease) { - // Snapshot inside the atomic section so the response carries the state - // as of the call, then travels through simulated latency. - return { - id: lease.id, - companyId: lease.companyId, - creditTypeId: lease.creditTypeId, - grantedAmount: lease.granted, - expiresAt: new Date(lease.expiresAtMs), - createdAt: new Date(0), - updatedAt: new Date(0), - }; - } - - client(): CreditsClient { - const acquireCreditLease = async (body: { - companyId: string; - creditTypeId: string; - requestedAmount: number; - expiresAt: Date; - }) => { - await jitter(this.rng); - const slotKey = `${body.companyId}:${body.creditTypeId}`; - let lease = this.activeLease(slotKey); - if (!lease) { - lease = { - id: `lse_srv_${++this.seq}`, - companyId: body.companyId, - creditTypeId: body.creditTypeId, - granted: body.requestedAmount, - expiresAtMs: body.expiresAt.getTime(), - }; - this.leasesById.set(lease.id, lease); - this.activeBySlot.set(slotKey, lease.id); - } - const data = this.toData(lease); - await jitter(this.rng); - return { data, params: {} }; - }; - - const extendCreditLease = async (leaseId: string, body: { additionalAmount: number; expiresAt: Date }) => { - await jitter(this.rng); - const lease = this.leasesById.get(leaseId); - if (!lease || this.released.has(leaseId) || lease.expiresAtMs <= this.clock.now()) { - throw new Error(`cannot extend inactive lease ${leaseId}`); - } - lease.granted += body.additionalAmount; - lease.expiresAtMs = Math.max(lease.expiresAtMs, body.expiresAt.getTime()); - const data = this.toData(lease); - await jitter(this.rng); - return { data, params: {} }; - }; - - const releaseCreditLease = async (leaseId: string) => { - await jitter(this.rng); - this.released.add(leaseId); - const lease = this.leasesById.get(leaseId); - if (lease) { - const slotKey = `${lease.companyId}:${lease.creditTypeId}`; - if (this.activeBySlot.get(slotKey) === leaseId) this.activeBySlot.delete(slotKey); - } - await jitter(this.rng); - return { data: {}, params: {} }; - }; - - return { acquireCreditLease, extendCreditLease, releaseCreditLease } as unknown as CreditsClient; - } -} diff --git a/tests/wire/accounts.test.ts b/tests/wire/accounts.test.ts index 28eebd1f..73ca7e54 100644 --- a/tests/wire/accounts.test.ts +++ b/tests/wire/accounts.test.ts @@ -2403,6 +2403,7 @@ describe("AccountsClient", () => { const rawResponseBody = { data: { agent_connected_at: "2024-01-15T09:30:00Z", + country: "country", dismissed_at: "2024-01-15T09:30:00Z", environment_id: "environment_id", milestones: [{ id: "evaluated", missing: ["connect_agent"], progress: 1.1 }], @@ -2423,6 +2424,7 @@ describe("AccountsClient", () => { expect(response).toEqual({ data: { agentConnectedAt: new Date("2024-01-15T09:30:00.000Z"), + country: "country", dismissedAt: new Date("2024-01-15T09:30:00.000Z"), environmentId: "environment_id", milestones: [ @@ -2510,6 +2512,7 @@ describe("AccountsClient", () => { const rawResponseBody = { data: { agent_connected_at: "2024-01-15T09:30:00Z", + country: "country", dismissed_at: "2024-01-15T09:30:00Z", environment_id: "environment_id", milestones: [{ id: "evaluated", missing: ["connect_agent"], progress: 1.1 }], @@ -2537,6 +2540,7 @@ describe("AccountsClient", () => { expect(response).toEqual({ data: { agentConnectedAt: new Date("2024-01-15T09:30:00.000Z"), + country: "country", dismissedAt: new Date("2024-01-15T09:30:00.000Z"), environmentId: "environment_id", milestones: [ diff --git a/tests/wire/billing.test.ts b/tests/wire/billing.test.ts index f7c3b475..12d3b324 100644 --- a/tests/wire/billing.test.ts +++ b/tests/wire/billing.test.ts @@ -4005,6 +4005,310 @@ describe("BillingClient", () => { }).rejects.toThrow(Schematic.InternalServerError); }); + test("listCompanyBillingProfiles (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { + data: [ + { + account_id: "account_id", + billing_customer_id: "billing_customer_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + days_until_due: 1000000, + environment_id: "environment_id", + id: "id", + is_default: true, + name: "name", + payment_method_id: "payment_method_id", + proration_behavior: "create_prorations", + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], + params: { + company_id: "company_id", + is_default: true, + limit: 1000000, + offset: 1000000, + provider_type: "metronome", + }, + }; + + server.mockEndpoint().get("/billing/profiles").respondWith().statusCode(200).jsonBody(rawResponseBody).build(); + + const response = await client.billing.listCompanyBillingProfiles({ + companyId: "company_id", + isDefault: true, + providerType: "metronome", + limit: 1000000, + offset: 1000000, + }); + expect(response).toEqual({ + data: [ + { + accountId: "account_id", + billingCustomerId: "billing_customer_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + daysUntilDue: 1000000, + environmentId: "environment_id", + id: "id", + isDefault: true, + name: "name", + paymentMethodId: "payment_method_id", + prorationBehavior: "create_prorations", + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], + params: { + companyId: "company_id", + isDefault: true, + limit: 1000000, + offset: 1000000, + providerType: "metronome", + }, + }); + }); + + test("listCompanyBillingProfiles (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server.mockEndpoint().get("/billing/profiles").respondWith().statusCode(400).jsonBody(rawResponseBody).build(); + + await expect(async () => { + return await client.billing.listCompanyBillingProfiles(); + }).rejects.toThrow(Schematic.BadRequestError); + }); + + test("listCompanyBillingProfiles (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server.mockEndpoint().get("/billing/profiles").respondWith().statusCode(401).jsonBody(rawResponseBody).build(); + + await expect(async () => { + return await client.billing.listCompanyBillingProfiles(); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("listCompanyBillingProfiles (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server.mockEndpoint().get("/billing/profiles").respondWith().statusCode(403).jsonBody(rawResponseBody).build(); + + await expect(async () => { + return await client.billing.listCompanyBillingProfiles(); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("listCompanyBillingProfiles (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server.mockEndpoint().get("/billing/profiles").respondWith().statusCode(404).jsonBody(rawResponseBody).build(); + + await expect(async () => { + return await client.billing.listCompanyBillingProfiles(); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("listCompanyBillingProfiles (6)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server.mockEndpoint().get("/billing/profiles").respondWith().statusCode(500).jsonBody(rawResponseBody).build(); + + await expect(async () => { + return await client.billing.listCompanyBillingProfiles(); + }).rejects.toThrow(Schematic.InternalServerError); + }); + + test("updateCompanyBillingProfile (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { collection_method: "charge_automatically" }; + const rawResponseBody = { + data: { + account_id: "account_id", + billing_customer_id: "billing_customer_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + days_until_due: 1000000, + environment_id: "environment_id", + id: "id", + is_default: true, + name: "name", + payment_method_id: "payment_method_id", + proration_behavior: "create_prorations", + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + params: { key: "value" }, + }; + + server + .mockEndpoint() + .put("/billing/profiles/billing_profile_id") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.billing.updateCompanyBillingProfile("billing_profile_id", { + collectionMethod: "charge_automatically", + }); + expect(response).toEqual({ + data: { + accountId: "account_id", + billingCustomerId: "billing_customer_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + daysUntilDue: 1000000, + environmentId: "environment_id", + id: "id", + isDefault: true, + name: "name", + paymentMethodId: "payment_method_id", + prorationBehavior: "create_prorations", + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + params: { + key: "value", + }, + }); + }); + + test("updateCompanyBillingProfile (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { collection_method: "charge_automatically" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .put("/billing/profiles/billing_profile_id") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(400) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.billing.updateCompanyBillingProfile("billing_profile_id", { + collectionMethod: "charge_automatically", + }); + }).rejects.toThrow(Schematic.BadRequestError); + }); + + test("updateCompanyBillingProfile (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { collection_method: "charge_automatically" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .put("/billing/profiles/billing_profile_id") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(401) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.billing.updateCompanyBillingProfile("billing_profile_id", { + collectionMethod: "charge_automatically", + }); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("updateCompanyBillingProfile (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { collection_method: "charge_automatically" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .put("/billing/profiles/billing_profile_id") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(403) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.billing.updateCompanyBillingProfile("billing_profile_id", { + collectionMethod: "charge_automatically", + }); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("updateCompanyBillingProfile (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { collection_method: "charge_automatically" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .put("/billing/profiles/billing_profile_id") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(404) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.billing.updateCompanyBillingProfile("billing_profile_id", { + collectionMethod: "charge_automatically", + }); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("updateCompanyBillingProfile (6)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { collection_method: "charge_automatically" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .put("/billing/profiles/billing_profile_id") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(500) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.billing.updateCompanyBillingProfile("billing_profile_id", { + collectionMethod: "charge_automatically", + }); + }).rejects.toThrow(Schematic.InternalServerError); + }); + test("upsertBillingSubscription (1)", async () => { const server = mockServerPool.createServer(); const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); diff --git a/tests/wire/checkout.test.ts b/tests/wire/checkout.test.ts index e2699d1c..a0b0b78b 100644 --- a/tests/wire/checkout.test.ts +++ b/tests/wire/checkout.test.ts @@ -1039,6 +1039,30 @@ describe("CheckoutClient", () => { }, ], billing_credit_balances: { key: 1.1 }, + billing_profile: { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { cancel_at_period_end: true, created_at: "2024-01-15T09:30:00Z", @@ -2147,6 +2171,30 @@ describe("CheckoutClient", () => { billingCreditBalances: { key: 1.1, }, + billingProfile: { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { cancelAtPeriodEnd: true, createdAt: new Date("2024-01-15T09:30:00.000Z"), @@ -4078,6 +4126,30 @@ describe("CheckoutClient", () => { }, ], billing_credit_balances: { key: 1.1 }, + billing_profile: { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { cancel_at_period_end: true, created_at: "2024-01-15T09:30:00Z", @@ -4407,6 +4479,30 @@ describe("CheckoutClient", () => { billingCreditBalances: { key: 1.1, }, + billingProfile: { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { cancelAtPeriodEnd: true, createdAt: new Date("2024-01-15T09:30:00.000Z"), @@ -5635,6 +5731,30 @@ describe("CheckoutClient", () => { }, ], billing_credit_balances: { key: 1.1 }, + billing_profile: { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { cancel_at_period_end: true, created_at: "2024-01-15T09:30:00Z", @@ -5941,6 +6061,30 @@ describe("CheckoutClient", () => { billingCreditBalances: { key: 1.1, }, + billingProfile: { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { cancelAtPeriodEnd: true, createdAt: new Date("2024-01-15T09:30:00.000Z"), diff --git a/tests/wire/companies.test.ts b/tests/wire/companies.test.ts index 3be53d1a..85f63a73 100644 --- a/tests/wire/companies.test.ts +++ b/tests/wire/companies.test.ts @@ -38,6 +38,30 @@ describe("CompaniesClient", () => { }, ], billing_credit_balances: { key: 1.1 }, + billing_profile: { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { cancel_at_period_end: true, created_at: "2024-01-15T09:30:00Z", @@ -378,6 +402,30 @@ describe("CompaniesClient", () => { billingCreditBalances: { key: 1.1, }, + billingProfile: { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { cancelAtPeriodEnd: true, createdAt: new Date("2024-01-15T09:30:00.000Z"), @@ -773,6 +821,35 @@ describe("CompaniesClient", () => { }, ], billing_credit_balances: { key: 1.1 }, + billing_profile: { + account_id: "account_id", + billing_customer_id: "billing_customer_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + days_until_due: 1000000, + environment_id: "environment_id", + id: "id", + is_default: true, + name: "name", + payment_method_id: "payment_method_id", + proration_behavior: "create_prorations", + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { application_id: "application_id", cancel_at: 1000000, @@ -1134,6 +1211,35 @@ describe("CompaniesClient", () => { billingCreditBalances: { key: 1.1, }, + billingProfile: { + accountId: "account_id", + billingCustomerId: "billing_customer_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + daysUntilDue: 1000000, + environmentId: "environment_id", + id: "id", + isDefault: true, + name: "name", + paymentMethodId: "payment_method_id", + prorationBehavior: "create_prorations", + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { applicationId: "application_id", cancelAt: 1000000, @@ -1621,6 +1727,35 @@ describe("CompaniesClient", () => { }, ], billing_credit_balances: { key: 1.1 }, + billing_profile: { + account_id: "account_id", + billing_customer_id: "billing_customer_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + days_until_due: 1000000, + environment_id: "environment_id", + id: "id", + is_default: true, + name: "name", + payment_method_id: "payment_method_id", + proration_behavior: "create_prorations", + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { application_id: "application_id", cancel_at: 1000000, @@ -1977,6 +2112,35 @@ describe("CompaniesClient", () => { billingCreditBalances: { key: 1.1, }, + billingProfile: { + accountId: "account_id", + billingCustomerId: "billing_customer_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + daysUntilDue: 1000000, + environmentId: "environment_id", + id: "id", + isDefault: true, + name: "name", + paymentMethodId: "payment_method_id", + prorationBehavior: "create_prorations", + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { applicationId: "application_id", cancelAt: 1000000, @@ -2695,6 +2859,35 @@ describe("CompaniesClient", () => { }, ], billing_credit_balances: { key: 1.1 }, + billing_profile: { + account_id: "account_id", + billing_customer_id: "billing_customer_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + days_until_due: 1000000, + environment_id: "environment_id", + id: "id", + is_default: true, + name: "name", + payment_method_id: "payment_method_id", + proration_behavior: "create_prorations", + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { application_id: "application_id", cancel_at: 1000000, @@ -3056,6 +3249,35 @@ describe("CompaniesClient", () => { billingCreditBalances: { key: 1.1, }, + billingProfile: { + accountId: "account_id", + billingCustomerId: "billing_customer_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + daysUntilDue: 1000000, + environmentId: "environment_id", + id: "id", + isDefault: true, + name: "name", + paymentMethodId: "payment_method_id", + prorationBehavior: "create_prorations", + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { applicationId: "application_id", cancelAt: 1000000, @@ -4079,6 +4301,56 @@ describe("CompaniesClient", () => { }, ], billing_credit_balances: { billing_credit_balances: 1.1 }, + billing_profile: { + account_id: "account_id", + billing_customer_id: "billing_customer_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + days_until_due: 1000000, + environment_id: "environment_id", + id: "id", + is_default: true, + name: "name", + payment_method_id: "payment_method_id", + proration_behavior: "create_prorations", + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + billing_customer_id: "billing_customer_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + days_until_due: 1000000, + environment_id: "environment_id", + id: "id", + is_default: true, + name: "name", + payment_method_id: "payment_method_id", + proration_behavior: "create_prorations", + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + { + account_id: "account_id", + billing_customer_id: "billing_customer_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + days_until_due: 1000000, + environment_id: "environment_id", + id: "id", + is_default: true, + name: "name", + payment_method_id: "payment_method_id", + proration_behavior: "create_prorations", + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { application_id: "application_id", cancel_at: 1000000, @@ -5850,6 +6122,56 @@ describe("CompaniesClient", () => { billingCreditBalances: { billing_credit_balances: 1.1, }, + billingProfile: { + accountId: "account_id", + billingCustomerId: "billing_customer_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + daysUntilDue: 1000000, + environmentId: "environment_id", + id: "id", + isDefault: true, + name: "name", + paymentMethodId: "payment_method_id", + prorationBehavior: "create_prorations", + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + billingCustomerId: "billing_customer_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + daysUntilDue: 1000000, + environmentId: "environment_id", + id: "id", + isDefault: true, + name: "name", + paymentMethodId: "payment_method_id", + prorationBehavior: "create_prorations", + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + { + accountId: "account_id", + billingCustomerId: "billing_customer_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + daysUntilDue: 1000000, + environmentId: "environment_id", + id: "id", + isDefault: true, + name: "name", + paymentMethodId: "payment_method_id", + prorationBehavior: "create_prorations", + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { applicationId: "application_id", cancelAt: 1000000, @@ -8565,6 +8887,35 @@ describe("CompaniesClient", () => { }, ], billing_credit_balances: { key: 1.1 }, + billing_profile: { + account_id: "account_id", + billing_customer_id: "billing_customer_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + days_until_due: 1000000, + environment_id: "environment_id", + id: "id", + is_default: true, + name: "name", + payment_method_id: "payment_method_id", + proration_behavior: "create_prorations", + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { application_id: "application_id", cancel_at: 1000000, @@ -8927,6 +9278,35 @@ describe("CompaniesClient", () => { billingCreditBalances: { key: 1.1, }, + billingProfile: { + accountId: "account_id", + billingCustomerId: "billing_customer_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + daysUntilDue: 1000000, + environmentId: "environment_id", + id: "id", + isDefault: true, + name: "name", + paymentMethodId: "payment_method_id", + prorationBehavior: "create_prorations", + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { applicationId: "application_id", cancelAt: 1000000, diff --git a/tests/wire/components.test.ts b/tests/wire/components.test.ts index 9333a457..ee20a5c2 100644 --- a/tests/wire/components.test.ts +++ b/tests/wire/components.test.ts @@ -1264,6 +1264,30 @@ describe("ComponentsClient", () => { }, ], billing_credit_balances: { key: 1.1 }, + billing_profile: { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { cancel_at_period_end: true, created_at: "2024-01-15T09:30:00Z", @@ -2660,6 +2684,30 @@ describe("ComponentsClient", () => { billingCreditBalances: { key: 1.1, }, + billingProfile: { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { cancelAtPeriodEnd: true, createdAt: new Date("2024-01-15T09:30:00.000Z"), diff --git a/tests/wire/credits.test.ts b/tests/wire/credits.test.ts index 6440ab83..ad33fa07 100644 --- a/tests/wire/credits.test.ts +++ b/tests/wire/credits.test.ts @@ -3811,6 +3811,30 @@ describe("CreditsClient", () => { const rawRequestBody = { company_id: "company_id", credit_type_id: "credit_type_id", requested_amount: 1.1 }; const rawResponseBody = { error: "error" }; + server + .mockEndpoint() + .post("/billing/credits/lease") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(402) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.acquireCreditLease({ + companyId: "company_id", + creditTypeId: "credit_type_id", + requestedAmount: 1.1, + }); + }).rejects.toThrow(Schematic.PaymentRequiredError); + }); + + test("acquireCreditLease (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { company_id: "company_id", credit_type_id: "credit_type_id", requested_amount: 1.1 }; + const rawResponseBody = { error: "error" }; + server .mockEndpoint() .post("/billing/credits/lease") @@ -3829,7 +3853,7 @@ describe("CreditsClient", () => { }).rejects.toThrow(Schematic.ForbiddenError); }); - test("acquireCreditLease (5)", async () => { + test("acquireCreditLease (6)", async () => { const server = mockServerPool.createServer(); const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); const rawRequestBody = { company_id: "company_id", credit_type_id: "credit_type_id", requested_amount: 1.1 }; @@ -3853,7 +3877,7 @@ describe("CreditsClient", () => { }).rejects.toThrow(Schematic.NotFoundError); }); - test("acquireCreditLease (6)", async () => { + test("acquireCreditLease (7)", async () => { const server = mockServerPool.createServer(); const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); const rawRequestBody = { company_id: "company_id", credit_type_id: "credit_type_id", requested_amount: 1.1 }; @@ -3976,6 +4000,28 @@ describe("CreditsClient", () => { const rawRequestBody = { additional_amount: 1.1 }; const rawResponseBody = { error: "error" }; + server + .mockEndpoint() + .put("/billing/credits/lease/lease_id/extend") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(402) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.extendCreditLease("lease_id", { + additionalAmount: 1.1, + }); + }).rejects.toThrow(Schematic.PaymentRequiredError); + }); + + test("extendCreditLease (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { additional_amount: 1.1 }; + const rawResponseBody = { error: "error" }; + server .mockEndpoint() .put("/billing/credits/lease/lease_id/extend") @@ -3992,7 +4038,7 @@ describe("CreditsClient", () => { }).rejects.toThrow(Schematic.ForbiddenError); }); - test("extendCreditLease (5)", async () => { + test("extendCreditLease (6)", async () => { const server = mockServerPool.createServer(); const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); const rawRequestBody = { additional_amount: 1.1 }; @@ -4014,7 +4060,7 @@ describe("CreditsClient", () => { }).rejects.toThrow(Schematic.NotFoundError); }); - test("extendCreditLease (6)", async () => { + test("extendCreditLease (7)", async () => { const server = mockServerPool.createServer(); const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); const rawRequestBody = { additional_amount: 1.1 }; @@ -5619,6 +5665,872 @@ describe("CreditsClient", () => { }).rejects.toThrow(Schematic.InternalServerError); }); + test("listCreditSpendPolicies (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { + data: [ + { + billing_credit_id: "billing_credit_id", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + id: "id", + label: "label", + max_per_draw: 1.1, + scope_type: "company", + updated_at: "2024-01-15T09:30:00Z", + user_id: "user_id", + }, + ], + params: { + billing_credit_id: "billing_credit_id", + company_id: "company_id", + limit: 1000000, + offset: 1000000, + scope_type: "company", + user_id: "user_id", + user_ids: ["user_ids"], + }, + }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies") + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.credits.listCreditSpendPolicies({ + billingCreditId: "billing_credit_id", + companyId: "company_id", + scopeType: "company", + userId: "user_id", + userIds: ["user_ids"], + limit: 1000000, + offset: 1000000, + }); + expect(response).toEqual({ + data: [ + { + billingCreditId: "billing_credit_id", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + id: "id", + label: "label", + maxPerDraw: 1.1, + scopeType: "company", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + userId: "user_id", + }, + ], + params: { + billingCreditId: "billing_credit_id", + companyId: "company_id", + limit: 1000000, + offset: 1000000, + scopeType: "company", + userId: "user_id", + userIds: ["user_ids"], + }, + }); + }); + + test("listCreditSpendPolicies (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies") + .respondWith() + .statusCode(400) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.listCreditSpendPolicies(); + }).rejects.toThrow(Schematic.BadRequestError); + }); + + test("listCreditSpendPolicies (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies") + .respondWith() + .statusCode(401) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.listCreditSpendPolicies(); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("listCreditSpendPolicies (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies") + .respondWith() + .statusCode(403) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.listCreditSpendPolicies(); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("listCreditSpendPolicies (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies") + .respondWith() + .statusCode(404) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.listCreditSpendPolicies(); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("listCreditSpendPolicies (6)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies") + .respondWith() + .statusCode(500) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.listCreditSpendPolicies(); + }).rejects.toThrow(Schematic.InternalServerError); + }); + + test("createCreditSpendPolicy (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { billing_credit_id: "billing_credit_id", max_per_draw: 1.1 }; + const rawResponseBody = { + data: { + billing_credit_id: "billing_credit_id", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + id: "id", + label: "label", + max_per_draw: 1.1, + scope_type: "company", + updated_at: "2024-01-15T09:30:00Z", + user_id: "user_id", + }, + params: { key: "value" }, + }; + + server + .mockEndpoint() + .post("/billing/credits/spend-policies") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.credits.createCreditSpendPolicy({ + billingCreditId: "billing_credit_id", + maxPerDraw: 1.1, + }); + expect(response).toEqual({ + data: { + billingCreditId: "billing_credit_id", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + id: "id", + label: "label", + maxPerDraw: 1.1, + scopeType: "company", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + userId: "user_id", + }, + params: { + key: "value", + }, + }); + }); + + test("createCreditSpendPolicy (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { billing_credit_id: "billing_credit_id", max_per_draw: 1.1 }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/billing/credits/spend-policies") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(400) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.createCreditSpendPolicy({ + billingCreditId: "billing_credit_id", + maxPerDraw: 1.1, + }); + }).rejects.toThrow(Schematic.BadRequestError); + }); + + test("createCreditSpendPolicy (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { billing_credit_id: "billing_credit_id", max_per_draw: 1.1 }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/billing/credits/spend-policies") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(401) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.createCreditSpendPolicy({ + billingCreditId: "billing_credit_id", + maxPerDraw: 1.1, + }); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("createCreditSpendPolicy (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { billing_credit_id: "billing_credit_id", max_per_draw: 1.1 }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/billing/credits/spend-policies") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(403) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.createCreditSpendPolicy({ + billingCreditId: "billing_credit_id", + maxPerDraw: 1.1, + }); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("createCreditSpendPolicy (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { billing_credit_id: "billing_credit_id", max_per_draw: 1.1 }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/billing/credits/spend-policies") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(404) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.createCreditSpendPolicy({ + billingCreditId: "billing_credit_id", + maxPerDraw: 1.1, + }); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("createCreditSpendPolicy (6)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { billing_credit_id: "billing_credit_id", max_per_draw: 1.1 }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/billing/credits/spend-policies") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(500) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.createCreditSpendPolicy({ + billingCreditId: "billing_credit_id", + maxPerDraw: 1.1, + }); + }).rejects.toThrow(Schematic.InternalServerError); + }); + + test("getCreditSpendPolicy (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { + data: { + billing_credit_id: "billing_credit_id", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + id: "id", + label: "label", + max_per_draw: 1.1, + scope_type: "company", + updated_at: "2024-01-15T09:30:00Z", + user_id: "user_id", + }, + params: { key: "value" }, + }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies/spend_policy_id") + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.credits.getCreditSpendPolicy("spend_policy_id"); + expect(response).toEqual({ + data: { + billingCreditId: "billing_credit_id", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + id: "id", + label: "label", + maxPerDraw: 1.1, + scopeType: "company", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + userId: "user_id", + }, + params: { + key: "value", + }, + }); + }); + + test("getCreditSpendPolicy (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies/spend_policy_id") + .respondWith() + .statusCode(401) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.getCreditSpendPolicy("spend_policy_id"); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("getCreditSpendPolicy (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies/spend_policy_id") + .respondWith() + .statusCode(403) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.getCreditSpendPolicy("spend_policy_id"); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("getCreditSpendPolicy (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies/spend_policy_id") + .respondWith() + .statusCode(404) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.getCreditSpendPolicy("spend_policy_id"); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("getCreditSpendPolicy (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies/spend_policy_id") + .respondWith() + .statusCode(500) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.getCreditSpendPolicy("spend_policy_id"); + }).rejects.toThrow(Schematic.InternalServerError); + }); + + test("updateCreditSpendPolicy (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = {}; + const rawResponseBody = { + data: { + billing_credit_id: "billing_credit_id", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + id: "id", + label: "label", + max_per_draw: 1.1, + scope_type: "company", + updated_at: "2024-01-15T09:30:00Z", + user_id: "user_id", + }, + params: { key: "value" }, + }; + + server + .mockEndpoint() + .put("/billing/credits/spend-policies/spend_policy_id") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.credits.updateCreditSpendPolicy("spend_policy_id"); + expect(response).toEqual({ + data: { + billingCreditId: "billing_credit_id", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + id: "id", + label: "label", + maxPerDraw: 1.1, + scopeType: "company", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + userId: "user_id", + }, + params: { + key: "value", + }, + }); + }); + + test("updateCreditSpendPolicy (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = {}; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .put("/billing/credits/spend-policies/spend_policy_id") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(400) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.updateCreditSpendPolicy("spend_policy_id"); + }).rejects.toThrow(Schematic.BadRequestError); + }); + + test("updateCreditSpendPolicy (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = {}; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .put("/billing/credits/spend-policies/spend_policy_id") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(401) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.updateCreditSpendPolicy("spend_policy_id"); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("updateCreditSpendPolicy (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = {}; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .put("/billing/credits/spend-policies/spend_policy_id") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(403) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.updateCreditSpendPolicy("spend_policy_id"); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("updateCreditSpendPolicy (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = {}; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .put("/billing/credits/spend-policies/spend_policy_id") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(404) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.updateCreditSpendPolicy("spend_policy_id"); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("updateCreditSpendPolicy (6)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = {}; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .put("/billing/credits/spend-policies/spend_policy_id") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(500) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.updateCreditSpendPolicy("spend_policy_id"); + }).rejects.toThrow(Schematic.InternalServerError); + }); + + test("deleteCreditSpendPolicy (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { data: { deleted: true }, params: { key: "value" } }; + + server + .mockEndpoint() + .delete("/billing/credits/spend-policies/spend_policy_id") + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.credits.deleteCreditSpendPolicy("spend_policy_id"); + expect(response).toEqual({ + data: { + deleted: true, + }, + params: { + key: "value", + }, + }); + }); + + test("deleteCreditSpendPolicy (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .delete("/billing/credits/spend-policies/spend_policy_id") + .respondWith() + .statusCode(400) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.deleteCreditSpendPolicy("spend_policy_id"); + }).rejects.toThrow(Schematic.BadRequestError); + }); + + test("deleteCreditSpendPolicy (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .delete("/billing/credits/spend-policies/spend_policy_id") + .respondWith() + .statusCode(401) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.deleteCreditSpendPolicy("spend_policy_id"); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("deleteCreditSpendPolicy (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .delete("/billing/credits/spend-policies/spend_policy_id") + .respondWith() + .statusCode(403) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.deleteCreditSpendPolicy("spend_policy_id"); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("deleteCreditSpendPolicy (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .delete("/billing/credits/spend-policies/spend_policy_id") + .respondWith() + .statusCode(404) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.deleteCreditSpendPolicy("spend_policy_id"); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("deleteCreditSpendPolicy (6)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .delete("/billing/credits/spend-policies/spend_policy_id") + .respondWith() + .statusCode(500) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.deleteCreditSpendPolicy("spend_policy_id"); + }).rejects.toThrow(Schematic.InternalServerError); + }); + + test("countCreditSpendPolicies (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { + data: { count: 1000000 }, + params: { + billing_credit_id: "billing_credit_id", + company_id: "company_id", + limit: 1000000, + offset: 1000000, + scope_type: "company", + user_id: "user_id", + user_ids: ["user_ids"], + }, + }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies/count") + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.credits.countCreditSpendPolicies({ + billingCreditId: "billing_credit_id", + companyId: "company_id", + scopeType: "company", + userId: "user_id", + userIds: ["user_ids"], + limit: 1000000, + offset: 1000000, + }); + expect(response).toEqual({ + data: { + count: 1000000, + }, + params: { + billingCreditId: "billing_credit_id", + companyId: "company_id", + limit: 1000000, + offset: 1000000, + scopeType: "company", + userId: "user_id", + userIds: ["user_ids"], + }, + }); + }); + + test("countCreditSpendPolicies (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies/count") + .respondWith() + .statusCode(400) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.countCreditSpendPolicies(); + }).rejects.toThrow(Schematic.BadRequestError); + }); + + test("countCreditSpendPolicies (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies/count") + .respondWith() + .statusCode(401) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.countCreditSpendPolicies(); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("countCreditSpendPolicies (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies/count") + .respondWith() + .statusCode(403) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.countCreditSpendPolicies(); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("countCreditSpendPolicies (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies/count") + .respondWith() + .statusCode(404) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.countCreditSpendPolicies(); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("countCreditSpendPolicies (6)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/billing/credits/spend-policies/count") + .respondWith() + .statusCode(500) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.credits.countCreditSpendPolicies(); + }).rejects.toThrow(Schematic.InternalServerError); + }); + test("listCreditEventLedger (1)", async () => { const server = mockServerPool.createServer(); const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); diff --git a/tests/wire/entitlements.test.ts b/tests/wire/entitlements.test.ts index b4c3b24d..5edac2be 100644 --- a/tests/wire/entitlements.test.ts +++ b/tests/wire/entitlements.test.ts @@ -228,6 +228,19 @@ describe("EntitlementsClient", () => { rule_id_usage_exceeded: "rule_id_usage_exceeded", updated_at: "2024-01-15T09:30:00Z", value_bool: true, + value_credit: { + burn_strategy: "expiration_priority", + cost_editable: true, + created_at: "2024-01-15T09:30:00Z", + currency_prices: [{ currency: "currency" }], + default_expiry_unit: "billing_periods", + default_rollover_policy: "expire", + description: "description", + id: "id", + name: "name", + updated_at: "2024-01-15T09:30:00Z", + }, + value_credit_id: "value_credit_id", value_numeric: 1000000, value_trait: { created_at: "2024-01-15T09:30:00Z", @@ -498,6 +511,23 @@ describe("EntitlementsClient", () => { ruleIdUsageExceeded: "rule_id_usage_exceeded", updatedAt: new Date("2024-01-15T09:30:00.000Z"), valueBool: true, + valueCredit: { + burnStrategy: "expiration_priority", + costEditable: true, + createdAt: new Date("2024-01-15T09:30:00.000Z"), + currencyPrices: [ + { + currency: "currency", + }, + ], + defaultExpiryUnit: "billing_periods", + defaultRolloverPolicy: "expire", + description: "description", + id: "id", + name: "name", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + valueCreditId: "value_credit_id", valueNumeric: 1000000, valueTrait: { createdAt: new Date("2024-01-15T09:30:00.000Z"), @@ -624,6 +654,30 @@ describe("EntitlementsClient", () => { }, ], billing_credit_balances: { key: 1.1 }, + billing_profile: { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { cancel_at_period_end: true, created_at: "2024-01-15T09:30:00Z", @@ -922,6 +976,46 @@ describe("EntitlementsClient", () => { rule_id_usage_exceeded: "rule_id_usage_exceeded", updated_at: "2024-01-15T09:30:00Z", value_bool: true, + value_credit: { + burn_strategy: "expiration_priority", + cost_editable: true, + created_at: "2024-01-15T09:30:00Z", + currency_prices: [{ currency: "currency" }], + default_expiry_unit: "billing_periods", + default_expiry_unit_count: 1000000, + default_rollover_policy: "expire", + description: "description", + icon: "icon", + id: "id", + name: "name", + plural_name: "plural_name", + price: { + currency: "currency", + external_price_id: "external_price_id", + id: "id", + interval: "day", + interval_count: 1000000, + price: 1000000, + provider_type: "metronome", + scheme: "per_unit", + }, + product: { + account_id: "account_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + external_id: "external_id", + is_active: true, + name: "name", + price: 1.1, + product_id: "product_id", + provider_type: "metronome", + quantity: 1.1, + updated_at: "2024-01-15T09:30:00Z", + }, + singular_name: "singular_name", + updated_at: "2024-01-15T09:30:00Z", + }, + value_credit_id: "value_credit_id", value_numeric: 1000000, value_trait: { created_at: "2024-01-15T09:30:00Z", @@ -983,6 +1077,30 @@ describe("EntitlementsClient", () => { billingCreditBalances: { key: 1.1, }, + billingProfile: { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { cancelAtPeriodEnd: true, createdAt: new Date("2024-01-15T09:30:00.000Z"), @@ -1294,6 +1412,50 @@ describe("EntitlementsClient", () => { ruleIdUsageExceeded: "rule_id_usage_exceeded", updatedAt: new Date("2024-01-15T09:30:00.000Z"), valueBool: true, + valueCredit: { + burnStrategy: "expiration_priority", + costEditable: true, + createdAt: new Date("2024-01-15T09:30:00.000Z"), + currencyPrices: [ + { + currency: "currency", + }, + ], + defaultExpiryUnit: "billing_periods", + defaultExpiryUnitCount: 1000000, + defaultRolloverPolicy: "expire", + description: "description", + icon: "icon", + id: "id", + name: "name", + pluralName: "plural_name", + price: { + currency: "currency", + externalPriceId: "external_price_id", + id: "id", + interval: "day", + intervalCount: 1000000, + price: 1000000, + providerType: "metronome", + scheme: "per_unit", + }, + product: { + accountId: "account_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + externalId: "external_id", + isActive: true, + name: "name", + price: 1.1, + productId: "product_id", + providerType: "metronome", + quantity: 1.1, + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + singularName: "singular_name", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + valueCreditId: "value_credit_id", valueNumeric: 1000000, valueTrait: { createdAt: new Date("2024-01-15T09:30:00.000Z"), @@ -1466,6 +1628,30 @@ describe("EntitlementsClient", () => { }, ], billing_credit_balances: { key: 1.1 }, + billing_profile: { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { cancel_at_period_end: true, created_at: "2024-01-15T09:30:00Z", @@ -1764,6 +1950,46 @@ describe("EntitlementsClient", () => { rule_id_usage_exceeded: "rule_id_usage_exceeded", updated_at: "2024-01-15T09:30:00Z", value_bool: true, + value_credit: { + burn_strategy: "expiration_priority", + cost_editable: true, + created_at: "2024-01-15T09:30:00Z", + currency_prices: [{ currency: "currency" }], + default_expiry_unit: "billing_periods", + default_expiry_unit_count: 1000000, + default_rollover_policy: "expire", + description: "description", + icon: "icon", + id: "id", + name: "name", + plural_name: "plural_name", + price: { + currency: "currency", + external_price_id: "external_price_id", + id: "id", + interval: "day", + interval_count: 1000000, + price: 1000000, + provider_type: "metronome", + scheme: "per_unit", + }, + product: { + account_id: "account_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + external_id: "external_id", + is_active: true, + name: "name", + price: 1.1, + product_id: "product_id", + provider_type: "metronome", + quantity: 1.1, + updated_at: "2024-01-15T09:30:00Z", + }, + singular_name: "singular_name", + updated_at: "2024-01-15T09:30:00Z", + }, + value_credit_id: "value_credit_id", value_numeric: 1000000, value_trait: { created_at: "2024-01-15T09:30:00Z", @@ -1820,6 +2046,30 @@ describe("EntitlementsClient", () => { billingCreditBalances: { key: 1.1, }, + billingProfile: { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { cancelAtPeriodEnd: true, createdAt: new Date("2024-01-15T09:30:00.000Z"), @@ -2131,6 +2381,50 @@ describe("EntitlementsClient", () => { ruleIdUsageExceeded: "rule_id_usage_exceeded", updatedAt: new Date("2024-01-15T09:30:00.000Z"), valueBool: true, + valueCredit: { + burnStrategy: "expiration_priority", + costEditable: true, + createdAt: new Date("2024-01-15T09:30:00.000Z"), + currencyPrices: [ + { + currency: "currency", + }, + ], + defaultExpiryUnit: "billing_periods", + defaultExpiryUnitCount: 1000000, + defaultRolloverPolicy: "expire", + description: "description", + icon: "icon", + id: "id", + name: "name", + pluralName: "plural_name", + price: { + currency: "currency", + externalPriceId: "external_price_id", + id: "id", + interval: "day", + intervalCount: 1000000, + price: 1000000, + providerType: "metronome", + scheme: "per_unit", + }, + product: { + accountId: "account_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + externalId: "external_id", + isActive: true, + name: "name", + price: 1.1, + productId: "product_id", + providerType: "metronome", + quantity: 1.1, + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + singularName: "singular_name", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + valueCreditId: "value_credit_id", valueNumeric: 1000000, valueTrait: { createdAt: new Date("2024-01-15T09:30:00.000Z"), @@ -2259,6 +2553,30 @@ describe("EntitlementsClient", () => { }, ], billing_credit_balances: { key: 1.1 }, + billing_profile: { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { cancel_at_period_end: true, created_at: "2024-01-15T09:30:00Z", @@ -2557,6 +2875,46 @@ describe("EntitlementsClient", () => { rule_id_usage_exceeded: "rule_id_usage_exceeded", updated_at: "2024-01-15T09:30:00Z", value_bool: true, + value_credit: { + burn_strategy: "expiration_priority", + cost_editable: true, + created_at: "2024-01-15T09:30:00Z", + currency_prices: [{ currency: "currency" }], + default_expiry_unit: "billing_periods", + default_expiry_unit_count: 1000000, + default_rollover_policy: "expire", + description: "description", + icon: "icon", + id: "id", + name: "name", + plural_name: "plural_name", + price: { + currency: "currency", + external_price_id: "external_price_id", + id: "id", + interval: "day", + interval_count: 1000000, + price: 1000000, + provider_type: "metronome", + scheme: "per_unit", + }, + product: { + account_id: "account_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + external_id: "external_id", + is_active: true, + name: "name", + price: 1.1, + product_id: "product_id", + provider_type: "metronome", + quantity: 1.1, + updated_at: "2024-01-15T09:30:00Z", + }, + singular_name: "singular_name", + updated_at: "2024-01-15T09:30:00Z", + }, + value_credit_id: "value_credit_id", value_numeric: 1000000, value_trait: { created_at: "2024-01-15T09:30:00Z", @@ -2613,9 +2971,33 @@ describe("EntitlementsClient", () => { name: "name", }, ], - billingCreditBalances: { - key: 1.1, - }, + billingCreditBalances: { + key: 1.1, + }, + billingProfile: { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { cancelAtPeriodEnd: true, createdAt: new Date("2024-01-15T09:30:00.000Z"), @@ -2927,6 +3309,50 @@ describe("EntitlementsClient", () => { ruleIdUsageExceeded: "rule_id_usage_exceeded", updatedAt: new Date("2024-01-15T09:30:00.000Z"), valueBool: true, + valueCredit: { + burnStrategy: "expiration_priority", + costEditable: true, + createdAt: new Date("2024-01-15T09:30:00.000Z"), + currencyPrices: [ + { + currency: "currency", + }, + ], + defaultExpiryUnit: "billing_periods", + defaultExpiryUnitCount: 1000000, + defaultRolloverPolicy: "expire", + description: "description", + icon: "icon", + id: "id", + name: "name", + pluralName: "plural_name", + price: { + currency: "currency", + externalPriceId: "external_price_id", + id: "id", + interval: "day", + intervalCount: 1000000, + price: 1000000, + providerType: "metronome", + scheme: "per_unit", + }, + product: { + accountId: "account_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + externalId: "external_id", + isActive: true, + name: "name", + price: 1.1, + productId: "product_id", + providerType: "metronome", + quantity: 1.1, + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + singularName: "singular_name", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + valueCreditId: "value_credit_id", valueNumeric: 1000000, valueTrait: { createdAt: new Date("2024-01-15T09:30:00.000Z"), @@ -9384,6 +9810,18 @@ describe("EntitlementsClient", () => { { id: "id", included_credit_grants: [], name: "name" }, ], billing_credit_balances: { billing_credit_balances: 1.1 }, + billing_profile: { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [], billing_subscription: { cancel_at_period_end: true, created_at: "2024-01-15T09:30:00Z", @@ -9668,6 +10106,46 @@ describe("EntitlementsClient", () => { rule_id_usage_exceeded: "rule_id_usage_exceeded", updated_at: "2024-01-15T09:30:00Z", value_bool: true, + value_credit: { + burn_strategy: "expiration_priority", + cost_editable: true, + created_at: "2024-01-15T09:30:00Z", + currency_prices: [{ currency: "currency" }, { currency: "currency" }], + default_expiry_unit: "billing_periods", + default_expiry_unit_count: 1000000, + default_rollover_policy: "expire", + description: "description", + icon: "icon", + id: "id", + name: "name", + plural_name: "plural_name", + price: { + currency: "currency", + external_price_id: "external_price_id", + id: "id", + interval: "day", + interval_count: 1000000, + price: 1000000, + provider_type: "metronome", + scheme: "per_unit", + }, + product: { + account_id: "account_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + external_id: "external_id", + is_active: true, + name: "name", + price: 1.1, + product_id: "product_id", + provider_type: "metronome", + quantity: 1.1, + updated_at: "2024-01-15T09:30:00Z", + }, + singular_name: "singular_name", + updated_at: "2024-01-15T09:30:00Z", + }, + value_credit_id: "value_credit_id", value_numeric: 1000000, value_trait: { created_at: "2024-01-15T09:30:00Z", @@ -10334,6 +10812,18 @@ describe("EntitlementsClient", () => { { id: "id", included_credit_grants: [], name: "name" }, ], billing_credit_balances: { billing_credit_balances: 1.1 }, + billing_profile: { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [], billing_subscription: { cancel_at_period_end: true, created_at: "2024-01-15T09:30:00Z", @@ -10618,6 +11108,46 @@ describe("EntitlementsClient", () => { rule_id_usage_exceeded: "rule_id_usage_exceeded", updated_at: "2024-01-15T09:30:00Z", value_bool: true, + value_credit: { + burn_strategy: "expiration_priority", + cost_editable: true, + created_at: "2024-01-15T09:30:00Z", + currency_prices: [{ currency: "currency" }, { currency: "currency" }], + default_expiry_unit: "billing_periods", + default_expiry_unit_count: 1000000, + default_rollover_policy: "expire", + description: "description", + icon: "icon", + id: "id", + name: "name", + plural_name: "plural_name", + price: { + currency: "currency", + external_price_id: "external_price_id", + id: "id", + interval: "day", + interval_count: 1000000, + price: 1000000, + provider_type: "metronome", + scheme: "per_unit", + }, + product: { + account_id: "account_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + external_id: "external_id", + is_active: true, + name: "name", + price: 1.1, + product_id: "product_id", + provider_type: "metronome", + quantity: 1.1, + updated_at: "2024-01-15T09:30:00Z", + }, + singular_name: "singular_name", + updated_at: "2024-01-15T09:30:00Z", + }, + value_credit_id: "value_credit_id", value_numeric: 1000000, value_trait: { created_at: "2024-01-15T09:30:00Z", @@ -11309,6 +11839,18 @@ describe("EntitlementsClient", () => { billingCreditBalances: { billing_credit_balances: 1.1, }, + billingProfile: { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [], billingSubscription: { cancelAtPeriodEnd: true, createdAt: new Date("2024-01-15T09:30:00.000Z"), @@ -11615,6 +12157,53 @@ describe("EntitlementsClient", () => { ruleIdUsageExceeded: "rule_id_usage_exceeded", updatedAt: new Date("2024-01-15T09:30:00.000Z"), valueBool: true, + valueCredit: { + burnStrategy: "expiration_priority", + costEditable: true, + createdAt: new Date("2024-01-15T09:30:00.000Z"), + currencyPrices: [ + { + currency: "currency", + }, + { + currency: "currency", + }, + ], + defaultExpiryUnit: "billing_periods", + defaultExpiryUnitCount: 1000000, + defaultRolloverPolicy: "expire", + description: "description", + icon: "icon", + id: "id", + name: "name", + pluralName: "plural_name", + price: { + currency: "currency", + externalPriceId: "external_price_id", + id: "id", + interval: "day", + intervalCount: 1000000, + price: 1000000, + providerType: "metronome", + scheme: "per_unit", + }, + product: { + accountId: "account_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + externalId: "external_id", + isActive: true, + name: "name", + price: 1.1, + productId: "product_id", + providerType: "metronome", + quantity: 1.1, + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + singularName: "singular_name", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + valueCreditId: "value_credit_id", valueNumeric: 1000000, valueTrait: { createdAt: new Date("2024-01-15T09:30:00.000Z"), @@ -12318,6 +12907,18 @@ describe("EntitlementsClient", () => { billingCreditBalances: { billing_credit_balances: 1.1, }, + billingProfile: { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [], billingSubscription: { cancelAtPeriodEnd: true, createdAt: new Date("2024-01-15T09:30:00.000Z"), @@ -12624,6 +13225,53 @@ describe("EntitlementsClient", () => { ruleIdUsageExceeded: "rule_id_usage_exceeded", updatedAt: new Date("2024-01-15T09:30:00.000Z"), valueBool: true, + valueCredit: { + burnStrategy: "expiration_priority", + costEditable: true, + createdAt: new Date("2024-01-15T09:30:00.000Z"), + currencyPrices: [ + { + currency: "currency", + }, + { + currency: "currency", + }, + ], + defaultExpiryUnit: "billing_periods", + defaultExpiryUnitCount: 1000000, + defaultRolloverPolicy: "expire", + description: "description", + icon: "icon", + id: "id", + name: "name", + pluralName: "plural_name", + price: { + currency: "currency", + externalPriceId: "external_price_id", + id: "id", + interval: "day", + intervalCount: 1000000, + price: 1000000, + providerType: "metronome", + scheme: "per_unit", + }, + product: { + accountId: "account_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + externalId: "external_id", + isActive: true, + name: "name", + price: 1.1, + productId: "product_id", + providerType: "metronome", + quantity: 1.1, + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + singularName: "singular_name", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + valueCreditId: "value_credit_id", valueNumeric: 1000000, valueTrait: { createdAt: new Date("2024-01-15T09:30:00.000Z"), diff --git a/tests/wire/events.test.ts b/tests/wire/events.test.ts index f412ef88..695d502a 100644 --- a/tests/wire/events.test.ts +++ b/tests/wire/events.test.ts @@ -819,6 +819,337 @@ describe("EventsClient", () => { }).rejects.toThrow(Schematic.InternalServerError); }); + test("getOTLPEnvironmentSettings (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { + data: { + company_attribute: "company_attribute", + company_key: "company_key", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + tool_events_enabled: true, + updated_at: "2024-01-15T09:30:00Z", + user_attribute: "user_attribute", + user_key: "user_key", + }, + params: { key: "value" }, + }; + + server.mockEndpoint().get("/otlp/settings").respondWith().statusCode(200).jsonBody(rawResponseBody).build(); + + const response = await client.events.getOtlpEnvironmentSettings(); + expect(response).toEqual({ + data: { + companyAttribute: "company_attribute", + companyKey: "company_key", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + toolEventsEnabled: true, + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + userAttribute: "user_attribute", + userKey: "user_key", + }, + params: { + key: "value", + }, + }); + }); + + test("getOTLPEnvironmentSettings (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server.mockEndpoint().get("/otlp/settings").respondWith().statusCode(401).jsonBody(rawResponseBody).build(); + + await expect(async () => { + return await client.events.getOtlpEnvironmentSettings(); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("getOTLPEnvironmentSettings (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server.mockEndpoint().get("/otlp/settings").respondWith().statusCode(403).jsonBody(rawResponseBody).build(); + + await expect(async () => { + return await client.events.getOtlpEnvironmentSettings(); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("getOTLPEnvironmentSettings (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server.mockEndpoint().get("/otlp/settings").respondWith().statusCode(404).jsonBody(rawResponseBody).build(); + + await expect(async () => { + return await client.events.getOtlpEnvironmentSettings(); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("getOTLPEnvironmentSettings (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server.mockEndpoint().get("/otlp/settings").respondWith().statusCode(500).jsonBody(rawResponseBody).build(); + + await expect(async () => { + return await client.events.getOtlpEnvironmentSettings(); + }).rejects.toThrow(Schematic.InternalServerError); + }); + + test("upsertOTLPEnvironmentSettings (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { tool_events_enabled: true }; + const rawResponseBody = { + data: { + company_attribute: "company_attribute", + company_key: "company_key", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + tool_events_enabled: true, + updated_at: "2024-01-15T09:30:00Z", + user_attribute: "user_attribute", + user_key: "user_key", + }, + params: { key: "value" }, + }; + + server + .mockEndpoint() + .post("/otlp/settings") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.events.upsertOtlpEnvironmentSettings({ + toolEventsEnabled: true, + }); + expect(response).toEqual({ + data: { + companyAttribute: "company_attribute", + companyKey: "company_key", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + toolEventsEnabled: true, + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + userAttribute: "user_attribute", + userKey: "user_key", + }, + params: { + key: "value", + }, + }); + }); + + test("upsertOTLPEnvironmentSettings (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { tool_events_enabled: true }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/otlp/settings") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(400) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.events.upsertOtlpEnvironmentSettings({ + toolEventsEnabled: true, + }); + }).rejects.toThrow(Schematic.BadRequestError); + }); + + test("upsertOTLPEnvironmentSettings (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { tool_events_enabled: true }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/otlp/settings") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(401) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.events.upsertOtlpEnvironmentSettings({ + toolEventsEnabled: true, + }); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("upsertOTLPEnvironmentSettings (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { tool_events_enabled: true }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/otlp/settings") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(403) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.events.upsertOtlpEnvironmentSettings({ + toolEventsEnabled: true, + }); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("upsertOTLPEnvironmentSettings (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { tool_events_enabled: true }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/otlp/settings") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(404) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.events.upsertOtlpEnvironmentSettings({ + toolEventsEnabled: true, + }); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("upsertOTLPEnvironmentSettings (6)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { tool_events_enabled: true }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/otlp/settings") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(500) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.events.upsertOtlpEnvironmentSettings({ + toolEventsEnabled: true, + }); + }).rejects.toThrow(Schematic.InternalServerError); + }); + + test("deleteOTLPEnvironmentSettings (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { data: { deleted: true }, params: { key: "value" } }; + + server.mockEndpoint().delete("/otlp/settings").respondWith().statusCode(200).jsonBody(rawResponseBody).build(); + + const response = await client.events.deleteOtlpEnvironmentSettings(); + expect(response).toEqual({ + data: { + deleted: true, + }, + params: { + key: "value", + }, + }); + }); + + test("deleteOTLPEnvironmentSettings (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server.mockEndpoint().delete("/otlp/settings").respondWith().statusCode(400).jsonBody(rawResponseBody).build(); + + await expect(async () => { + return await client.events.deleteOtlpEnvironmentSettings(); + }).rejects.toThrow(Schematic.BadRequestError); + }); + + test("deleteOTLPEnvironmentSettings (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server.mockEndpoint().delete("/otlp/settings").respondWith().statusCode(401).jsonBody(rawResponseBody).build(); + + await expect(async () => { + return await client.events.deleteOtlpEnvironmentSettings(); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("deleteOTLPEnvironmentSettings (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server.mockEndpoint().delete("/otlp/settings").respondWith().statusCode(403).jsonBody(rawResponseBody).build(); + + await expect(async () => { + return await client.events.deleteOtlpEnvironmentSettings(); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("deleteOTLPEnvironmentSettings (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server.mockEndpoint().delete("/otlp/settings").respondWith().statusCode(404).jsonBody(rawResponseBody).build(); + + await expect(async () => { + return await client.events.deleteOtlpEnvironmentSettings(); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("deleteOTLPEnvironmentSettings (6)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server.mockEndpoint().delete("/otlp/settings").respondWith().statusCode(500).jsonBody(rawResponseBody).build(); + + await expect(async () => { + return await client.events.deleteOtlpEnvironmentSettings(); + }).rejects.toThrow(Schematic.InternalServerError); + }); + test("getSegmentIntegrationStatus (1)", async () => { const server = mockServerPool.createServer(); const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); diff --git a/tests/wire/integrationsapi.test.ts b/tests/wire/integrationsapi.test.ts index 2d9d820a..cb2e33b8 100644 --- a/tests/wire/integrationsapi.test.ts +++ b/tests/wire/integrationsapi.test.ts @@ -795,6 +795,367 @@ describe("IntegrationsapiClient", () => { }).rejects.toThrow(Schematic.InternalServerError); }); + test("getStripeSandboxClaimLink (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { + data: { + claim_url: "claim_url", + expires_at: "2024-01-15T09:30:00Z", + sandbox_id: "sandbox_id", + status: "status", + }, + params: { key: "value" }, + }; + + server + .mockEndpoint() + .get("/integrations/stripe/sandbox/claim-link") + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.integrationsapi.getStripeSandboxClaimLink(); + expect(response).toEqual({ + data: { + claimUrl: "claim_url", + expiresAt: new Date("2024-01-15T09:30:00.000Z"), + sandboxId: "sandbox_id", + status: "status", + }, + params: { + key: "value", + }, + }); + }); + + test("getStripeSandboxClaimLink (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/integrations/stripe/sandbox/claim-link") + .respondWith() + .statusCode(401) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.getStripeSandboxClaimLink(); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("getStripeSandboxClaimLink (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/integrations/stripe/sandbox/claim-link") + .respondWith() + .statusCode(403) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.getStripeSandboxClaimLink(); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("getStripeSandboxClaimLink (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/integrations/stripe/sandbox/claim-link") + .respondWith() + .statusCode(404) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.getStripeSandboxClaimLink(); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("getStripeSandboxClaimLink (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/integrations/stripe/sandbox/claim-link") + .respondWith() + .statusCode(500) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.getStripeSandboxClaimLink(); + }).rejects.toThrow(Schematic.InternalServerError); + }); + + test("getStripeSandboxKeys (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { + data: { publishable: "publishable", sandbox_id: "sandbox_id", secret: "secret" }, + params: { key: "value" }, + }; + + server + .mockEndpoint() + .get("/integrations/stripe/sandbox/keys") + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.integrationsapi.getStripeSandboxKeys(); + expect(response).toEqual({ + data: { + publishable: "publishable", + sandboxId: "sandbox_id", + secret: "secret", + }, + params: { + key: "value", + }, + }); + }); + + test("getStripeSandboxKeys (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/integrations/stripe/sandbox/keys") + .respondWith() + .statusCode(401) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.getStripeSandboxKeys(); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("getStripeSandboxKeys (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/integrations/stripe/sandbox/keys") + .respondWith() + .statusCode(403) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.getStripeSandboxKeys(); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("getStripeSandboxKeys (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/integrations/stripe/sandbox/keys") + .respondWith() + .statusCode(404) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.getStripeSandboxKeys(); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("getStripeSandboxKeys (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/integrations/stripe/sandbox/keys") + .respondWith() + .statusCode(500) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.getStripeSandboxKeys(); + }).rejects.toThrow(Schematic.InternalServerError); + }); + + test("claimStripeSandboxKeys (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { token: "token" }; + const rawResponseBody = { + data: { publishable: "publishable", sandbox_id: "sandbox_id", secret: "secret" }, + params: { key: "value" }, + }; + + server + .mockEndpoint() + .post("/integrations/stripe/sandbox/keys/claim") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.integrationsapi.claimStripeSandboxKeys({ + token: "token", + }); + expect(response).toEqual({ + data: { + publishable: "publishable", + sandboxId: "sandbox_id", + secret: "secret", + }, + params: { + key: "value", + }, + }); + }); + + test("claimStripeSandboxKeys (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { token: "x" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/integrations/stripe/sandbox/keys/claim") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(400) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.claimStripeSandboxKeys({ + token: "x", + }); + }).rejects.toThrow(Schematic.BadRequestError); + }); + + test("claimStripeSandboxKeys (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { token: "x" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/integrations/stripe/sandbox/keys/claim") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(401) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.claimStripeSandboxKeys({ + token: "x", + }); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("claimStripeSandboxKeys (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { token: "x" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/integrations/stripe/sandbox/keys/claim") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(403) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.claimStripeSandboxKeys({ + token: "x", + }); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("claimStripeSandboxKeys (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { token: "x" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/integrations/stripe/sandbox/keys/claim") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(404) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.claimStripeSandboxKeys({ + token: "x", + }); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("claimStripeSandboxKeys (6)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { token: "x" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/integrations/stripe/sandbox/keys/claim") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(500) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.claimStripeSandboxKeys({ + token: "x", + }); + }).rejects.toThrow(Schematic.InternalServerError); + }); + test("assumeStripeInstalled (1)", async () => { const server = mockServerPool.createServer(); const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); @@ -1169,6 +1530,306 @@ describe("IntegrationsapiClient", () => { }).rejects.toThrow(Schematic.InternalServerError); }); + test("installStripeClaimableSandbox (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { email: "email" }; + const rawResponseBody = { + data: { + api_keys: { mcp: "mcp", publishable: "publishable", secret: "secret" }, + claim_url: "claim_url", + claim_url_expires_at: "2024-01-15T09:30:00Z", + expires_at: "2024-01-15T09:30:00Z", + install: { + capabilities: { author_plans: true, checkout: true, edit_billing: true }, + config: { + created_at: "2024-01-15T09:30:00Z", + id: "id", + integration_id: "integration_id", + is_app_install: true, + is_connect_install: true, + live_mode: true, + updated_at: "2024-01-15T09:30:00Z", + }, + integration: { + created_at: "2024-01-15T09:30:00Z", + id: "id", + state: "active", + type: "clerk", + updated_at: "2024-01-15T09:30:00Z", + }, + }, + sandbox_id: "sandbox_id", + stripe_account_id: "stripe_account_id", + }, + params: { key: "value" }, + }; + + server + .mockEndpoint() + .post("/integrations/stripe/v2/sandbox") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.integrationsapi.installStripeClaimableSandbox({ + email: "email", + }); + expect(response).toEqual({ + data: { + apiKeys: { + mcp: "mcp", + publishable: "publishable", + secret: "secret", + }, + claimUrl: "claim_url", + claimUrlExpiresAt: new Date("2024-01-15T09:30:00.000Z"), + expiresAt: new Date("2024-01-15T09:30:00.000Z"), + install: { + capabilities: { + authorPlans: true, + checkout: true, + editBilling: true, + }, + config: { + createdAt: new Date("2024-01-15T09:30:00.000Z"), + id: "id", + integrationId: "integration_id", + isAppInstall: true, + isConnectInstall: true, + liveMode: true, + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + integration: { + createdAt: new Date("2024-01-15T09:30:00.000Z"), + id: "id", + state: "active", + type: "clerk", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + }, + sandboxId: "sandbox_id", + stripeAccountId: "stripe_account_id", + }, + params: { + key: "value", + }, + }); + }); + + test("installStripeClaimableSandbox (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { email: "email" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/integrations/stripe/v2/sandbox") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(400) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.installStripeClaimableSandbox({ + email: "email", + }); + }).rejects.toThrow(Schematic.BadRequestError); + }); + + test("installStripeClaimableSandbox (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { email: "email" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/integrations/stripe/v2/sandbox") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(401) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.installStripeClaimableSandbox({ + email: "email", + }); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("installStripeClaimableSandbox (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { email: "email" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/integrations/stripe/v2/sandbox") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(403) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.installStripeClaimableSandbox({ + email: "email", + }); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("installStripeClaimableSandbox (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { email: "email" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/integrations/stripe/v2/sandbox") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(404) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.installStripeClaimableSandbox({ + email: "email", + }); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("installStripeClaimableSandbox (6)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + const rawRequestBody = { email: "email" }; + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .post("/integrations/stripe/v2/sandbox") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(500) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.installStripeClaimableSandbox({ + email: "email", + }); + }).rejects.toThrow(Schematic.InternalServerError); + }); + + test("listStripeSandboxCountries (1)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { data: { countries: ["countries"] }, params: { key: "value" } }; + + server + .mockEndpoint() + .get("/integrations/stripe/v2/sandbox-countries") + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.integrationsapi.listStripeSandboxCountries(); + expect(response).toEqual({ + data: { + countries: ["countries"], + }, + params: { + key: "value", + }, + }); + }); + + test("listStripeSandboxCountries (2)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/integrations/stripe/v2/sandbox-countries") + .respondWith() + .statusCode(401) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.listStripeSandboxCountries(); + }).rejects.toThrow(Schematic.UnauthorizedError); + }); + + test("listStripeSandboxCountries (3)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/integrations/stripe/v2/sandbox-countries") + .respondWith() + .statusCode(403) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.listStripeSandboxCountries(); + }).rejects.toThrow(Schematic.ForbiddenError); + }); + + test("listStripeSandboxCountries (4)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/integrations/stripe/v2/sandbox-countries") + .respondWith() + .statusCode(404) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.listStripeSandboxCountries(); + }).rejects.toThrow(Schematic.NotFoundError); + }); + + test("listStripeSandboxCountries (5)", async () => { + const server = mockServerPool.createServer(); + const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); + + const rawResponseBody = { error: "error" }; + + server + .mockEndpoint() + .get("/integrations/stripe/v2/sandbox-countries") + .respondWith() + .statusCode(500) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.integrationsapi.listStripeSandboxCountries(); + }).rejects.toThrow(Schematic.InternalServerError); + }); + test("uninstallIntegration (1)", async () => { const server = mockServerPool.createServer(); const client = new SchematicClient({ maxRetries: 0, apiKey: "test", environment: server.baseUrl }); diff --git a/tests/wire/plans.test.ts b/tests/wire/plans.test.ts index e654e745..feca3e4a 100644 --- a/tests/wire/plans.test.ts +++ b/tests/wire/plans.test.ts @@ -37,6 +37,35 @@ describe("PlansClient", () => { }, ], billing_credit_balances: { key: 1.1 }, + billing_profile: { + account_id: "account_id", + billing_customer_id: "billing_customer_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + days_until_due: 1000000, + environment_id: "environment_id", + id: "id", + is_default: true, + name: "name", + payment_method_id: "payment_method_id", + proration_behavior: "create_prorations", + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { application_id: "application_id", cancel_at: 1000000, @@ -396,6 +425,35 @@ describe("PlansClient", () => { billingCreditBalances: { key: 1.1, }, + billingProfile: { + accountId: "account_id", + billingCustomerId: "billing_customer_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + daysUntilDue: 1000000, + environmentId: "environment_id", + id: "id", + isDefault: true, + name: "name", + paymentMethodId: "payment_method_id", + prorationBehavior: "create_prorations", + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { applicationId: "application_id", cancelAt: 1000000, @@ -5835,6 +5893,30 @@ describe("PlansClient", () => { }, ], billing_credit_balances: { key: 1.1 }, + billing_profile: { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + billing_profiles: [ + { + account_id: "account_id", + collection_method: "charge_automatically", + company_id: "company_id", + created_at: "2024-01-15T09:30:00Z", + environment_id: "environment_id", + id: "id", + is_default: true, + provider_type: "metronome", + updated_at: "2024-01-15T09:30:00Z", + }, + ], billing_subscription: { cancel_at_period_end: true, created_at: "2024-01-15T09:30:00Z", @@ -6142,6 +6224,30 @@ describe("PlansClient", () => { billingCreditBalances: { key: 1.1, }, + billingProfile: { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + billingProfiles: [ + { + accountId: "account_id", + collectionMethod: "charge_automatically", + companyId: "company_id", + createdAt: new Date("2024-01-15T09:30:00.000Z"), + environmentId: "environment_id", + id: "id", + isDefault: true, + providerType: "metronome", + updatedAt: new Date("2024-01-15T09:30:00.000Z"), + }, + ], billingSubscription: { cancelAtPeriodEnd: true, createdAt: new Date("2024-01-15T09:30:00.000Z"), diff --git a/yarn.lock b/yarn.lock index e80853df..182558b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1182,9 +1182,9 @@ form-data "^4.0.4" "@types/node@*": - version "26.4.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-26.4.0.tgz#4c4ca071c42241fe602741d02999f16b4e64c468" - integrity sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ== + version "26.4.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-26.4.1.tgz#3d8dc80515894958448ee266cf5d6bc3e5205bd5" + integrity sha512-k97ENvZWtvA6yqz5/FS6a7duDgOPEeOQOc2iKS/nY6mX6qJUKtLnWzQS+Xj6tXweyj6ZcTAK2Qecetnvi9nCLA== dependencies: undici-types "~8.3.0" @@ -1547,10 +1547,10 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -baseline-browser-mapping@^2.11.12: - version "2.11.20" - resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz#26078c7a4b08299656ea7ddceaebec955dc44303" - integrity sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw== +baseline-browser-mapping@^2.11.20: + version "2.11.21" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.11.21.tgz#99af73cb8e54007e4f5345e132278e26c2662f2c" + integrity sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ== brace-expansion@^1.1.7: version "1.1.18" @@ -1568,15 +1568,15 @@ braces@^3.0.3: fill-range "^7.1.1" browserslist@^4.24.0, browserslist@^4.28.1: - version "4.28.8" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.8.tgz#a3c79ceb70028527e5da7dafc887f3200b5168c0" - integrity sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA== + version "4.28.9" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.9.tgz#07ce6b449b90af880eb9bfb7cd39372cc4f71c8c" + integrity sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg== dependencies: - baseline-browser-mapping "^2.11.12" - caniuse-lite "^1.0.30001809" - electron-to-chromium "^1.5.402" - node-releases "^2.0.53" - update-browserslist-db "^1.3.0" + baseline-browser-mapping "^2.11.20" + caniuse-lite "^1.0.30001810" + electron-to-chromium "^1.5.420" + node-releases "^2.0.54" + update-browserslist-db "^1.3.2" bs-logger@^0.2.6: version "0.2.6" @@ -1628,7 +1628,7 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001809: +caniuse-lite@^1.0.30001810: version "1.0.30001810" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz#4970b477dea3278374de9bc43aa8f5d39fc3cda2" integrity sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg== @@ -1840,10 +1840,10 @@ dunder-proto@^1.0.1: es-errors "^1.3.0" gopd "^1.2.0" -electron-to-chromium@^1.5.402: - version "1.5.417" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.417.tgz#5c2feb4670edfadf88c86c51886675802f584975" - integrity sha512-4T+DTDWuMPM4aHlHwWdAVCVWwp7LDilnhzkj+c/Lbj91XSQrLuOmZSLtS9Q4iIqjlPUbPOnC624zDVVHCHaolQ== +electron-to-chromium@^1.5.420: + version "1.5.422" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.422.tgz#e27fb1ca0e6bef612a647022e1469701fea9ee1f" + integrity sha512-UvA/32XqrLDdZSn7Jllo1AYNcWji/G0d5M0GTViE7KoGBiMunw3a34Sb2KO4ZZyrSEhqsxFoVhWWJshdyfKqJA== emittery@^0.13.1: version "0.13.1" @@ -2032,9 +2032,9 @@ fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.1.0: integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fast-uri@^3.0.1: - version "3.1.6" - resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.6.tgz#bfdd308ef763f835fed059f3c6c925f708e33e3a" - integrity sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q== + version "3.1.7" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.7.tgz#743157d957f3cbb4c65310e033dc2ad4ad7dc60a" + integrity sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg== fb-watchman@^2.0.0: version "2.0.2" @@ -2947,9 +2947,9 @@ minimist@^1.2.5: integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== minimizer-webpack-plugin@^5.7.0: - version "5.8.0" - resolved "https://registry.yarnpkg.com/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.8.0.tgz#744f0e28da888aa1708e2be32b4ddcf2eeb09e58" - integrity sha512-2cT9+goJfBhtMz+gJqejSf09ClgmYhPhccRb/fb0ztVbixt0BkO8mRuI26FoPPuUNkRk6iEDryWAIouc5W8eJA== + version "5.9.0" + resolved "https://registry.yarnpkg.com/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.9.0.tgz#06c5ade7d028f3ff63321eab87f9c8c20bfa5ee8" + integrity sha512-OASqv+dewv8vjkOBjqMOHvxUaXhtGBLZAXq7JbmYE8TSzBvOswiGq5JcBdc8ypuLL/8YUT1OEyupga6/iqdyTA== dependencies: "@jridgewell/trace-mapping" "^0.3.31" jest-worker "^27.4.5" @@ -3013,7 +3013,7 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.53: +node-releases@^2.0.54: version "2.0.54" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.54.tgz#09af17d5647aa9f221ec5cf2becb95b68a981afe" integrity sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ== @@ -3636,17 +3636,17 @@ undici-types@~8.3.0: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-8.3.0.tgz#44e9fc9f3244648cdea35e4f9bb2d681e9410809" integrity sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ== -undici@7.28.0, undici@7.29.0: - version "7.29.0" - resolved "https://registry.yarnpkg.com/undici/-/undici-7.29.0.tgz#ae0f6f62e06e057a9cbb7b2b5fde2bb74f791b8f" - integrity sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw== +undici@7.28.0: + version "7.28.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-7.28.0.tgz#97d64564198b285bc281f0e8e29597e3d11fe7ec" + integrity sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA== universalify@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== -update-browserslist-db@^1.3.0: +update-browserslist-db@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz#9d99fbff56c50bb11ba5fd35cece5916da595836" integrity sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw== @@ -3708,9 +3708,9 @@ webpack-sources@^3.5.1: integrity sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw== webpack@^5.105.4: - version "5.110.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.110.2.tgz#ef23a0e62fe5e1ba71b033e3505b7f005d8d5c6e" - integrity sha512-TciLrfM7zgEjqGdY851HkirDsSPQgTFsWQpl9oHqMAMYsHhEC0bKjscvjpnz+pzx10hLC8qISApGrsnrCP4UtQ== + version "5.110.3" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.110.3.tgz#e122b66f6226b7af8f209b6102cd13238c4813a8" + integrity sha512-GuizBzRvo9YPpyoNMf3ag7AzxbaW85qrRSqTha345KyJbAFPt3/cMzBM0h+RWg7SK/7DdzRLINP3LvQ0hvr4hg== dependencies: "@types/estree" "^1.0.8" "@types/json-schema" "^7.0.15" From b83080140c6a303d1e67155d556a101cfb013dcf Mon Sep 17 00:00:00 2001 From: "fern-api[bot]" <115122769+fern-api[bot]@users.noreply.github.com> Date: Sat, 5 Sep 2026 06:37:36 +0000 Subject: [PATCH 2/2] [fern-replay] Applied customizations Patches applied (1): - patch-7a37bae5: chore(deps): resolve dependabot security alerts (#156) --- .fern/replay.lock | 78 +++++++++++++++++++++++++---------------------- package.json | 3 ++ yarn.lock | 8 ++--- 3 files changed, 49 insertions(+), 40 deletions(-) diff --git a/.fern/replay.lock b/.fern/replay.lock index 3264e8cb..8c837454 100644 --- a/.fern/replay.lock +++ b/.fern/replay.lock @@ -60,20 +60,26 @@ generations: cli_version: unknown generator_versions: fernapi/fern-typescript-node-sdk: 3.88.3 -current_generation: 1ddbfa34c9d81f17bce913c7f1633cc61befa9c8 + - commit_sha: a723439c1cfc640f590bb2140cf318040c7a3a4e + tree_hash: abc4284d81d318150972967e01fa5a0d99c8c207 + timestamp: 2026-09-05T06:37:33.288Z + cli_version: unknown + generator_versions: + fernapi/fern-typescript-node-sdk: 3.90.0 +current_generation: a723439c1cfc640f590bb2140cf318040c7a3a4e patches: - id: patch-7a37bae5 content_hash: sha256:d668134d32b63ddb680e8e6c5c499b6e6871061c050e7aad130e876c514bc8ef original_commit: 7a37bae547cd7e3acf4123558f38a67e8de1449b original_message: "chore(deps): resolve dependabot security alerts (#156)" original_author: Orbit - base_generation: 1ddbfa34c9d81f17bce913c7f1633cc61befa9c8 + base_generation: a723439c1cfc640f590bb2140cf318040c7a3a4e files: - package.json - yarn.lock patch_content: | diff --git a/package.json b/package.json - index e9dd4f5..84df190 100644 + index d779590..e6c1d02 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,9 @@ @@ -87,7 +93,7 @@ patches: "engines": { "node": ">=18.0.0" diff --git a/yarn.lock b/yarn.lock - index 88ec73a..e80853d 100644 + index 182558b..ec63c7c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3636,10 +3636,10 @@ undici-types@~8.3.0: @@ -109,7 +115,7 @@ patches: package.json: | { "name": "@schematichq/schematic-typescript-node", - "version": "1.5.11", + "version": "1.5.12", "private": false, "repository": { "type": "git", @@ -1369,9 +1375,9 @@ patches: form-data "^4.0.4" "@types/node@*": - version "26.4.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-26.4.0.tgz#4c4ca071c42241fe602741d02999f16b4e64c468" - integrity sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ== + version "26.4.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-26.4.1.tgz#3d8dc80515894958448ee266cf5d6bc3e5205bd5" + integrity sha512-k97ENvZWtvA6yqz5/FS6a7duDgOPEeOQOc2iKS/nY6mX6qJUKtLnWzQS+Xj6tXweyj6ZcTAK2Qecetnvi9nCLA== dependencies: undici-types "~8.3.0" @@ -1734,10 +1740,10 @@ patches: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - baseline-browser-mapping@^2.11.12: - version "2.11.20" - resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz#26078c7a4b08299656ea7ddceaebec955dc44303" - integrity sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw== + baseline-browser-mapping@^2.11.20: + version "2.11.21" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.11.21.tgz#99af73cb8e54007e4f5345e132278e26c2662f2c" + integrity sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ== brace-expansion@^1.1.7: version "1.1.18" @@ -1755,15 +1761,15 @@ patches: fill-range "^7.1.1" browserslist@^4.24.0, browserslist@^4.28.1: - version "4.28.8" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.8.tgz#a3c79ceb70028527e5da7dafc887f3200b5168c0" - integrity sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA== + version "4.28.9" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.9.tgz#07ce6b449b90af880eb9bfb7cd39372cc4f71c8c" + integrity sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg== dependencies: - baseline-browser-mapping "^2.11.12" - caniuse-lite "^1.0.30001809" - electron-to-chromium "^1.5.402" - node-releases "^2.0.53" - update-browserslist-db "^1.3.0" + baseline-browser-mapping "^2.11.20" + caniuse-lite "^1.0.30001810" + electron-to-chromium "^1.5.420" + node-releases "^2.0.54" + update-browserslist-db "^1.3.2" bs-logger@^0.2.6: version "0.2.6" @@ -1815,7 +1821,7 @@ patches: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - caniuse-lite@^1.0.30001809: + caniuse-lite@^1.0.30001810: version "1.0.30001810" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz#4970b477dea3278374de9bc43aa8f5d39fc3cda2" integrity sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg== @@ -2027,10 +2033,10 @@ patches: es-errors "^1.3.0" gopd "^1.2.0" - electron-to-chromium@^1.5.402: - version "1.5.417" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.417.tgz#5c2feb4670edfadf88c86c51886675802f584975" - integrity sha512-4T+DTDWuMPM4aHlHwWdAVCVWwp7LDilnhzkj+c/Lbj91XSQrLuOmZSLtS9Q4iIqjlPUbPOnC624zDVVHCHaolQ== + electron-to-chromium@^1.5.420: + version "1.5.422" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.422.tgz#e27fb1ca0e6bef612a647022e1469701fea9ee1f" + integrity sha512-UvA/32XqrLDdZSn7Jllo1AYNcWji/G0d5M0GTViE7KoGBiMunw3a34Sb2KO4ZZyrSEhqsxFoVhWWJshdyfKqJA== emittery@^0.13.1: version "0.13.1" @@ -2219,9 +2225,9 @@ patches: integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fast-uri@^3.0.1: - version "3.1.6" - resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.6.tgz#bfdd308ef763f835fed059f3c6c925f708e33e3a" - integrity sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q== + version "3.1.7" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.7.tgz#743157d957f3cbb4c65310e033dc2ad4ad7dc60a" + integrity sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg== fb-watchman@^2.0.0: version "2.0.2" @@ -3134,9 +3140,9 @@ patches: integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== minimizer-webpack-plugin@^5.7.0: - version "5.8.0" - resolved "https://registry.yarnpkg.com/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.8.0.tgz#744f0e28da888aa1708e2be32b4ddcf2eeb09e58" - integrity sha512-2cT9+goJfBhtMz+gJqejSf09ClgmYhPhccRb/fb0ztVbixt0BkO8mRuI26FoPPuUNkRk6iEDryWAIouc5W8eJA== + version "5.9.0" + resolved "https://registry.yarnpkg.com/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.9.0.tgz#06c5ade7d028f3ff63321eab87f9c8c20bfa5ee8" + integrity sha512-OASqv+dewv8vjkOBjqMOHvxUaXhtGBLZAXq7JbmYE8TSzBvOswiGq5JcBdc8ypuLL/8YUT1OEyupga6/iqdyTA== dependencies: "@jridgewell/trace-mapping" "^0.3.31" jest-worker "^27.4.5" @@ -3200,7 +3206,7 @@ patches: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== - node-releases@^2.0.53: + node-releases@^2.0.54: version "2.0.54" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.54.tgz#09af17d5647aa9f221ec5cf2becb95b68a981afe" integrity sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ== @@ -3833,7 +3839,7 @@ patches: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== - update-browserslist-db@^1.3.0: + update-browserslist-db@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz#9d99fbff56c50bb11ba5fd35cece5916da595836" integrity sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw== @@ -3895,9 +3901,9 @@ patches: integrity sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw== webpack@^5.105.4: - version "5.110.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.110.2.tgz#ef23a0e62fe5e1ba71b033e3505b7f005d8d5c6e" - integrity sha512-TciLrfM7zgEjqGdY851HkirDsSPQgTFsWQpl9oHqMAMYsHhEC0bKjscvjpnz+pzx10hLC8qISApGrsnrCP4UtQ== + version "5.110.3" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.110.3.tgz#e122b66f6226b7af8f209b6102cd13238c4813a8" + integrity sha512-GuizBzRvo9YPpyoNMf3ag7AzxbaW85qrRSqTha345KyJbAFPt3/cMzBM0h+RWg7SK/7DdzRLINP3LvQ0hvr4hg== dependencies: "@types/estree" "^1.0.8" "@types/json-schema" "^7.0.15" diff --git a/package.json b/package.json index d779590c..e6c1d02e 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,9 @@ "crypto": false, "timers": false }, + "resolutions": { + "undici": "7.29.0" + }, "packageManager": "yarn@1.22.22", "engines": { "node": ">=18.0.0" diff --git a/yarn.lock b/yarn.lock index 182558b7..ec63c7cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3636,10 +3636,10 @@ undici-types@~8.3.0: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-8.3.0.tgz#44e9fc9f3244648cdea35e4f9bb2d681e9410809" integrity sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ== -undici@7.28.0: - version "7.28.0" - resolved "https://registry.yarnpkg.com/undici/-/undici-7.28.0.tgz#97d64564198b285bc281f0e8e29597e3d11fe7ec" - integrity sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA== +undici@7.28.0, undici@7.29.0: + version "7.29.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-7.29.0.tgz#ae0f6f62e06e057a9cbb7b2b5fde2bb74f791b8f" + integrity sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw== universalify@^0.2.0: version "0.2.0"