resolved merge conflicts
5
.gitignore
vendored
@@ -16,6 +16,7 @@ supabase.sh
|
||||
**/dist/
|
||||
**/.next/
|
||||
**/.vercel/
|
||||
**/.turbo/
|
||||
**/.DS_Store
|
||||
**/.env*
|
||||
tests/
|
||||
@@ -141,4 +142,6 @@ TAKEHOME.md
|
||||
.agents/
|
||||
.mcp.json
|
||||
.opencode/skills/
|
||||
AGENTS.md
|
||||
AGENTS.md
|
||||
|
||||
server/.turbo
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
set -e
|
||||
|
||||
bun knip
|
||||
(cd server && bun ts)
|
||||
|
||||
changed_files="$(git diff --cached --name-only)"
|
||||
|
||||
bun knip
|
||||
|
||||
if printf '%s\n' "$changed_files" | grep -q '^server/'; then
|
||||
(cd server && bun test tests/unit)
|
||||
bunx turbo run ts --filter=@autumn/server
|
||||
fi
|
||||
|
||||
if printf '%s\n' "$changed_files" | grep -q '^vite/'; then
|
||||
(cd vite && bun test tests/)
|
||||
bunx turbo run ts --filter=@autumn/vite
|
||||
fi
|
||||
|
||||
22
.husky/pre-push
Normal file
@@ -0,0 +1,22 @@
|
||||
set -e
|
||||
|
||||
zero_sha="0000000000000000000000000000000000000000"
|
||||
changed_files="$(
|
||||
while read local_ref local_sha remote_ref remote_sha; do
|
||||
if [ "$local_sha" = "$zero_sha" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "$remote_sha" = "$zero_sha" ]; then
|
||||
base="$(git merge-base "$local_sha" origin/dev)"
|
||||
else
|
||||
base="$remote_sha"
|
||||
fi
|
||||
|
||||
git diff --name-only "$base" "$local_sha"
|
||||
done | sort -u
|
||||
)"
|
||||
|
||||
# if printf '%s\n' "$changed_files" | grep -q '^vite/'; then
|
||||
# bunx turbo run test:unit --filter=@autumn/vite
|
||||
# fi
|
||||
@@ -34,6 +34,22 @@
|
||||
"type": "remote",
|
||||
"url": "https://mcp.incident.io/mcp",
|
||||
"oauth": {}
|
||||
},
|
||||
"plain": {
|
||||
"type": "remote",
|
||||
"url": "https://mcp.plain.com/mcp",
|
||||
"oauth": {}
|
||||
},
|
||||
"autumn-internal": {
|
||||
"type": "local",
|
||||
"command": [
|
||||
"sh",
|
||||
"-c",
|
||||
"cd \"/Users/johnyeocx/Autumn/autumn-cloud\" && exec infisical run --env=prod --recursive -- bun run \"/Users/johnyeocx/Autumn/autumn-cloud/ai/src/mcp/index.ts\""
|
||||
],
|
||||
"env": {
|
||||
"AUTUMN_REPO_ROOT": "/Users/johnyeocx/Autumn"
|
||||
}
|
||||
}
|
||||
},
|
||||
"plugin": [
|
||||
|
||||
37
AGENTS.md
@@ -1,5 +1,42 @@
|
||||
<!-- Generated by ai-sync. Edit ai/rules/ instead. -->
|
||||
|
||||
# Autumn Shared Utils
|
||||
|
||||
Before writing inline `.filter()`, `.find()`, `.some()`, boolean predicate, or `<src>To<dst>` transform logic over Autumn objects (`Price`, `Entitlement`, `FullCusProduct`, `FullCustomer`, `Feature`, etc.), **check `autumn/shared/utils/` for an existing helper.** Reaching for `array.filter(... === id)` directly is almost always a sign the utility was missed.
|
||||
|
||||
The package is organized resource-first, pattern-second. Within each `<resource>Utils/` folder:
|
||||
|
||||
- `classify*/` — `is*` boolean predicates (`isPrepaidPrice`, `isCustomerProductPaidRecurring`)
|
||||
- `convert*/` — `<src>To<dst>` transforms (`cusProductToPrices`, `entToPrice`)
|
||||
- `find*/` — `Array.find` lookups (`findFeatureById`, `findPriceByFeatureId`)
|
||||
- `filter*/` — `Array.filter` collections (`filterCustomerProductsByFeatureId`)
|
||||
- `enrich*` files — augment with joined data (`enrichEntitlementWithFeature`)
|
||||
|
||||
**If the helper you need doesn't exist, ALWAYS ask the user before adding one.** Naming and folder placement are cross-cutting and non-trivial — wrong placement clutters `@autumn/shared` for every consumer.
|
||||
|
||||
Full convention (folder tree, naming nuances, anti-patterns): see the `shared-utils` skill.
|
||||
|
||||
# Installing External Skills
|
||||
|
||||
Third-party skills installed via `bunx skills add <pkg>` land under each agent's local skill dir (`.claude/skills/`, `.cursor/skills/`, etc.). Those locations are NOT a source of truth — `bun ai sync` only reads from `ai/config/skills/**` and prunes anything else it manages, so a raw `bunx skills add` will not propagate to the other consumer repos (autumn, cloud).
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Install via the CLI as usual:
|
||||
```sh
|
||||
bunx skills add <owner>/<repo>
|
||||
```
|
||||
2. Move the installed skill folder(s) into `ai/config/skills/external/<skill-name>/`. `external/` is core, so both `autumn` and `cloud` consume it. Use `cloud/external/` only if the skill references cloud-only code.
|
||||
3. Delete the leftover copies from `.claude/skills/`, `.cursor/skills/`, `.agents/skills/`, `.opencode/skills/` — `bun ai sync` will recreate them as symlinks.
|
||||
4. Run `bun ai sync` to symlink the skill into every agent dir across every repo that pulls the `ai/` submodule.
|
||||
|
||||
## Notes
|
||||
|
||||
- Skill folder names must be globally unique across `ai/config/skills/**` (sync flattens them).
|
||||
- Keep upstream `SKILL.md` frontmatter intact — `name` and `description` drive when the agent loads it. Only edit if the description is not specific enough about WHEN to use the skill.
|
||||
- If the skill ships a `references/` or `scripts/` subfolder, copy the whole directory tree, not just `SKILL.md`.
|
||||
- Re-running `bunx skills add` upstream-updates: install fresh, diff against `ai/config/skills/external/<name>/`, then promote the changes.
|
||||
|
||||
# Scope Cache Refresh Changes Safely
|
||||
|
||||
When changing cache-refresh behavior for API routes:
|
||||
|
||||
2
ai
@@ -8,7 +8,7 @@ import { DynamicResponseField } from "/components/dynamic-response-field.jsx";
|
||||
import { DynamicResponseExample } from "/components/dynamic-response-example.jsx";
|
||||
|
||||
<Note>
|
||||
The update endpoint modifies an existing subscription. Use this to change prepaid quantities, cancel subscriptions, or modify plan configuration. For subscribing to a new plan, use [attach](/api-reference/billing/billingAttach) instead.
|
||||
The update endpoint modifies an existing subscription. Use this to change prepaid quantities, cancel subscriptions, or modify plan configuration. For subscribing to a new plan, use [attach](/api-reference/billing/attach) instead.
|
||||
</Note>
|
||||
|
||||
### Common Use Cases
|
||||
|
||||
@@ -7,7 +7,7 @@ import { DynamicParamField } from "/components/dynamic-param-field.jsx";
|
||||
import { DynamicResponseField } from "/components/dynamic-response-field.jsx";
|
||||
import { DynamicResponseExample } from "/components/dynamic-response-example.jsx";
|
||||
|
||||
Creates a new plan with optional base price and feature configurations. See [How plans work](/documentation/pricing/plans) for concepts and [Adding features to plans](/documentation/pricing/plan-features) for item configuration.
|
||||
Creates a new plan with optional base price and feature configurations. See [How plans work](/documentation/concepts/plans) for concepts and [Adding features to plans](/documentation/concepts/plan-items) for item configuration.
|
||||
|
||||
### Plan Configuration
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { DynamicParamField } from "/components/dynamic-param-field.jsx";
|
||||
import { DynamicResponseField } from "/components/dynamic-response-field.jsx";
|
||||
import { DynamicResponseExample } from "/components/dynamic-response-example.jsx";
|
||||
|
||||
Updates an existing plan. By default, creates a new version of the plan. See [Adding features to plans](/documentation/pricing/plan-features) for item configuration.
|
||||
Updates an existing plan. By default, creates a new version of the plan. See [Adding features to plans](/documentation/concepts/plan-items) for item configuration.
|
||||
|
||||
<Note>
|
||||
Updates create a new plan version by default. Existing customers remain on their current version until their subscription renews or they explicitly upgrade.
|
||||
|
||||
@@ -382,6 +382,10 @@ This is useful for attaching custom metadata to the Stripe subscription created
|
||||
If true, skips any billing changes for the attach operation.
|
||||
</DynamicParamField>
|
||||
|
||||
<DynamicParamField body="enable_plan_immediately" type="boolean">
|
||||
If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form.
|
||||
</DynamicParamField>
|
||||
|
||||
|
||||
### Response
|
||||
|
||||
|
||||
@@ -255,6 +255,10 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one.
|
||||
</DynamicParamField>
|
||||
|
||||
<DynamicParamField body="enable_plan_immediately" type="boolean">
|
||||
If true, the cusProducts are activated immediately even when payment is pending via Stripe checkout.
|
||||
</DynamicParamField>
|
||||
|
||||
<DynamicParamField body="customer_data" type="object">
|
||||
Customer details to set when creating a customer
|
||||
<Expandable title="properties">
|
||||
|
||||
@@ -315,6 +315,10 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If true, skips any billing changes for the attach operation.
|
||||
</DynamicParamField>
|
||||
|
||||
<DynamicParamField body="enable_plan_immediately" type="boolean">
|
||||
If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form.
|
||||
</DynamicParamField>
|
||||
|
||||
|
||||
### Response
|
||||
|
||||
@@ -769,6 +773,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -1084,6 +1098,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -1149,6 +1173,32 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
The type of checkout that will be used if the customer is redirected to a checkout page.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="tax" type="object">
|
||||
Tax preview for the immediate charge. Contact us to enable the tax flag on your organisation. Shows only with flag enabled, a Stripe customer exists and has a location.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="total" type="number">
|
||||
Total tax amount in major currency units.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="amount_inclusive" type="number">
|
||||
Tax included in line item subtotals.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="amount_exclusive" type="number">
|
||||
Tax added on top of subtotals.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="currency" type="string">
|
||||
Three-letter currency code.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="status" type="'complete' | 'incomplete'">
|
||||
Calculation status ('complete' when Stripe Tax succeeds or 'incomplete' when Stripe Tax returned 0 or errored).
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
|
||||
<ResponseExample>
|
||||
```json 200
|
||||
|
||||
@@ -255,6 +255,10 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one.
|
||||
</DynamicParamField>
|
||||
|
||||
<DynamicParamField body="enable_plan_immediately" type="boolean">
|
||||
If true, the cusProducts are activated immediately even when payment is pending via Stripe checkout.
|
||||
</DynamicParamField>
|
||||
|
||||
<DynamicParamField body="customer_data" type="object">
|
||||
Customer details to set when creating a customer
|
||||
<Expandable title="properties">
|
||||
@@ -942,6 +946,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -1257,6 +1271,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -1322,6 +1346,32 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
The type of checkout that will be used if the customer is redirected to a checkout page.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="tax" type="object">
|
||||
Tax preview for the immediate charge. Contact us to enable the tax flag on your organisation. Shows only with flag enabled, a Stripe customer exists and has a location.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="total" type="number">
|
||||
Total tax amount in major currency units.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="amount_inclusive" type="number">
|
||||
Tax included in line item subtotals.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="amount_exclusive" type="number">
|
||||
Tax added on top of subtotals.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="currency" type="string">
|
||||
Three-letter currency code.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="status" type="'complete' | 'incomplete'">
|
||||
Calculation status ('complete' when Stripe Tax succeeds or 'incomplete' when Stripe Tax returned 0 or errored).
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
|
||||
<ResponseExample>
|
||||
```json 200
|
||||
|
||||
@@ -718,6 +718,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -1033,6 +1043,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
|
||||
@@ -285,6 +285,10 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If true, skips any billing changes for the attach operation.
|
||||
</DynamicParamField>
|
||||
|
||||
<DynamicParamField body="enable_plan_immediately" type="boolean">
|
||||
If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form.
|
||||
</DynamicParamField>
|
||||
|
||||
|
||||
### Response
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="purchase_limit" type="object">
|
||||
Optional rate limit to cap how often auto top-ups occur.
|
||||
Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="interval" type="'hour' | 'day' | 'week' | 'month'">
|
||||
The time interval for the purchase limit window.
|
||||
@@ -576,6 +576,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -909,6 +919,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
|
||||
@@ -104,7 +104,7 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="purchase_limit" type="object">
|
||||
Optional rate limit to cap how often auto top-ups occur.
|
||||
Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="interval" type="'hour' | 'day' | 'week' | 'month'">
|
||||
The time interval for the purchase limit window.
|
||||
@@ -447,6 +447,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -780,6 +790,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
|
||||
@@ -221,7 +221,7 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="purchase_limit" type="object">
|
||||
Optional rate limit to cap how often auto top-ups occur.
|
||||
Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="interval" type="'hour' | 'day' | 'week' | 'month'">
|
||||
The time interval for the purchase limit window.
|
||||
@@ -564,6 +564,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -897,6 +907,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
|
||||
@@ -529,6 +529,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -861,6 +871,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
|
||||
@@ -301,6 +301,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -633,6 +643,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
|
||||
@@ -365,6 +365,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -697,6 +707,16 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
|
||||
@@ -312,6 +312,16 @@ await autumn.plans.create({
|
||||
</Expandable>
|
||||
</DynamicParamField>
|
||||
|
||||
<DynamicParamField body="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicParamField body="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicParamField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicParamField>
|
||||
|
||||
|
||||
### Response
|
||||
|
||||
@@ -563,6 +573,16 @@ await autumn.plans.create({
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -647,7 +667,10 @@ await autumn.plans.create({
|
||||
"createdAt": 1771513979217,
|
||||
"env": "sandbox",
|
||||
"archived": false,
|
||||
"baseVariantId": null
|
||||
"baseVariantId": null,
|
||||
"config": {
|
||||
"ignore_past_due": false
|
||||
}
|
||||
}
|
||||
```
|
||||
</ResponseExample>
|
||||
|
||||
@@ -289,6 +289,16 @@ const plan = await autumn.plans.get({
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -373,7 +383,10 @@ const plan = await autumn.plans.get({
|
||||
"createdAt": 1771513979217,
|
||||
"env": "sandbox",
|
||||
"archived": false,
|
||||
"baseVariantId": null
|
||||
"baseVariantId": null,
|
||||
"config": {
|
||||
"ignore_past_due": false
|
||||
}
|
||||
}
|
||||
```
|
||||
</ResponseExample>
|
||||
|
||||
@@ -306,6 +306,16 @@ const plans = await autumn.plans.list({
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -395,7 +405,10 @@ const plans = await autumn.plans.list({
|
||||
"createdAt": 1771513979217,
|
||||
"env": "sandbox",
|
||||
"archived": false,
|
||||
"baseVariantId": null
|
||||
"baseVariantId": null,
|
||||
"config": {
|
||||
"ignore_past_due": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -239,6 +239,16 @@ await autumn.plans.update({
|
||||
</Expandable>
|
||||
</DynamicParamField>
|
||||
|
||||
<DynamicParamField body="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicParamField body="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicParamField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicParamField>
|
||||
|
||||
<DynamicParamField body="version" type="number" />
|
||||
|
||||
<DynamicParamField body="archived" type="boolean" />
|
||||
@@ -498,6 +508,16 @@ await autumn.plans.update({
|
||||
If this is a variant, the ID of the base plan it was created from.
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="config" type="object">
|
||||
Miscellaneous plan-level configuration flags.
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="ignore_past_due" type="boolean">
|
||||
If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state.
|
||||
</DynamicResponseField>
|
||||
|
||||
</Expandable>
|
||||
</DynamicResponseField>
|
||||
|
||||
<DynamicResponseField name="customer_eligibility" type="object">
|
||||
<Expandable title="properties">
|
||||
<DynamicResponseField name="trial_available" type="boolean">
|
||||
@@ -582,7 +602,10 @@ await autumn.plans.update({
|
||||
"createdAt": 1771513979217,
|
||||
"env": "sandbox",
|
||||
"archived": false,
|
||||
"baseVariantId": null
|
||||
"baseVariantId": null,
|
||||
"config": {
|
||||
"ignore_past_due": false
|
||||
}
|
||||
}
|
||||
```
|
||||
</ResponseExample>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
title: "Auto Top-Up Succeeded"
|
||||
openapi: "api/openapi.yml webhook billing.auto_topup_succeeded"
|
||||
---
|
||||
|
||||
### Payload Fields
|
||||
|
||||
<ParamField body="customer_id" type="string" required>
|
||||
The ID of the customer whose balance was topped up.
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="feature_id" type="string" required>
|
||||
The feature ID that was automatically topped up.
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="quantity_granted" type="number" required>
|
||||
The normalized amount of balance granted by the top-up.
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="threshold" type="number" required>
|
||||
The configured balance threshold that triggered the top-up.
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="balance_after" type="number" required>
|
||||
The customer's remaining balance for the feature after the top-up.
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="invoice_mode" type="boolean" required>
|
||||
Whether the auto top-up created a `send_invoice` invoice instead of auto-charging the saved payment method.
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="invoice" type="object" required>
|
||||
The invoice created for the auto top-up.
|
||||
<Expandable title="properties">
|
||||
<ParamField body="stripe_id" type="string" required>
|
||||
The Stripe invoice ID. Use this as a stable dedupe key.
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="status" type="string">
|
||||
The status of the invoice. `"paid"` for auto-charged top-ups; `"open"` for `invoice_mode` top-ups where credits were granted but the invoice has not yet been paid.
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="total" type="number" required>
|
||||
The total amount of the invoice in the smallest currency unit (e.g. cents for USD), matching Stripe's `invoice.total`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="currency" type="string" required>
|
||||
The ISO currency code for the invoice.
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="hosted_invoice_url" type="string">
|
||||
URL to the hosted invoice page, if available.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
@@ -130,6 +130,7 @@
|
||||
"group": "Additional Resources",
|
||||
"pages": [
|
||||
"documentation/webhooks",
|
||||
"documentation/slack-discord-notifications",
|
||||
"documentation/fail-open",
|
||||
"documentation/rate-limits",
|
||||
"documentation/external-providers/convex",
|
||||
@@ -271,6 +272,12 @@
|
||||
"api-reference/webhooks/balancesLimitReached"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Billing",
|
||||
"pages": [
|
||||
"api-reference/webhooks/billingAutoTopupSucceeded"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Vercel",
|
||||
"pages": [
|
||||
|
||||
@@ -170,4 +170,8 @@ This limits the customer to 5 auto top-ups per month. Supported intervals: `hour
|
||||
|
||||
<Note>
|
||||
Auto top-ups use burst suppression to prevent duplicate purchases when multiple track events happen in quick succession. There's a 30-second cooldown between top-ups for the same feature.
|
||||
</Note>
|
||||
</Note>
|
||||
|
||||
## Notifications
|
||||
|
||||
Subscribe to the [`billing.auto_topup_succeeded`](/api-reference/webhooks/billingAutoTopupSucceeded) webhook to be notified when a top-up grants credits. The payload includes the granted quantity, the new balance, and the underlying invoice — useful for sending receipts, updating internal ledgers, or reconciling balance after a recharge.
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
title: "Slack and Discord Notifications"
|
||||
description: "Send Autumn webhook events to Slack or Discord channels with rich, formatted messages using Svix transformations."
|
||||
---
|
||||
|
||||
import SlackTransform from "/snippets/svix-transforms/slack.mdx";
|
||||
import DiscordTransform from "/snippets/svix-transforms/discord.mdx";
|
||||
|
||||
Forward Autumn webhook events to a Slack or Discord channel with ready-made
|
||||
[Svix transformations](https://docs.svix.com/transformations) that turn each
|
||||
event into a clean, formatted message.
|
||||
|
||||
## Supported events
|
||||
|
||||
| Event | Slack | Discord |
|
||||
| --- | :---: | :---: |
|
||||
| `customer.products.updated` | ✓ | ✓ |
|
||||
| `balances.limit_reached` | ✓ | ✓ |
|
||||
| `balances.usage_alert_triggered` | ✓ | ✓ |
|
||||
|
||||
Other event types — including Vercel Marketplace events — are skipped by the
|
||||
transforms so they are never delivered to your Slack or Discord channel.
|
||||
|
||||
## Setup
|
||||
|
||||
<Steps>
|
||||
<Step title="Get an incoming webhook URL">
|
||||
Follow the official guide for the platform you want to use:
|
||||
|
||||
- [Slack — Sending messages using incoming webhooks](https://docs.slack.dev/messaging/sending-messages-using-incoming-webhooks/)
|
||||
- [Discord — Intro to webhooks](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks)
|
||||
|
||||
Both flows give you a webhook URL that looks like
|
||||
`https://hooks.slack.com/services/...` or
|
||||
`https://discord.com/api/webhooks/...`. Keep it handy for the next step.
|
||||
</Step>
|
||||
|
||||
<Step title="Add the webhook endpoint in Autumn">
|
||||
In your Autumn dashboard, go to **Developer → Webhooks** and click
|
||||
**Add Endpoint**. Paste in the URL from the previous step and select the
|
||||
events you want to subscribe to.
|
||||
|
||||
<Frame>
|
||||
<img src="/images/svix-notifications/01-add-endpoint.png" alt="Adding a webhook endpoint in the Autumn dashboard" />
|
||||
</Frame>
|
||||
</Step>
|
||||
|
||||
<Step title="Enable transformations">
|
||||
Open the endpoint you just created, switch to the **Advanced** tab, and
|
||||
click **Edit transformation**.
|
||||
|
||||
<Frame>
|
||||
<img src="/images/svix-notifications/02-advanced-tab.png" alt="The Advanced tab on a webhook endpoint, showing the Edit transformation button" />
|
||||
</Frame>
|
||||
|
||||
Paste in the transform code below for the platform you're targeting,
|
||||
then click **Save and Enable**.
|
||||
|
||||
<Frame>
|
||||
<img src="/images/svix-notifications/03-transformation-editor.png" alt="The transformation editor with the Enabled toggle, code area, and Save and Enable button highlighted" />
|
||||
</Frame>
|
||||
</Step>
|
||||
|
||||
<Step title="Enable throttling">
|
||||
Back on the **Advanced** tab, click **Edit** next to **Endpoint Throttling**
|
||||
and set a sensible RPS (requests-per-second) limit. This prevents your
|
||||
Slack or Discord channel from being flooded during high-volume events such
|
||||
as bulk customer migrations or backfills.
|
||||
|
||||
<Frame>
|
||||
<img src="/images/svix-notifications/04-throttling.png" alt="Endpoint throttling editor with an RPS input field" />
|
||||
</Frame>
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Transform code
|
||||
|
||||
Copy the transform for your platform into the **Code** editor on the
|
||||
transformation page, then click **Save and Enable**.
|
||||
|
||||
<CodeGroup>
|
||||
<SlackTransform />
|
||||
<DiscordTransform />
|
||||
</CodeGroup>
|
||||
@@ -97,6 +97,64 @@ For entity-scoped usage, the payload will also include an `entity_id`:
|
||||
}
|
||||
```
|
||||
|
||||
### billing.auto_topup_succeeded
|
||||
|
||||
Fired when an [auto top-up](/documentation/modelling-pricing/auto-top-ups) successfully grants additional prepaid balance. Useful for sending receipts, updating internal ledgers, or reconciling balance after a recharge.
|
||||
|
||||
For auto-charged top-ups, the event fires only after the Stripe invoice is `paid`. For `invoice_mode` top-ups, the event fires once credits are granted and the invoice is finalized — `invoice.status` will typically be `"open"` until the customer pays.
|
||||
|
||||
Use `invoice.stripe_id` as a stable dedupe key. The top-level `id` field (e.g. `evt_auto_topup_...`) is a unique identifier for the event itself.
|
||||
|
||||
**Example payload (auto-charge):**
|
||||
|
||||
```json expandable
|
||||
{
|
||||
"type": "billing.auto_topup_succeeded",
|
||||
"id": "evt_auto_topup_2abc123",
|
||||
"occurred_at": 1761840000000,
|
||||
"data": {
|
||||
"customer_id": "user_123",
|
||||
"feature_id": "credits",
|
||||
"quantity_granted": 1000,
|
||||
"threshold": 500,
|
||||
"balance_after": 1450,
|
||||
"invoice_mode": false,
|
||||
"invoice": {
|
||||
"stripe_id": "in_1A2B3C4D5E6F",
|
||||
"status": "paid",
|
||||
"total": 1000,
|
||||
"currency": "usd",
|
||||
"hosted_invoice_url": "https://invoice.stripe.com/i/..."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Example payload (invoice mode):**
|
||||
|
||||
```json expandable
|
||||
{
|
||||
"type": "billing.auto_topup_succeeded",
|
||||
"id": "evt_auto_topup_3xyz456",
|
||||
"occurred_at": 1761840000000,
|
||||
"data": {
|
||||
"customer_id": "user_123",
|
||||
"feature_id": "credits",
|
||||
"quantity_granted": 1000,
|
||||
"threshold": 500,
|
||||
"balance_after": 1450,
|
||||
"invoice_mode": true,
|
||||
"invoice": {
|
||||
"stripe_id": "in_2G3H4I5J6K7L",
|
||||
"status": "open",
|
||||
"total": 1000,
|
||||
"currency": "usd",
|
||||
"hosted_invoice_url": "https://invoice.stripe.com/i/..."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### balances.usage_alert_triggered
|
||||
|
||||
Fired when a customer crosses a configured usage alert threshold. Usage alerts let you monitor when customers approach or exceed specific usage levels for a feature.
|
||||
|
||||
BIN
apps/docs/mintlify/images/svix-notifications/01-add-endpoint.png
Normal file
|
After Width: | Height: | Size: 253 KiB |
BIN
apps/docs/mintlify/images/svix-notifications/02-advanced-tab.png
Normal file
|
After Width: | Height: | Size: 279 KiB |
|
After Width: | Height: | Size: 91 KiB |
BIN
apps/docs/mintlify/images/svix-notifications/04-throttling.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
248
apps/docs/mintlify/snippets/svix-transforms/discord.mdx
Normal file
@@ -0,0 +1,248 @@
|
||||
{/* AUTO-GENERATED by syncSvixTransforms in packages/openapi/utils/mintlifyTransform/index.ts */}
|
||||
{/* Source: others/svix-transforms/discord.ts */}
|
||||
{/* Edit the source file, not this snippet. */}
|
||||
|
||||
```js Discord
|
||||
/**
|
||||
* @param webhook the webhook object
|
||||
* @param webhook.method destination method. Allowed values: "POST", "PUT"
|
||||
* @param webhook.url current destination address
|
||||
* @param webhook.eventType current webhook Event Type
|
||||
* @param webhook.payload JSON payload
|
||||
* @param webhook.cancel whether to cancel dispatch of the given webhook
|
||||
*/
|
||||
function handler(webhook) {
|
||||
var AUTUMN_BASE = "https://app.useautumn.com/customers/";
|
||||
var AUTUMN_USERNAME = "Autumn";
|
||||
var AUTUMN_AVATAR_URL = "https://i.ibb.co/BHCF1ZqL/autumnicon.png";
|
||||
|
||||
// Discord embed colors (decimal RGB).
|
||||
var COLOR_SUCCESS = 0x22c55e;
|
||||
var COLOR_INFO = 0x3b82f6;
|
||||
var COLOR_WARNING = 0xf59e0b;
|
||||
var COLOR_DANGER = 0xef4444;
|
||||
var COLOR_NEUTRAL = 0x6b7280;
|
||||
|
||||
var payload = webhook.payload || {};
|
||||
var data = payload.data || payload;
|
||||
|
||||
// ============ customer.products.updated ============
|
||||
if (webhook.eventType === "customer.products.updated") {
|
||||
var scenario = data.scenario || "updated";
|
||||
var customer = data.customer || {};
|
||||
var entity = data.entity || null;
|
||||
var product = data.updated_product || {};
|
||||
|
||||
var customerName = customer.name || customer.email || customer.id || "Customer";
|
||||
var customerEmail = customer.email || null;
|
||||
var customerId = customer.id || "";
|
||||
|
||||
var productName = product.name || "their plan";
|
||||
if (product.version && product.version !== 1) {
|
||||
productName = productName + " V" + product.version;
|
||||
}
|
||||
|
||||
var entityLabel = null;
|
||||
if (entity) {
|
||||
entityLabel = entity.name || entity.id || null;
|
||||
}
|
||||
|
||||
var emoji = "🔔";
|
||||
var header = "Subscription Updated";
|
||||
var verb = "updated";
|
||||
var color = COLOR_NEUTRAL;
|
||||
|
||||
if (scenario === "new") {
|
||||
emoji = "🎉"; header = "New Subscription"; verb = "subscribed to"; color = COLOR_SUCCESS;
|
||||
} else if (scenario === "upgrade") {
|
||||
emoji = "🚀"; header = "Customer Upgraded"; verb = "upgraded to"; color = COLOR_SUCCESS;
|
||||
} else if (scenario === "downgrade") {
|
||||
emoji = "📉"; header = "Customer Downgraded"; verb = "downgraded to"; color = COLOR_WARNING;
|
||||
} else if (scenario === "cancel") {
|
||||
emoji = "⚠️"; header = "Subscription Cancelled"; verb = "cancelled"; color = COLOR_WARNING;
|
||||
} else if (scenario === "renew") {
|
||||
emoji = "🔄"; header = "Subscription Uncancelled"; verb = "uncancelled"; color = COLOR_SUCCESS;
|
||||
} else if (scenario === "expired") {
|
||||
emoji = "💀"; header = "Subscription Expired"; verb = "expired on"; color = COLOR_DANGER;
|
||||
} else if (scenario === "scheduled") {
|
||||
emoji = "📅"; header = "Change Scheduled"; verb = "scheduled a change to"; color = COLOR_INFO;
|
||||
}
|
||||
|
||||
var sentence;
|
||||
if (scenario === "expired") {
|
||||
sentence = "**" + customerName + "**'s **" + productName + "** expired";
|
||||
} else {
|
||||
sentence = "**" + customerName + "** " + verb + " **" + productName + "**";
|
||||
}
|
||||
|
||||
var description = sentence;
|
||||
if (customerId) {
|
||||
description += "\n\n[View in Autumn](" + AUTUMN_BASE + customerId + ")";
|
||||
}
|
||||
|
||||
var fields = [
|
||||
{ name: "Customer", value: customerName, inline: true }
|
||||
];
|
||||
if (customerEmail) {
|
||||
fields.push({ name: "Email", value: customerEmail, inline: true });
|
||||
}
|
||||
fields.push({ name: "Product", value: productName, inline: true });
|
||||
fields.push({ name: "Scenario", value: "`" + scenario + "`", inline: true });
|
||||
if (entityLabel) {
|
||||
fields.push({ name: "Entity", value: entityLabel, inline: true });
|
||||
}
|
||||
|
||||
var embed = {
|
||||
title: emoji + " " + header,
|
||||
description: description,
|
||||
color: color,
|
||||
fields: fields
|
||||
};
|
||||
if (customerId) {
|
||||
embed.url = AUTUMN_BASE + customerId;
|
||||
}
|
||||
var footerParts = [];
|
||||
if (customerId) footerParts.push("Customer ID: " + customerId);
|
||||
if (entity && entity.id) footerParts.push("Entity: " + entity.id);
|
||||
if (footerParts.length > 0) {
|
||||
embed.footer = { text: footerParts.join(" | ") };
|
||||
}
|
||||
|
||||
webhook.payload = {
|
||||
username: AUTUMN_USERNAME,
|
||||
avatar_url: AUTUMN_AVATAR_URL,
|
||||
embeds: [embed]
|
||||
};
|
||||
return webhook;
|
||||
}
|
||||
|
||||
// ============ balances.limit_reached ============
|
||||
if (webhook.eventType === "balances.limit_reached") {
|
||||
var lrCustomerId = data.customer_id || "";
|
||||
var lrFeatureId = data.feature_id || "feature";
|
||||
var lrLimitType = data.limit_type || "included";
|
||||
var lrEntityId = data.entity_id || null;
|
||||
|
||||
var lrCustomerDisplay = lrCustomerId
|
||||
? "[`" + lrCustomerId + "`](" + AUTUMN_BASE + lrCustomerId + ")"
|
||||
: "`unknown`";
|
||||
|
||||
var lrDescription =
|
||||
lrCustomerDisplay + " hit their **" + lrFeatureId + "** `" + lrLimitType + "` limit";
|
||||
if (lrCustomerId) {
|
||||
lrDescription += "\n\n[View in Autumn](" + AUTUMN_BASE + lrCustomerId + ")";
|
||||
}
|
||||
|
||||
var lrFields = [
|
||||
{
|
||||
name: "Customer",
|
||||
value: lrCustomerId ? "`" + lrCustomerId + "`" : "—",
|
||||
inline: true
|
||||
},
|
||||
{ name: "Feature", value: "`" + lrFeatureId + "`", inline: true },
|
||||
{ name: "Limit Type", value: "`" + lrLimitType + "`", inline: true }
|
||||
];
|
||||
if (lrEntityId) {
|
||||
lrFields.push({ name: "Entity", value: "`" + lrEntityId + "`", inline: true });
|
||||
}
|
||||
|
||||
var lrEmbed = {
|
||||
title: "🚫 Limit Reached",
|
||||
description: lrDescription,
|
||||
color: COLOR_DANGER,
|
||||
fields: lrFields
|
||||
};
|
||||
if (lrCustomerId) {
|
||||
lrEmbed.url = AUTUMN_BASE + lrCustomerId;
|
||||
}
|
||||
var lrFooterParts = [];
|
||||
if (lrCustomerId) lrFooterParts.push("Customer ID: " + lrCustomerId);
|
||||
if (lrEntityId) lrFooterParts.push("Entity: " + lrEntityId);
|
||||
if (lrFooterParts.length > 0) {
|
||||
lrEmbed.footer = { text: lrFooterParts.join(" | ") };
|
||||
}
|
||||
|
||||
webhook.payload = {
|
||||
username: AUTUMN_USERNAME,
|
||||
avatar_url: AUTUMN_AVATAR_URL,
|
||||
embeds: [lrEmbed]
|
||||
};
|
||||
return webhook;
|
||||
}
|
||||
|
||||
// ============ balances.usage_alert_triggered ============
|
||||
if (webhook.eventType === "balances.usage_alert_triggered") {
|
||||
var uaCustomerId = data.customer_id || "";
|
||||
var uaFeatureId = data.feature_id || "feature";
|
||||
var uaEntityId = data.entity_id || null;
|
||||
var uaAlert = data.usage_alert || {};
|
||||
var uaAlertName = uaAlert.name || "Usage alert";
|
||||
var uaThreshold = uaAlert.threshold;
|
||||
var uaThresholdType = uaAlert.threshold_type || "usage";
|
||||
|
||||
var uaThresholdLabel = "—";
|
||||
if (uaThreshold !== undefined && uaThreshold !== null) {
|
||||
if (uaThresholdType === "usage_percentage") {
|
||||
uaThresholdLabel = uaThreshold + "% used";
|
||||
} else if (uaThresholdType === "remaining_percentage") {
|
||||
uaThresholdLabel = uaThreshold + "% remaining";
|
||||
} else if (uaThresholdType === "remaining") {
|
||||
uaThresholdLabel = uaThreshold + " remaining";
|
||||
} else {
|
||||
uaThresholdLabel = uaThreshold + " used";
|
||||
}
|
||||
}
|
||||
|
||||
var uaCustomerDisplay = uaCustomerId
|
||||
? "[`" + uaCustomerId + "`](" + AUTUMN_BASE + uaCustomerId + ")"
|
||||
: "`unknown`";
|
||||
|
||||
var uaDescription =
|
||||
uaCustomerDisplay + " crossed the **" + uaAlertName + "** threshold on **" + uaFeatureId + "**";
|
||||
if (uaCustomerId) {
|
||||
uaDescription += "\n\n[View in Autumn](" + AUTUMN_BASE + uaCustomerId + ")";
|
||||
}
|
||||
|
||||
var uaFields = [
|
||||
{
|
||||
name: "Customer",
|
||||
value: uaCustomerId ? "`" + uaCustomerId + "`" : "—",
|
||||
inline: true
|
||||
},
|
||||
{ name: "Feature", value: "`" + uaFeatureId + "`", inline: true },
|
||||
{ name: "Alert", value: uaAlertName, inline: true },
|
||||
{ name: "Threshold", value: uaThresholdLabel, inline: true }
|
||||
];
|
||||
if (uaEntityId) {
|
||||
uaFields.push({ name: "Entity", value: "`" + uaEntityId + "`", inline: true });
|
||||
}
|
||||
|
||||
var uaEmbed = {
|
||||
title: "📊 Usage Alert: " + uaAlertName,
|
||||
description: uaDescription,
|
||||
color: COLOR_WARNING,
|
||||
fields: uaFields
|
||||
};
|
||||
if (uaCustomerId) {
|
||||
uaEmbed.url = AUTUMN_BASE + uaCustomerId;
|
||||
}
|
||||
var uaFooterParts = [];
|
||||
if (uaCustomerId) uaFooterParts.push("Customer ID: " + uaCustomerId);
|
||||
if (uaEntityId) uaFooterParts.push("Entity: " + uaEntityId);
|
||||
if (uaFooterParts.length > 0) {
|
||||
uaEmbed.footer = { text: uaFooterParts.join(" | ") };
|
||||
}
|
||||
|
||||
webhook.payload = {
|
||||
username: AUTUMN_USERNAME,
|
||||
avatar_url: AUTUMN_AVATAR_URL,
|
||||
embeds: [uaEmbed]
|
||||
};
|
||||
return webhook;
|
||||
}
|
||||
|
||||
// Unmatched event type — cancel dispatch.
|
||||
webhook.cancel = true;
|
||||
return webhook;
|
||||
}
|
||||
```
|
||||
298
apps/docs/mintlify/snippets/svix-transforms/slack.mdx
Normal file
@@ -0,0 +1,298 @@
|
||||
{/* AUTO-GENERATED by syncSvixTransforms in packages/openapi/utils/mintlifyTransform/index.ts */}
|
||||
{/* Source: others/svix-transforms/slack.ts */}
|
||||
{/* Edit the source file, not this snippet. */}
|
||||
|
||||
```js Slack
|
||||
/**
|
||||
* @param webhook the webhook object
|
||||
* @param webhook.method destination method. Allowed values: "POST", "PUT"
|
||||
* @param webhook.url current destination address
|
||||
* @param webhook.eventType current webhook Event Type
|
||||
* @param webhook.payload JSON payload
|
||||
* @param webhook.cancel whether to cancel dispatch of the given webhook
|
||||
*/
|
||||
function handler(webhook) {
|
||||
var AUTUMN_BASE = "https://app.useautumn.com/customers/";
|
||||
var AUTUMN_USERNAME = "Autumn";
|
||||
var AUTUMN_ICON_URL = "https://i.ibb.co/BHCF1ZqL/autumnicon.png";
|
||||
|
||||
var payload = webhook.payload || {};
|
||||
var data = payload.data || payload;
|
||||
|
||||
// ============ customer.products.updated ============
|
||||
if (webhook.eventType === "customer.products.updated") {
|
||||
var scenario = data.scenario || "updated";
|
||||
var customer = data.customer || {};
|
||||
var entity = data.entity || null;
|
||||
var product = data.updated_product || {};
|
||||
|
||||
var customerName = customer.name || customer.email || customer.id || "Customer";
|
||||
var customerEmail = customer.email || null;
|
||||
var customerId = customer.id || "";
|
||||
|
||||
var productName = product.name || "their plan";
|
||||
if (product.version && product.version !== 1) {
|
||||
productName = productName + " V" + product.version;
|
||||
}
|
||||
|
||||
var entityLabel = null;
|
||||
if (entity) {
|
||||
entityLabel = entity.name || entity.id || null;
|
||||
}
|
||||
|
||||
var meta = {
|
||||
"new": { emoji: "🎉", header: "New Subscription", verb: "subscribed to" },
|
||||
"upgrade": { emoji: "🚀", header: "Customer Upgraded", verb: "upgraded to" },
|
||||
"downgrade": { emoji: "📉", header: "Customer Downgraded", verb: "downgraded to" },
|
||||
"cancel": { emoji: "⚠️", header: "Subscription Cancelled", verb: "cancelled" },
|
||||
"renew": { emoji: "🔄", header: "Subscription Uncancelled", verb: "uncancelled" },
|
||||
"expired": { emoji: "💀", header: "Subscription Expired", verb: "expired on" },
|
||||
"scheduled": { emoji: "📅", header: "Change Scheduled", verb: "scheduled a change to" }
|
||||
}[scenario] || { emoji: "🔔", header: "Subscription Updated", verb: "updated" };
|
||||
|
||||
var sentence;
|
||||
if (scenario === "expired") {
|
||||
sentence = "*" + customerName + "*'s *" + productName + "* expired";
|
||||
} else {
|
||||
sentence = "*" + customerName + "* " + meta.verb + " *" + productName + "*";
|
||||
}
|
||||
|
||||
var previewText = meta.emoji + " " + customerName + " " + meta.verb + " " + productName;
|
||||
|
||||
var fields = [
|
||||
{ type: "mrkdwn", text: "*Customer:*\n" + customerName }
|
||||
];
|
||||
if (customerEmail) {
|
||||
fields.push({ type: "mrkdwn", text: "*Email:*\n" + customerEmail });
|
||||
}
|
||||
fields.push({ type: "mrkdwn", text: "*Product:*\n" + productName });
|
||||
fields.push({ type: "mrkdwn", text: "*Scenario:*\n`" + scenario + "`" });
|
||||
if (entityLabel) {
|
||||
fields.push({ type: "mrkdwn", text: "*Entity:*\n" + entityLabel });
|
||||
}
|
||||
|
||||
var contextParts = [];
|
||||
if (customerId) {
|
||||
contextParts.push("Customer ID: `" + customerId + "`");
|
||||
}
|
||||
if (entity && entity.id) {
|
||||
contextParts.push("Entity: `" + entity.id + "`");
|
||||
}
|
||||
|
||||
var blocks = [
|
||||
{
|
||||
type: "header",
|
||||
text: { type: "plain_text", text: meta.emoji + " " + meta.header, emoji: true }
|
||||
},
|
||||
{
|
||||
type: "section",
|
||||
text: { type: "mrkdwn", text: sentence }
|
||||
},
|
||||
{
|
||||
type: "section",
|
||||
fields: fields
|
||||
}
|
||||
];
|
||||
|
||||
if (customerId) {
|
||||
blocks.push({
|
||||
type: "actions",
|
||||
elements: [
|
||||
{
|
||||
type: "button",
|
||||
text: { type: "plain_text", text: "View in Autumn", emoji: true },
|
||||
url: AUTUMN_BASE + customerId,
|
||||
style: "primary"
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
if (contextParts.length > 0) {
|
||||
blocks.push({
|
||||
type: "context",
|
||||
elements: [
|
||||
{ type: "mrkdwn", text: contextParts.join(" | ") }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
webhook.payload = {
|
||||
username: AUTUMN_USERNAME,
|
||||
icon_url: AUTUMN_ICON_URL,
|
||||
text: previewText,
|
||||
blocks: blocks
|
||||
};
|
||||
return webhook;
|
||||
}
|
||||
|
||||
// ============ balances.limit_reached ============
|
||||
if (webhook.eventType === "balances.limit_reached") {
|
||||
var lrCustomerId = data.customer_id || "";
|
||||
var lrFeatureId = data.feature_id || "feature";
|
||||
var lrLimitType = data.limit_type || "included";
|
||||
var lrEntityId = data.entity_id || null;
|
||||
|
||||
var lrCustomerLink = lrCustomerId
|
||||
? "<" + AUTUMN_BASE + lrCustomerId + "|`" + lrCustomerId + "`>"
|
||||
: "`unknown`";
|
||||
|
||||
var lrSentence =
|
||||
lrCustomerLink + " hit their *" + lrFeatureId + "* `" + lrLimitType + "` limit";
|
||||
|
||||
var lrPreview = "🚫 " + lrCustomerId + " hit their " + lrFeatureId + " limit";
|
||||
|
||||
var lrFields = [
|
||||
{ type: "mrkdwn", text: "*Customer:*\n" + lrCustomerLink },
|
||||
{ type: "mrkdwn", text: "*Feature:*\n`" + lrFeatureId + "`" },
|
||||
{ type: "mrkdwn", text: "*Limit Type:*\n`" + lrLimitType + "`" }
|
||||
];
|
||||
if (lrEntityId) {
|
||||
lrFields.push({ type: "mrkdwn", text: "*Entity:*\n`" + lrEntityId + "`" });
|
||||
}
|
||||
|
||||
var lrContextParts = [];
|
||||
if (lrCustomerId) lrContextParts.push("Customer ID: `" + lrCustomerId + "`");
|
||||
if (lrEntityId) lrContextParts.push("Entity: `" + lrEntityId + "`");
|
||||
|
||||
var lrBlocks = [
|
||||
{
|
||||
type: "header",
|
||||
text: { type: "plain_text", text: "🚫 Limit Reached", emoji: true }
|
||||
},
|
||||
{
|
||||
type: "section",
|
||||
text: { type: "mrkdwn", text: lrSentence }
|
||||
},
|
||||
{
|
||||
type: "section",
|
||||
fields: lrFields
|
||||
}
|
||||
];
|
||||
|
||||
if (lrCustomerId) {
|
||||
lrBlocks.push({
|
||||
type: "actions",
|
||||
elements: [
|
||||
{
|
||||
type: "button",
|
||||
text: { type: "plain_text", text: "View in Autumn", emoji: true },
|
||||
url: AUTUMN_BASE + lrCustomerId,
|
||||
style: "danger"
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
if (lrContextParts.length > 0) {
|
||||
lrBlocks.push({
|
||||
type: "context",
|
||||
elements: [
|
||||
{ type: "mrkdwn", text: lrContextParts.join(" | ") }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
webhook.payload = {
|
||||
username: AUTUMN_USERNAME,
|
||||
icon_url: AUTUMN_ICON_URL,
|
||||
text: lrPreview,
|
||||
blocks: lrBlocks
|
||||
};
|
||||
return webhook;
|
||||
}
|
||||
|
||||
// ============ balances.usage_alert_triggered ============
|
||||
if (webhook.eventType === "balances.usage_alert_triggered") {
|
||||
var uaCustomerId = data.customer_id || "";
|
||||
var uaFeatureId = data.feature_id || "feature";
|
||||
var uaEntityId = data.entity_id || null;
|
||||
var uaAlert = data.usage_alert || {};
|
||||
var uaAlertName = uaAlert.name || "Usage alert";
|
||||
var uaThreshold = uaAlert.threshold;
|
||||
var uaThresholdType = uaAlert.threshold_type || "usage";
|
||||
|
||||
function formatThreshold(value, type) {
|
||||
if (value === undefined || value === null) return "—";
|
||||
if (type === "usage_percentage") return value + "% used";
|
||||
if (type === "remaining_percentage") return value + "% remaining";
|
||||
if (type === "remaining") return value + " remaining";
|
||||
return value + " used";
|
||||
}
|
||||
|
||||
var uaThresholdLabel = formatThreshold(uaThreshold, uaThresholdType);
|
||||
|
||||
var uaCustomerLink = uaCustomerId
|
||||
? "<" + AUTUMN_BASE + uaCustomerId + "|`" + uaCustomerId + "`>"
|
||||
: "`unknown`";
|
||||
|
||||
var uaSentence =
|
||||
uaCustomerLink + " crossed the *" + uaAlertName + "* threshold on *" + uaFeatureId + "*";
|
||||
|
||||
var uaPreview = "📊 Usage Alert: " + uaAlertName + " (" + uaCustomerId + ")";
|
||||
|
||||
var uaFields = [
|
||||
{ type: "mrkdwn", text: "*Customer:*\n" + uaCustomerLink },
|
||||
{ type: "mrkdwn", text: "*Feature:*\n`" + uaFeatureId + "`" },
|
||||
{ type: "mrkdwn", text: "*Alert:*\n" + uaAlertName },
|
||||
{ type: "mrkdwn", text: "*Threshold:*\n" + uaThresholdLabel }
|
||||
];
|
||||
if (uaEntityId) {
|
||||
uaFields.push({ type: "mrkdwn", text: "*Entity:*\n`" + uaEntityId + "`" });
|
||||
}
|
||||
|
||||
var uaContextParts = [];
|
||||
if (uaCustomerId) uaContextParts.push("Customer ID: `" + uaCustomerId + "`");
|
||||
if (uaEntityId) uaContextParts.push("Entity: `" + uaEntityId + "`");
|
||||
|
||||
var uaBlocks = [
|
||||
{
|
||||
type: "header",
|
||||
text: { type: "plain_text", text: "📊 Usage Alert: " + uaAlertName, emoji: true }
|
||||
},
|
||||
{
|
||||
type: "section",
|
||||
text: { type: "mrkdwn", text: uaSentence }
|
||||
},
|
||||
{
|
||||
type: "section",
|
||||
fields: uaFields
|
||||
}
|
||||
];
|
||||
|
||||
if (uaCustomerId) {
|
||||
uaBlocks.push({
|
||||
type: "actions",
|
||||
elements: [
|
||||
{
|
||||
type: "button",
|
||||
text: { type: "plain_text", text: "View in Autumn", emoji: true },
|
||||
url: AUTUMN_BASE + uaCustomerId
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
if (uaContextParts.length > 0) {
|
||||
uaBlocks.push({
|
||||
type: "context",
|
||||
elements: [
|
||||
{ type: "mrkdwn", text: uaContextParts.join(" | ") }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
webhook.payload = {
|
||||
username: AUTUMN_USERNAME,
|
||||
icon_url: AUTUMN_ICON_URL,
|
||||
text: uaPreview,
|
||||
blocks: uaBlocks
|
||||
};
|
||||
return webhook;
|
||||
}
|
||||
|
||||
// Cancel any other event types — they don't match Slack's expected schema and would error.
|
||||
webhook.cancel = true;
|
||||
return webhook;
|
||||
}
|
||||
```
|
||||
@@ -332,3 +332,10 @@ body {
|
||||
color: #b08aff;
|
||||
text-decoration-color: #b08aff;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
HERO REVEAL — desktop only (lg+), driven by GSAP
|
||||
On mobile, GSAP is skipped and hero elements are immediately visible.
|
||||
The lg:opacity-0 utility class on .hero-reveal / .hero-cta elements
|
||||
ensures they start hidden on desktop where GSAP animates them in.
|
||||
========================================================================== */
|
||||
|
||||
@@ -7,11 +7,13 @@ import "./globals.css";
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
display: "swap",
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
display: "swap",
|
||||
});
|
||||
|
||||
const url = "https://useautumn.com";
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 0,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "@autumn/website",
|
||||
"dependencies": {
|
||||
"@gsap/react": "^2.1.2",
|
||||
"@mdx-js/loader": "^3.1.1",
|
||||
"@mdx-js/mdx": "^3.1.1",
|
||||
"@mdx-js/react": "^3.1.1",
|
||||
"@next/mdx": "^16.2.4",
|
||||
"@types/react": "^19.2.14",
|
||||
"@vercel/analytics": "^2.0.1",
|
||||
"framer-motion": "^12.38.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"gsap": "^3.15.0",
|
||||
"lottie-react": "^2.4.1",
|
||||
"lottie-web": "^5.13.0",
|
||||
"matter-js": "^0.20.0",
|
||||
"motion": "^12.38.0",
|
||||
"next": "16.2.4",
|
||||
"next-mdx-remote": "^6.0.0",
|
||||
"ngrok": "^5.0.0-beta.2",
|
||||
"react": "19.2.4",
|
||||
"react-dom": "19.2.4",
|
||||
"react-syntax-highlighter": "^16.1.1",
|
||||
"remark-frontmatter": "^5.0.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.2.2",
|
||||
@@ -159,6 +161,8 @@
|
||||
|
||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||
|
||||
"@mdx-js/loader": ["@mdx-js/loader@3.1.1", "", { "dependencies": { "@mdx-js/mdx": "^3.0.0", "source-map": "^0.7.0" }, "peerDependencies": { "webpack": ">=5" }, "optionalPeers": ["webpack"] }, "sha512-0TTacJyZ9mDmY+VefuthVshaNIyCGZHJG2fMnGaDttCt8HmjUF7SizlHJpaCDoGnN635nK1wpzfpx/Xx5S4WnQ=="],
|
||||
|
||||
"@mdx-js/mdx": ["@mdx-js/mdx@3.1.1", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "acorn": "^8.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ=="],
|
||||
|
||||
"@mdx-js/react": ["@mdx-js/react@3.1.1", "", { "dependencies": { "@types/mdx": "^2.0.0" }, "peerDependencies": { "@types/react": ">=16", "react": ">=16" } }, "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw=="],
|
||||
@@ -169,6 +173,8 @@
|
||||
|
||||
"@next/eslint-plugin-next": ["@next/eslint-plugin-next@16.2.1", "", { "dependencies": { "fast-glob": "3.3.1" } }, "sha512-r0epZGo24eT4g08jJlg2OEryBphXqO8aL18oajoTKLzHJ6jVr6P6FI58DLMug04MwD3j8Fj0YK0slyzneKVyzA=="],
|
||||
|
||||
"@next/mdx": ["@next/mdx@16.2.4", "", { "dependencies": { "source-map": "^0.7.0" }, "peerDependencies": { "@mdx-js/loader": ">=0.15.0", "@mdx-js/react": ">=0.15.0" }, "optionalPeers": ["@mdx-js/loader", "@mdx-js/react"] }, "sha512-e/3bgla+/oF3vDlndI0eFPa0bnP47HPVA0InsAJi7Jr3DwV8WpEGuOcm/3PdI5/93FfNiBhMVeVHZpm1sFlmJw=="],
|
||||
|
||||
"@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-OXTFFox5EKN1Ym08vfrz+OXxmCcEjT4SFMbNRsWZE99dMqt2Kcusl5MqPXcW232RYkMLQTy0hqgAMEsfEd/l2A=="],
|
||||
|
||||
"@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-XhpVnUfmYWvD3YrXu55XdcAkQtOnvaI6wtQa8fuF5fGoKoxIUZ0kWPtcOfqJEWngFF/lOS9l3+O9CcownhiQxQ=="],
|
||||
@@ -805,10 +811,10 @@
|
||||
|
||||
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||
|
||||
"matter-js": ["matter-js@0.20.0", "", {}, "sha512-iC9fYR7zVT3HppNnsFsp9XOoQdQN2tUyfaKg4CHLH8bN+j6GT4Gw7IH2rP0tflAebrHFw730RR3DkVSZRX8hwA=="],
|
||||
|
||||
"mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.3", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q=="],
|
||||
|
||||
"mdast-util-frontmatter": ["mdast-util-frontmatter@2.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "escape-string-regexp": "^5.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "micromark-extension-frontmatter": "^2.0.0" } }, "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA=="],
|
||||
|
||||
"mdast-util-mdx": ["mdast-util-mdx@3.0.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w=="],
|
||||
|
||||
"mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="],
|
||||
@@ -831,6 +837,8 @@
|
||||
|
||||
"micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="],
|
||||
|
||||
"micromark-extension-frontmatter": ["micromark-extension-frontmatter@2.0.0", "", { "dependencies": { "fault": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg=="],
|
||||
|
||||
"micromark-extension-mdx-expression": ["micromark-extension-mdx-expression@3.0.1", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q=="],
|
||||
|
||||
"micromark-extension-mdx-jsx": ["micromark-extension-mdx-jsx@3.0.2", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ=="],
|
||||
@@ -907,8 +915,6 @@
|
||||
|
||||
"next": ["next@16.2.4", "", { "dependencies": { "@next/env": "16.2.4", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.2.4", "@next/swc-darwin-x64": "16.2.4", "@next/swc-linux-arm64-gnu": "16.2.4", "@next/swc-linux-arm64-musl": "16.2.4", "@next/swc-linux-x64-gnu": "16.2.4", "@next/swc-linux-x64-musl": "16.2.4", "@next/swc-win32-arm64-msvc": "16.2.4", "@next/swc-win32-x64-msvc": "16.2.4", "sharp": "^0.34.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": "dist/bin/next" }, "sha512-kPvz56wF5frc+FxlHI5qnklCzbq53HTwORaWBGdT0vNoKh1Aya9XC8aPauH4NJxqtzbWsS5mAbctm4cr+EkQ2Q=="],
|
||||
|
||||
"next-mdx-remote": ["next-mdx-remote@6.0.0", "", { "dependencies": { "@babel/code-frame": "^7.23.5", "@mdx-js/mdx": "^3.0.1", "@mdx-js/react": "^3.0.1", "unist-util-remove": "^4.0.0", "unist-util-visit": "^5.1.0", "vfile": "^6.0.1", "vfile-matter": "^5.0.0" }, "peerDependencies": { "react": ">=16" } }, "sha512-cJEpEZlgD6xGjB4jL8BnI8FaYdN9BzZM4NwadPe1YQr7pqoWjg9EBCMv3nXBkuHqMRfv2y33SzUsuyNh9LFAQQ=="],
|
||||
|
||||
"ngrok": ["ngrok@5.0.0-beta.2", "", { "dependencies": { "extract-zip": "^2.0.1", "got": "^11.8.5", "lodash.clonedeep": "^4.5.0", "uuid": "^7.0.0 || ^8.0.0", "yaml": "^2.2.2" }, "optionalDependencies": { "hpagent": "^0.1.2" }, "bin": "bin/ngrok" }, "sha512-UzsyGiJ4yTTQLCQD11k1DQaMwq2/SsztBg2b34zAqcyjS25qjDpogMKPaCKHwe/APRTHeel3iDXcVctk5CNaCQ=="],
|
||||
|
||||
"node-exports-info": ["node-exports-info@1.6.0", "", { "dependencies": { "array.prototype.flatmap": "^1.3.3", "es-errors": "^1.3.0", "object.entries": "^1.1.9", "semver": "^6.3.1" } }, "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw=="],
|
||||
@@ -1005,6 +1011,8 @@
|
||||
|
||||
"rehype-recma": ["rehype-recma@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "hast-util-to-estree": "^3.0.0" } }, "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw=="],
|
||||
|
||||
"remark-frontmatter": ["remark-frontmatter@5.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-frontmatter": "^2.0.0", "micromark-extension-frontmatter": "^2.0.0", "unified": "^11.0.0" } }, "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ=="],
|
||||
|
||||
"remark-mdx": ["remark-mdx@3.1.1", "", { "dependencies": { "mdast-util-mdx": "^3.0.0", "micromark-extension-mdxjs": "^3.0.0" } }, "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg=="],
|
||||
|
||||
"remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="],
|
||||
@@ -1137,8 +1145,6 @@
|
||||
|
||||
"unist-util-position-from-estree": ["unist-util-position-from-estree@2.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ=="],
|
||||
|
||||
"unist-util-remove": ["unist-util-remove@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-b4gokeGId57UVRX/eVKej5gXqGlc9+trkORhFJpu9raqZkZhU0zm8Doi05+HaiBsMEIJowL+2WtQ5ItjsngPXg=="],
|
||||
|
||||
"unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
|
||||
|
||||
"unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="],
|
||||
@@ -1157,8 +1163,6 @@
|
||||
|
||||
"vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
|
||||
|
||||
"vfile-matter": ["vfile-matter@5.0.1", "", { "dependencies": { "vfile": "^6.0.0", "yaml": "^2.0.0" } }, "sha512-o6roP82AiX0XfkyTHyRCMXgHfltUNlXSEqCIS80f+mbAyiQBE2fxtDVMtseyytGx75sihiJFo/zR6r/4LTs2Cw=="],
|
||||
|
||||
"vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
@@ -1217,6 +1221,10 @@
|
||||
|
||||
"is-bun-module/semver": ["semver@7.7.4", "", { "bin": "bin/semver.js" }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
||||
|
||||
"mdast-util-frontmatter/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
|
||||
|
||||
"micromark-extension-frontmatter/fault": ["fault@2.0.1", "", { "dependencies": { "format": "^0.2.0" } }, "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ=="],
|
||||
|
||||
"micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="],
|
||||
|
||||
"next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
"use client";
|
||||
import gsap from "gsap";
|
||||
import { forwardRef, useEffect, useImperativeHandle, useRef } from "react";
|
||||
import type { PixelHoverHandle, PixelIconComponent } from "@/lib/types";
|
||||
import { getGsap } from "@/lib/lazyGsap";
|
||||
|
||||
type GSAPTimeline = {
|
||||
play: () => GSAPTimeline;
|
||||
reverse: () => GSAPTimeline;
|
||||
kill: () => void;
|
||||
// biome-ignore lint/suspicious/noExplicitAny: structural shim for GSAP's overloaded .to() signature
|
||||
to: (...args: any[]) => GSAPTimeline;
|
||||
};
|
||||
|
||||
export const DashboardIconPixel = forwardRef<
|
||||
PixelHoverHandle,
|
||||
{ Icon: PixelIconComponent }
|
||||
>(function DashboardIconPixel({ Icon }, ref) {
|
||||
const iconRef = useRef<SVGSVGElement | null>(null);
|
||||
const tlRef = useRef<gsap.core.Timeline | null>(null);
|
||||
const tlRef = useRef<GSAPTimeline | null>(null);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
restart: () => tlRef.current?.play(),
|
||||
@@ -16,47 +24,40 @@ export const DashboardIconPixel = forwardRef<
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
const pixelEls =
|
||||
iconRef.current?.querySelectorAll<SVGGraphicsElement>(".icon-pixel-path");
|
||||
if (!pixelEls?.length) return;
|
||||
const el = iconRef.current;
|
||||
if (!el) return;
|
||||
let cancelled = false;
|
||||
|
||||
// Sort pixels by visual position: bottom-left → top-right diagonal
|
||||
const pixels = Array.from(pixelEls).sort((a, b) => {
|
||||
const aBox = a.getBBox();
|
||||
const bBox = b.getBBox();
|
||||
return (
|
||||
aBox.x +
|
||||
aBox.width / 2 -
|
||||
(aBox.y + aBox.height / 2) -
|
||||
(bBox.x + bBox.width / 2 - (bBox.y + bBox.height / 2))
|
||||
);
|
||||
});
|
||||
getGsap().then((gsap) => {
|
||||
if (cancelled) return;
|
||||
const pixelEls = el.querySelectorAll<SVGGraphicsElement>(".icon-pixel-path");
|
||||
if (!pixelEls.length) return;
|
||||
|
||||
gsap.set(pixels, {
|
||||
opacity: 0.15,
|
||||
scale: 0.8,
|
||||
transformOrigin: "left bottom",
|
||||
fill: "currentColor",
|
||||
});
|
||||
|
||||
tlRef.current = gsap.timeline({ paused: true });
|
||||
|
||||
tlRef.current
|
||||
.to(pixels, {
|
||||
opacity: 1,
|
||||
scale: 1.15,
|
||||
fill: "#FFFFFF",
|
||||
duration: 0.2,
|
||||
stagger: 0.01,
|
||||
ease: "power2.out",
|
||||
})
|
||||
.to(pixels, {
|
||||
scale: 1,
|
||||
duration: 0.01,
|
||||
ease: "back.out(3)",
|
||||
// Sort pixels by visual position: bottom-left → top-right diagonal
|
||||
const pixels = Array.from(pixelEls).sort((a, b) => {
|
||||
const aBox = a.getBBox();
|
||||
const bBox = b.getBBox();
|
||||
return (
|
||||
aBox.x + aBox.width / 2 - (aBox.y + aBox.height / 2) -
|
||||
(bBox.x + bBox.width / 2 - (bBox.y + bBox.height / 2))
|
||||
);
|
||||
});
|
||||
|
||||
gsap.set(pixels, {
|
||||
opacity: 0.15,
|
||||
scale: 0.8,
|
||||
transformOrigin: "left bottom",
|
||||
fill: "currentColor",
|
||||
});
|
||||
|
||||
tlRef.current = gsap.timeline({ paused: true });
|
||||
tlRef.current!
|
||||
.to(pixels, { opacity: 1, scale: 1.15, fill: "#FFFFFF", duration: 0.2, stagger: 0.01, ease: "power2.out" })
|
||||
.to(pixels, { scale: 1, duration: 0.01, ease: "back.out(3)" });
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
tlRef.current?.kill();
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"use client";
|
||||
import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
|
||||
import { motion, useMotionValue, useSpring, useTransform } from "motion/react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import type { LayoutProps } from "@/lib/types";
|
||||
import AnimatedFooterImage from "./animated-footer-image";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"use client";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
import { useState } from "react";
|
||||
import { AnimatedPlusMinus, faqData } from "@/app/constant";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { useGSAP } from "@gsap/react";
|
||||
import gsap from "gsap";
|
||||
import { motion } from "motion/react";
|
||||
import dynamic from "next/dynamic";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { CTALines, IconCTADocs, IconCTAStart } from "@/app/constant";
|
||||
import { getGsap } from "@/lib/lazyGsap";
|
||||
|
||||
// `AutumnConfig` pulls in `react-syntax-highlighter` + `highlight.js` (~100KB
|
||||
// gzipped + meaningful parse cost on mobile). It only renders on `xl+`
|
||||
@@ -88,88 +87,51 @@ export default function Hero() {
|
||||
};
|
||||
}, []);
|
||||
|
||||
useGSAP(
|
||||
() => {
|
||||
gsap.set(".hero-root", { opacity: 0 });
|
||||
useEffect(() => {
|
||||
const container = containerRef.current;
|
||||
if (!container) return;
|
||||
|
||||
gsap.set(".hero-bg", {
|
||||
opacity: 0,
|
||||
filter: "blur(6px) brightness(1)",
|
||||
scale: 0.97,
|
||||
transformOrigin: "center top",
|
||||
});
|
||||
let ctx: { revert: () => void } | null = null;
|
||||
let cancelled = false;
|
||||
|
||||
gsap.set(".hero-reveal", {
|
||||
opacity: 0,
|
||||
y: 25,
|
||||
filter: "blur(12px)",
|
||||
scale: 0.96,
|
||||
transformOrigin: "center bottom",
|
||||
});
|
||||
// Mobile: CSS animations in globals.css handle the hero reveal.
|
||||
// Guard here so mobile never initiates the ~60KB GSAP dynamic import.
|
||||
if (window.innerWidth < 1024) return;
|
||||
|
||||
gsap.set(".hero-cta", { opacity: 0, scale: 0.95 });
|
||||
getGsap().then((gsap) => {
|
||||
if (cancelled) return;
|
||||
ctx = gsap.context(() => {
|
||||
gsap.set(".hero-reveal", {
|
||||
opacity: 0,
|
||||
y: 25,
|
||||
scale: 0.96,
|
||||
transformOrigin: "center bottom",
|
||||
});
|
||||
gsap.set(".hero-cta", { opacity: 0, scale: 0.95 });
|
||||
|
||||
const tl = gsap.timeline({
|
||||
defaults: { overwrite: "auto" },
|
||||
});
|
||||
const tl = gsap.timeline({ defaults: { overwrite: "auto" } });
|
||||
|
||||
tl.to(".hero-root", { opacity: 1, duration: 0.3, ease: "none" })
|
||||
// hero-bg is intentionally NOT hidden — it is the LCP element and
|
||||
// must be visible from first paint. The brightness flash still runs.
|
||||
tl.to(".hero-bg", { filter: "brightness(1.6)", duration: 0.125, ease: "power2.in" })
|
||||
.to(".hero-bg", { filter: "brightness(1)", duration: 0.125, ease: "power2.out" })
|
||||
.to(".hero-reveal", { opacity: 1, y: 0, scale: 1, duration: 1.1, stagger: 0.1, ease: "power3.out" }, "-=0.2")
|
||||
.to(".hero-cta", { opacity: 1, scale: 1, duration: 0.3, stagger: 0.06, ease: "back.out(1.5)" }, "-=0.1");
|
||||
}, container);
|
||||
});
|
||||
|
||||
.to(".hero-bg", {
|
||||
opacity: 1,
|
||||
filter: "blur(0px) brightness(1)",
|
||||
scale: 1,
|
||||
duration: 0.4,
|
||||
ease: "power2.out",
|
||||
})
|
||||
|
||||
.to(".hero-bg", {
|
||||
filter: "blur(0px) brightness(1.6)",
|
||||
duration: 0.125,
|
||||
ease: "power2.in",
|
||||
})
|
||||
|
||||
.to(".hero-bg", {
|
||||
filter: "blur(0px) brightness(1)",
|
||||
duration: 0.125,
|
||||
ease: "power2.out",
|
||||
})
|
||||
|
||||
.to(
|
||||
".hero-reveal",
|
||||
{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
filter: "blur(0px)",
|
||||
scale: 1,
|
||||
duration: 1.1,
|
||||
stagger: 0.1,
|
||||
ease: "power3.out",
|
||||
},
|
||||
"-=0.2",
|
||||
)
|
||||
|
||||
.to(
|
||||
".hero-cta",
|
||||
{
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
duration: 0.3,
|
||||
stagger: 0.06,
|
||||
ease: "back.out(1.5)",
|
||||
},
|
||||
"-=0.1",
|
||||
);
|
||||
},
|
||||
{ scope: containerRef },
|
||||
);
|
||||
return () => {
|
||||
cancelled = true;
|
||||
ctx?.revert();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div ref={containerRef}>
|
||||
<div className="relative hero-root opacity-0 flex flex-col items-stretch pb-0 md:pb-12 mb-0 bg-[#0F0F0F]">
|
||||
<div className="relative hero-root flex flex-col items-stretch pb-0 mb-0 bg-[#0F0F0F]">
|
||||
<div className="flex justify-between">
|
||||
<div className="flex flex-col gap-6 px-4 xl:px-22.75 py-8 bg-[#0F0F0F] mt-26">
|
||||
<h4 className="hero-reveal relative uppercase font-mono tracking-[-2%] text-[12px] md:text-sm leading-sm text-white md:text-[#FFFFFF99] bg-[#2c2c2d] w-fit p-2 min-h-[30px] md:min-h-[36px] flex items-center">
|
||||
<h4 className="hero-reveal lg:opacity-0 relative uppercase font-mono tracking-[-2%] text-[12px] md:text-sm leading-sm text-white md:text-[#FFFFFF99] bg-[#2c2c2d] w-fit p-2 min-h-[30px] md:min-h-[36px] flex items-center">
|
||||
<span className="invisible select-none" aria-hidden="true">
|
||||
{BADGE_TEXT}
|
||||
</span>
|
||||
@@ -178,13 +140,13 @@ export default function Hero() {
|
||||
</span>
|
||||
</h4>
|
||||
<div className="flex flex-col gap-6 w-full px-0 lg:px-0">
|
||||
<h1 className="hero-reveal text-[44px] md:text-[56px] w-full max-w-sm sm:max-w-[480px] md:max-w-xl leading-[44px] tracking-[-5%] md:leading-14 font-sans">
|
||||
<h1 className="hero-reveal lg:opacity-0 text-[44px] md:text-[56px] w-full max-w-sm sm:max-w-[480px] md:max-w-xl leading-[44px] tracking-[-5%] md:leading-14 font-sans">
|
||||
<span className="text-[#FFFFFF99] font-normal">
|
||||
Drop-in credits and billing for
|
||||
</span>{" "}
|
||||
<span className="text-white block md:inline">AI agents</span>
|
||||
</h1>
|
||||
<p className="hero-reveal tracking-[-2%] w-full max-w-xs sm:max-w-[480px] md:max-w-xl text-[#FFFFFF99] md:text-[16px] text-[14px] font-light leading-5 font-sans">
|
||||
<p className="hero-reveal lg:opacity-0 tracking-[-2%] w-full max-w-xs sm:max-w-[480px] md:max-w-xl text-[#FFFFFF99] md:text-[16px] text-[14px] font-light leading-5 font-sans">
|
||||
Stop rebuilding usage limits, credit ledgers and payment logic.{" "}
|
||||
<span className="text-white font-light">
|
||||
Autumn is the customer database
|
||||
@@ -201,7 +163,7 @@ export default function Hero() {
|
||||
so mobile never downloads them, and desktop fills the
|
||||
already-reserved space once it hydrates.
|
||||
*/}
|
||||
<div className="hero-reveal relative w-[50vw] max-w-[720px] min-h-[525px] p-16 py-0 mx-auto hidden xl:block">
|
||||
<div className="hero-reveal lg:opacity-0 relative w-[50vw] max-w-[720px] min-h-[525px] p-16 py-0 mx-auto hidden xl:block">
|
||||
{isXl && (
|
||||
<>
|
||||
<div className="absolute inset-0 z-0 pointer-events-none">
|
||||
@@ -224,7 +186,7 @@ export default function Hero() {
|
||||
<div className="border-t border-[#292929]" />
|
||||
<div className="flex flex-nowrap items-center xl:px-22.75 px-4 bg-[#0F0F0F] w-full overflow-hidden">
|
||||
{/* Primary CTA */}
|
||||
<div className="hero-cta w-full md:w-fit md:flex-shrink-0">
|
||||
<div className="hero-cta lg:opacity-0 w-full md:w-fit md:flex-shrink-0">
|
||||
<Link
|
||||
href={
|
||||
isLoggedIn
|
||||
@@ -253,7 +215,7 @@ export default function Hero() {
|
||||
</div>
|
||||
|
||||
{/* Secondary CTA */}
|
||||
<div className="hero-cta w-full md:w-fit md:flex-shrink-0">
|
||||
<div className="hero-cta lg:opacity-0 w-full md:w-fit md:flex-shrink-0">
|
||||
<Link href={"https://cal.com/ayrod"}>
|
||||
<motion.div
|
||||
initial="initial"
|
||||
@@ -274,7 +236,7 @@ export default function Hero() {
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="hero-cta hidden md:flex flex-nowrap gap-2 md:gap-3 ml-2 md:ml-3 h-10.5 md:h-12.5 flex-1">
|
||||
<div className="hero-cta lg:opacity-0 hidden md:flex flex-nowrap gap-2 md:gap-3 ml-2 md:ml-3 h-10.5 md:h-12.5 flex-1">
|
||||
<div className="border-r border-[#292929] h-full hidden md:block" />
|
||||
<div className="border-r border-[#292929] h-full hidden md:block" />
|
||||
<div className="border-r border-[#292929] h-full hidden md:block" />
|
||||
@@ -305,11 +267,12 @@ export default function Hero() {
|
||||
aria-hidden="true"
|
||||
fill
|
||||
priority
|
||||
fetchPriority="high"
|
||||
sizes="100vw"
|
||||
className="hero-bg absolute inset-0 w-full h-full object-cover mix-blend-screen opacity-100 pointer-events-none select-none"
|
||||
/>
|
||||
|
||||
<div className="hero-reveal relative z-10 w-[96%] sm:w-[90%] max-w-[520px] flex justify-center items-center">
|
||||
<div className="hero-reveal lg:opacity-0 relative z-10 w-[96%] sm:w-[90%] max-w-[520px] flex justify-center items-center">
|
||||
{/* <AutumnConfig lines={16} initialDelay={1000} awaitEvent="preloader:complete" /> */}
|
||||
<Image
|
||||
src={"/images/hero/autumn_mobile.svg"}
|
||||
|
||||
@@ -3,11 +3,15 @@
|
||||
import dynamic from "next/dynamic";
|
||||
import { useEffect } from "react";
|
||||
import Hero from "./hero";
|
||||
import LazySection from "./lazy-section";
|
||||
import SectionDivider from "./section-divider";
|
||||
|
||||
// All below-fold sections are code-split into separate lazy chunks so the
|
||||
// initial JS bundle only contains the hero. Framer-motion, GSAP ScrollTrigger,
|
||||
// and lottie-web are pulled into these chunks rather than the main bundle.
|
||||
// LazySection gates each component behind an IntersectionObserver so chunks
|
||||
// and their heavy assets (Lottie JSON, ScrollTrigger) only download as the
|
||||
// user scrolls toward them rather than all at once on page load.
|
||||
const LogoWall = dynamic(() => import("./logo-wall"));
|
||||
const Problem = dynamic(() => import("./problem"));
|
||||
const Solution = dynamic(() => import("./solution"));
|
||||
@@ -42,32 +46,25 @@ export default function HomeSections() {
|
||||
return (
|
||||
<>
|
||||
<Hero />
|
||||
{/*
|
||||
<div className="flex flex-col gap-2.5 bg-[#000000]">
|
||||
<div className="border-t border-[#292929] w-full" />
|
||||
<div className="border-t border-[#292929] w-full" />
|
||||
<div className="border-t border-[#292929] w-full" />
|
||||
<div className="border-t border-[#292929] w-full" />
|
||||
<div className="border-t border-[#292929] w-full" />
|
||||
</div>
|
||||
<LogoWall /> */}
|
||||
|
||||
<LogoWall />
|
||||
<SectionDivider title="THE PROBLEM" />
|
||||
<Problem />
|
||||
<LazySection><Problem /></LazySection>
|
||||
<SectionDivider title="THE SOLUTION" />
|
||||
<Solution />
|
||||
<LazySection><Solution /></LazySection>
|
||||
<SectionDivider title="PRICING MODELS" />
|
||||
<PricingModels />
|
||||
<LazySection><PricingModels /></LazySection>
|
||||
<SectionDivider title="FEATURES" />
|
||||
<Features />
|
||||
<LazySection><Features /></LazySection>
|
||||
<SectionDivider title="TESTIMONIALS" />
|
||||
<Testimonials />
|
||||
<LazySection><Testimonials /></LazySection>
|
||||
<SectionDivider title="PRODUCTION SCALE" />
|
||||
<ProductionScale />
|
||||
<LazySection><ProductionScale /></LazySection>
|
||||
<SectionDivider title="PRICING" />
|
||||
<Pricing />
|
||||
<LazySection><Pricing /></LazySection>
|
||||
<SectionDivider title="FAQ" />
|
||||
<FAQ />
|
||||
<Footer />
|
||||
<LazySection><FAQ /></LazySection>
|
||||
<LazySection><Footer /></LazySection>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
37
apps/website/components/lazy-section.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
"use client";
|
||||
import { useEffect, useRef, useState, type ReactNode } from "react";
|
||||
|
||||
export default function LazySection({ children }: { children: ReactNode }) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const el = ref.current;
|
||||
if (!el) return;
|
||||
|
||||
// iOS < 12.2 has no IntersectionObserver — mount everything immediately.
|
||||
if (!("IntersectionObserver" in window)) {
|
||||
setMounted(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
// intersectionRatio > 0 guards against a Safari bug where
|
||||
// isIntersecting fires as false on the initial sync callback.
|
||||
if (entry.isIntersecting || entry.intersectionRatio > 0) {
|
||||
setMounted(true);
|
||||
observer.disconnect();
|
||||
}
|
||||
},
|
||||
{ rootMargin: "1000px 0px" },
|
||||
);
|
||||
|
||||
observer.observe(el);
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
// min-height: 1px prevents the wrapper collapsing to zero height before
|
||||
// content mounts, which would cause iOS to jump scroll position on mount.
|
||||
return <div ref={ref} style={{ minHeight: "1px" }}>{mounted ? children : null}</div>;
|
||||
}
|
||||
@@ -1,71 +1,101 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { getGsap } from "@/lib/lazyGsap";
|
||||
|
||||
const LOGOS = [
|
||||
{ id: 1, name: "Mintlify", src: "/images/logos/mintlify_logo.svg.svg" },
|
||||
{ id: 2, name: "Browser Use", src: "/images/logos/Browser use.svg" },
|
||||
{ id: 3, name: "Firecrawl", src: "/images/logos/Firecrawl.svg.svg" },
|
||||
{ id: 4, name: "Mastra", src: "/images/logos/Mastra.svg.svg" },
|
||||
{ id: 5, name: "T3.chat", src: "/images/logos/T3_svg.svg" },
|
||||
{ id: 6, name: "", src: null },
|
||||
{ id: 1, name: "Mintlify", src: "/images/logos/mintlify_logo.svg.svg", className: "scale-90 md:scale-70" },
|
||||
{ id: 3, name: "Firecrawl", src: "/images/logos/Firecrawl.svg.svg", className: "scale-95 md:scale-75 -translate-y-0.5" },
|
||||
{ id: 4, name: "Mastra", src: "/images/logos/Mastra.svg.svg", className: "scale-105 md:scale-95" },
|
||||
{ id: 2, name: "Browser Use", src: "/images/logos/Browser use.svg", className: "scale-85 md:scale-65" },
|
||||
{ id: 5, name: "T3.chat", src: "/images/logos/T3_svg.svg", className: "scale-65 md:scale-55" },
|
||||
];
|
||||
|
||||
const NUM_MOBILE_COLS = 2;
|
||||
const NUM_DESKTOP_COLS = 3;
|
||||
|
||||
export default function LogoWall() {
|
||||
const sectionRef = useRef<HTMLElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const section = sectionRef.current;
|
||||
if (!section) return;
|
||||
|
||||
let ctx: { revert: () => void } | null = null;
|
||||
let cancelled = false;
|
||||
|
||||
if (window.innerWidth < 1024) return;
|
||||
|
||||
getGsap().then((gsap) => {
|
||||
if (cancelled) return;
|
||||
ctx = gsap.context(() => {
|
||||
gsap.set(".logo-wall-title", {
|
||||
opacity: 0,
|
||||
y: 20,
|
||||
scale: 0.97,
|
||||
transformOrigin: "center bottom",
|
||||
});
|
||||
gsap.set(".logo-wall-item", {
|
||||
opacity: 0,
|
||||
y: 15,
|
||||
scale: 0.96,
|
||||
});
|
||||
|
||||
const tl = gsap.timeline({
|
||||
defaults: { overwrite: "auto" },
|
||||
delay: 0.35,
|
||||
});
|
||||
|
||||
tl.to(".logo-wall-title, .logo-wall-item", {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
scale: 1,
|
||||
duration: 1.1,
|
||||
ease: "power3.out",
|
||||
});
|
||||
}, section);
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
ctx?.revert();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<section className="w-full bg-[#000000]">
|
||||
<div className="flex flex-col md:flex-row">
|
||||
{/* Left heading — full width on mobile, 42% on desktop */}
|
||||
<div className="md:w-[42%] px-4 xl:px-22.75 py-8 md:py-0 flex items-center border-b md:border-b-0 md:border-r border-[#292929]">
|
||||
<div>
|
||||
<p className="font-sans text-[28px] md:text-[36px] xl:text-[40px] font-normal leading-[1.1] tracking-[-0.03em]">
|
||||
<span className="text-[#FFFFFF66]">Trusted by </span>
|
||||
<span className="text-white">AI teams</span>
|
||||
</p>
|
||||
<p className="font-sans text-[28px] md:text-[36px] xl:text-[40px] font-normal leading-[1.1] tracking-[-0.03em] text-white">
|
||||
shipping fast
|
||||
</p>
|
||||
</div>
|
||||
<section
|
||||
ref={sectionRef}
|
||||
className="w-full bg-[#0F0F0F]"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"radial-gradient(circle, rgba(255,255,255,0.06) 1px, transparent 1px)",
|
||||
backgroundSize: "14px 14px",
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
<div className="px-4 xl:px-22.75 pt-10.5 flex items-center justify-center">
|
||||
<span className="logo-wall-title lg:opacity-0 font-sans text-[14px] font-light text-[#FFFFFF99] tracking-[-2%] leading-5">
|
||||
Powering millions of customers for growing startups
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Logo grid — 2 cols on mobile, 3 cols on desktop */}
|
||||
<div className="flex-1 grid grid-cols-2 md:grid-cols-3">
|
||||
{LOGOS.map((logo, i) => {
|
||||
const isLastMobileCol = (i + 1) % NUM_MOBILE_COLS === 0;
|
||||
const isLastDesktopCol = (i + 1) % NUM_DESKTOP_COLS === 0;
|
||||
const isLastMobileRow = i >= LOGOS.length - NUM_MOBILE_COLS;
|
||||
const isLastDesktopRow = i >= LOGOS.length - NUM_DESKTOP_COLS;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={logo.id}
|
||||
className={cn(
|
||||
"flex items-center justify-center min-h-[90px] md:min-h-[166px] border-[#292929]",
|
||||
!isLastMobileCol && "border-r",
|
||||
!isLastMobileRow && "border-b",
|
||||
isLastDesktopCol ? "md:border-r-0" : "md:border-r",
|
||||
isLastDesktopRow ? "md:border-b-0" : "md:border-b",
|
||||
)}
|
||||
style={{
|
||||
backgroundImage:
|
||||
"radial-gradient(circle, rgba(255,255,255,0.06) 1px, transparent 1px)",
|
||||
backgroundSize: "14px 14px",
|
||||
}}
|
||||
>
|
||||
{logo.src && (
|
||||
<img
|
||||
src={logo.src}
|
||||
alt={logo.name}
|
||||
className="h-5 md:h-7 w-auto max-w-[110px] md:max-w-[150px] object-contain"
|
||||
loading="lazy"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<div className="flex-1 flex flex-wrap justify-center md:grid md:grid-cols-5 px-4 py-4 md:py-0">
|
||||
{LOGOS.map((logo) => (
|
||||
<div
|
||||
key={logo.id}
|
||||
className="logo-wall-item lg:opacity-0 flex items-center justify-center min-h-[50px] md:min-h-[100px] border-[#292929] w-1/3 md:w-auto"
|
||||
>
|
||||
{logo.src && (
|
||||
<img
|
||||
src={logo.src}
|
||||
alt={logo.name}
|
||||
className={cn(
|
||||
"h-5 md:h-7 w-auto max-w-full object-contain",
|
||||
logo.className,
|
||||
)}
|
||||
loading="lazy"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { useGSAP } from "@gsap/react";
|
||||
import gsap from "gsap";
|
||||
import { motion } from "motion/react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
@@ -29,6 +27,7 @@ import type {
|
||||
PixelIconComponent,
|
||||
} from "@/lib/types";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { getGsap } from "@/lib/lazyGsap";
|
||||
import { DashboardIconPixel } from "./dashboard-icon-pixel";
|
||||
|
||||
const NAV_LINKS = [
|
||||
@@ -42,10 +41,18 @@ const NAV_LINKS = [
|
||||
},
|
||||
];
|
||||
|
||||
type GSAPTimeline = {
|
||||
play: () => GSAPTimeline;
|
||||
reverse: () => GSAPTimeline;
|
||||
kill: () => void;
|
||||
// biome-ignore lint/suspicious/noExplicitAny: structural shim for GSAP's overloaded .to() signature
|
||||
to: (...args: any[]) => GSAPTimeline;
|
||||
};
|
||||
|
||||
const NavIconPixel = forwardRef<PixelHoverHandle, { Icon: PixelIconComponent }>(
|
||||
function NavIconPixel({ Icon }, ref) {
|
||||
const iconRef = useRef<SVGSVGElement | null>(null);
|
||||
const tlRef = useRef<gsap.core.Timeline | null>(null);
|
||||
const tlRef = useRef<GSAPTimeline | null>(null);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
restart: () => tlRef.current?.play(),
|
||||
@@ -53,46 +60,39 @@ const NavIconPixel = forwardRef<PixelHoverHandle, { Icon: PixelIconComponent }>(
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
const pixelEls =
|
||||
iconRef.current?.querySelectorAll<SVGPathElement>(".icon-pixel-path");
|
||||
if (!pixelEls?.length) return;
|
||||
const el = iconRef.current;
|
||||
if (!el) return;
|
||||
let cancelled = false;
|
||||
|
||||
const pixels = Array.from(pixelEls).sort((a, b) => {
|
||||
const aBox = a.getBBox();
|
||||
const bBox = b.getBBox();
|
||||
return (
|
||||
aBox.x +
|
||||
aBox.width / 2 -
|
||||
(aBox.y + aBox.height / 2) -
|
||||
(bBox.x + bBox.width / 2 - (bBox.y + bBox.height / 2))
|
||||
);
|
||||
});
|
||||
getGsap().then((gsap) => {
|
||||
if (cancelled) return;
|
||||
const pixelEls = el.querySelectorAll<SVGPathElement>(".icon-pixel-path");
|
||||
if (!pixelEls.length) return;
|
||||
|
||||
gsap.set(pixels, {
|
||||
opacity: 0.15,
|
||||
scale: 0.8,
|
||||
transformOrigin: "left bottom",
|
||||
fill: "currentColor",
|
||||
});
|
||||
|
||||
tlRef.current = gsap.timeline({ paused: true });
|
||||
|
||||
tlRef.current
|
||||
.to(pixels, {
|
||||
opacity: 1,
|
||||
scale: 1.15,
|
||||
fill: "#FFFFFF",
|
||||
duration: 0.01,
|
||||
stagger: 0.025,
|
||||
ease: "power2.out",
|
||||
})
|
||||
.to(pixels, {
|
||||
scale: 1,
|
||||
duration: 0.01,
|
||||
ease: "back.out(3)",
|
||||
const pixels = Array.from(pixelEls).sort((a, b) => {
|
||||
const aBox = a.getBBox();
|
||||
const bBox = b.getBBox();
|
||||
return (
|
||||
aBox.x + aBox.width / 2 - (aBox.y + aBox.height / 2) -
|
||||
(bBox.x + bBox.width / 2 - (bBox.y + bBox.height / 2))
|
||||
);
|
||||
});
|
||||
|
||||
gsap.set(pixels, {
|
||||
opacity: 0.15,
|
||||
scale: 0.8,
|
||||
transformOrigin: "left bottom",
|
||||
fill: "currentColor",
|
||||
});
|
||||
|
||||
tlRef.current = gsap.timeline({ paused: true });
|
||||
tlRef.current!
|
||||
.to(pixels, { opacity: 1, scale: 1.15, fill: "#FFFFFF", duration: 0.01, stagger: 0.025, ease: "power2.out" })
|
||||
.to(pixels, { scale: 1, duration: 0.01, ease: "back.out(3)" });
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
tlRef.current?.kill();
|
||||
};
|
||||
}, []);
|
||||
@@ -189,137 +189,21 @@ export default function Navbar({
|
||||
};
|
||||
}, [menuOpen]);
|
||||
|
||||
useGSAP(
|
||||
() => {
|
||||
if (!animateIntro) return;
|
||||
// Skip the entrance animation on non-desktop viewports, or when
|
||||
// hydration landed well after first paint. On mobile the GSAP chunk
|
||||
// can arrive many seconds after the server-rendered navbar has
|
||||
// already painted; hiding it with `gsap.set({ opacity: 0 })` at
|
||||
// that point and re-animating it in is a visible flash that's much
|
||||
// worse than no animation.
|
||||
if (
|
||||
window.matchMedia("(max-width: 1023px)").matches ||
|
||||
performance.now() > 300
|
||||
) {
|
||||
return;
|
||||
}
|
||||
gsap.set(".nav-root", { opacity: 0 });
|
||||
gsap.set(".nav-logo", {
|
||||
opacity: 0,
|
||||
filter: "blur(6px) brightness(1)",
|
||||
scale: 0.92,
|
||||
transformOrigin: "left center",
|
||||
});
|
||||
gsap.set(".nav-link", { opacity: 0, y: -8 });
|
||||
gsap.set(".nav-dashboard", { opacity: 0, scale: 0.95 });
|
||||
const navMobileRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const tl = gsap.timeline({ defaults: { overwrite: "auto" } });
|
||||
|
||||
tl.to(".nav-root", { opacity: 1, duration: 0.3, ease: "none" })
|
||||
.to(".nav-logo", {
|
||||
opacity: 1,
|
||||
filter: "blur(0px) brightness(1)",
|
||||
scale: 1,
|
||||
duration: 0.7,
|
||||
ease: "power2.out",
|
||||
})
|
||||
.to(".nav-logo", {
|
||||
filter: "blur(0px) brightness(1.6)",
|
||||
duration: 0.225,
|
||||
ease: "power2.in",
|
||||
})
|
||||
.to(".nav-logo", {
|
||||
filter: "blur(0px) brightness(1)",
|
||||
duration: 0.125,
|
||||
ease: "power2.out",
|
||||
})
|
||||
.to(
|
||||
".nav-link",
|
||||
{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
duration: 0.25,
|
||||
stagger: 0.06,
|
||||
ease: "power2.out",
|
||||
},
|
||||
"-=0.05",
|
||||
)
|
||||
.to(
|
||||
".nav-dashboard",
|
||||
{
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
duration: 0.3,
|
||||
ease: "back.out(1.5)",
|
||||
},
|
||||
"-=0.1",
|
||||
);
|
||||
},
|
||||
{ scope: containerRef, dependencies: [animateIntro] },
|
||||
);
|
||||
|
||||
const mobileTl = useRef<gsap.core.Timeline | null>(null);
|
||||
|
||||
useGSAP(
|
||||
() => {
|
||||
gsap.set(".nav-mobile", {
|
||||
opacity: 0,
|
||||
clipPath: "inset(0% 0 100% 0)",
|
||||
pointerEvents: "none",
|
||||
});
|
||||
|
||||
gsap.set(
|
||||
".nav-mobile a, .nav-mobile img, .nav-mobile button, .nav-mobile .border-b",
|
||||
{
|
||||
opacity: 0,
|
||||
filter: "blur(8px)",
|
||||
scale: 0.95,
|
||||
},
|
||||
);
|
||||
|
||||
mobileTl.current = gsap.timeline({
|
||||
paused: true,
|
||||
defaults: { overwrite: "auto" },
|
||||
});
|
||||
|
||||
mobileTl.current
|
||||
.to(".nav-mobile", {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
pointerEvents: "auto",
|
||||
clipPath: "inset(0% 0 0% 0)",
|
||||
duration: 0.2,
|
||||
ease: "power3.inOut",
|
||||
})
|
||||
.to(
|
||||
".nav-mobile a, .nav-mobile img, .nav-mobile button, .nav-mobile .border-b",
|
||||
{
|
||||
opacity: 1,
|
||||
filter: "blur(0px)",
|
||||
scale: 1,
|
||||
duration: 0.15,
|
||||
stagger: 0.01,
|
||||
ease: "power2.out",
|
||||
},
|
||||
"-=0.1",
|
||||
);
|
||||
},
|
||||
{ scope: containerRef },
|
||||
);
|
||||
|
||||
useGSAP(
|
||||
() => {
|
||||
if (mobileTl.current) {
|
||||
if (menuOpen) {
|
||||
mobileTl.current.timeScale(1).play();
|
||||
} else {
|
||||
mobileTl.current.timeScale(1.8).reverse();
|
||||
}
|
||||
}
|
||||
},
|
||||
{ scope: containerRef, dependencies: [menuOpen] },
|
||||
);
|
||||
useEffect(() => {
|
||||
const el = navMobileRef.current;
|
||||
if (!el) return;
|
||||
if (menuOpen) {
|
||||
el.style.opacity = "1";
|
||||
el.style.pointerEvents = "auto";
|
||||
el.style.clipPath = "inset(0% 0 0% 0)";
|
||||
} else {
|
||||
el.style.opacity = "0";
|
||||
el.style.pointerEvents = "none";
|
||||
el.style.clipPath = "inset(0% 0 100% 0)";
|
||||
}
|
||||
}, [menuOpen]);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -404,8 +288,9 @@ export default function Navbar({
|
||||
</nav>
|
||||
</div>
|
||||
<div
|
||||
ref={navMobileRef}
|
||||
className={cn(
|
||||
"fixed nav-mobile inset-x-0 z-40 flex h-[calc(100dvh-58px)] flex-col overflow-x-hidden overflow-y-auto bg-[#000000] px-4 pb-8 font-mono uppercase transition-all duration-300 md:px-(--page-pad) lg:top-5",
|
||||
"fixed inset-x-0 z-40 flex h-[calc(100dvh-58px)] flex-col overflow-x-hidden overflow-y-auto bg-[#000000] px-4 pb-8 font-mono uppercase md:px-(--page-pad) lg:top-5",
|
||||
scrolled && !recoilHidden
|
||||
? "top-[58px] sm:top-[60px]"
|
||||
: "top-[66px] sm:top-[62px]",
|
||||
@@ -414,6 +299,7 @@ export default function Navbar({
|
||||
opacity: 0,
|
||||
pointerEvents: "none",
|
||||
clipPath: "inset(0% 0 100% 0)",
|
||||
transition: "opacity 0.2s ease, clip-path 0.2s cubic-bezier(0.87, 0, 0.13, 1)",
|
||||
}}
|
||||
>
|
||||
{/* Nav items */}
|
||||
|
||||
@@ -66,9 +66,16 @@ export default function SolutionAnimation() {
|
||||
// Defer the 1.4–2.1 MB Lottie JSON fetch until the element is close to
|
||||
// the viewport. Without this the browser fetches it during initial load
|
||||
// and blocks the main thread while parsing the large JSON blob.
|
||||
if (!("IntersectionObserver" in window)) {
|
||||
initAnimation();
|
||||
return;
|
||||
}
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
if (entries[0].isIntersecting) {
|
||||
// intersectionRatio > 0 guards against a Safari bug where
|
||||
// isIntersecting fires as false on the initial sync callback.
|
||||
if (entries[0].isIntersecting || entries[0].intersectionRatio > 0) {
|
||||
observer.disconnect();
|
||||
initAnimation();
|
||||
}
|
||||
|
||||
10
apps/website/lib/lazyGsap.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
// Loads GSAP exactly once — first call triggers the dynamic import,
|
||||
// subsequent calls reuse the same promise.
|
||||
type Gsap = (typeof import("gsap"))["default"];
|
||||
|
||||
let promise: Promise<Gsap> | null = null;
|
||||
|
||||
export const getGsap = (): Promise<Gsap> => {
|
||||
if (!promise) promise = import("gsap").then((m) => m.default);
|
||||
return promise;
|
||||
};
|
||||
@@ -7,13 +7,13 @@ const nextConfig = {
|
||||
pageExtensions: ["ts", "tsx", "md", "mdx"],
|
||||
allowedDevOrigins: ["*.ngrok-free.dev"],
|
||||
experimental: {
|
||||
optimizePackageImports: ["framer-motion", "motion", "gsap", "@gsap/react"],
|
||||
optimizePackageImports: ["motion", "gsap", "@gsap/react"],
|
||||
optimizeCss: true,
|
||||
},
|
||||
images: {
|
||||
// Serve AVIF to supporting browsers (better compression than WebP),
|
||||
// falling back to WebP. Next.js negotiates via Accept header automatically.
|
||||
// formats: ["image/avif", "image/webp"],
|
||||
formats: ["image/avif", "image/webp"],
|
||||
},
|
||||
async headers() {
|
||||
if (!isProd) return [];
|
||||
|
||||
@@ -16,12 +16,9 @@
|
||||
"@next/mdx": "^16.2.4",
|
||||
"@types/react": "^19.2.14",
|
||||
"@vercel/analytics": "^2.0.1",
|
||||
"framer-motion": "^12.38.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"gsap": "^3.15.0",
|
||||
"lottie-react": "^2.4.1",
|
||||
"lottie-web": "^5.13.0",
|
||||
"matter-js": "^0.20.0",
|
||||
"motion": "^12.38.0",
|
||||
"next": "16.2.4",
|
||||
"ngrok": "^5.0.0-beta.2",
|
||||
|
||||
|
Before Width: | Height: | Size: 884 KiB |
|
Before Width: | Height: | Size: 22 MiB |
|
Before Width: | Height: | Size: 226 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 21 KiB |
BIN
apps/website/public/images/navbar/autumnicon.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
4
apps/website/public/images/navbar/autumnicon.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="28" height="28" fill="white"/>
|
||||
<path d="M10.7139 9.06887C9.77726 11.211 8.84052 13.3532 7.90386 15.4953C8.63795 16.4465 9.37205 17.3984 10.1061 18.3496C12.2827 15.537 14.4599 12.7244 16.637 9.91183L9.27077 22.9514C12.9161 20.7518 16.5615 18.5529 20.2069 16.3534V4.85034L10.7139 9.06887Z" fill="#8838FF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 421 B |
|
Before Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 996 KiB |
20
bun.lock
@@ -26,6 +26,7 @@
|
||||
"inquirer": "^12.10.0",
|
||||
"knip": "^6.7.0",
|
||||
"ts-to-zod": "^5.1.0",
|
||||
"turbo": "^2.9.6",
|
||||
},
|
||||
},
|
||||
"apps/checkout": {
|
||||
@@ -115,12 +116,9 @@
|
||||
"@next/mdx": "^16.2.4",
|
||||
"@types/react": "^19.2.14",
|
||||
"@vercel/analytics": "^2.0.1",
|
||||
"framer-motion": "^12.38.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"gsap": "^3.15.0",
|
||||
"lottie-react": "^2.4.1",
|
||||
"lottie-web": "^5.13.0",
|
||||
"matter-js": "^0.20.0",
|
||||
"motion": "^12.38.0",
|
||||
"next": "16.2.4",
|
||||
"ngrok": "^5.0.0-beta.2",
|
||||
@@ -2174,6 +2172,18 @@
|
||||
|
||||
"@tsconfig/node16": ["@tsconfig/node16@1.0.4", "", {}, "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA=="],
|
||||
|
||||
"@turbo/darwin-64": ["@turbo/darwin-64@2.9.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-X/56SnVXIQZBLKwniGTwEQTGmtE5brSACnKMBWpY3YafuxVYefrC2acamfjgxP7BG5w3I+6jf0UrLoSzgPcSJg=="],
|
||||
|
||||
"@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.9.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-aalBeSl4agT/QtYGDyf/XLajedWzUC9Vg/pm/YO6QQ93vkQ91Vz5uK1ta5RbVRDozQSz4njxUNqRNmOXDzW+qw=="],
|
||||
|
||||
"@turbo/linux-64": ["@turbo/linux-64@2.9.6", "", { "os": "linux", "cpu": "x64" }, "sha512-YKi05jnNHaD7vevgYwahpzGwbsNNTwzU2c7VZdmdFm7+cGDP4oREUWSsainiMfRqjRuolQxBwRn8wf1jmu+YZA=="],
|
||||
|
||||
"@turbo/linux-arm64": ["@turbo/linux-arm64@2.9.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-02o/ZS69cOYEDczXvOB2xmyrtzjQ2hVFtWZK1iqxXUfzMmTjZK4UumrfNnjckSg+gqeBfnPRHa0NstA173Ik3g=="],
|
||||
|
||||
"@turbo/windows-64": ["@turbo/windows-64@2.9.6", "", { "os": "win32", "cpu": "x64" }, "sha512-wVdQjvnBI15wB6JrA+43CtUtagjIMmX6XYO758oZHAsCNSxqRlJtdyujih0D8OCnwCRWiGWGI63zAxR0hO6s9g=="],
|
||||
|
||||
"@turbo/windows-arm64": ["@turbo/windows-arm64@2.9.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-1XUUyWW0W6FTSqGEhU8RHVqb2wP1SPkr7hIvBlMEwH9jr+sJQK5kqeosLJ/QaUv4ecSAd1ZhIrLoW7qslAzT4A=="],
|
||||
|
||||
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
|
||||
|
||||
"@types/acorn": ["@types/acorn@4.0.6", "", { "dependencies": { "@types/estree": "*" } }, "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ=="],
|
||||
@@ -4228,8 +4238,6 @@
|
||||
|
||||
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||
|
||||
"matter-js": ["matter-js@0.20.0", "", {}, "sha512-iC9fYR7zVT3HppNnsFsp9XOoQdQN2tUyfaKg4CHLH8bN+j6GT4Gw7IH2rP0tflAebrHFw730RR3DkVSZRX8hwA=="],
|
||||
|
||||
"md-to-react-email": ["md-to-react-email@5.0.6", "", { "dependencies": { "marked": "7.0.4" }, "peerDependencies": { "react": "^18.0 || ^19.0" } }, "sha512-lKaTJqpmO88JdE3FnE7V1dtS+ta0ORyKTRhk/YoCRmeE9LozyfR2ashnUW0p0hK13VnF2TqZURXtSwgyh0zZkA=="],
|
||||
|
||||
"md5-hex": ["md5-hex@3.0.1", "", { "dependencies": { "blueimp-md5": "^2.10.0" } }, "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw=="],
|
||||
@@ -5446,6 +5454,8 @@
|
||||
|
||||
"tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="],
|
||||
|
||||
"turbo": ["turbo@2.9.6", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.6", "@turbo/darwin-arm64": "2.9.6", "@turbo/linux-64": "2.9.6", "@turbo/linux-arm64": "2.9.6", "@turbo/windows-64": "2.9.6", "@turbo/windows-arm64": "2.9.6" }, "bin": { "turbo": "bin/turbo" } }, "sha512-+v2QJey7ZUeUiuigkU+uFfklvNUyPI2VO2vBpMYJA+a1hKFLFiKtUYlRHdb3P9CrAvMzi0upbjI4WT+zKtqkBg=="],
|
||||
|
||||
"tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="],
|
||||
|
||||
"twoslash": ["twoslash@0.3.8", "", { "dependencies": { "@typescript/vfs": "^1.6.4", "twoslash-protocol": "0.3.8" }, "peerDependencies": { "typescript": "^5.5.0 || ^6.0.0" } }, "sha512-OeDz0kDl8sqPUN3nr7gqcvOs70f5lZsdhKYTX3/SgB9OvdadzzoYJI/4SBXhXV1HG8E9fLc+e17itoRYTxmoig=="],
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"enumMembers",
|
||||
"duplicates"
|
||||
],
|
||||
"ignore": ["ai/**", "others/**"],
|
||||
"ignoreWorkspaces": [
|
||||
"packages/atmn",
|
||||
"packages/autumn-js",
|
||||
@@ -63,7 +64,12 @@
|
||||
"project": ["**/*.{ts,tsx}"]
|
||||
},
|
||||
"apps/website": {
|
||||
"entry": ["app/**/*.{ts,tsx,mdx}", "components/**/*.{ts,tsx}", "content/**/*.mdx", "*.mjs"],
|
||||
"entry": [
|
||||
"app/**/*.{ts,tsx,mdx}",
|
||||
"components/**/*.{ts,tsx}",
|
||||
"content/**/*.mdx",
|
||||
"*.mjs"
|
||||
],
|
||||
"project": ["**/*.{ts,tsx,mdx,mjs}"]
|
||||
},
|
||||
"apps/checkout": {
|
||||
|
||||
@@ -778,7 +778,9 @@ class Balances(BaseSDK):
|
||||
)
|
||||
|
||||
if utils.match_response(http_res, "200", "application/json"):
|
||||
return unmarshal_json_response(models.FinalizeLockResponse, http_res)
|
||||
return unmarshal_json_response(models.FinalizeLockResponseBody1, http_res)
|
||||
if utils.match_response(http_res, "202", "application/json"):
|
||||
return unmarshal_json_response(models.FinalizeLockResponseBody2, http_res)
|
||||
if utils.match_response(http_res, "4XX", "*"):
|
||||
http_res_text = utils.stream_to_text(http_res)
|
||||
raise errors.AutumnDefaultError(
|
||||
@@ -877,7 +879,9 @@ class Balances(BaseSDK):
|
||||
)
|
||||
|
||||
if utils.match_response(http_res, "200", "application/json"):
|
||||
return unmarshal_json_response(models.FinalizeLockResponse, http_res)
|
||||
return unmarshal_json_response(models.FinalizeLockResponseBody1, http_res)
|
||||
if utils.match_response(http_res, "202", "application/json"):
|
||||
return unmarshal_json_response(models.FinalizeLockResponseBody2, http_res)
|
||||
if utils.match_response(http_res, "4XX", "*"):
|
||||
http_res_text = await utils.stream_to_text_async(http_res)
|
||||
raise errors.AutumnDefaultError(
|
||||
|
||||
@@ -58,6 +58,7 @@ class Billing(BaseSDK):
|
||||
] = None,
|
||||
metadata: Optional[Dict[str, str]] = None,
|
||||
no_billing_changes: Optional[bool] = None,
|
||||
enable_plan_immediately: Optional[bool] = None,
|
||||
retries: OptionalNullable[utils.RetryConfig] = UNSET,
|
||||
server_url: Optional[str] = None,
|
||||
timeout_ms: Optional[int] = None,
|
||||
@@ -88,6 +89,7 @@ class Billing(BaseSDK):
|
||||
:param carry_over_usages: Whether to carry over usages from the previous plan.
|
||||
:param metadata: Key-value metadata to attach to the Stripe subscription, invoice, and checkout session created during this attach flow. Keys prefixed with 'autumn_' are reserved and will be stripped.
|
||||
:param no_billing_changes: If true, skips any billing changes for the attach operation.
|
||||
:param enable_plan_immediately: If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form.
|
||||
:param retries: Override the default retry configuration for this method
|
||||
:param server_url: Override the default server URL for this method
|
||||
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
|
||||
@@ -139,6 +141,7 @@ class Billing(BaseSDK):
|
||||
),
|
||||
metadata=metadata,
|
||||
no_billing_changes=no_billing_changes,
|
||||
enable_plan_immediately=enable_plan_immediately,
|
||||
)
|
||||
|
||||
req = self._build_request(
|
||||
@@ -249,6 +252,7 @@ class Billing(BaseSDK):
|
||||
] = None,
|
||||
metadata: Optional[Dict[str, str]] = None,
|
||||
no_billing_changes: Optional[bool] = None,
|
||||
enable_plan_immediately: Optional[bool] = None,
|
||||
retries: OptionalNullable[utils.RetryConfig] = UNSET,
|
||||
server_url: Optional[str] = None,
|
||||
timeout_ms: Optional[int] = None,
|
||||
@@ -279,6 +283,7 @@ class Billing(BaseSDK):
|
||||
:param carry_over_usages: Whether to carry over usages from the previous plan.
|
||||
:param metadata: Key-value metadata to attach to the Stripe subscription, invoice, and checkout session created during this attach flow. Keys prefixed with 'autumn_' are reserved and will be stripped.
|
||||
:param no_billing_changes: If true, skips any billing changes for the attach operation.
|
||||
:param enable_plan_immediately: If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form.
|
||||
:param retries: Override the default retry configuration for this method
|
||||
:param server_url: Override the default server URL for this method
|
||||
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
|
||||
@@ -330,6 +335,7 @@ class Billing(BaseSDK):
|
||||
),
|
||||
metadata=metadata,
|
||||
no_billing_changes=no_billing_changes,
|
||||
enable_plan_immediately=enable_plan_immediately,
|
||||
)
|
||||
|
||||
req = self._build_request_async(
|
||||
@@ -418,6 +424,7 @@ class Billing(BaseSDK):
|
||||
checkout_session_params: Optional[Dict[str, Any]] = None,
|
||||
redirect_mode: Optional[models.MultiAttachRedirectMode] = "if_required",
|
||||
new_billing_subscription: Optional[bool] = None,
|
||||
enable_plan_immediately: Optional[bool] = None,
|
||||
customer_data: Optional[
|
||||
Union[models.CustomerData, models.CustomerDataTypedDict]
|
||||
] = None,
|
||||
@@ -443,6 +450,7 @@ class Billing(BaseSDK):
|
||||
:param checkout_session_params: Additional parameters to pass into the creation of the Stripe checkout session.
|
||||
:param redirect_mode: Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects.
|
||||
:param new_billing_subscription: Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one.
|
||||
:param enable_plan_immediately: If true, the cusProducts are activated immediately even when payment is pending via Stripe checkout.
|
||||
:param customer_data: Customer details to set when creating a customer
|
||||
:param entity_data:
|
||||
:param retries: Override the default retry configuration for this method
|
||||
@@ -477,6 +485,7 @@ class Billing(BaseSDK):
|
||||
checkout_session_params=checkout_session_params,
|
||||
redirect_mode=redirect_mode,
|
||||
new_billing_subscription=new_billing_subscription,
|
||||
enable_plan_immediately=enable_plan_immediately,
|
||||
customer_data=utils.get_pydantic_model(
|
||||
customer_data, Optional[models.CustomerData]
|
||||
),
|
||||
@@ -571,6 +580,7 @@ class Billing(BaseSDK):
|
||||
checkout_session_params: Optional[Dict[str, Any]] = None,
|
||||
redirect_mode: Optional[models.MultiAttachRedirectMode] = "if_required",
|
||||
new_billing_subscription: Optional[bool] = None,
|
||||
enable_plan_immediately: Optional[bool] = None,
|
||||
customer_data: Optional[
|
||||
Union[models.CustomerData, models.CustomerDataTypedDict]
|
||||
] = None,
|
||||
@@ -596,6 +606,7 @@ class Billing(BaseSDK):
|
||||
:param checkout_session_params: Additional parameters to pass into the creation of the Stripe checkout session.
|
||||
:param redirect_mode: Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects.
|
||||
:param new_billing_subscription: Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one.
|
||||
:param enable_plan_immediately: If true, the cusProducts are activated immediately even when payment is pending via Stripe checkout.
|
||||
:param customer_data: Customer details to set when creating a customer
|
||||
:param entity_data:
|
||||
:param retries: Override the default retry configuration for this method
|
||||
@@ -630,6 +641,7 @@ class Billing(BaseSDK):
|
||||
checkout_session_params=checkout_session_params,
|
||||
redirect_mode=redirect_mode,
|
||||
new_billing_subscription=new_billing_subscription,
|
||||
enable_plan_immediately=enable_plan_immediately,
|
||||
customer_data=utils.get_pydantic_model(
|
||||
customer_data, Optional[models.CustomerData]
|
||||
),
|
||||
@@ -753,6 +765,7 @@ class Billing(BaseSDK):
|
||||
] = None,
|
||||
metadata: Optional[Dict[str, str]] = None,
|
||||
no_billing_changes: Optional[bool] = None,
|
||||
enable_plan_immediately: Optional[bool] = None,
|
||||
retries: OptionalNullable[utils.RetryConfig] = UNSET,
|
||||
server_url: Optional[str] = None,
|
||||
timeout_ms: Optional[int] = None,
|
||||
@@ -783,6 +796,7 @@ class Billing(BaseSDK):
|
||||
:param carry_over_usages: Whether to carry over usages from the previous plan.
|
||||
:param metadata: Key-value metadata to attach to the Stripe subscription, invoice, and checkout session created during this attach flow. Keys prefixed with 'autumn_' are reserved and will be stripped.
|
||||
:param no_billing_changes: If true, skips any billing changes for the attach operation.
|
||||
:param enable_plan_immediately: If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form.
|
||||
:param retries: Override the default retry configuration for this method
|
||||
:param server_url: Override the default server URL for this method
|
||||
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
|
||||
@@ -835,6 +849,7 @@ class Billing(BaseSDK):
|
||||
),
|
||||
metadata=metadata,
|
||||
no_billing_changes=no_billing_changes,
|
||||
enable_plan_immediately=enable_plan_immediately,
|
||||
)
|
||||
|
||||
req = self._build_request(
|
||||
@@ -952,6 +967,7 @@ class Billing(BaseSDK):
|
||||
] = None,
|
||||
metadata: Optional[Dict[str, str]] = None,
|
||||
no_billing_changes: Optional[bool] = None,
|
||||
enable_plan_immediately: Optional[bool] = None,
|
||||
retries: OptionalNullable[utils.RetryConfig] = UNSET,
|
||||
server_url: Optional[str] = None,
|
||||
timeout_ms: Optional[int] = None,
|
||||
@@ -982,6 +998,7 @@ class Billing(BaseSDK):
|
||||
:param carry_over_usages: Whether to carry over usages from the previous plan.
|
||||
:param metadata: Key-value metadata to attach to the Stripe subscription, invoice, and checkout session created during this attach flow. Keys prefixed with 'autumn_' are reserved and will be stripped.
|
||||
:param no_billing_changes: If true, skips any billing changes for the attach operation.
|
||||
:param enable_plan_immediately: If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form.
|
||||
:param retries: Override the default retry configuration for this method
|
||||
:param server_url: Override the default server URL for this method
|
||||
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
|
||||
@@ -1034,6 +1051,7 @@ class Billing(BaseSDK):
|
||||
),
|
||||
metadata=metadata,
|
||||
no_billing_changes=no_billing_changes,
|
||||
enable_plan_immediately=enable_plan_immediately,
|
||||
)
|
||||
|
||||
req = self._build_request_async(
|
||||
@@ -1126,6 +1144,7 @@ class Billing(BaseSDK):
|
||||
checkout_session_params: Optional[Dict[str, Any]] = None,
|
||||
redirect_mode: Optional[models.PreviewMultiAttachRedirectMode] = "if_required",
|
||||
new_billing_subscription: Optional[bool] = None,
|
||||
enable_plan_immediately: Optional[bool] = None,
|
||||
customer_data: Optional[
|
||||
Union[models.CustomerData, models.CustomerDataTypedDict]
|
||||
] = None,
|
||||
@@ -1154,6 +1173,7 @@ class Billing(BaseSDK):
|
||||
:param checkout_session_params: Additional parameters to pass into the creation of the Stripe checkout session.
|
||||
:param redirect_mode: Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects.
|
||||
:param new_billing_subscription: Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one.
|
||||
:param enable_plan_immediately: If true, the cusProducts are activated immediately even when payment is pending via Stripe checkout.
|
||||
:param customer_data: Customer details to set when creating a customer
|
||||
:param entity_data:
|
||||
:param retries: Override the default retry configuration for this method
|
||||
@@ -1188,6 +1208,7 @@ class Billing(BaseSDK):
|
||||
checkout_session_params=checkout_session_params,
|
||||
redirect_mode=redirect_mode,
|
||||
new_billing_subscription=new_billing_subscription,
|
||||
enable_plan_immediately=enable_plan_immediately,
|
||||
customer_data=utils.get_pydantic_model(
|
||||
customer_data, Optional[models.CustomerData]
|
||||
),
|
||||
@@ -1286,6 +1307,7 @@ class Billing(BaseSDK):
|
||||
checkout_session_params: Optional[Dict[str, Any]] = None,
|
||||
redirect_mode: Optional[models.PreviewMultiAttachRedirectMode] = "if_required",
|
||||
new_billing_subscription: Optional[bool] = None,
|
||||
enable_plan_immediately: Optional[bool] = None,
|
||||
customer_data: Optional[
|
||||
Union[models.CustomerData, models.CustomerDataTypedDict]
|
||||
] = None,
|
||||
@@ -1314,6 +1336,7 @@ class Billing(BaseSDK):
|
||||
:param checkout_session_params: Additional parameters to pass into the creation of the Stripe checkout session.
|
||||
:param redirect_mode: Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects.
|
||||
:param new_billing_subscription: Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one.
|
||||
:param enable_plan_immediately: If true, the cusProducts are activated immediately even when payment is pending via Stripe checkout.
|
||||
:param customer_data: Customer details to set when creating a customer
|
||||
:param entity_data:
|
||||
:param retries: Override the default retry configuration for this method
|
||||
@@ -1348,6 +1371,7 @@ class Billing(BaseSDK):
|
||||
checkout_session_params=checkout_session_params,
|
||||
redirect_mode=redirect_mode,
|
||||
new_billing_subscription=new_billing_subscription,
|
||||
enable_plan_immediately=enable_plan_immediately,
|
||||
customer_data=utils.get_pydantic_model(
|
||||
customer_data, Optional[models.CustomerData]
|
||||
),
|
||||
@@ -2308,6 +2332,7 @@ class Billing(BaseSDK):
|
||||
] = None,
|
||||
metadata: Optional[Dict[str, str]] = None,
|
||||
no_billing_changes: Optional[bool] = None,
|
||||
enable_plan_immediately: Optional[bool] = None,
|
||||
retries: OptionalNullable[utils.RetryConfig] = UNSET,
|
||||
server_url: Optional[str] = None,
|
||||
timeout_ms: Optional[int] = None,
|
||||
@@ -2332,6 +2357,7 @@ class Billing(BaseSDK):
|
||||
:param carry_over_usages: Whether to carry over usages from the previous plan.
|
||||
:param metadata: Key-value metadata to attach to the Stripe subscription, invoice, and checkout session created during this attach flow. Keys prefixed with 'autumn_' are reserved and will be stripped.
|
||||
:param no_billing_changes: If true, skips any billing changes for the attach operation.
|
||||
:param enable_plan_immediately: If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form.
|
||||
:param retries: Override the default retry configuration for this method
|
||||
:param server_url: Override the default server URL for this method
|
||||
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
|
||||
@@ -2377,6 +2403,7 @@ class Billing(BaseSDK):
|
||||
),
|
||||
metadata=metadata,
|
||||
no_billing_changes=no_billing_changes,
|
||||
enable_plan_immediately=enable_plan_immediately,
|
||||
)
|
||||
|
||||
req = self._build_request(
|
||||
@@ -2485,6 +2512,7 @@ class Billing(BaseSDK):
|
||||
] = None,
|
||||
metadata: Optional[Dict[str, str]] = None,
|
||||
no_billing_changes: Optional[bool] = None,
|
||||
enable_plan_immediately: Optional[bool] = None,
|
||||
retries: OptionalNullable[utils.RetryConfig] = UNSET,
|
||||
server_url: Optional[str] = None,
|
||||
timeout_ms: Optional[int] = None,
|
||||
@@ -2509,6 +2537,7 @@ class Billing(BaseSDK):
|
||||
:param carry_over_usages: Whether to carry over usages from the previous plan.
|
||||
:param metadata: Key-value metadata to attach to the Stripe subscription, invoice, and checkout session created during this attach flow. Keys prefixed with 'autumn_' are reserved and will be stripped.
|
||||
:param no_billing_changes: If true, skips any billing changes for the attach operation.
|
||||
:param enable_plan_immediately: If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form.
|
||||
:param retries: Override the default retry configuration for this method
|
||||
:param server_url: Override the default server URL for this method
|
||||
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
|
||||
@@ -2554,6 +2583,7 @@ class Billing(BaseSDK):
|
||||
),
|
||||
metadata=metadata,
|
||||
no_billing_changes=no_billing_changes,
|
||||
enable_plan_immediately=enable_plan_immediately,
|
||||
)
|
||||
|
||||
req = self._build_request_async(
|
||||
|
||||
@@ -158,53 +158,96 @@ if TYPE_CHECKING:
|
||||
UpdateSubscriptionParamsTypedDict,
|
||||
)
|
||||
from .checkop import (
|
||||
CheckConfig,
|
||||
CheckConfigTypedDict,
|
||||
CheckCreditSchema,
|
||||
CheckCreditSchemaTypedDict,
|
||||
CheckEnv,
|
||||
CheckFeature,
|
||||
CheckFeatureTypedDict,
|
||||
CheckFreeTrial,
|
||||
CheckFreeTrialTypedDict,
|
||||
CheckConfig1,
|
||||
CheckConfig1TypedDict,
|
||||
CheckConfig2,
|
||||
CheckConfig2TypedDict,
|
||||
CheckCreditSchema1,
|
||||
CheckCreditSchema1TypedDict,
|
||||
CheckCreditSchema2,
|
||||
CheckCreditSchema2TypedDict,
|
||||
CheckEnv1,
|
||||
CheckEnv2,
|
||||
CheckFeature1,
|
||||
CheckFeature1TypedDict,
|
||||
CheckFeature2,
|
||||
CheckFeature2TypedDict,
|
||||
CheckFreeTrial1,
|
||||
CheckFreeTrial1TypedDict,
|
||||
CheckFreeTrial2,
|
||||
CheckFreeTrial2TypedDict,
|
||||
CheckGlobals,
|
||||
CheckGlobalsTypedDict,
|
||||
CheckInterval,
|
||||
CheckItem,
|
||||
CheckItemTypedDict,
|
||||
CheckInterval1,
|
||||
CheckInterval2,
|
||||
CheckItem1,
|
||||
CheckItem1TypedDict,
|
||||
CheckItem2,
|
||||
CheckItem2TypedDict,
|
||||
CheckLock,
|
||||
CheckLockTypedDict,
|
||||
CheckOnDecrease,
|
||||
CheckOnIncrease,
|
||||
CheckOnDecrease1,
|
||||
CheckOnDecrease2,
|
||||
CheckOnIncrease1,
|
||||
CheckOnIncrease2,
|
||||
CheckParams,
|
||||
CheckParamsTypedDict,
|
||||
CheckResponse,
|
||||
CheckResponseBody1,
|
||||
CheckResponseBody1TypedDict,
|
||||
CheckResponseBody2,
|
||||
CheckResponseBody2TypedDict,
|
||||
CheckResponseTypedDict,
|
||||
CheckRollover,
|
||||
CheckRolloverTypedDict,
|
||||
CheckTierBehavior,
|
||||
ConfigDuration,
|
||||
FeatureType,
|
||||
Flag,
|
||||
FlagDisplay,
|
||||
FlagDisplayTypedDict,
|
||||
FlagType,
|
||||
FlagTypedDict,
|
||||
FreeTrialDuration,
|
||||
IncludedUsage,
|
||||
IncludedUsageTypedDict,
|
||||
Preview,
|
||||
PreviewTypedDict,
|
||||
Product,
|
||||
ProductDisplay,
|
||||
ProductDisplayTypedDict,
|
||||
ProductScenario,
|
||||
ProductType,
|
||||
ProductTypedDict,
|
||||
Properties,
|
||||
PropertiesTypedDict,
|
||||
Scenario,
|
||||
UsageModel,
|
||||
CheckRollover1,
|
||||
CheckRollover1TypedDict,
|
||||
CheckRollover2,
|
||||
CheckRollover2TypedDict,
|
||||
CheckTierBehavior1,
|
||||
CheckTierBehavior2,
|
||||
ConfigDuration1,
|
||||
ConfigDuration2,
|
||||
FeatureType1,
|
||||
FeatureType2,
|
||||
Flag1,
|
||||
Flag1TypedDict,
|
||||
Flag2,
|
||||
Flag2TypedDict,
|
||||
FlagDisplay1,
|
||||
FlagDisplay1TypedDict,
|
||||
FlagDisplay2,
|
||||
FlagDisplay2TypedDict,
|
||||
FlagType1,
|
||||
FlagType2,
|
||||
FreeTrialDuration1,
|
||||
FreeTrialDuration2,
|
||||
IncludedUsage1,
|
||||
IncludedUsage1TypedDict,
|
||||
IncludedUsage2,
|
||||
IncludedUsage2TypedDict,
|
||||
Preview1,
|
||||
Preview1TypedDict,
|
||||
Preview2,
|
||||
Preview2TypedDict,
|
||||
Product1,
|
||||
Product1TypedDict,
|
||||
Product2,
|
||||
Product2TypedDict,
|
||||
ProductDisplay1,
|
||||
ProductDisplay1TypedDict,
|
||||
ProductDisplay2,
|
||||
ProductDisplay2TypedDict,
|
||||
ProductScenario1,
|
||||
ProductScenario2,
|
||||
ProductType1,
|
||||
ProductType2,
|
||||
Properties1,
|
||||
Properties1TypedDict,
|
||||
Properties2,
|
||||
Properties2TypedDict,
|
||||
Scenario1,
|
||||
Scenario2,
|
||||
UsageModel1,
|
||||
UsageModel2,
|
||||
)
|
||||
from .createbalanceop import (
|
||||
CreateBalanceDuration,
|
||||
@@ -285,6 +328,10 @@ if TYPE_CHECKING:
|
||||
CreatePlanAttachAction,
|
||||
CreatePlanBillingMethodRequest,
|
||||
CreatePlanBillingMethodResponse,
|
||||
CreatePlanConfigRequest,
|
||||
CreatePlanConfigRequestTypedDict,
|
||||
CreatePlanConfigResponse,
|
||||
CreatePlanConfigResponseTypedDict,
|
||||
CreatePlanCreditSchema,
|
||||
CreatePlanCreditSchemaTypedDict,
|
||||
CreatePlanCustomerEligibility,
|
||||
@@ -376,11 +423,16 @@ if TYPE_CHECKING:
|
||||
CustomerFeature,
|
||||
CustomerFeatureTypedDict,
|
||||
CustomerFlagsType,
|
||||
CustomerInterval,
|
||||
CustomerInterval1,
|
||||
CustomerInterval2,
|
||||
CustomerOverageAllowed,
|
||||
CustomerOverageAllowedTypedDict,
|
||||
CustomerPurchaseLimit,
|
||||
CustomerPurchaseLimitTypedDict,
|
||||
CustomerPurchaseLimit1,
|
||||
CustomerPurchaseLimit1TypedDict,
|
||||
CustomerPurchaseLimit2,
|
||||
CustomerPurchaseLimit2TypedDict,
|
||||
CustomerPurchaseLimitUnion,
|
||||
CustomerPurchaseLimitUnionTypedDict,
|
||||
CustomerSpendLimit,
|
||||
CustomerSpendLimitTypedDict,
|
||||
CustomerStatus,
|
||||
@@ -479,6 +531,10 @@ if TYPE_CHECKING:
|
||||
FinalizeLockGlobals,
|
||||
FinalizeLockGlobalsTypedDict,
|
||||
FinalizeLockResponse,
|
||||
FinalizeLockResponseBody1,
|
||||
FinalizeLockResponseBody1TypedDict,
|
||||
FinalizeLockResponseBody2,
|
||||
FinalizeLockResponseBody2TypedDict,
|
||||
FinalizeLockResponseTypedDict,
|
||||
)
|
||||
from .getentityop import (
|
||||
@@ -553,6 +609,8 @@ if TYPE_CHECKING:
|
||||
from .getplanop import (
|
||||
GetPlanAttachAction,
|
||||
GetPlanBillingMethod,
|
||||
GetPlanConfig,
|
||||
GetPlanConfigTypedDict,
|
||||
GetPlanCreditSchema,
|
||||
GetPlanCreditSchemaTypedDict,
|
||||
GetPlanCustomerEligibility,
|
||||
@@ -611,7 +669,8 @@ if TYPE_CHECKING:
|
||||
ListCustomersFlagsTypedDict,
|
||||
ListCustomersGlobals,
|
||||
ListCustomersGlobalsTypedDict,
|
||||
ListCustomersInterval,
|
||||
ListCustomersInterval1,
|
||||
ListCustomersInterval2,
|
||||
ListCustomersList,
|
||||
ListCustomersListTypedDict,
|
||||
ListCustomersOverageAllowed,
|
||||
@@ -621,8 +680,12 @@ if TYPE_CHECKING:
|
||||
ListCustomersPlan,
|
||||
ListCustomersPlanTypedDict,
|
||||
ListCustomersPurchase,
|
||||
ListCustomersPurchaseLimit,
|
||||
ListCustomersPurchaseLimitTypedDict,
|
||||
ListCustomersPurchaseLimit1,
|
||||
ListCustomersPurchaseLimit1TypedDict,
|
||||
ListCustomersPurchaseLimit2,
|
||||
ListCustomersPurchaseLimit2TypedDict,
|
||||
ListCustomersPurchaseLimitUnion,
|
||||
ListCustomersPurchaseLimitUnionTypedDict,
|
||||
ListCustomersPurchaseTypedDict,
|
||||
ListCustomersResponse,
|
||||
ListCustomersResponseTypedDict,
|
||||
@@ -670,6 +733,8 @@ if TYPE_CHECKING:
|
||||
from .listplansop import (
|
||||
ListPlansAttachAction,
|
||||
ListPlansBillingMethod,
|
||||
ListPlansConfig,
|
||||
ListPlansConfigTypedDict,
|
||||
ListPlansCreditSchema,
|
||||
ListPlansCreditSchemaTypedDict,
|
||||
ListPlansCustomerEligibility,
|
||||
@@ -793,6 +858,8 @@ if TYPE_CHECKING:
|
||||
ItemTypedDict,
|
||||
Plan,
|
||||
PlanBillingMethod,
|
||||
PlanConfig,
|
||||
PlanConfigTypedDict,
|
||||
PlanCreditSchema,
|
||||
PlanCreditSchemaTypedDict,
|
||||
PlanDurationType,
|
||||
@@ -890,6 +957,9 @@ if TYPE_CHECKING:
|
||||
PreviewAttachResponseTypedDict,
|
||||
PreviewAttachRollover,
|
||||
PreviewAttachRolloverTypedDict,
|
||||
PreviewAttachStatus,
|
||||
PreviewAttachTax,
|
||||
PreviewAttachTaxTypedDict,
|
||||
PreviewAttachTier,
|
||||
PreviewAttachTierBehavior,
|
||||
PreviewAttachTierTypedDict,
|
||||
@@ -971,6 +1041,9 @@ if TYPE_CHECKING:
|
||||
PreviewMultiAttachRolloverTypedDict,
|
||||
PreviewMultiAttachSpendLimit,
|
||||
PreviewMultiAttachSpendLimitTypedDict,
|
||||
PreviewMultiAttachStatus,
|
||||
PreviewMultiAttachTax,
|
||||
PreviewMultiAttachTaxTypedDict,
|
||||
PreviewMultiAttachThresholdType,
|
||||
PreviewMultiAttachTier,
|
||||
PreviewMultiAttachTierBehavior,
|
||||
@@ -1124,6 +1197,10 @@ if TYPE_CHECKING:
|
||||
TrackParams,
|
||||
TrackParamsTypedDict,
|
||||
TrackResponse,
|
||||
TrackResponseBody1,
|
||||
TrackResponseBody1TypedDict,
|
||||
TrackResponseBody2,
|
||||
TrackResponseBody2TypedDict,
|
||||
TrackResponseTypedDict,
|
||||
)
|
||||
from .updatebalanceop import (
|
||||
@@ -1160,7 +1237,8 @@ if TYPE_CHECKING:
|
||||
UpdateCustomerGlobals,
|
||||
UpdateCustomerGlobalsTypedDict,
|
||||
UpdateCustomerIntervalRequest,
|
||||
UpdateCustomerIntervalResponse,
|
||||
UpdateCustomerIntervalResponse1,
|
||||
UpdateCustomerIntervalResponse2,
|
||||
UpdateCustomerOverageAllowedRequest,
|
||||
UpdateCustomerOverageAllowedRequestTypedDict,
|
||||
UpdateCustomerOverageAllowedResponse,
|
||||
@@ -1170,8 +1248,12 @@ if TYPE_CHECKING:
|
||||
UpdateCustomerPurchase,
|
||||
UpdateCustomerPurchaseLimitRequest,
|
||||
UpdateCustomerPurchaseLimitRequestTypedDict,
|
||||
UpdateCustomerPurchaseLimitResponse,
|
||||
UpdateCustomerPurchaseLimitResponseTypedDict,
|
||||
UpdateCustomerPurchaseLimitResponse1,
|
||||
UpdateCustomerPurchaseLimitResponse1TypedDict,
|
||||
UpdateCustomerPurchaseLimitResponse2,
|
||||
UpdateCustomerPurchaseLimitResponse2TypedDict,
|
||||
UpdateCustomerPurchaseLimitUnion,
|
||||
UpdateCustomerPurchaseLimitUnionTypedDict,
|
||||
UpdateCustomerPurchaseTypedDict,
|
||||
UpdateCustomerResponse,
|
||||
UpdateCustomerResponseTypedDict,
|
||||
@@ -1257,6 +1339,10 @@ if TYPE_CHECKING:
|
||||
UpdatePlanBasePriceTypedDict,
|
||||
UpdatePlanBillingMethodRequest,
|
||||
UpdatePlanBillingMethodResponse,
|
||||
UpdatePlanConfigRequest,
|
||||
UpdatePlanConfigRequestTypedDict,
|
||||
UpdatePlanConfigResponse,
|
||||
UpdatePlanConfigResponseTypedDict,
|
||||
UpdatePlanCreditSchema,
|
||||
UpdatePlanCreditSchemaTypedDict,
|
||||
UpdatePlanCustomerEligibility,
|
||||
@@ -1461,32 +1547,54 @@ __all__ = [
|
||||
"BinSize",
|
||||
"Breakdown",
|
||||
"BreakdownTypedDict",
|
||||
"CheckConfig",
|
||||
"CheckConfigTypedDict",
|
||||
"CheckCreditSchema",
|
||||
"CheckCreditSchemaTypedDict",
|
||||
"CheckEnv",
|
||||
"CheckFeature",
|
||||
"CheckFeatureTypedDict",
|
||||
"CheckFreeTrial",
|
||||
"CheckFreeTrialTypedDict",
|
||||
"CheckConfig1",
|
||||
"CheckConfig1TypedDict",
|
||||
"CheckConfig2",
|
||||
"CheckConfig2TypedDict",
|
||||
"CheckCreditSchema1",
|
||||
"CheckCreditSchema1TypedDict",
|
||||
"CheckCreditSchema2",
|
||||
"CheckCreditSchema2TypedDict",
|
||||
"CheckEnv1",
|
||||
"CheckEnv2",
|
||||
"CheckFeature1",
|
||||
"CheckFeature1TypedDict",
|
||||
"CheckFeature2",
|
||||
"CheckFeature2TypedDict",
|
||||
"CheckFreeTrial1",
|
||||
"CheckFreeTrial1TypedDict",
|
||||
"CheckFreeTrial2",
|
||||
"CheckFreeTrial2TypedDict",
|
||||
"CheckGlobals",
|
||||
"CheckGlobalsTypedDict",
|
||||
"CheckInterval",
|
||||
"CheckItem",
|
||||
"CheckItemTypedDict",
|
||||
"CheckInterval1",
|
||||
"CheckInterval2",
|
||||
"CheckItem1",
|
||||
"CheckItem1TypedDict",
|
||||
"CheckItem2",
|
||||
"CheckItem2TypedDict",
|
||||
"CheckLock",
|
||||
"CheckLockTypedDict",
|
||||
"CheckOnDecrease",
|
||||
"CheckOnIncrease",
|
||||
"CheckOnDecrease1",
|
||||
"CheckOnDecrease2",
|
||||
"CheckOnIncrease1",
|
||||
"CheckOnIncrease2",
|
||||
"CheckParams",
|
||||
"CheckParamsTypedDict",
|
||||
"CheckResponse",
|
||||
"CheckResponseBody1",
|
||||
"CheckResponseBody1TypedDict",
|
||||
"CheckResponseBody2",
|
||||
"CheckResponseBody2TypedDict",
|
||||
"CheckResponseTypedDict",
|
||||
"CheckRollover",
|
||||
"CheckRolloverTypedDict",
|
||||
"CheckTierBehavior",
|
||||
"ConfigDuration",
|
||||
"CheckRollover1",
|
||||
"CheckRollover1TypedDict",
|
||||
"CheckRollover2",
|
||||
"CheckRollover2TypedDict",
|
||||
"CheckTierBehavior1",
|
||||
"CheckTierBehavior2",
|
||||
"ConfigDuration1",
|
||||
"ConfigDuration2",
|
||||
"CreateBalanceDuration",
|
||||
"CreateBalanceGlobals",
|
||||
"CreateBalanceGlobalsTypedDict",
|
||||
@@ -1559,6 +1667,10 @@ __all__ = [
|
||||
"CreatePlanAttachAction",
|
||||
"CreatePlanBillingMethodRequest",
|
||||
"CreatePlanBillingMethodResponse",
|
||||
"CreatePlanConfigRequest",
|
||||
"CreatePlanConfigRequestTypedDict",
|
||||
"CreatePlanConfigResponse",
|
||||
"CreatePlanConfigResponseTypedDict",
|
||||
"CreatePlanCreditSchema",
|
||||
"CreatePlanCreditSchemaTypedDict",
|
||||
"CreatePlanCustomerEligibility",
|
||||
@@ -1664,11 +1776,16 @@ __all__ = [
|
||||
"CustomerFeature",
|
||||
"CustomerFeatureTypedDict",
|
||||
"CustomerFlagsType",
|
||||
"CustomerInterval",
|
||||
"CustomerInterval1",
|
||||
"CustomerInterval2",
|
||||
"CustomerOverageAllowed",
|
||||
"CustomerOverageAllowedTypedDict",
|
||||
"CustomerPurchaseLimit",
|
||||
"CustomerPurchaseLimitTypedDict",
|
||||
"CustomerPurchaseLimit1",
|
||||
"CustomerPurchaseLimit1TypedDict",
|
||||
"CustomerPurchaseLimit2",
|
||||
"CustomerPurchaseLimit2TypedDict",
|
||||
"CustomerPurchaseLimitUnion",
|
||||
"CustomerPurchaseLimitUnionTypedDict",
|
||||
"CustomerSpendLimit",
|
||||
"CustomerSpendLimitTypedDict",
|
||||
"CustomerStatus",
|
||||
@@ -1717,22 +1834,33 @@ __all__ = [
|
||||
"EventsListParams",
|
||||
"EventsListParamsTypedDict",
|
||||
"ExpiryDurationType",
|
||||
"FeatureType",
|
||||
"FeatureType1",
|
||||
"FeatureType2",
|
||||
"FinalizeBalanceParams",
|
||||
"FinalizeBalanceParamsTypedDict",
|
||||
"FinalizeLockGlobals",
|
||||
"FinalizeLockGlobalsTypedDict",
|
||||
"FinalizeLockResponse",
|
||||
"FinalizeLockResponseBody1",
|
||||
"FinalizeLockResponseBody1TypedDict",
|
||||
"FinalizeLockResponseBody2",
|
||||
"FinalizeLockResponseBody2TypedDict",
|
||||
"FinalizeLockResponseTypedDict",
|
||||
"Flag",
|
||||
"FlagDisplay",
|
||||
"FlagDisplayTypedDict",
|
||||
"FlagType",
|
||||
"FlagTypedDict",
|
||||
"Flag1",
|
||||
"Flag1TypedDict",
|
||||
"Flag2",
|
||||
"Flag2TypedDict",
|
||||
"FlagDisplay1",
|
||||
"FlagDisplay1TypedDict",
|
||||
"FlagDisplay2",
|
||||
"FlagDisplay2TypedDict",
|
||||
"FlagType1",
|
||||
"FlagType2",
|
||||
"Flags",
|
||||
"FlagsTypedDict",
|
||||
"FreeTrial",
|
||||
"FreeTrialDuration",
|
||||
"FreeTrialDuration1",
|
||||
"FreeTrialDuration2",
|
||||
"FreeTrialRequest",
|
||||
"FreeTrialRequestTypedDict",
|
||||
"FreeTrialTypedDict",
|
||||
@@ -1801,6 +1929,8 @@ __all__ = [
|
||||
"GetOrCreateCustomerUsageAlertTypedDict",
|
||||
"GetPlanAttachAction",
|
||||
"GetPlanBillingMethod",
|
||||
"GetPlanConfig",
|
||||
"GetPlanConfigTypedDict",
|
||||
"GetPlanCreditSchema",
|
||||
"GetPlanCreditSchemaTypedDict",
|
||||
"GetPlanCustomerEligibility",
|
||||
@@ -1840,8 +1970,10 @@ __all__ = [
|
||||
"GetPlanStatus",
|
||||
"GetPlanTierBehavior",
|
||||
"GetPlanType",
|
||||
"IncludedUsage",
|
||||
"IncludedUsageTypedDict",
|
||||
"IncludedUsage1",
|
||||
"IncludedUsage1TypedDict",
|
||||
"IncludedUsage2",
|
||||
"IncludedUsage2TypedDict",
|
||||
"Intent",
|
||||
"Interval",
|
||||
"IntervalTypedDict",
|
||||
@@ -1866,7 +1998,8 @@ __all__ = [
|
||||
"ListCustomersFlagsTypedDict",
|
||||
"ListCustomersGlobals",
|
||||
"ListCustomersGlobalsTypedDict",
|
||||
"ListCustomersInterval",
|
||||
"ListCustomersInterval1",
|
||||
"ListCustomersInterval2",
|
||||
"ListCustomersList",
|
||||
"ListCustomersListTypedDict",
|
||||
"ListCustomersOverageAllowed",
|
||||
@@ -1876,8 +2009,12 @@ __all__ = [
|
||||
"ListCustomersPlan",
|
||||
"ListCustomersPlanTypedDict",
|
||||
"ListCustomersPurchase",
|
||||
"ListCustomersPurchaseLimit",
|
||||
"ListCustomersPurchaseLimitTypedDict",
|
||||
"ListCustomersPurchaseLimit1",
|
||||
"ListCustomersPurchaseLimit1TypedDict",
|
||||
"ListCustomersPurchaseLimit2",
|
||||
"ListCustomersPurchaseLimit2TypedDict",
|
||||
"ListCustomersPurchaseLimitUnion",
|
||||
"ListCustomersPurchaseLimitUnionTypedDict",
|
||||
"ListCustomersPurchaseTypedDict",
|
||||
"ListCustomersResponse",
|
||||
"ListCustomersResponseTypedDict",
|
||||
@@ -1915,6 +2052,8 @@ __all__ = [
|
||||
"ListFeaturesType",
|
||||
"ListPlansAttachAction",
|
||||
"ListPlansBillingMethod",
|
||||
"ListPlansConfig",
|
||||
"ListPlansConfigTypedDict",
|
||||
"ListPlansCreditSchema",
|
||||
"ListPlansCreditSchemaTypedDict",
|
||||
"ListPlansCustomerEligibility",
|
||||
@@ -2024,6 +2163,8 @@ __all__ = [
|
||||
"OpenCustomerPortalResponseTypedDict",
|
||||
"Plan",
|
||||
"PlanBillingMethod",
|
||||
"PlanConfig",
|
||||
"PlanConfigTypedDict",
|
||||
"PlanCreditSchema",
|
||||
"PlanCreditSchemaTypedDict",
|
||||
"PlanDurationType",
|
||||
@@ -2051,7 +2192,10 @@ __all__ = [
|
||||
"PlanTierBehavior",
|
||||
"PlanType",
|
||||
"PlanTypedDict",
|
||||
"Preview",
|
||||
"Preview1",
|
||||
"Preview1TypedDict",
|
||||
"Preview2",
|
||||
"Preview2TypedDict",
|
||||
"PreviewAttachAttachDiscount",
|
||||
"PreviewAttachAttachDiscountTypedDict",
|
||||
"PreviewAttachBasePrice",
|
||||
@@ -2120,6 +2264,9 @@ __all__ = [
|
||||
"PreviewAttachResponseTypedDict",
|
||||
"PreviewAttachRollover",
|
||||
"PreviewAttachRolloverTypedDict",
|
||||
"PreviewAttachStatus",
|
||||
"PreviewAttachTax",
|
||||
"PreviewAttachTaxTypedDict",
|
||||
"PreviewAttachTier",
|
||||
"PreviewAttachTierBehavior",
|
||||
"PreviewAttachTierTypedDict",
|
||||
@@ -2199,6 +2346,9 @@ __all__ = [
|
||||
"PreviewMultiAttachRolloverTypedDict",
|
||||
"PreviewMultiAttachSpendLimit",
|
||||
"PreviewMultiAttachSpendLimitTypedDict",
|
||||
"PreviewMultiAttachStatus",
|
||||
"PreviewMultiAttachTax",
|
||||
"PreviewMultiAttachTaxTypedDict",
|
||||
"PreviewMultiAttachThresholdType",
|
||||
"PreviewMultiAttachTier",
|
||||
"PreviewMultiAttachTierBehavior",
|
||||
@@ -2211,7 +2361,6 @@ __all__ = [
|
||||
"PreviewMultiAttachUsageLineItemPeriod",
|
||||
"PreviewMultiAttachUsageLineItemPeriodTypedDict",
|
||||
"PreviewMultiAttachUsageLineItemTypedDict",
|
||||
"PreviewTypedDict",
|
||||
"PreviewUpdateAttachDiscount",
|
||||
"PreviewUpdateAttachDiscountTypedDict",
|
||||
"PreviewUpdateBasePrice",
|
||||
@@ -2285,14 +2434,22 @@ __all__ = [
|
||||
"PreviewUpdateUsageLineItemPeriodTypedDict",
|
||||
"PreviewUpdateUsageLineItemTypedDict",
|
||||
"Processor",
|
||||
"Product",
|
||||
"ProductDisplay",
|
||||
"ProductDisplayTypedDict",
|
||||
"ProductScenario",
|
||||
"ProductType",
|
||||
"ProductTypedDict",
|
||||
"Properties",
|
||||
"PropertiesTypedDict",
|
||||
"Product1",
|
||||
"Product1TypedDict",
|
||||
"Product2",
|
||||
"Product2TypedDict",
|
||||
"ProductDisplay1",
|
||||
"ProductDisplay1TypedDict",
|
||||
"ProductDisplay2",
|
||||
"ProductDisplay2TypedDict",
|
||||
"ProductScenario1",
|
||||
"ProductScenario2",
|
||||
"ProductType1",
|
||||
"ProductType2",
|
||||
"Properties1",
|
||||
"Properties1TypedDict",
|
||||
"Properties2",
|
||||
"Properties2TypedDict",
|
||||
"Purchase",
|
||||
"PurchaseTypedDict",
|
||||
"Range",
|
||||
@@ -2309,7 +2466,8 @@ __all__ = [
|
||||
"Rewards",
|
||||
"RewardsType",
|
||||
"RewardsTypedDict",
|
||||
"Scenario",
|
||||
"Scenario1",
|
||||
"Scenario2",
|
||||
"Security",
|
||||
"SecurityTypedDict",
|
||||
"SetupPaymentAttachDiscount",
|
||||
@@ -2370,6 +2528,10 @@ __all__ = [
|
||||
"TrackParams",
|
||||
"TrackParamsTypedDict",
|
||||
"TrackResponse",
|
||||
"TrackResponseBody1",
|
||||
"TrackResponseBody1TypedDict",
|
||||
"TrackResponseBody2",
|
||||
"TrackResponseBody2TypedDict",
|
||||
"TrackResponseTypedDict",
|
||||
"TrialsUsed",
|
||||
"TrialsUsedTypedDict",
|
||||
@@ -2404,7 +2566,8 @@ __all__ = [
|
||||
"UpdateCustomerGlobals",
|
||||
"UpdateCustomerGlobalsTypedDict",
|
||||
"UpdateCustomerIntervalRequest",
|
||||
"UpdateCustomerIntervalResponse",
|
||||
"UpdateCustomerIntervalResponse1",
|
||||
"UpdateCustomerIntervalResponse2",
|
||||
"UpdateCustomerOverageAllowedRequest",
|
||||
"UpdateCustomerOverageAllowedRequestTypedDict",
|
||||
"UpdateCustomerOverageAllowedResponse",
|
||||
@@ -2414,8 +2577,12 @@ __all__ = [
|
||||
"UpdateCustomerPurchase",
|
||||
"UpdateCustomerPurchaseLimitRequest",
|
||||
"UpdateCustomerPurchaseLimitRequestTypedDict",
|
||||
"UpdateCustomerPurchaseLimitResponse",
|
||||
"UpdateCustomerPurchaseLimitResponseTypedDict",
|
||||
"UpdateCustomerPurchaseLimitResponse1",
|
||||
"UpdateCustomerPurchaseLimitResponse1TypedDict",
|
||||
"UpdateCustomerPurchaseLimitResponse2",
|
||||
"UpdateCustomerPurchaseLimitResponse2TypedDict",
|
||||
"UpdateCustomerPurchaseLimitUnion",
|
||||
"UpdateCustomerPurchaseLimitUnionTypedDict",
|
||||
"UpdateCustomerPurchaseTypedDict",
|
||||
"UpdateCustomerResponse",
|
||||
"UpdateCustomerResponseTypedDict",
|
||||
@@ -2495,6 +2662,10 @@ __all__ = [
|
||||
"UpdatePlanBasePriceTypedDict",
|
||||
"UpdatePlanBillingMethodRequest",
|
||||
"UpdatePlanBillingMethodResponse",
|
||||
"UpdatePlanConfigRequest",
|
||||
"UpdatePlanConfigRequestTypedDict",
|
||||
"UpdatePlanConfigResponse",
|
||||
"UpdatePlanConfigResponseTypedDict",
|
||||
"UpdatePlanCreditSchema",
|
||||
"UpdatePlanCreditSchemaTypedDict",
|
||||
"UpdatePlanCustomerEligibility",
|
||||
@@ -2560,7 +2731,8 @@ __all__ = [
|
||||
"UpdatePlanType",
|
||||
"UpdateSubscriptionParams",
|
||||
"UpdateSubscriptionParamsTypedDict",
|
||||
"UsageModel",
|
||||
"UsageModel1",
|
||||
"UsageModel2",
|
||||
]
|
||||
|
||||
_dynamic_imports: dict[str, str] = {
|
||||
@@ -2708,53 +2880,96 @@ _dynamic_imports: dict[str, str] = {
|
||||
"BillingUpdateToTypedDict": ".billingupdateop",
|
||||
"UpdateSubscriptionParams": ".billingupdateop",
|
||||
"UpdateSubscriptionParamsTypedDict": ".billingupdateop",
|
||||
"CheckConfig": ".checkop",
|
||||
"CheckConfigTypedDict": ".checkop",
|
||||
"CheckCreditSchema": ".checkop",
|
||||
"CheckCreditSchemaTypedDict": ".checkop",
|
||||
"CheckEnv": ".checkop",
|
||||
"CheckFeature": ".checkop",
|
||||
"CheckFeatureTypedDict": ".checkop",
|
||||
"CheckFreeTrial": ".checkop",
|
||||
"CheckFreeTrialTypedDict": ".checkop",
|
||||
"CheckConfig1": ".checkop",
|
||||
"CheckConfig1TypedDict": ".checkop",
|
||||
"CheckConfig2": ".checkop",
|
||||
"CheckConfig2TypedDict": ".checkop",
|
||||
"CheckCreditSchema1": ".checkop",
|
||||
"CheckCreditSchema1TypedDict": ".checkop",
|
||||
"CheckCreditSchema2": ".checkop",
|
||||
"CheckCreditSchema2TypedDict": ".checkop",
|
||||
"CheckEnv1": ".checkop",
|
||||
"CheckEnv2": ".checkop",
|
||||
"CheckFeature1": ".checkop",
|
||||
"CheckFeature1TypedDict": ".checkop",
|
||||
"CheckFeature2": ".checkop",
|
||||
"CheckFeature2TypedDict": ".checkop",
|
||||
"CheckFreeTrial1": ".checkop",
|
||||
"CheckFreeTrial1TypedDict": ".checkop",
|
||||
"CheckFreeTrial2": ".checkop",
|
||||
"CheckFreeTrial2TypedDict": ".checkop",
|
||||
"CheckGlobals": ".checkop",
|
||||
"CheckGlobalsTypedDict": ".checkop",
|
||||
"CheckInterval": ".checkop",
|
||||
"CheckItem": ".checkop",
|
||||
"CheckItemTypedDict": ".checkop",
|
||||
"CheckInterval1": ".checkop",
|
||||
"CheckInterval2": ".checkop",
|
||||
"CheckItem1": ".checkop",
|
||||
"CheckItem1TypedDict": ".checkop",
|
||||
"CheckItem2": ".checkop",
|
||||
"CheckItem2TypedDict": ".checkop",
|
||||
"CheckLock": ".checkop",
|
||||
"CheckLockTypedDict": ".checkop",
|
||||
"CheckOnDecrease": ".checkop",
|
||||
"CheckOnIncrease": ".checkop",
|
||||
"CheckOnDecrease1": ".checkop",
|
||||
"CheckOnDecrease2": ".checkop",
|
||||
"CheckOnIncrease1": ".checkop",
|
||||
"CheckOnIncrease2": ".checkop",
|
||||
"CheckParams": ".checkop",
|
||||
"CheckParamsTypedDict": ".checkop",
|
||||
"CheckResponse": ".checkop",
|
||||
"CheckResponseBody1": ".checkop",
|
||||
"CheckResponseBody1TypedDict": ".checkop",
|
||||
"CheckResponseBody2": ".checkop",
|
||||
"CheckResponseBody2TypedDict": ".checkop",
|
||||
"CheckResponseTypedDict": ".checkop",
|
||||
"CheckRollover": ".checkop",
|
||||
"CheckRolloverTypedDict": ".checkop",
|
||||
"CheckTierBehavior": ".checkop",
|
||||
"ConfigDuration": ".checkop",
|
||||
"FeatureType": ".checkop",
|
||||
"Flag": ".checkop",
|
||||
"FlagDisplay": ".checkop",
|
||||
"FlagDisplayTypedDict": ".checkop",
|
||||
"FlagType": ".checkop",
|
||||
"FlagTypedDict": ".checkop",
|
||||
"FreeTrialDuration": ".checkop",
|
||||
"IncludedUsage": ".checkop",
|
||||
"IncludedUsageTypedDict": ".checkop",
|
||||
"Preview": ".checkop",
|
||||
"PreviewTypedDict": ".checkop",
|
||||
"Product": ".checkop",
|
||||
"ProductDisplay": ".checkop",
|
||||
"ProductDisplayTypedDict": ".checkop",
|
||||
"ProductScenario": ".checkop",
|
||||
"ProductType": ".checkop",
|
||||
"ProductTypedDict": ".checkop",
|
||||
"Properties": ".checkop",
|
||||
"PropertiesTypedDict": ".checkop",
|
||||
"Scenario": ".checkop",
|
||||
"UsageModel": ".checkop",
|
||||
"CheckRollover1": ".checkop",
|
||||
"CheckRollover1TypedDict": ".checkop",
|
||||
"CheckRollover2": ".checkop",
|
||||
"CheckRollover2TypedDict": ".checkop",
|
||||
"CheckTierBehavior1": ".checkop",
|
||||
"CheckTierBehavior2": ".checkop",
|
||||
"ConfigDuration1": ".checkop",
|
||||
"ConfigDuration2": ".checkop",
|
||||
"FeatureType1": ".checkop",
|
||||
"FeatureType2": ".checkop",
|
||||
"Flag1": ".checkop",
|
||||
"Flag1TypedDict": ".checkop",
|
||||
"Flag2": ".checkop",
|
||||
"Flag2TypedDict": ".checkop",
|
||||
"FlagDisplay1": ".checkop",
|
||||
"FlagDisplay1TypedDict": ".checkop",
|
||||
"FlagDisplay2": ".checkop",
|
||||
"FlagDisplay2TypedDict": ".checkop",
|
||||
"FlagType1": ".checkop",
|
||||
"FlagType2": ".checkop",
|
||||
"FreeTrialDuration1": ".checkop",
|
||||
"FreeTrialDuration2": ".checkop",
|
||||
"IncludedUsage1": ".checkop",
|
||||
"IncludedUsage1TypedDict": ".checkop",
|
||||
"IncludedUsage2": ".checkop",
|
||||
"IncludedUsage2TypedDict": ".checkop",
|
||||
"Preview1": ".checkop",
|
||||
"Preview1TypedDict": ".checkop",
|
||||
"Preview2": ".checkop",
|
||||
"Preview2TypedDict": ".checkop",
|
||||
"Product1": ".checkop",
|
||||
"Product1TypedDict": ".checkop",
|
||||
"Product2": ".checkop",
|
||||
"Product2TypedDict": ".checkop",
|
||||
"ProductDisplay1": ".checkop",
|
||||
"ProductDisplay1TypedDict": ".checkop",
|
||||
"ProductDisplay2": ".checkop",
|
||||
"ProductDisplay2TypedDict": ".checkop",
|
||||
"ProductScenario1": ".checkop",
|
||||
"ProductScenario2": ".checkop",
|
||||
"ProductType1": ".checkop",
|
||||
"ProductType2": ".checkop",
|
||||
"Properties1": ".checkop",
|
||||
"Properties1TypedDict": ".checkop",
|
||||
"Properties2": ".checkop",
|
||||
"Properties2TypedDict": ".checkop",
|
||||
"Scenario1": ".checkop",
|
||||
"Scenario2": ".checkop",
|
||||
"UsageModel1": ".checkop",
|
||||
"UsageModel2": ".checkop",
|
||||
"CreateBalanceDuration": ".createbalanceop",
|
||||
"CreateBalanceGlobals": ".createbalanceop",
|
||||
"CreateBalanceGlobalsTypedDict": ".createbalanceop",
|
||||
@@ -2827,6 +3042,10 @@ _dynamic_imports: dict[str, str] = {
|
||||
"CreatePlanAttachAction": ".createplanop",
|
||||
"CreatePlanBillingMethodRequest": ".createplanop",
|
||||
"CreatePlanBillingMethodResponse": ".createplanop",
|
||||
"CreatePlanConfigRequest": ".createplanop",
|
||||
"CreatePlanConfigRequestTypedDict": ".createplanop",
|
||||
"CreatePlanConfigResponse": ".createplanop",
|
||||
"CreatePlanConfigResponseTypedDict": ".createplanop",
|
||||
"CreatePlanCreditSchema": ".createplanop",
|
||||
"CreatePlanCreditSchemaTypedDict": ".createplanop",
|
||||
"CreatePlanCustomerEligibility": ".createplanop",
|
||||
@@ -2914,11 +3133,16 @@ _dynamic_imports: dict[str, str] = {
|
||||
"CustomerFeature": ".customer",
|
||||
"CustomerFeatureTypedDict": ".customer",
|
||||
"CustomerFlagsType": ".customer",
|
||||
"CustomerInterval": ".customer",
|
||||
"CustomerInterval1": ".customer",
|
||||
"CustomerInterval2": ".customer",
|
||||
"CustomerOverageAllowed": ".customer",
|
||||
"CustomerOverageAllowedTypedDict": ".customer",
|
||||
"CustomerPurchaseLimit": ".customer",
|
||||
"CustomerPurchaseLimitTypedDict": ".customer",
|
||||
"CustomerPurchaseLimit1": ".customer",
|
||||
"CustomerPurchaseLimit1TypedDict": ".customer",
|
||||
"CustomerPurchaseLimit2": ".customer",
|
||||
"CustomerPurchaseLimit2TypedDict": ".customer",
|
||||
"CustomerPurchaseLimitUnion": ".customer",
|
||||
"CustomerPurchaseLimitUnionTypedDict": ".customer",
|
||||
"CustomerSpendLimit": ".customer",
|
||||
"CustomerSpendLimitTypedDict": ".customer",
|
||||
"CustomerStatus": ".customer",
|
||||
@@ -3003,6 +3227,10 @@ _dynamic_imports: dict[str, str] = {
|
||||
"FinalizeLockGlobals": ".finalizelockop",
|
||||
"FinalizeLockGlobalsTypedDict": ".finalizelockop",
|
||||
"FinalizeLockResponse": ".finalizelockop",
|
||||
"FinalizeLockResponseBody1": ".finalizelockop",
|
||||
"FinalizeLockResponseBody1TypedDict": ".finalizelockop",
|
||||
"FinalizeLockResponseBody2": ".finalizelockop",
|
||||
"FinalizeLockResponseBody2TypedDict": ".finalizelockop",
|
||||
"FinalizeLockResponseTypedDict": ".finalizelockop",
|
||||
"GetEntityBillingControls": ".getentityop",
|
||||
"GetEntityBillingControlsTypedDict": ".getentityop",
|
||||
@@ -3069,6 +3297,8 @@ _dynamic_imports: dict[str, str] = {
|
||||
"GetOrCreateCustomerUsageAlertTypedDict": ".getorcreatecustomerop",
|
||||
"GetPlanAttachAction": ".getplanop",
|
||||
"GetPlanBillingMethod": ".getplanop",
|
||||
"GetPlanConfig": ".getplanop",
|
||||
"GetPlanConfigTypedDict": ".getplanop",
|
||||
"GetPlanCreditSchema": ".getplanop",
|
||||
"GetPlanCreditSchemaTypedDict": ".getplanop",
|
||||
"GetPlanCustomerEligibility": ".getplanop",
|
||||
@@ -3125,7 +3355,8 @@ _dynamic_imports: dict[str, str] = {
|
||||
"ListCustomersFlagsTypedDict": ".listcustomersop",
|
||||
"ListCustomersGlobals": ".listcustomersop",
|
||||
"ListCustomersGlobalsTypedDict": ".listcustomersop",
|
||||
"ListCustomersInterval": ".listcustomersop",
|
||||
"ListCustomersInterval1": ".listcustomersop",
|
||||
"ListCustomersInterval2": ".listcustomersop",
|
||||
"ListCustomersList": ".listcustomersop",
|
||||
"ListCustomersListTypedDict": ".listcustomersop",
|
||||
"ListCustomersOverageAllowed": ".listcustomersop",
|
||||
@@ -3135,8 +3366,12 @@ _dynamic_imports: dict[str, str] = {
|
||||
"ListCustomersPlan": ".listcustomersop",
|
||||
"ListCustomersPlanTypedDict": ".listcustomersop",
|
||||
"ListCustomersPurchase": ".listcustomersop",
|
||||
"ListCustomersPurchaseLimit": ".listcustomersop",
|
||||
"ListCustomersPurchaseLimitTypedDict": ".listcustomersop",
|
||||
"ListCustomersPurchaseLimit1": ".listcustomersop",
|
||||
"ListCustomersPurchaseLimit1TypedDict": ".listcustomersop",
|
||||
"ListCustomersPurchaseLimit2": ".listcustomersop",
|
||||
"ListCustomersPurchaseLimit2TypedDict": ".listcustomersop",
|
||||
"ListCustomersPurchaseLimitUnion": ".listcustomersop",
|
||||
"ListCustomersPurchaseLimitUnionTypedDict": ".listcustomersop",
|
||||
"ListCustomersPurchaseTypedDict": ".listcustomersop",
|
||||
"ListCustomersResponse": ".listcustomersop",
|
||||
"ListCustomersResponseTypedDict": ".listcustomersop",
|
||||
@@ -3178,6 +3413,8 @@ _dynamic_imports: dict[str, str] = {
|
||||
"ListFeaturesType": ".listfeaturesop",
|
||||
"ListPlansAttachAction": ".listplansop",
|
||||
"ListPlansBillingMethod": ".listplansop",
|
||||
"ListPlansConfig": ".listplansop",
|
||||
"ListPlansConfigTypedDict": ".listplansop",
|
||||
"ListPlansCreditSchema": ".listplansop",
|
||||
"ListPlansCreditSchemaTypedDict": ".listplansop",
|
||||
"ListPlansCustomerEligibility": ".listplansop",
|
||||
@@ -3295,6 +3532,8 @@ _dynamic_imports: dict[str, str] = {
|
||||
"ItemTypedDict": ".plan",
|
||||
"Plan": ".plan",
|
||||
"PlanBillingMethod": ".plan",
|
||||
"PlanConfig": ".plan",
|
||||
"PlanConfigTypedDict": ".plan",
|
||||
"PlanCreditSchema": ".plan",
|
||||
"PlanCreditSchemaTypedDict": ".plan",
|
||||
"PlanDurationType": ".plan",
|
||||
@@ -3390,6 +3629,9 @@ _dynamic_imports: dict[str, str] = {
|
||||
"PreviewAttachResponseTypedDict": ".previewattachop",
|
||||
"PreviewAttachRollover": ".previewattachop",
|
||||
"PreviewAttachRolloverTypedDict": ".previewattachop",
|
||||
"PreviewAttachStatus": ".previewattachop",
|
||||
"PreviewAttachTax": ".previewattachop",
|
||||
"PreviewAttachTaxTypedDict": ".previewattachop",
|
||||
"PreviewAttachTier": ".previewattachop",
|
||||
"PreviewAttachTierBehavior": ".previewattachop",
|
||||
"PreviewAttachTierTypedDict": ".previewattachop",
|
||||
@@ -3469,6 +3711,9 @@ _dynamic_imports: dict[str, str] = {
|
||||
"PreviewMultiAttachRolloverTypedDict": ".previewmultiattachop",
|
||||
"PreviewMultiAttachSpendLimit": ".previewmultiattachop",
|
||||
"PreviewMultiAttachSpendLimitTypedDict": ".previewmultiattachop",
|
||||
"PreviewMultiAttachStatus": ".previewmultiattachop",
|
||||
"PreviewMultiAttachTax": ".previewmultiattachop",
|
||||
"PreviewMultiAttachTaxTypedDict": ".previewmultiattachop",
|
||||
"PreviewMultiAttachThresholdType": ".previewmultiattachop",
|
||||
"PreviewMultiAttachTier": ".previewmultiattachop",
|
||||
"PreviewMultiAttachTierBehavior": ".previewmultiattachop",
|
||||
@@ -3615,6 +3860,10 @@ _dynamic_imports: dict[str, str] = {
|
||||
"TrackParams": ".trackop",
|
||||
"TrackParamsTypedDict": ".trackop",
|
||||
"TrackResponse": ".trackop",
|
||||
"TrackResponseBody1": ".trackop",
|
||||
"TrackResponseBody1TypedDict": ".trackop",
|
||||
"TrackResponseBody2": ".trackop",
|
||||
"TrackResponseBody2TypedDict": ".trackop",
|
||||
"TrackResponseTypedDict": ".trackop",
|
||||
"UpdateBalanceGlobals": ".updatebalanceop",
|
||||
"UpdateBalanceGlobalsTypedDict": ".updatebalanceop",
|
||||
@@ -3647,7 +3896,8 @@ _dynamic_imports: dict[str, str] = {
|
||||
"UpdateCustomerGlobals": ".updatecustomerop",
|
||||
"UpdateCustomerGlobalsTypedDict": ".updatecustomerop",
|
||||
"UpdateCustomerIntervalRequest": ".updatecustomerop",
|
||||
"UpdateCustomerIntervalResponse": ".updatecustomerop",
|
||||
"UpdateCustomerIntervalResponse1": ".updatecustomerop",
|
||||
"UpdateCustomerIntervalResponse2": ".updatecustomerop",
|
||||
"UpdateCustomerOverageAllowedRequest": ".updatecustomerop",
|
||||
"UpdateCustomerOverageAllowedRequestTypedDict": ".updatecustomerop",
|
||||
"UpdateCustomerOverageAllowedResponse": ".updatecustomerop",
|
||||
@@ -3657,8 +3907,12 @@ _dynamic_imports: dict[str, str] = {
|
||||
"UpdateCustomerPurchase": ".updatecustomerop",
|
||||
"UpdateCustomerPurchaseLimitRequest": ".updatecustomerop",
|
||||
"UpdateCustomerPurchaseLimitRequestTypedDict": ".updatecustomerop",
|
||||
"UpdateCustomerPurchaseLimitResponse": ".updatecustomerop",
|
||||
"UpdateCustomerPurchaseLimitResponseTypedDict": ".updatecustomerop",
|
||||
"UpdateCustomerPurchaseLimitResponse1": ".updatecustomerop",
|
||||
"UpdateCustomerPurchaseLimitResponse1TypedDict": ".updatecustomerop",
|
||||
"UpdateCustomerPurchaseLimitResponse2": ".updatecustomerop",
|
||||
"UpdateCustomerPurchaseLimitResponse2TypedDict": ".updatecustomerop",
|
||||
"UpdateCustomerPurchaseLimitUnion": ".updatecustomerop",
|
||||
"UpdateCustomerPurchaseLimitUnionTypedDict": ".updatecustomerop",
|
||||
"UpdateCustomerPurchaseTypedDict": ".updatecustomerop",
|
||||
"UpdateCustomerResponse": ".updatecustomerop",
|
||||
"UpdateCustomerResponseTypedDict": ".updatecustomerop",
|
||||
@@ -3738,6 +3992,10 @@ _dynamic_imports: dict[str, str] = {
|
||||
"UpdatePlanBasePriceTypedDict": ".updateplanop",
|
||||
"UpdatePlanBillingMethodRequest": ".updateplanop",
|
||||
"UpdatePlanBillingMethodResponse": ".updateplanop",
|
||||
"UpdatePlanConfigRequest": ".updateplanop",
|
||||
"UpdatePlanConfigRequestTypedDict": ".updateplanop",
|
||||
"UpdatePlanConfigResponse": ".updateplanop",
|
||||
"UpdatePlanConfigResponseTypedDict": ".updateplanop",
|
||||
"UpdatePlanCreditSchema": ".updateplanop",
|
||||
"UpdatePlanCreditSchemaTypedDict": ".updateplanop",
|
||||
"UpdatePlanCustomerEligibility": ".updateplanop",
|
||||
|
||||
@@ -793,6 +793,8 @@ class AttachParamsTypedDict(TypedDict):
|
||||
r"""Key-value metadata to attach to the Stripe subscription, invoice, and checkout session created during this attach flow. Keys prefixed with 'autumn_' are reserved and will be stripped."""
|
||||
no_billing_changes: NotRequired[bool]
|
||||
r"""If true, skips any billing changes for the attach operation."""
|
||||
enable_plan_immediately: NotRequired[bool]
|
||||
r"""If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form."""
|
||||
|
||||
|
||||
class AttachParams(BaseModel):
|
||||
@@ -865,6 +867,9 @@ class AttachParams(BaseModel):
|
||||
no_billing_changes: Optional[bool] = None
|
||||
r"""If true, skips any billing changes for the attach operation."""
|
||||
|
||||
enable_plan_immediately: Optional[bool] = None
|
||||
r"""If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
optional_fields = set(
|
||||
@@ -889,6 +894,7 @@ class AttachParams(BaseModel):
|
||||
"carry_over_usages",
|
||||
"metadata",
|
||||
"no_billing_changes",
|
||||
"enable_plan_immediately",
|
||||
]
|
||||
)
|
||||
serialized = handler(self)
|
||||
|
||||
@@ -476,6 +476,36 @@ class FreeTrialRequest(BaseModel):
|
||||
return m
|
||||
|
||||
|
||||
class CreatePlanConfigRequestTypedDict(TypedDict):
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
ignore_past_due: NotRequired[bool]
|
||||
r"""If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state."""
|
||||
|
||||
|
||||
class CreatePlanConfigRequest(BaseModel):
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
ignore_past_due: Optional[bool] = False
|
||||
r"""If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
optional_fields = set(["ignore_past_due"])
|
||||
serialized = handler(self)
|
||||
m = {}
|
||||
|
||||
for n, f in type(self).model_fields.items():
|
||||
k = f.alias or n
|
||||
val = serialized.get(k, serialized.get(n))
|
||||
|
||||
if val != UNSET_SENTINEL:
|
||||
if val is not None or k not in optional_fields:
|
||||
m[k] = val
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class CreatePlanParamsTypedDict(TypedDict):
|
||||
plan_id: str
|
||||
r"""The ID of the plan to create."""
|
||||
@@ -495,6 +525,8 @@ class CreatePlanParamsTypedDict(TypedDict):
|
||||
r"""Feature configurations for this plan. Each item defines included units, pricing, and reset behavior."""
|
||||
free_trial: NotRequired[FreeTrialRequestTypedDict]
|
||||
r"""Free trial configuration. Customers can try this plan before being charged."""
|
||||
config: NotRequired[CreatePlanConfigRequestTypedDict]
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
|
||||
class CreatePlanParams(BaseModel):
|
||||
@@ -525,6 +557,9 @@ class CreatePlanParams(BaseModel):
|
||||
free_trial: Optional[FreeTrialRequest] = None
|
||||
r"""Free trial configuration. Customers can try this plan before being charged."""
|
||||
|
||||
config: Optional[CreatePlanConfigRequest] = None
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
optional_fields = set(
|
||||
@@ -536,6 +571,7 @@ class CreatePlanParams(BaseModel):
|
||||
"price",
|
||||
"items",
|
||||
"free_trial",
|
||||
"config",
|
||||
]
|
||||
)
|
||||
nullable_fields = set(["description"])
|
||||
@@ -1121,6 +1157,36 @@ CreatePlanEnv = Union[
|
||||
r"""Environment this plan belongs to ('sandbox' or 'live')."""
|
||||
|
||||
|
||||
class CreatePlanConfigResponseTypedDict(TypedDict):
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
ignore_past_due: NotRequired[bool]
|
||||
r"""If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state."""
|
||||
|
||||
|
||||
class CreatePlanConfigResponse(BaseModel):
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
ignore_past_due: Optional[bool] = False
|
||||
r"""If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
optional_fields = set(["ignore_past_due"])
|
||||
serialized = handler(self)
|
||||
m = {}
|
||||
|
||||
for n, f in type(self).model_fields.items():
|
||||
k = f.alias or n
|
||||
val = serialized.get(k, serialized.get(n))
|
||||
|
||||
if val != UNSET_SENTINEL:
|
||||
if val is not None or k not in optional_fields:
|
||||
m[k] = val
|
||||
|
||||
return m
|
||||
|
||||
|
||||
CreatePlanStatus = Union[
|
||||
Literal[
|
||||
"active",
|
||||
@@ -1219,6 +1285,8 @@ class CreatePlanResponseTypedDict(TypedDict):
|
||||
r"""Whether the plan is archived. Archived plans cannot be attached to new customers."""
|
||||
base_variant_id: Nullable[str]
|
||||
r"""If this is a variant, the ID of the base plan it was created from."""
|
||||
config: CreatePlanConfigResponseTypedDict
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
free_trial: NotRequired[CreatePlanFreeTrialResponseTypedDict]
|
||||
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
|
||||
customer_eligibility: NotRequired[CreatePlanCustomerEligibilityTypedDict]
|
||||
@@ -1266,6 +1334,9 @@ class CreatePlanResponse(BaseModel):
|
||||
base_variant_id: Nullable[str]
|
||||
r"""If this is a variant, the ID of the base plan it was created from."""
|
||||
|
||||
config: CreatePlanConfigResponse
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
free_trial: Optional[CreatePlanFreeTrialResponse] = None
|
||||
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ from autumn_sdk.types import (
|
||||
)
|
||||
from pydantic import model_serializer
|
||||
from typing import Any, Dict, List, Literal, Optional, Union
|
||||
from typing_extensions import NotRequired, TypedDict
|
||||
from typing_extensions import NotRequired, TypeAliasType, TypedDict
|
||||
|
||||
|
||||
CustomerEnv = Union[
|
||||
@@ -26,7 +26,62 @@ CustomerEnv = Union[
|
||||
r"""The environment this customer was created in."""
|
||||
|
||||
|
||||
CustomerInterval = Union[
|
||||
CustomerInterval2 = Union[
|
||||
Literal[
|
||||
"hour",
|
||||
"day",
|
||||
"week",
|
||||
"month",
|
||||
],
|
||||
UnrecognizedStr,
|
||||
]
|
||||
|
||||
|
||||
class CustomerPurchaseLimit2TypedDict(TypedDict):
|
||||
interval: Nullable[CustomerInterval2]
|
||||
r"""The time interval for the purchase limit window. Null when no purchase limit is configured."""
|
||||
interval_count: Nullable[float]
|
||||
r"""Number of intervals in the purchase limit window. Null when no purchase limit is configured."""
|
||||
limit: Nullable[float]
|
||||
r"""Maximum number of auto top-ups allowed within the interval. Null when no purchase limit is configured."""
|
||||
count: float
|
||||
r"""Number of auto top-ups already consumed in the current window."""
|
||||
next_reset_at: float
|
||||
r"""Unix ms timestamp when the current purchase window ends and the count resets."""
|
||||
|
||||
|
||||
class CustomerPurchaseLimit2(BaseModel):
|
||||
interval: Nullable[CustomerInterval2]
|
||||
r"""The time interval for the purchase limit window. Null when no purchase limit is configured."""
|
||||
|
||||
interval_count: Nullable[float]
|
||||
r"""Number of intervals in the purchase limit window. Null when no purchase limit is configured."""
|
||||
|
||||
limit: Nullable[float]
|
||||
r"""Maximum number of auto top-ups allowed within the interval. Null when no purchase limit is configured."""
|
||||
|
||||
count: float
|
||||
r"""Number of auto top-ups already consumed in the current window."""
|
||||
|
||||
next_reset_at: float
|
||||
r"""Unix ms timestamp when the current purchase window ends and the count resets."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
serialized = handler(self)
|
||||
m = {}
|
||||
|
||||
for n, f in type(self).model_fields.items():
|
||||
k = f.alias or n
|
||||
val = serialized.get(k, serialized.get(n))
|
||||
|
||||
if val != UNSET_SENTINEL:
|
||||
m[k] = val
|
||||
|
||||
return m
|
||||
|
||||
|
||||
CustomerInterval1 = Union[
|
||||
Literal[
|
||||
"hour",
|
||||
"day",
|
||||
@@ -38,10 +93,8 @@ CustomerInterval = Union[
|
||||
r"""The time interval for the purchase limit window."""
|
||||
|
||||
|
||||
class CustomerPurchaseLimitTypedDict(TypedDict):
|
||||
r"""Optional rate limit to cap how often auto top-ups occur."""
|
||||
|
||||
interval: CustomerInterval
|
||||
class CustomerPurchaseLimit1TypedDict(TypedDict):
|
||||
interval: CustomerInterval1
|
||||
r"""The time interval for the purchase limit window."""
|
||||
limit: float
|
||||
r"""Maximum number of auto top-ups allowed within the interval."""
|
||||
@@ -49,10 +102,8 @@ class CustomerPurchaseLimitTypedDict(TypedDict):
|
||||
r"""Number of intervals in the purchase limit window."""
|
||||
|
||||
|
||||
class CustomerPurchaseLimit(BaseModel):
|
||||
r"""Optional rate limit to cap how often auto top-ups occur."""
|
||||
|
||||
interval: CustomerInterval
|
||||
class CustomerPurchaseLimit1(BaseModel):
|
||||
interval: CustomerInterval1
|
||||
r"""The time interval for the purchase limit window."""
|
||||
|
||||
limit: float
|
||||
@@ -78,6 +129,19 @@ class CustomerPurchaseLimit(BaseModel):
|
||||
return m
|
||||
|
||||
|
||||
CustomerPurchaseLimitUnionTypedDict = TypeAliasType(
|
||||
"CustomerPurchaseLimitUnionTypedDict",
|
||||
Union[CustomerPurchaseLimit1TypedDict, CustomerPurchaseLimit2TypedDict],
|
||||
)
|
||||
r"""Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at."""
|
||||
|
||||
|
||||
CustomerPurchaseLimitUnion = TypeAliasType(
|
||||
"CustomerPurchaseLimitUnion", Union[CustomerPurchaseLimit1, CustomerPurchaseLimit2]
|
||||
)
|
||||
r"""Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at."""
|
||||
|
||||
|
||||
class CustomerAutoTopupTypedDict(TypedDict):
|
||||
feature_id: str
|
||||
r"""The ID of the feature (credit balance) to auto top-up."""
|
||||
@@ -87,8 +151,8 @@ class CustomerAutoTopupTypedDict(TypedDict):
|
||||
r"""Amount of credits to add per auto top-up."""
|
||||
enabled: NotRequired[bool]
|
||||
r"""Whether auto top-up is enabled."""
|
||||
purchase_limit: NotRequired[CustomerPurchaseLimitTypedDict]
|
||||
r"""Optional rate limit to cap how often auto top-ups occur."""
|
||||
purchase_limit: NotRequired[CustomerPurchaseLimitUnionTypedDict]
|
||||
r"""Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at."""
|
||||
invoice_mode: NotRequired[bool]
|
||||
r"""When true, auto top-up creates a send_invoice invoice instead of auto-charging."""
|
||||
|
||||
@@ -106,8 +170,8 @@ class CustomerAutoTopup(BaseModel):
|
||||
enabled: Optional[bool] = False
|
||||
r"""Whether auto top-up is enabled."""
|
||||
|
||||
purchase_limit: Optional[CustomerPurchaseLimit] = None
|
||||
r"""Optional rate limit to cap how often auto top-ups occur."""
|
||||
purchase_limit: Optional[CustomerPurchaseLimitUnion] = None
|
||||
r"""Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at."""
|
||||
|
||||
invoice_mode: Optional[bool] = None
|
||||
r"""When true, auto top-up creates a send_invoice invoice instead of auto-charging."""
|
||||
|
||||
@@ -5,8 +5,8 @@ from autumn_sdk.types import BaseModel, UNSET_SENTINEL
|
||||
from autumn_sdk.utils import FieldMetadata, HeaderMetadata
|
||||
import pydantic
|
||||
from pydantic import model_serializer
|
||||
from typing import Any, Dict, Literal, Optional
|
||||
from typing_extensions import Annotated, NotRequired, TypedDict
|
||||
from typing import Any, Dict, Literal, Optional, Union
|
||||
from typing_extensions import Annotated, NotRequired, TypeAliasType, TypedDict
|
||||
|
||||
|
||||
class FinalizeLockGlobalsTypedDict(TypedDict):
|
||||
@@ -85,13 +85,36 @@ class FinalizeBalanceParams(BaseModel):
|
||||
return m
|
||||
|
||||
|
||||
class FinalizeLockResponseTypedDict(TypedDict):
|
||||
class FinalizeLockResponseBody2TypedDict(TypedDict):
|
||||
r"""Accepted. Autumn is experiencing degraded service from a downstream provider, so the finalize request was allowed fail-open."""
|
||||
|
||||
success: bool
|
||||
|
||||
|
||||
class FinalizeLockResponseBody2(BaseModel):
|
||||
r"""Accepted. Autumn is experiencing degraded service from a downstream provider, so the finalize request was allowed fail-open."""
|
||||
|
||||
success: bool
|
||||
|
||||
|
||||
class FinalizeLockResponseBody1TypedDict(TypedDict):
|
||||
r"""OK"""
|
||||
|
||||
success: bool
|
||||
|
||||
|
||||
class FinalizeLockResponse(BaseModel):
|
||||
class FinalizeLockResponseBody1(BaseModel):
|
||||
r"""OK"""
|
||||
|
||||
success: bool
|
||||
|
||||
|
||||
FinalizeLockResponseTypedDict = TypeAliasType(
|
||||
"FinalizeLockResponseTypedDict",
|
||||
Union[FinalizeLockResponseBody1TypedDict, FinalizeLockResponseBody2TypedDict],
|
||||
)
|
||||
|
||||
|
||||
FinalizeLockResponse = TypeAliasType(
|
||||
"FinalizeLockResponse", Union[FinalizeLockResponseBody1, FinalizeLockResponseBody2]
|
||||
)
|
||||
|
||||
@@ -635,6 +635,36 @@ GetPlanEnv = Union[
|
||||
r"""Environment this plan belongs to ('sandbox' or 'live')."""
|
||||
|
||||
|
||||
class GetPlanConfigTypedDict(TypedDict):
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
ignore_past_due: NotRequired[bool]
|
||||
r"""If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state."""
|
||||
|
||||
|
||||
class GetPlanConfig(BaseModel):
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
ignore_past_due: Optional[bool] = False
|
||||
r"""If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
optional_fields = set(["ignore_past_due"])
|
||||
serialized = handler(self)
|
||||
m = {}
|
||||
|
||||
for n, f in type(self).model_fields.items():
|
||||
k = f.alias or n
|
||||
val = serialized.get(k, serialized.get(n))
|
||||
|
||||
if val != UNSET_SENTINEL:
|
||||
if val is not None or k not in optional_fields:
|
||||
m[k] = val
|
||||
|
||||
return m
|
||||
|
||||
|
||||
GetPlanStatus = Union[
|
||||
Literal[
|
||||
"active",
|
||||
@@ -733,6 +763,8 @@ class GetPlanResponseTypedDict(TypedDict):
|
||||
r"""Whether the plan is archived. Archived plans cannot be attached to new customers."""
|
||||
base_variant_id: Nullable[str]
|
||||
r"""If this is a variant, the ID of the base plan it was created from."""
|
||||
config: GetPlanConfigTypedDict
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
free_trial: NotRequired[GetPlanFreeTrialTypedDict]
|
||||
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
|
||||
customer_eligibility: NotRequired[GetPlanCustomerEligibilityTypedDict]
|
||||
@@ -780,6 +812,9 @@ class GetPlanResponse(BaseModel):
|
||||
base_variant_id: Nullable[str]
|
||||
r"""If this is a variant, the ID of the base plan it was created from."""
|
||||
|
||||
config: GetPlanConfig
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
free_trial: Optional[GetPlanFreeTrial] = None
|
||||
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ from autumn_sdk.utils import FieldMetadata, HeaderMetadata
|
||||
import pydantic
|
||||
from pydantic import model_serializer
|
||||
from typing import Any, Dict, List, Literal, Optional, Union
|
||||
from typing_extensions import Annotated, NotRequired, TypedDict
|
||||
from typing_extensions import Annotated, NotRequired, TypeAliasType, TypedDict
|
||||
|
||||
|
||||
class ListCustomersGlobalsTypedDict(TypedDict):
|
||||
@@ -150,7 +150,62 @@ ListCustomersEnv = Union[
|
||||
r"""The environment this customer was created in."""
|
||||
|
||||
|
||||
ListCustomersInterval = Union[
|
||||
ListCustomersInterval2 = Union[
|
||||
Literal[
|
||||
"hour",
|
||||
"day",
|
||||
"week",
|
||||
"month",
|
||||
],
|
||||
UnrecognizedStr,
|
||||
]
|
||||
|
||||
|
||||
class ListCustomersPurchaseLimit2TypedDict(TypedDict):
|
||||
interval: Nullable[ListCustomersInterval2]
|
||||
r"""The time interval for the purchase limit window. Null when no purchase limit is configured."""
|
||||
interval_count: Nullable[float]
|
||||
r"""Number of intervals in the purchase limit window. Null when no purchase limit is configured."""
|
||||
limit: Nullable[float]
|
||||
r"""Maximum number of auto top-ups allowed within the interval. Null when no purchase limit is configured."""
|
||||
count: float
|
||||
r"""Number of auto top-ups already consumed in the current window."""
|
||||
next_reset_at: float
|
||||
r"""Unix ms timestamp when the current purchase window ends and the count resets."""
|
||||
|
||||
|
||||
class ListCustomersPurchaseLimit2(BaseModel):
|
||||
interval: Nullable[ListCustomersInterval2]
|
||||
r"""The time interval for the purchase limit window. Null when no purchase limit is configured."""
|
||||
|
||||
interval_count: Nullable[float]
|
||||
r"""Number of intervals in the purchase limit window. Null when no purchase limit is configured."""
|
||||
|
||||
limit: Nullable[float]
|
||||
r"""Maximum number of auto top-ups allowed within the interval. Null when no purchase limit is configured."""
|
||||
|
||||
count: float
|
||||
r"""Number of auto top-ups already consumed in the current window."""
|
||||
|
||||
next_reset_at: float
|
||||
r"""Unix ms timestamp when the current purchase window ends and the count resets."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
serialized = handler(self)
|
||||
m = {}
|
||||
|
||||
for n, f in type(self).model_fields.items():
|
||||
k = f.alias or n
|
||||
val = serialized.get(k, serialized.get(n))
|
||||
|
||||
if val != UNSET_SENTINEL:
|
||||
m[k] = val
|
||||
|
||||
return m
|
||||
|
||||
|
||||
ListCustomersInterval1 = Union[
|
||||
Literal[
|
||||
"hour",
|
||||
"day",
|
||||
@@ -162,10 +217,8 @@ ListCustomersInterval = Union[
|
||||
r"""The time interval for the purchase limit window."""
|
||||
|
||||
|
||||
class ListCustomersPurchaseLimitTypedDict(TypedDict):
|
||||
r"""Optional rate limit to cap how often auto top-ups occur."""
|
||||
|
||||
interval: ListCustomersInterval
|
||||
class ListCustomersPurchaseLimit1TypedDict(TypedDict):
|
||||
interval: ListCustomersInterval1
|
||||
r"""The time interval for the purchase limit window."""
|
||||
limit: float
|
||||
r"""Maximum number of auto top-ups allowed within the interval."""
|
||||
@@ -173,10 +226,8 @@ class ListCustomersPurchaseLimitTypedDict(TypedDict):
|
||||
r"""Number of intervals in the purchase limit window."""
|
||||
|
||||
|
||||
class ListCustomersPurchaseLimit(BaseModel):
|
||||
r"""Optional rate limit to cap how often auto top-ups occur."""
|
||||
|
||||
interval: ListCustomersInterval
|
||||
class ListCustomersPurchaseLimit1(BaseModel):
|
||||
interval: ListCustomersInterval1
|
||||
r"""The time interval for the purchase limit window."""
|
||||
|
||||
limit: float
|
||||
@@ -202,6 +253,20 @@ class ListCustomersPurchaseLimit(BaseModel):
|
||||
return m
|
||||
|
||||
|
||||
ListCustomersPurchaseLimitUnionTypedDict = TypeAliasType(
|
||||
"ListCustomersPurchaseLimitUnionTypedDict",
|
||||
Union[ListCustomersPurchaseLimit1TypedDict, ListCustomersPurchaseLimit2TypedDict],
|
||||
)
|
||||
r"""Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at."""
|
||||
|
||||
|
||||
ListCustomersPurchaseLimitUnion = TypeAliasType(
|
||||
"ListCustomersPurchaseLimitUnion",
|
||||
Union[ListCustomersPurchaseLimit1, ListCustomersPurchaseLimit2],
|
||||
)
|
||||
r"""Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at."""
|
||||
|
||||
|
||||
class ListCustomersAutoTopupTypedDict(TypedDict):
|
||||
feature_id: str
|
||||
r"""The ID of the feature (credit balance) to auto top-up."""
|
||||
@@ -211,8 +276,8 @@ class ListCustomersAutoTopupTypedDict(TypedDict):
|
||||
r"""Amount of credits to add per auto top-up."""
|
||||
enabled: NotRequired[bool]
|
||||
r"""Whether auto top-up is enabled."""
|
||||
purchase_limit: NotRequired[ListCustomersPurchaseLimitTypedDict]
|
||||
r"""Optional rate limit to cap how often auto top-ups occur."""
|
||||
purchase_limit: NotRequired[ListCustomersPurchaseLimitUnionTypedDict]
|
||||
r"""Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at."""
|
||||
invoice_mode: NotRequired[bool]
|
||||
r"""When true, auto top-up creates a send_invoice invoice instead of auto-charging."""
|
||||
|
||||
@@ -230,8 +295,8 @@ class ListCustomersAutoTopup(BaseModel):
|
||||
enabled: Optional[bool] = False
|
||||
r"""Whether auto top-up is enabled."""
|
||||
|
||||
purchase_limit: Optional[ListCustomersPurchaseLimit] = None
|
||||
r"""Optional rate limit to cap how often auto top-ups occur."""
|
||||
purchase_limit: Optional[ListCustomersPurchaseLimitUnion] = None
|
||||
r"""Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at."""
|
||||
|
||||
invoice_mode: Optional[bool] = None
|
||||
r"""When true, auto top-up creates a send_invoice invoice instead of auto-charging."""
|
||||
|
||||
@@ -640,6 +640,36 @@ ListPlansEnv = Union[
|
||||
r"""Environment this plan belongs to ('sandbox' or 'live')."""
|
||||
|
||||
|
||||
class ListPlansConfigTypedDict(TypedDict):
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
ignore_past_due: NotRequired[bool]
|
||||
r"""If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state."""
|
||||
|
||||
|
||||
class ListPlansConfig(BaseModel):
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
ignore_past_due: Optional[bool] = False
|
||||
r"""If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
optional_fields = set(["ignore_past_due"])
|
||||
serialized = handler(self)
|
||||
m = {}
|
||||
|
||||
for n, f in type(self).model_fields.items():
|
||||
k = f.alias or n
|
||||
val = serialized.get(k, serialized.get(n))
|
||||
|
||||
if val != UNSET_SENTINEL:
|
||||
if val is not None or k not in optional_fields:
|
||||
m[k] = val
|
||||
|
||||
return m
|
||||
|
||||
|
||||
ListPlansStatus = Union[
|
||||
Literal[
|
||||
"active",
|
||||
@@ -738,6 +768,8 @@ class ListPlansListTypedDict(TypedDict):
|
||||
r"""Whether the plan is archived. Archived plans cannot be attached to new customers."""
|
||||
base_variant_id: Nullable[str]
|
||||
r"""If this is a variant, the ID of the base plan it was created from."""
|
||||
config: ListPlansConfigTypedDict
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
free_trial: NotRequired[ListPlansFreeTrialTypedDict]
|
||||
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
|
||||
customer_eligibility: NotRequired[ListPlansCustomerEligibilityTypedDict]
|
||||
@@ -785,6 +817,9 @@ class ListPlansList(BaseModel):
|
||||
base_variant_id: Nullable[str]
|
||||
r"""If this is a variant, the ID of the base plan it was created from."""
|
||||
|
||||
config: ListPlansConfig
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
free_trial: Optional[ListPlansFreeTrial] = None
|
||||
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
|
||||
|
||||
|
||||
@@ -911,6 +911,8 @@ class MultiAttachParamsTypedDict(TypedDict):
|
||||
r"""Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects."""
|
||||
new_billing_subscription: NotRequired[bool]
|
||||
r"""Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one."""
|
||||
enable_plan_immediately: NotRequired[bool]
|
||||
r"""If true, the cusProducts are activated immediately even when payment is pending via Stripe checkout."""
|
||||
customer_data: NotRequired[CustomerDataTypedDict]
|
||||
r"""Customer details to set when creating a customer"""
|
||||
entity_data: NotRequired[MultiAttachEntityDataTypedDict]
|
||||
@@ -947,6 +949,9 @@ class MultiAttachParams(BaseModel):
|
||||
new_billing_subscription: Optional[bool] = None
|
||||
r"""Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one."""
|
||||
|
||||
enable_plan_immediately: Optional[bool] = None
|
||||
r"""If true, the cusProducts are activated immediately even when payment is pending via Stripe checkout."""
|
||||
|
||||
customer_data: Optional[CustomerData] = None
|
||||
r"""Customer details to set when creating a customer"""
|
||||
|
||||
@@ -964,6 +969,7 @@ class MultiAttachParams(BaseModel):
|
||||
"checkout_session_params",
|
||||
"redirect_mode",
|
||||
"new_billing_subscription",
|
||||
"enable_plan_immediately",
|
||||
"customer_data",
|
||||
"entity_data",
|
||||
]
|
||||
|
||||
@@ -574,6 +574,36 @@ PlanEnv = Union[
|
||||
r"""Environment this plan belongs to ('sandbox' or 'live')."""
|
||||
|
||||
|
||||
class PlanConfigTypedDict(TypedDict):
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
ignore_past_due: NotRequired[bool]
|
||||
r"""If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state."""
|
||||
|
||||
|
||||
class PlanConfig(BaseModel):
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
ignore_past_due: Optional[bool] = False
|
||||
r"""If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
optional_fields = set(["ignore_past_due"])
|
||||
serialized = handler(self)
|
||||
m = {}
|
||||
|
||||
for n, f in type(self).model_fields.items():
|
||||
k = f.alias or n
|
||||
val = serialized.get(k, serialized.get(n))
|
||||
|
||||
if val != UNSET_SENTINEL:
|
||||
if val is not None or k not in optional_fields:
|
||||
m[k] = val
|
||||
|
||||
return m
|
||||
|
||||
|
||||
PlanStatus = Union[
|
||||
Literal[
|
||||
"active",
|
||||
@@ -670,6 +700,8 @@ class PlanTypedDict(TypedDict):
|
||||
r"""Whether the plan is archived. Archived plans cannot be attached to new customers."""
|
||||
base_variant_id: Nullable[str]
|
||||
r"""If this is a variant, the ID of the base plan it was created from."""
|
||||
config: PlanConfigTypedDict
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
free_trial: NotRequired[FreeTrialTypedDict]
|
||||
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
|
||||
customer_eligibility: NotRequired[CustomerEligibilityTypedDict]
|
||||
@@ -715,6 +747,9 @@ class Plan(BaseModel):
|
||||
base_variant_id: Nullable[str]
|
||||
r"""If this is a variant, the ID of the base plan it was created from."""
|
||||
|
||||
config: PlanConfig
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
free_trial: Optional[FreeTrial] = None
|
||||
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
|
||||
|
||||
|
||||
@@ -794,6 +794,8 @@ class PreviewAttachParamsTypedDict(TypedDict):
|
||||
r"""Key-value metadata to attach to the Stripe subscription, invoice, and checkout session created during this attach flow. Keys prefixed with 'autumn_' are reserved and will be stripped."""
|
||||
no_billing_changes: NotRequired[bool]
|
||||
r"""If true, skips any billing changes for the attach operation."""
|
||||
enable_plan_immediately: NotRequired[bool]
|
||||
r"""If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form."""
|
||||
|
||||
|
||||
class PreviewAttachParams(BaseModel):
|
||||
@@ -866,6 +868,9 @@ class PreviewAttachParams(BaseModel):
|
||||
no_billing_changes: Optional[bool] = None
|
||||
r"""If true, skips any billing changes for the attach operation."""
|
||||
|
||||
enable_plan_immediately: Optional[bool] = None
|
||||
r"""If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
optional_fields = set(
|
||||
@@ -890,6 +895,7 @@ class PreviewAttachParams(BaseModel):
|
||||
"carry_over_usages",
|
||||
"metadata",
|
||||
"no_billing_changes",
|
||||
"enable_plan_immediately",
|
||||
]
|
||||
)
|
||||
serialized = handler(self)
|
||||
@@ -1418,6 +1424,50 @@ PreviewAttachCheckoutType = Union[
|
||||
]
|
||||
|
||||
|
||||
PreviewAttachStatus = Union[
|
||||
Literal[
|
||||
"complete",
|
||||
"incomplete",
|
||||
],
|
||||
UnrecognizedStr,
|
||||
]
|
||||
r"""Calculation status ('complete' when Stripe Tax succeeds or 'incomplete' when Stripe Tax returned 0 or errored)."""
|
||||
|
||||
|
||||
class PreviewAttachTaxTypedDict(TypedDict):
|
||||
r"""Tax preview for the immediate charge. Contact us to enable the tax flag on your organisation. Shows only with flag enabled, a Stripe customer exists and has a location."""
|
||||
|
||||
total: float
|
||||
r"""Total tax amount in major currency units."""
|
||||
amount_inclusive: float
|
||||
r"""Tax included in line item subtotals."""
|
||||
amount_exclusive: float
|
||||
r"""Tax added on top of subtotals."""
|
||||
currency: str
|
||||
r"""Three-letter currency code."""
|
||||
status: PreviewAttachStatus
|
||||
r"""Calculation status ('complete' when Stripe Tax succeeds or 'incomplete' when Stripe Tax returned 0 or errored)."""
|
||||
|
||||
|
||||
class PreviewAttachTax(BaseModel):
|
||||
r"""Tax preview for the immediate charge. Contact us to enable the tax flag on your organisation. Shows only with flag enabled, a Stripe customer exists and has a location."""
|
||||
|
||||
total: float
|
||||
r"""Total tax amount in major currency units."""
|
||||
|
||||
amount_inclusive: float
|
||||
r"""Tax included in line item subtotals."""
|
||||
|
||||
amount_exclusive: float
|
||||
r"""Tax added on top of subtotals."""
|
||||
|
||||
currency: str
|
||||
r"""Three-letter currency code."""
|
||||
|
||||
status: PreviewAttachStatus
|
||||
r"""Calculation status ('complete' when Stripe Tax succeeds or 'incomplete' when Stripe Tax returned 0 or errored)."""
|
||||
|
||||
|
||||
class PreviewAttachResponseTypedDict(TypedDict):
|
||||
r"""OK"""
|
||||
|
||||
@@ -1442,6 +1492,8 @@ class PreviewAttachResponseTypedDict(TypedDict):
|
||||
r"""Preview of the next billing cycle, if applicable. This shows what the customer will be charged in subsequent cycles."""
|
||||
expand: NotRequired[List[str]]
|
||||
r"""Expand the response with additional data."""
|
||||
tax: NotRequired[PreviewAttachTaxTypedDict]
|
||||
r"""Tax preview for the immediate charge. Contact us to enable the tax flag on your organisation. Shows only with flag enabled, a Stripe customer exists and has a location."""
|
||||
|
||||
|
||||
class PreviewAttachResponse(BaseModel):
|
||||
@@ -1479,9 +1531,12 @@ class PreviewAttachResponse(BaseModel):
|
||||
expand: Optional[List[str]] = None
|
||||
r"""Expand the response with additional data."""
|
||||
|
||||
tax: Optional[PreviewAttachTax] = None
|
||||
r"""Tax preview for the immediate charge. Contact us to enable the tax flag on your organisation. Shows only with flag enabled, a Stripe customer exists and has a location."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
optional_fields = set(["next_cycle", "expand"])
|
||||
optional_fields = set(["next_cycle", "expand", "tax"])
|
||||
nullable_fields = set(["checkout_type"])
|
||||
serialized = handler(self)
|
||||
m = {}
|
||||
|
||||
@@ -916,6 +916,8 @@ class PreviewMultiAttachParamsTypedDict(TypedDict):
|
||||
r"""Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects."""
|
||||
new_billing_subscription: NotRequired[bool]
|
||||
r"""Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one."""
|
||||
enable_plan_immediately: NotRequired[bool]
|
||||
r"""If true, the cusProducts are activated immediately even when payment is pending via Stripe checkout."""
|
||||
customer_data: NotRequired[CustomerDataTypedDict]
|
||||
r"""Customer details to set when creating a customer"""
|
||||
entity_data: NotRequired[PreviewMultiAttachEntityDataTypedDict]
|
||||
@@ -952,6 +954,9 @@ class PreviewMultiAttachParams(BaseModel):
|
||||
new_billing_subscription: Optional[bool] = None
|
||||
r"""Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one."""
|
||||
|
||||
enable_plan_immediately: Optional[bool] = None
|
||||
r"""If true, the cusProducts are activated immediately even when payment is pending via Stripe checkout."""
|
||||
|
||||
customer_data: Optional[CustomerData] = None
|
||||
r"""Customer details to set when creating a customer"""
|
||||
|
||||
@@ -969,6 +974,7 @@ class PreviewMultiAttachParams(BaseModel):
|
||||
"checkout_session_params",
|
||||
"redirect_mode",
|
||||
"new_billing_subscription",
|
||||
"enable_plan_immediately",
|
||||
"customer_data",
|
||||
"entity_data",
|
||||
]
|
||||
@@ -1508,6 +1514,50 @@ PreviewMultiAttachCheckoutType = Union[
|
||||
]
|
||||
|
||||
|
||||
PreviewMultiAttachStatus = Union[
|
||||
Literal[
|
||||
"complete",
|
||||
"incomplete",
|
||||
],
|
||||
UnrecognizedStr,
|
||||
]
|
||||
r"""Calculation status ('complete' when Stripe Tax succeeds or 'incomplete' when Stripe Tax returned 0 or errored)."""
|
||||
|
||||
|
||||
class PreviewMultiAttachTaxTypedDict(TypedDict):
|
||||
r"""Tax preview for the immediate charge. Contact us to enable the tax flag on your organisation. Shows only with flag enabled, a Stripe customer exists and has a location."""
|
||||
|
||||
total: float
|
||||
r"""Total tax amount in major currency units."""
|
||||
amount_inclusive: float
|
||||
r"""Tax included in line item subtotals."""
|
||||
amount_exclusive: float
|
||||
r"""Tax added on top of subtotals."""
|
||||
currency: str
|
||||
r"""Three-letter currency code."""
|
||||
status: PreviewMultiAttachStatus
|
||||
r"""Calculation status ('complete' when Stripe Tax succeeds or 'incomplete' when Stripe Tax returned 0 or errored)."""
|
||||
|
||||
|
||||
class PreviewMultiAttachTax(BaseModel):
|
||||
r"""Tax preview for the immediate charge. Contact us to enable the tax flag on your organisation. Shows only with flag enabled, a Stripe customer exists and has a location."""
|
||||
|
||||
total: float
|
||||
r"""Total tax amount in major currency units."""
|
||||
|
||||
amount_inclusive: float
|
||||
r"""Tax included in line item subtotals."""
|
||||
|
||||
amount_exclusive: float
|
||||
r"""Tax added on top of subtotals."""
|
||||
|
||||
currency: str
|
||||
r"""Three-letter currency code."""
|
||||
|
||||
status: PreviewMultiAttachStatus
|
||||
r"""Calculation status ('complete' when Stripe Tax succeeds or 'incomplete' when Stripe Tax returned 0 or errored)."""
|
||||
|
||||
|
||||
class PreviewMultiAttachResponseTypedDict(TypedDict):
|
||||
r"""OK"""
|
||||
|
||||
@@ -1532,6 +1582,8 @@ class PreviewMultiAttachResponseTypedDict(TypedDict):
|
||||
r"""Preview of the next billing cycle, if applicable. This shows what the customer will be charged in subsequent cycles."""
|
||||
expand: NotRequired[List[str]]
|
||||
r"""Expand the response with additional data."""
|
||||
tax: NotRequired[PreviewMultiAttachTaxTypedDict]
|
||||
r"""Tax preview for the immediate charge. Contact us to enable the tax flag on your organisation. Shows only with flag enabled, a Stripe customer exists and has a location."""
|
||||
|
||||
|
||||
class PreviewMultiAttachResponse(BaseModel):
|
||||
@@ -1569,9 +1621,12 @@ class PreviewMultiAttachResponse(BaseModel):
|
||||
expand: Optional[List[str]] = None
|
||||
r"""Expand the response with additional data."""
|
||||
|
||||
tax: Optional[PreviewMultiAttachTax] = None
|
||||
r"""Tax preview for the immediate charge. Contact us to enable the tax flag on your organisation. Shows only with flag enabled, a Stripe customer exists and has a location."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
optional_fields = set(["next_cycle", "expand"])
|
||||
optional_fields = set(["next_cycle", "expand", "tax"])
|
||||
nullable_fields = set(["checkout_type"])
|
||||
serialized = handler(self)
|
||||
m = {}
|
||||
|
||||
@@ -729,6 +729,8 @@ class SetupPaymentParamsTypedDict(TypedDict):
|
||||
r"""Key-value metadata to attach to the Stripe subscription, invoice, and checkout session created during this attach flow. Keys prefixed with 'autumn_' are reserved and will be stripped."""
|
||||
no_billing_changes: NotRequired[bool]
|
||||
r"""If true, skips any billing changes for the attach operation."""
|
||||
enable_plan_immediately: NotRequired[bool]
|
||||
r"""If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form."""
|
||||
|
||||
|
||||
class SetupPaymentParams(BaseModel):
|
||||
@@ -789,6 +791,9 @@ class SetupPaymentParams(BaseModel):
|
||||
no_billing_changes: Optional[bool] = None
|
||||
r"""If true, skips any billing changes for the attach operation."""
|
||||
|
||||
enable_plan_immediately: Optional[bool] = None
|
||||
r"""If true, the customer's plan is activated immediately even when payment is deferred (invoice mode) or pending (Stripe checkout). For Stripe checkout, the customer_product is inserted before the customer completes the hosted form."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
optional_fields = set(
|
||||
@@ -810,6 +815,7 @@ class SetupPaymentParams(BaseModel):
|
||||
"carry_over_usages",
|
||||
"metadata",
|
||||
"no_billing_changes",
|
||||
"enable_plan_immediately",
|
||||
]
|
||||
)
|
||||
serialized = handler(self)
|
||||
|
||||
@@ -7,8 +7,8 @@ from autumn_sdk.utils import FieldMetadata, HeaderMetadata, validate_const
|
||||
import pydantic
|
||||
from pydantic import model_serializer
|
||||
from pydantic.functional_validators import AfterValidator
|
||||
from typing import Any, Dict, Literal, Optional
|
||||
from typing_extensions import Annotated, NotRequired, TypedDict
|
||||
from typing import Any, Dict, Literal, Optional, Union
|
||||
from typing_extensions import Annotated, NotRequired, TypeAliasType, TypedDict
|
||||
|
||||
|
||||
class TrackGlobalsTypedDict(TypedDict):
|
||||
@@ -134,7 +134,71 @@ class TrackParams(BaseModel):
|
||||
return m
|
||||
|
||||
|
||||
class TrackResponseTypedDict(TypedDict):
|
||||
class TrackResponseBody2TypedDict(TypedDict):
|
||||
r"""Accepted. Autumn is experiencing degraded service from a downstream provider, so the event was accepted for replay and will be tracked as soon as the service is restored."""
|
||||
|
||||
customer_id: str
|
||||
r"""The ID of the customer whose usage was tracked."""
|
||||
value: float
|
||||
r"""The amount of usage that was recorded."""
|
||||
balance: Nullable[BalanceTypedDict]
|
||||
r"""The updated balance for the tracked feature. Null if tracking by event_name that affects multiple features."""
|
||||
entity_id: NotRequired[str]
|
||||
r"""The ID of the entity, if entity-scoped tracking was performed."""
|
||||
event_name: NotRequired[str]
|
||||
r"""The event name that was tracked, if event_name was used instead of feature_id."""
|
||||
balances: NotRequired[Dict[str, BalanceTypedDict]]
|
||||
r"""Map of feature_id to updated balance when tracking by event_name affects multiple features."""
|
||||
|
||||
|
||||
class TrackResponseBody2(BaseModel):
|
||||
r"""Accepted. Autumn is experiencing degraded service from a downstream provider, so the event was accepted for replay and will be tracked as soon as the service is restored."""
|
||||
|
||||
customer_id: str
|
||||
r"""The ID of the customer whose usage was tracked."""
|
||||
|
||||
value: float
|
||||
r"""The amount of usage that was recorded."""
|
||||
|
||||
balance: Nullable[Balance]
|
||||
r"""The updated balance for the tracked feature. Null if tracking by event_name that affects multiple features."""
|
||||
|
||||
entity_id: Optional[str] = None
|
||||
r"""The ID of the entity, if entity-scoped tracking was performed."""
|
||||
|
||||
event_name: Optional[str] = None
|
||||
r"""The event name that was tracked, if event_name was used instead of feature_id."""
|
||||
|
||||
balances: Optional[Dict[str, Balance]] = None
|
||||
r"""Map of feature_id to updated balance when tracking by event_name affects multiple features."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
optional_fields = set(["entity_id", "event_name", "balances"])
|
||||
nullable_fields = set(["balance"])
|
||||
serialized = handler(self)
|
||||
m = {}
|
||||
|
||||
for n, f in type(self).model_fields.items():
|
||||
k = f.alias or n
|
||||
val = serialized.get(k, serialized.get(n))
|
||||
is_nullable_and_explicitly_set = (
|
||||
k in nullable_fields
|
||||
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
|
||||
)
|
||||
|
||||
if val != UNSET_SENTINEL:
|
||||
if (
|
||||
val is not None
|
||||
or k not in optional_fields
|
||||
or is_nullable_and_explicitly_set
|
||||
):
|
||||
m[k] = val
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class TrackResponseBody1TypedDict(TypedDict):
|
||||
r"""OK"""
|
||||
|
||||
customer_id: str
|
||||
@@ -151,7 +215,7 @@ class TrackResponseTypedDict(TypedDict):
|
||||
r"""Map of feature_id to updated balance when tracking by event_name affects multiple features."""
|
||||
|
||||
|
||||
class TrackResponse(BaseModel):
|
||||
class TrackResponseBody1(BaseModel):
|
||||
r"""OK"""
|
||||
|
||||
customer_id: str
|
||||
@@ -198,6 +262,17 @@ class TrackResponse(BaseModel):
|
||||
return m
|
||||
|
||||
|
||||
TrackResponseTypedDict = TypeAliasType(
|
||||
"TrackResponseTypedDict",
|
||||
Union[TrackResponseBody1TypedDict, TrackResponseBody2TypedDict],
|
||||
)
|
||||
|
||||
|
||||
TrackResponse = TypeAliasType(
|
||||
"TrackResponse", Union[TrackResponseBody1, TrackResponseBody2]
|
||||
)
|
||||
|
||||
|
||||
try:
|
||||
TrackLock.model_rebuild()
|
||||
except NameError:
|
||||
|
||||
@@ -15,7 +15,7 @@ from autumn_sdk.utils import FieldMetadata, HeaderMetadata
|
||||
import pydantic
|
||||
from pydantic import model_serializer
|
||||
from typing import Any, Dict, List, Literal, Optional, Union
|
||||
from typing_extensions import Annotated, NotRequired, TypedDict
|
||||
from typing_extensions import Annotated, NotRequired, TypeAliasType, TypedDict
|
||||
|
||||
|
||||
class UpdateCustomerGlobalsTypedDict(TypedDict):
|
||||
@@ -447,7 +447,62 @@ UpdateCustomerEnv = Union[
|
||||
r"""The environment this customer was created in."""
|
||||
|
||||
|
||||
UpdateCustomerIntervalResponse = Union[
|
||||
UpdateCustomerIntervalResponse2 = Union[
|
||||
Literal[
|
||||
"hour",
|
||||
"day",
|
||||
"week",
|
||||
"month",
|
||||
],
|
||||
UnrecognizedStr,
|
||||
]
|
||||
|
||||
|
||||
class UpdateCustomerPurchaseLimitResponse2TypedDict(TypedDict):
|
||||
interval: Nullable[UpdateCustomerIntervalResponse2]
|
||||
r"""The time interval for the purchase limit window. Null when no purchase limit is configured."""
|
||||
interval_count: Nullable[float]
|
||||
r"""Number of intervals in the purchase limit window. Null when no purchase limit is configured."""
|
||||
limit: Nullable[float]
|
||||
r"""Maximum number of auto top-ups allowed within the interval. Null when no purchase limit is configured."""
|
||||
count: float
|
||||
r"""Number of auto top-ups already consumed in the current window."""
|
||||
next_reset_at: float
|
||||
r"""Unix ms timestamp when the current purchase window ends and the count resets."""
|
||||
|
||||
|
||||
class UpdateCustomerPurchaseLimitResponse2(BaseModel):
|
||||
interval: Nullable[UpdateCustomerIntervalResponse2]
|
||||
r"""The time interval for the purchase limit window. Null when no purchase limit is configured."""
|
||||
|
||||
interval_count: Nullable[float]
|
||||
r"""Number of intervals in the purchase limit window. Null when no purchase limit is configured."""
|
||||
|
||||
limit: Nullable[float]
|
||||
r"""Maximum number of auto top-ups allowed within the interval. Null when no purchase limit is configured."""
|
||||
|
||||
count: float
|
||||
r"""Number of auto top-ups already consumed in the current window."""
|
||||
|
||||
next_reset_at: float
|
||||
r"""Unix ms timestamp when the current purchase window ends and the count resets."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
serialized = handler(self)
|
||||
m = {}
|
||||
|
||||
for n, f in type(self).model_fields.items():
|
||||
k = f.alias or n
|
||||
val = serialized.get(k, serialized.get(n))
|
||||
|
||||
if val != UNSET_SENTINEL:
|
||||
m[k] = val
|
||||
|
||||
return m
|
||||
|
||||
|
||||
UpdateCustomerIntervalResponse1 = Union[
|
||||
Literal[
|
||||
"hour",
|
||||
"day",
|
||||
@@ -459,10 +514,8 @@ UpdateCustomerIntervalResponse = Union[
|
||||
r"""The time interval for the purchase limit window."""
|
||||
|
||||
|
||||
class UpdateCustomerPurchaseLimitResponseTypedDict(TypedDict):
|
||||
r"""Optional rate limit to cap how often auto top-ups occur."""
|
||||
|
||||
interval: UpdateCustomerIntervalResponse
|
||||
class UpdateCustomerPurchaseLimitResponse1TypedDict(TypedDict):
|
||||
interval: UpdateCustomerIntervalResponse1
|
||||
r"""The time interval for the purchase limit window."""
|
||||
limit: float
|
||||
r"""Maximum number of auto top-ups allowed within the interval."""
|
||||
@@ -470,10 +523,8 @@ class UpdateCustomerPurchaseLimitResponseTypedDict(TypedDict):
|
||||
r"""Number of intervals in the purchase limit window."""
|
||||
|
||||
|
||||
class UpdateCustomerPurchaseLimitResponse(BaseModel):
|
||||
r"""Optional rate limit to cap how often auto top-ups occur."""
|
||||
|
||||
interval: UpdateCustomerIntervalResponse
|
||||
class UpdateCustomerPurchaseLimitResponse1(BaseModel):
|
||||
interval: UpdateCustomerIntervalResponse1
|
||||
r"""The time interval for the purchase limit window."""
|
||||
|
||||
limit: float
|
||||
@@ -499,6 +550,23 @@ class UpdateCustomerPurchaseLimitResponse(BaseModel):
|
||||
return m
|
||||
|
||||
|
||||
UpdateCustomerPurchaseLimitUnionTypedDict = TypeAliasType(
|
||||
"UpdateCustomerPurchaseLimitUnionTypedDict",
|
||||
Union[
|
||||
UpdateCustomerPurchaseLimitResponse1TypedDict,
|
||||
UpdateCustomerPurchaseLimitResponse2TypedDict,
|
||||
],
|
||||
)
|
||||
r"""Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at."""
|
||||
|
||||
|
||||
UpdateCustomerPurchaseLimitUnion = TypeAliasType(
|
||||
"UpdateCustomerPurchaseLimitUnion",
|
||||
Union[UpdateCustomerPurchaseLimitResponse1, UpdateCustomerPurchaseLimitResponse2],
|
||||
)
|
||||
r"""Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at."""
|
||||
|
||||
|
||||
class UpdateCustomerAutoTopupResponseTypedDict(TypedDict):
|
||||
feature_id: str
|
||||
r"""The ID of the feature (credit balance) to auto top-up."""
|
||||
@@ -508,8 +576,8 @@ class UpdateCustomerAutoTopupResponseTypedDict(TypedDict):
|
||||
r"""Amount of credits to add per auto top-up."""
|
||||
enabled: NotRequired[bool]
|
||||
r"""Whether auto top-up is enabled."""
|
||||
purchase_limit: NotRequired[UpdateCustomerPurchaseLimitResponseTypedDict]
|
||||
r"""Optional rate limit to cap how often auto top-ups occur."""
|
||||
purchase_limit: NotRequired[UpdateCustomerPurchaseLimitUnionTypedDict]
|
||||
r"""Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at."""
|
||||
invoice_mode: NotRequired[bool]
|
||||
r"""When true, auto top-up creates a send_invoice invoice instead of auto-charging."""
|
||||
|
||||
@@ -527,8 +595,8 @@ class UpdateCustomerAutoTopupResponse(BaseModel):
|
||||
enabled: Optional[bool] = False
|
||||
r"""Whether auto top-up is enabled."""
|
||||
|
||||
purchase_limit: Optional[UpdateCustomerPurchaseLimitResponse] = None
|
||||
r"""Optional rate limit to cap how often auto top-ups occur."""
|
||||
purchase_limit: Optional[UpdateCustomerPurchaseLimitUnion] = None
|
||||
r"""Optional rate limit to cap how often auto top-ups occur. Expand billing_controls.auto_topups.purchase_limit for a count of top ups and the next_reset_at."""
|
||||
|
||||
invoice_mode: Optional[bool] = None
|
||||
r"""When true, auto top-up creates a send_invoice invoice instead of auto-charging."""
|
||||
|
||||
@@ -476,6 +476,36 @@ class UpdatePlanFreeTrialParams(BaseModel):
|
||||
return m
|
||||
|
||||
|
||||
class UpdatePlanConfigRequestTypedDict(TypedDict):
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
ignore_past_due: NotRequired[bool]
|
||||
r"""If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state."""
|
||||
|
||||
|
||||
class UpdatePlanConfigRequest(BaseModel):
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
ignore_past_due: Optional[bool] = False
|
||||
r"""If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
optional_fields = set(["ignore_past_due"])
|
||||
serialized = handler(self)
|
||||
m = {}
|
||||
|
||||
for n, f in type(self).model_fields.items():
|
||||
k = f.alias or n
|
||||
val = serialized.get(k, serialized.get(n))
|
||||
|
||||
if val != UNSET_SENTINEL:
|
||||
if val is not None or k not in optional_fields:
|
||||
m[k] = val
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class UpdatePlanParamsTypedDict(TypedDict):
|
||||
plan_id: str
|
||||
r"""The ID of the plan to update."""
|
||||
@@ -494,6 +524,8 @@ class UpdatePlanParamsTypedDict(TypedDict):
|
||||
r"""Feature configurations for this plan. Each item defines included units, pricing, and reset behavior."""
|
||||
free_trial: NotRequired[Nullable[UpdatePlanFreeTrialParamsTypedDict]]
|
||||
r"""The free trial of the plan. Set to null to remove the free trial."""
|
||||
config: NotRequired[UpdatePlanConfigRequestTypedDict]
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
version: NotRequired[float]
|
||||
archived: NotRequired[bool]
|
||||
new_plan_id: NotRequired[str]
|
||||
@@ -527,6 +559,9 @@ class UpdatePlanParams(BaseModel):
|
||||
free_trial: OptionalNullable[UpdatePlanFreeTrialParams] = UNSET
|
||||
r"""The free trial of the plan. Set to null to remove the free trial."""
|
||||
|
||||
config: Optional[UpdatePlanConfigRequest] = None
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
version: Optional[float] = None
|
||||
|
||||
archived: Optional[bool] = False
|
||||
@@ -546,6 +581,7 @@ class UpdatePlanParams(BaseModel):
|
||||
"price",
|
||||
"items",
|
||||
"free_trial",
|
||||
"config",
|
||||
"version",
|
||||
"archived",
|
||||
"new_plan_id",
|
||||
@@ -1134,6 +1170,36 @@ UpdatePlanEnv = Union[
|
||||
r"""Environment this plan belongs to ('sandbox' or 'live')."""
|
||||
|
||||
|
||||
class UpdatePlanConfigResponseTypedDict(TypedDict):
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
ignore_past_due: NotRequired[bool]
|
||||
r"""If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state."""
|
||||
|
||||
|
||||
class UpdatePlanConfigResponse(BaseModel):
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
ignore_past_due: Optional[bool] = False
|
||||
r"""If true, entitlements attached to this plan will still reset on schedule even when the customer's product is in a past_due state."""
|
||||
|
||||
@model_serializer(mode="wrap")
|
||||
def serialize_model(self, handler):
|
||||
optional_fields = set(["ignore_past_due"])
|
||||
serialized = handler(self)
|
||||
m = {}
|
||||
|
||||
for n, f in type(self).model_fields.items():
|
||||
k = f.alias or n
|
||||
val = serialized.get(k, serialized.get(n))
|
||||
|
||||
if val != UNSET_SENTINEL:
|
||||
if val is not None or k not in optional_fields:
|
||||
m[k] = val
|
||||
|
||||
return m
|
||||
|
||||
|
||||
UpdatePlanStatus = Union[
|
||||
Literal[
|
||||
"active",
|
||||
@@ -1232,6 +1298,8 @@ class UpdatePlanResponseTypedDict(TypedDict):
|
||||
r"""Whether the plan is archived. Archived plans cannot be attached to new customers."""
|
||||
base_variant_id: Nullable[str]
|
||||
r"""If this is a variant, the ID of the base plan it was created from."""
|
||||
config: UpdatePlanConfigResponseTypedDict
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
free_trial: NotRequired[UpdatePlanFreeTrialTypedDict]
|
||||
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
|
||||
customer_eligibility: NotRequired[UpdatePlanCustomerEligibilityTypedDict]
|
||||
@@ -1279,6 +1347,9 @@ class UpdatePlanResponse(BaseModel):
|
||||
base_variant_id: Nullable[str]
|
||||
r"""If this is a variant, the ID of the base plan it was created from."""
|
||||
|
||||
config: UpdatePlanConfigResponse
|
||||
r"""Miscellaneous plan-level configuration flags."""
|
||||
|
||||
free_trial: Optional[UpdatePlanFreeTrial] = None
|
||||
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
|
||||
|
||||
|
||||
@@ -30,6 +30,11 @@ class Plans(BaseSDK):
|
||||
free_trial: Optional[
|
||||
Union[models.FreeTrialRequest, models.FreeTrialRequestTypedDict]
|
||||
] = None,
|
||||
config: Optional[
|
||||
Union[
|
||||
models.CreatePlanConfigRequest, models.CreatePlanConfigRequestTypedDict
|
||||
]
|
||||
] = None,
|
||||
retries: OptionalNullable[utils.RetryConfig] = UNSET,
|
||||
server_url: Optional[str] = None,
|
||||
timeout_ms: Optional[int] = None,
|
||||
@@ -50,6 +55,7 @@ class Plans(BaseSDK):
|
||||
:param price: Base recurring price for the plan. Omit for free or usage-only plans.
|
||||
:param items: Feature configurations for this plan. Each item defines included units, pricing, and reset behavior.
|
||||
:param free_trial: Free trial configuration. Customers can try this plan before being charged.
|
||||
:param config: Miscellaneous plan-level configuration flags.
|
||||
:param retries: Override the default retry configuration for this method
|
||||
:param server_url: Override the default server URL for this method
|
||||
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
|
||||
@@ -81,6 +87,9 @@ class Plans(BaseSDK):
|
||||
free_trial=utils.get_pydantic_model(
|
||||
free_trial, Optional[models.FreeTrialRequest]
|
||||
),
|
||||
config=utils.get_pydantic_model(
|
||||
config, Optional[models.CreatePlanConfigRequest]
|
||||
),
|
||||
)
|
||||
|
||||
req = self._build_request(
|
||||
@@ -163,6 +172,11 @@ class Plans(BaseSDK):
|
||||
free_trial: Optional[
|
||||
Union[models.FreeTrialRequest, models.FreeTrialRequestTypedDict]
|
||||
] = None,
|
||||
config: Optional[
|
||||
Union[
|
||||
models.CreatePlanConfigRequest, models.CreatePlanConfigRequestTypedDict
|
||||
]
|
||||
] = None,
|
||||
retries: OptionalNullable[utils.RetryConfig] = UNSET,
|
||||
server_url: Optional[str] = None,
|
||||
timeout_ms: Optional[int] = None,
|
||||
@@ -183,6 +197,7 @@ class Plans(BaseSDK):
|
||||
:param price: Base recurring price for the plan. Omit for free or usage-only plans.
|
||||
:param items: Feature configurations for this plan. Each item defines included units, pricing, and reset behavior.
|
||||
:param free_trial: Free trial configuration. Customers can try this plan before being charged.
|
||||
:param config: Miscellaneous plan-level configuration flags.
|
||||
:param retries: Override the default retry configuration for this method
|
||||
:param server_url: Override the default server URL for this method
|
||||
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
|
||||
@@ -214,6 +229,9 @@ class Plans(BaseSDK):
|
||||
free_trial=utils.get_pydantic_model(
|
||||
free_trial, Optional[models.FreeTrialRequest]
|
||||
),
|
||||
config=utils.get_pydantic_model(
|
||||
config, Optional[models.CreatePlanConfigRequest]
|
||||
),
|
||||
)
|
||||
|
||||
req = self._build_request_async(
|
||||
@@ -685,6 +703,11 @@ class Plans(BaseSDK):
|
||||
models.UpdatePlanFreeTrialParamsTypedDict,
|
||||
]
|
||||
] = UNSET,
|
||||
config: Optional[
|
||||
Union[
|
||||
models.UpdatePlanConfigRequest, models.UpdatePlanConfigRequestTypedDict
|
||||
]
|
||||
] = None,
|
||||
version: Optional[float] = None,
|
||||
archived: Optional[bool] = False,
|
||||
new_plan_id: Optional[str] = None,
|
||||
@@ -708,6 +731,7 @@ class Plans(BaseSDK):
|
||||
:param price: The price of the plan. Set to null to remove the base price.
|
||||
:param items: Feature configurations for this plan. Each item defines included units, pricing, and reset behavior.
|
||||
:param free_trial: The free trial of the plan. Set to null to remove the free trial.
|
||||
:param config: Miscellaneous plan-level configuration flags.
|
||||
:param version:
|
||||
:param archived:
|
||||
:param new_plan_id: The new ID to use for the plan. Can only be updated if the plan has not been used by any customers.
|
||||
@@ -742,6 +766,9 @@ class Plans(BaseSDK):
|
||||
free_trial=utils.get_pydantic_model(
|
||||
free_trial, OptionalNullable[models.UpdatePlanFreeTrialParams]
|
||||
),
|
||||
config=utils.get_pydantic_model(
|
||||
config, Optional[models.UpdatePlanConfigRequest]
|
||||
),
|
||||
version=version,
|
||||
archived=archived,
|
||||
new_plan_id=new_plan_id,
|
||||
@@ -830,6 +857,11 @@ class Plans(BaseSDK):
|
||||
models.UpdatePlanFreeTrialParamsTypedDict,
|
||||
]
|
||||
] = UNSET,
|
||||
config: Optional[
|
||||
Union[
|
||||
models.UpdatePlanConfigRequest, models.UpdatePlanConfigRequestTypedDict
|
||||
]
|
||||
] = None,
|
||||
version: Optional[float] = None,
|
||||
archived: Optional[bool] = False,
|
||||
new_plan_id: Optional[str] = None,
|
||||
@@ -853,6 +885,7 @@ class Plans(BaseSDK):
|
||||
:param price: The price of the plan. Set to null to remove the base price.
|
||||
:param items: Feature configurations for this plan. Each item defines included units, pricing, and reset behavior.
|
||||
:param free_trial: The free trial of the plan. Set to null to remove the free trial.
|
||||
:param config: Miscellaneous plan-level configuration flags.
|
||||
:param version:
|
||||
:param archived:
|
||||
:param new_plan_id: The new ID to use for the plan. Can only be updated if the plan has not been used by any customers.
|
||||
@@ -887,6 +920,9 @@ class Plans(BaseSDK):
|
||||
free_trial=utils.get_pydantic_model(
|
||||
free_trial, OptionalNullable[models.UpdatePlanFreeTrialParams]
|
||||
),
|
||||
config=utils.get_pydantic_model(
|
||||
config, Optional[models.UpdatePlanConfigRequest]
|
||||
),
|
||||
version=version,
|
||||
archived=archived,
|
||||
new_plan_id=new_plan_id,
|
||||
|
||||
@@ -307,7 +307,9 @@ class Autumn(BaseSDK):
|
||||
)
|
||||
|
||||
if utils.match_response(http_res, "200", "application/json"):
|
||||
return unmarshal_json_response(models.CheckResponse, http_res)
|
||||
return unmarshal_json_response(models.CheckResponseBody1, http_res)
|
||||
if utils.match_response(http_res, "202", "application/json"):
|
||||
return unmarshal_json_response(models.CheckResponseBody2, http_res)
|
||||
if utils.match_response(http_res, "4XX", "*"):
|
||||
http_res_text = utils.stream_to_text(http_res)
|
||||
raise errors.AutumnDefaultError(
|
||||
@@ -420,7 +422,9 @@ class Autumn(BaseSDK):
|
||||
)
|
||||
|
||||
if utils.match_response(http_res, "200", "application/json"):
|
||||
return unmarshal_json_response(models.CheckResponse, http_res)
|
||||
return unmarshal_json_response(models.CheckResponseBody1, http_res)
|
||||
if utils.match_response(http_res, "202", "application/json"):
|
||||
return unmarshal_json_response(models.CheckResponseBody2, http_res)
|
||||
if utils.match_response(http_res, "4XX", "*"):
|
||||
http_res_text = await utils.stream_to_text_async(http_res)
|
||||
raise errors.AutumnDefaultError(
|
||||
@@ -530,7 +534,9 @@ class Autumn(BaseSDK):
|
||||
)
|
||||
|
||||
if utils.match_response(http_res, "200", "application/json"):
|
||||
return unmarshal_json_response(models.TrackResponse, http_res)
|
||||
return unmarshal_json_response(models.TrackResponseBody1, http_res)
|
||||
if utils.match_response(http_res, "202", "application/json"):
|
||||
return unmarshal_json_response(models.TrackResponseBody2, http_res)
|
||||
if utils.match_response(http_res, "4XX", "*"):
|
||||
http_res_text = utils.stream_to_text(http_res)
|
||||
raise errors.AutumnDefaultError(
|
||||
@@ -640,7 +646,9 @@ class Autumn(BaseSDK):
|
||||
)
|
||||
|
||||
if utils.match_response(http_res, "200", "application/json"):
|
||||
return unmarshal_json_response(models.TrackResponse, http_res)
|
||||
return unmarshal_json_response(models.TrackResponseBody1, http_res)
|
||||
if utils.match_response(http_res, "202", "application/json"):
|
||||
return unmarshal_json_response(models.TrackResponseBody2, http_res)
|
||||
if utils.match_response(http_res, "4XX", "*"):
|
||||
http_res_text = await utils.stream_to_text_async(http_res)
|
||||
raise errors.AutumnDefaultError(
|
||||
|
||||
242
others/svix-transforms/discord.ts
Normal file
@@ -0,0 +1,242 @@
|
||||
/**
|
||||
* @param webhook the webhook object
|
||||
* @param webhook.method destination method. Allowed values: "POST", "PUT"
|
||||
* @param webhook.url current destination address
|
||||
* @param webhook.eventType current webhook Event Type
|
||||
* @param webhook.payload JSON payload
|
||||
* @param webhook.cancel whether to cancel dispatch of the given webhook
|
||||
*/
|
||||
function handler(webhook) {
|
||||
var AUTUMN_BASE = "https://app.useautumn.com/customers/";
|
||||
var AUTUMN_USERNAME = "Autumn";
|
||||
var AUTUMN_AVATAR_URL = "https://i.ibb.co/BHCF1ZqL/autumnicon.png";
|
||||
|
||||
// Discord embed colors (decimal RGB).
|
||||
var COLOR_SUCCESS = 0x22c55e;
|
||||
var COLOR_INFO = 0x3b82f6;
|
||||
var COLOR_WARNING = 0xf59e0b;
|
||||
var COLOR_DANGER = 0xef4444;
|
||||
var COLOR_NEUTRAL = 0x6b7280;
|
||||
|
||||
var payload = webhook.payload || {};
|
||||
var data = payload.data || payload;
|
||||
|
||||
// ============ customer.products.updated ============
|
||||
if (webhook.eventType === "customer.products.updated") {
|
||||
var scenario = data.scenario || "updated";
|
||||
var customer = data.customer || {};
|
||||
var entity = data.entity || null;
|
||||
var product = data.updated_product || {};
|
||||
|
||||
var customerName = customer.name || customer.email || customer.id || "Customer";
|
||||
var customerEmail = customer.email || null;
|
||||
var customerId = customer.id || "";
|
||||
|
||||
var productName = product.name || "their plan";
|
||||
if (product.version && product.version !== 1) {
|
||||
productName = productName + " V" + product.version;
|
||||
}
|
||||
|
||||
var entityLabel = null;
|
||||
if (entity) {
|
||||
entityLabel = entity.name || entity.id || null;
|
||||
}
|
||||
|
||||
var emoji = "🔔";
|
||||
var header = "Subscription Updated";
|
||||
var verb = "updated";
|
||||
var color = COLOR_NEUTRAL;
|
||||
|
||||
if (scenario === "new") {
|
||||
emoji = "🎉"; header = "New Subscription"; verb = "subscribed to"; color = COLOR_SUCCESS;
|
||||
} else if (scenario === "upgrade") {
|
||||
emoji = "🚀"; header = "Customer Upgraded"; verb = "upgraded to"; color = COLOR_SUCCESS;
|
||||
} else if (scenario === "downgrade") {
|
||||
emoji = "📉"; header = "Customer Downgraded"; verb = "downgraded to"; color = COLOR_WARNING;
|
||||
} else if (scenario === "cancel") {
|
||||
emoji = "⚠️"; header = "Subscription Cancelled"; verb = "cancelled"; color = COLOR_WARNING;
|
||||
} else if (scenario === "renew") {
|
||||
emoji = "🔄"; header = "Subscription Uncancelled"; verb = "uncancelled"; color = COLOR_SUCCESS;
|
||||
} else if (scenario === "expired") {
|
||||
emoji = "💀"; header = "Subscription Expired"; verb = "expired on"; color = COLOR_DANGER;
|
||||
} else if (scenario === "scheduled") {
|
||||
emoji = "📅"; header = "Change Scheduled"; verb = "scheduled a change to"; color = COLOR_INFO;
|
||||
}
|
||||
|
||||
var sentence;
|
||||
if (scenario === "expired") {
|
||||
sentence = "**" + customerName + "**'s **" + productName + "** expired";
|
||||
} else {
|
||||
sentence = "**" + customerName + "** " + verb + " **" + productName + "**";
|
||||
}
|
||||
|
||||
var description = sentence;
|
||||
if (customerId) {
|
||||
description += "\n\n[View in Autumn](" + AUTUMN_BASE + customerId + ")";
|
||||
}
|
||||
|
||||
var fields = [
|
||||
{ name: "Customer", value: customerName, inline: true }
|
||||
];
|
||||
if (customerEmail) {
|
||||
fields.push({ name: "Email", value: customerEmail, inline: true });
|
||||
}
|
||||
fields.push({ name: "Product", value: productName, inline: true });
|
||||
fields.push({ name: "Scenario", value: "`" + scenario + "`", inline: true });
|
||||
if (entityLabel) {
|
||||
fields.push({ name: "Entity", value: entityLabel, inline: true });
|
||||
}
|
||||
|
||||
var embed = {
|
||||
title: emoji + " " + header,
|
||||
description: description,
|
||||
color: color,
|
||||
fields: fields
|
||||
};
|
||||
if (customerId) {
|
||||
embed.url = AUTUMN_BASE + customerId;
|
||||
}
|
||||
var footerParts = [];
|
||||
if (customerId) footerParts.push("Customer ID: " + customerId);
|
||||
if (entity && entity.id) footerParts.push("Entity: " + entity.id);
|
||||
if (footerParts.length > 0) {
|
||||
embed.footer = { text: footerParts.join(" | ") };
|
||||
}
|
||||
|
||||
webhook.payload = {
|
||||
username: AUTUMN_USERNAME,
|
||||
avatar_url: AUTUMN_AVATAR_URL,
|
||||
embeds: [embed]
|
||||
};
|
||||
return webhook;
|
||||
}
|
||||
|
||||
// ============ balances.limit_reached ============
|
||||
if (webhook.eventType === "balances.limit_reached") {
|
||||
var lrCustomerId = data.customer_id || "";
|
||||
var lrFeatureId = data.feature_id || "feature";
|
||||
var lrLimitType = data.limit_type || "included";
|
||||
var lrEntityId = data.entity_id || null;
|
||||
|
||||
var lrCustomerDisplay = lrCustomerId
|
||||
? "[`" + lrCustomerId + "`](" + AUTUMN_BASE + lrCustomerId + ")"
|
||||
: "`unknown`";
|
||||
|
||||
var lrDescription =
|
||||
lrCustomerDisplay + " hit their **" + lrFeatureId + "** `" + lrLimitType + "` limit";
|
||||
if (lrCustomerId) {
|
||||
lrDescription += "\n\n[View in Autumn](" + AUTUMN_BASE + lrCustomerId + ")";
|
||||
}
|
||||
|
||||
var lrFields = [
|
||||
{
|
||||
name: "Customer",
|
||||
value: lrCustomerId ? "`" + lrCustomerId + "`" : "—",
|
||||
inline: true
|
||||
},
|
||||
{ name: "Feature", value: "`" + lrFeatureId + "`", inline: true },
|
||||
{ name: "Limit Type", value: "`" + lrLimitType + "`", inline: true }
|
||||
];
|
||||
if (lrEntityId) {
|
||||
lrFields.push({ name: "Entity", value: "`" + lrEntityId + "`", inline: true });
|
||||
}
|
||||
|
||||
var lrEmbed = {
|
||||
title: "🚫 Limit Reached",
|
||||
description: lrDescription,
|
||||
color: COLOR_DANGER,
|
||||
fields: lrFields
|
||||
};
|
||||
if (lrCustomerId) {
|
||||
lrEmbed.url = AUTUMN_BASE + lrCustomerId;
|
||||
}
|
||||
var lrFooterParts = [];
|
||||
if (lrCustomerId) lrFooterParts.push("Customer ID: " + lrCustomerId);
|
||||
if (lrEntityId) lrFooterParts.push("Entity: " + lrEntityId);
|
||||
if (lrFooterParts.length > 0) {
|
||||
lrEmbed.footer = { text: lrFooterParts.join(" | ") };
|
||||
}
|
||||
|
||||
webhook.payload = {
|
||||
username: AUTUMN_USERNAME,
|
||||
avatar_url: AUTUMN_AVATAR_URL,
|
||||
embeds: [lrEmbed]
|
||||
};
|
||||
return webhook;
|
||||
}
|
||||
|
||||
// ============ balances.usage_alert_triggered ============
|
||||
if (webhook.eventType === "balances.usage_alert_triggered") {
|
||||
var uaCustomerId = data.customer_id || "";
|
||||
var uaFeatureId = data.feature_id || "feature";
|
||||
var uaEntityId = data.entity_id || null;
|
||||
var uaAlert = data.usage_alert || {};
|
||||
var uaAlertName = uaAlert.name || "Usage alert";
|
||||
var uaThreshold = uaAlert.threshold;
|
||||
var uaThresholdType = uaAlert.threshold_type || "usage";
|
||||
|
||||
var uaThresholdLabel = "—";
|
||||
if (uaThreshold !== undefined && uaThreshold !== null) {
|
||||
if (uaThresholdType === "usage_percentage") {
|
||||
uaThresholdLabel = uaThreshold + "% used";
|
||||
} else if (uaThresholdType === "remaining_percentage") {
|
||||
uaThresholdLabel = uaThreshold + "% remaining";
|
||||
} else if (uaThresholdType === "remaining") {
|
||||
uaThresholdLabel = uaThreshold + " remaining";
|
||||
} else {
|
||||
uaThresholdLabel = uaThreshold + " used";
|
||||
}
|
||||
}
|
||||
|
||||
var uaCustomerDisplay = uaCustomerId
|
||||
? "[`" + uaCustomerId + "`](" + AUTUMN_BASE + uaCustomerId + ")"
|
||||
: "`unknown`";
|
||||
|
||||
var uaDescription =
|
||||
uaCustomerDisplay + " crossed the **" + uaAlertName + "** threshold on **" + uaFeatureId + "**";
|
||||
if (uaCustomerId) {
|
||||
uaDescription += "\n\n[View in Autumn](" + AUTUMN_BASE + uaCustomerId + ")";
|
||||
}
|
||||
|
||||
var uaFields = [
|
||||
{
|
||||
name: "Customer",
|
||||
value: uaCustomerId ? "`" + uaCustomerId + "`" : "—",
|
||||
inline: true
|
||||
},
|
||||
{ name: "Feature", value: "`" + uaFeatureId + "`", inline: true },
|
||||
{ name: "Alert", value: uaAlertName, inline: true },
|
||||
{ name: "Threshold", value: uaThresholdLabel, inline: true }
|
||||
];
|
||||
if (uaEntityId) {
|
||||
uaFields.push({ name: "Entity", value: "`" + uaEntityId + "`", inline: true });
|
||||
}
|
||||
|
||||
var uaEmbed = {
|
||||
title: "📊 Usage Alert: " + uaAlertName,
|
||||
description: uaDescription,
|
||||
color: COLOR_WARNING,
|
||||
fields: uaFields
|
||||
};
|
||||
if (uaCustomerId) {
|
||||
uaEmbed.url = AUTUMN_BASE + uaCustomerId;
|
||||
}
|
||||
var uaFooterParts = [];
|
||||
if (uaCustomerId) uaFooterParts.push("Customer ID: " + uaCustomerId);
|
||||
if (uaEntityId) uaFooterParts.push("Entity: " + uaEntityId);
|
||||
if (uaFooterParts.length > 0) {
|
||||
uaEmbed.footer = { text: uaFooterParts.join(" | ") };
|
||||
}
|
||||
|
||||
webhook.payload = {
|
||||
username: AUTUMN_USERNAME,
|
||||
avatar_url: AUTUMN_AVATAR_URL,
|
||||
embeds: [uaEmbed]
|
||||
};
|
||||
return webhook;
|
||||
}
|
||||
|
||||
// Unmatched event type — cancel dispatch.
|
||||
webhook.cancel = true;
|
||||
return webhook;
|
||||
}
|
||||
292
others/svix-transforms/slack.ts
Normal file
@@ -0,0 +1,292 @@
|
||||
/**
|
||||
* @param webhook the webhook object
|
||||
* @param webhook.method destination method. Allowed values: "POST", "PUT"
|
||||
* @param webhook.url current destination address
|
||||
* @param webhook.eventType current webhook Event Type
|
||||
* @param webhook.payload JSON payload
|
||||
* @param webhook.cancel whether to cancel dispatch of the given webhook
|
||||
*/
|
||||
function handler(webhook) {
|
||||
var AUTUMN_BASE = "https://app.useautumn.com/customers/";
|
||||
var AUTUMN_USERNAME = "Autumn";
|
||||
var AUTUMN_ICON_URL = "https://i.ibb.co/BHCF1ZqL/autumnicon.png";
|
||||
|
||||
var payload = webhook.payload || {};
|
||||
var data = payload.data || payload;
|
||||
|
||||
// ============ customer.products.updated ============
|
||||
if (webhook.eventType === "customer.products.updated") {
|
||||
var scenario = data.scenario || "updated";
|
||||
var customer = data.customer || {};
|
||||
var entity = data.entity || null;
|
||||
var product = data.updated_product || {};
|
||||
|
||||
var customerName = customer.name || customer.email || customer.id || "Customer";
|
||||
var customerEmail = customer.email || null;
|
||||
var customerId = customer.id || "";
|
||||
|
||||
var productName = product.name || "their plan";
|
||||
if (product.version && product.version !== 1) {
|
||||
productName = productName + " V" + product.version;
|
||||
}
|
||||
|
||||
var entityLabel = null;
|
||||
if (entity) {
|
||||
entityLabel = entity.name || entity.id || null;
|
||||
}
|
||||
|
||||
var meta = {
|
||||
"new": { emoji: "🎉", header: "New Subscription", verb: "subscribed to" },
|
||||
"upgrade": { emoji: "🚀", header: "Customer Upgraded", verb: "upgraded to" },
|
||||
"downgrade": { emoji: "📉", header: "Customer Downgraded", verb: "downgraded to" },
|
||||
"cancel": { emoji: "⚠️", header: "Subscription Cancelled", verb: "cancelled" },
|
||||
"renew": { emoji: "🔄", header: "Subscription Uncancelled", verb: "uncancelled" },
|
||||
"expired": { emoji: "💀", header: "Subscription Expired", verb: "expired on" },
|
||||
"scheduled": { emoji: "📅", header: "Change Scheduled", verb: "scheduled a change to" }
|
||||
}[scenario] || { emoji: "🔔", header: "Subscription Updated", verb: "updated" };
|
||||
|
||||
var sentence;
|
||||
if (scenario === "expired") {
|
||||
sentence = "*" + customerName + "*'s *" + productName + "* expired";
|
||||
} else {
|
||||
sentence = "*" + customerName + "* " + meta.verb + " *" + productName + "*";
|
||||
}
|
||||
|
||||
var previewText = meta.emoji + " " + customerName + " " + meta.verb + " " + productName;
|
||||
|
||||
var fields = [
|
||||
{ type: "mrkdwn", text: "*Customer:*\n" + customerName }
|
||||
];
|
||||
if (customerEmail) {
|
||||
fields.push({ type: "mrkdwn", text: "*Email:*\n" + customerEmail });
|
||||
}
|
||||
fields.push({ type: "mrkdwn", text: "*Product:*\n" + productName });
|
||||
fields.push({ type: "mrkdwn", text: "*Scenario:*\n`" + scenario + "`" });
|
||||
if (entityLabel) {
|
||||
fields.push({ type: "mrkdwn", text: "*Entity:*\n" + entityLabel });
|
||||
}
|
||||
|
||||
var contextParts = [];
|
||||
if (customerId) {
|
||||
contextParts.push("Customer ID: `" + customerId + "`");
|
||||
}
|
||||
if (entity && entity.id) {
|
||||
contextParts.push("Entity: `" + entity.id + "`");
|
||||
}
|
||||
|
||||
var blocks = [
|
||||
{
|
||||
type: "header",
|
||||
text: { type: "plain_text", text: meta.emoji + " " + meta.header, emoji: true }
|
||||
},
|
||||
{
|
||||
type: "section",
|
||||
text: { type: "mrkdwn", text: sentence }
|
||||
},
|
||||
{
|
||||
type: "section",
|
||||
fields: fields
|
||||
}
|
||||
];
|
||||
|
||||
if (customerId) {
|
||||
blocks.push({
|
||||
type: "actions",
|
||||
elements: [
|
||||
{
|
||||
type: "button",
|
||||
text: { type: "plain_text", text: "View in Autumn", emoji: true },
|
||||
url: AUTUMN_BASE + customerId,
|
||||
style: "primary"
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
if (contextParts.length > 0) {
|
||||
blocks.push({
|
||||
type: "context",
|
||||
elements: [
|
||||
{ type: "mrkdwn", text: contextParts.join(" | ") }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
webhook.payload = {
|
||||
username: AUTUMN_USERNAME,
|
||||
icon_url: AUTUMN_ICON_URL,
|
||||
text: previewText,
|
||||
blocks: blocks
|
||||
};
|
||||
return webhook;
|
||||
}
|
||||
|
||||
// ============ balances.limit_reached ============
|
||||
if (webhook.eventType === "balances.limit_reached") {
|
||||
var lrCustomerId = data.customer_id || "";
|
||||
var lrFeatureId = data.feature_id || "feature";
|
||||
var lrLimitType = data.limit_type || "included";
|
||||
var lrEntityId = data.entity_id || null;
|
||||
|
||||
var lrCustomerLink = lrCustomerId
|
||||
? "<" + AUTUMN_BASE + lrCustomerId + "|`" + lrCustomerId + "`>"
|
||||
: "`unknown`";
|
||||
|
||||
var lrSentence =
|
||||
lrCustomerLink + " hit their *" + lrFeatureId + "* `" + lrLimitType + "` limit";
|
||||
|
||||
var lrPreview = "🚫 " + lrCustomerId + " hit their " + lrFeatureId + " limit";
|
||||
|
||||
var lrFields = [
|
||||
{ type: "mrkdwn", text: "*Customer:*\n" + lrCustomerLink },
|
||||
{ type: "mrkdwn", text: "*Feature:*\n`" + lrFeatureId + "`" },
|
||||
{ type: "mrkdwn", text: "*Limit Type:*\n`" + lrLimitType + "`" }
|
||||
];
|
||||
if (lrEntityId) {
|
||||
lrFields.push({ type: "mrkdwn", text: "*Entity:*\n`" + lrEntityId + "`" });
|
||||
}
|
||||
|
||||
var lrContextParts = [];
|
||||
if (lrCustomerId) lrContextParts.push("Customer ID: `" + lrCustomerId + "`");
|
||||
if (lrEntityId) lrContextParts.push("Entity: `" + lrEntityId + "`");
|
||||
|
||||
var lrBlocks = [
|
||||
{
|
||||
type: "header",
|
||||
text: { type: "plain_text", text: "🚫 Limit Reached", emoji: true }
|
||||
},
|
||||
{
|
||||
type: "section",
|
||||
text: { type: "mrkdwn", text: lrSentence }
|
||||
},
|
||||
{
|
||||
type: "section",
|
||||
fields: lrFields
|
||||
}
|
||||
];
|
||||
|
||||
if (lrCustomerId) {
|
||||
lrBlocks.push({
|
||||
type: "actions",
|
||||
elements: [
|
||||
{
|
||||
type: "button",
|
||||
text: { type: "plain_text", text: "View in Autumn", emoji: true },
|
||||
url: AUTUMN_BASE + lrCustomerId,
|
||||
style: "danger"
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
if (lrContextParts.length > 0) {
|
||||
lrBlocks.push({
|
||||
type: "context",
|
||||
elements: [
|
||||
{ type: "mrkdwn", text: lrContextParts.join(" | ") }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
webhook.payload = {
|
||||
username: AUTUMN_USERNAME,
|
||||
icon_url: AUTUMN_ICON_URL,
|
||||
text: lrPreview,
|
||||
blocks: lrBlocks
|
||||
};
|
||||
return webhook;
|
||||
}
|
||||
|
||||
// ============ balances.usage_alert_triggered ============
|
||||
if (webhook.eventType === "balances.usage_alert_triggered") {
|
||||
var uaCustomerId = data.customer_id || "";
|
||||
var uaFeatureId = data.feature_id || "feature";
|
||||
var uaEntityId = data.entity_id || null;
|
||||
var uaAlert = data.usage_alert || {};
|
||||
var uaAlertName = uaAlert.name || "Usage alert";
|
||||
var uaThreshold = uaAlert.threshold;
|
||||
var uaThresholdType = uaAlert.threshold_type || "usage";
|
||||
|
||||
function formatThreshold(value, type) {
|
||||
if (value === undefined || value === null) return "—";
|
||||
if (type === "usage_percentage") return value + "% used";
|
||||
if (type === "remaining_percentage") return value + "% remaining";
|
||||
if (type === "remaining") return value + " remaining";
|
||||
return value + " used";
|
||||
}
|
||||
|
||||
var uaThresholdLabel = formatThreshold(uaThreshold, uaThresholdType);
|
||||
|
||||
var uaCustomerLink = uaCustomerId
|
||||
? "<" + AUTUMN_BASE + uaCustomerId + "|`" + uaCustomerId + "`>"
|
||||
: "`unknown`";
|
||||
|
||||
var uaSentence =
|
||||
uaCustomerLink + " crossed the *" + uaAlertName + "* threshold on *" + uaFeatureId + "*";
|
||||
|
||||
var uaPreview = "📊 Usage Alert: " + uaAlertName + " (" + uaCustomerId + ")";
|
||||
|
||||
var uaFields = [
|
||||
{ type: "mrkdwn", text: "*Customer:*\n" + uaCustomerLink },
|
||||
{ type: "mrkdwn", text: "*Feature:*\n`" + uaFeatureId + "`" },
|
||||
{ type: "mrkdwn", text: "*Alert:*\n" + uaAlertName },
|
||||
{ type: "mrkdwn", text: "*Threshold:*\n" + uaThresholdLabel }
|
||||
];
|
||||
if (uaEntityId) {
|
||||
uaFields.push({ type: "mrkdwn", text: "*Entity:*\n`" + uaEntityId + "`" });
|
||||
}
|
||||
|
||||
var uaContextParts = [];
|
||||
if (uaCustomerId) uaContextParts.push("Customer ID: `" + uaCustomerId + "`");
|
||||
if (uaEntityId) uaContextParts.push("Entity: `" + uaEntityId + "`");
|
||||
|
||||
var uaBlocks = [
|
||||
{
|
||||
type: "header",
|
||||
text: { type: "plain_text", text: "📊 Usage Alert: " + uaAlertName, emoji: true }
|
||||
},
|
||||
{
|
||||
type: "section",
|
||||
text: { type: "mrkdwn", text: uaSentence }
|
||||
},
|
||||
{
|
||||
type: "section",
|
||||
fields: uaFields
|
||||
}
|
||||
];
|
||||
|
||||
if (uaCustomerId) {
|
||||
uaBlocks.push({
|
||||
type: "actions",
|
||||
elements: [
|
||||
{
|
||||
type: "button",
|
||||
text: { type: "plain_text", text: "View in Autumn", emoji: true },
|
||||
url: AUTUMN_BASE + uaCustomerId
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
if (uaContextParts.length > 0) {
|
||||
uaBlocks.push({
|
||||
type: "context",
|
||||
elements: [
|
||||
{ type: "mrkdwn", text: uaContextParts.join(" | ") }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
webhook.payload = {
|
||||
username: AUTUMN_USERNAME,
|
||||
icon_url: AUTUMN_ICON_URL,
|
||||
text: uaPreview,
|
||||
blocks: uaBlocks
|
||||
};
|
||||
return webhook;
|
||||
}
|
||||
|
||||
// Cancel any other event types — they don't match Slack's expected schema and would error.
|
||||
webhook.cancel = true;
|
||||
return webhook;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "autumn",
|
||||
"private": true,
|
||||
"packageManager": "bun@1.3.10",
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"server",
|
||||
@@ -83,6 +84,7 @@
|
||||
"setup": "node scripts/setup/setup.js",
|
||||
"setup:s3-admin": "bun scripts/setup/setupS3Admin.ts",
|
||||
"setup:test": "infisical run --env=dev --recursive -- bun scripts/setup/setup-test.ts",
|
||||
"stripe:link-test": "ENV_FILE=.env infisical run --env=dev --recursive -- bun scripts/setup/link-test-stripe-account.ts",
|
||||
"agent:bootstrap": "bash scripts/setup/agent-bootstrap.sh",
|
||||
"dev:agent": "bash scripts/setup/devAgent.sh",
|
||||
"migrate-functions": "infisical run --env=dev --recursive -- bun scripts/migrations/migrate-functions.ts",
|
||||
@@ -110,7 +112,7 @@
|
||||
"site": "cd apps/website && bun dev && cd ../..",
|
||||
"docs": "bun -F @autumn/docs dev",
|
||||
"docs:build": "bun -F @autumn/docs build",
|
||||
"ts": "bun -F @autumn/server ts && bun -F autumn-js ts && bun -F @autumn/openapi ts && bun -F atmn ts && bun -F checkout ts",
|
||||
"ts": "turbo run ts --filter=@autumn/server --filter=autumn-js --filter=@autumn/openapi --filter=atmn --filter=checkout",
|
||||
"atmn:build": "bun -F atmn build",
|
||||
"openapi:ts": "bun -F @autumn/openapi ts",
|
||||
"js:ts": "bun -F autumn-js ts",
|
||||
@@ -143,6 +145,7 @@
|
||||
"husky": "^9.1.7",
|
||||
"inquirer": "^12.10.0",
|
||||
"knip": "^6.7.0",
|
||||
"ts-to-zod": "^5.1.0"
|
||||
"ts-to-zod": "^5.1.0",
|
||||
"turbo": "^2.9.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "autumn-js",
|
||||
"description": "Autumn JS Library",
|
||||
"version": "1.2.10",
|
||||
"version": "1.2.17",
|
||||
"repository": "github:useautumn/autumn",
|
||||
"homepage": "https://docs.useautumn.com",
|
||||
"main": "./dist/sdk/index.js",
|
||||
|
||||
@@ -10,6 +10,8 @@ export type HandleBetterAuthRouteFn = (args: {
|
||||
routeName: RouteName;
|
||||
}) => Promise<{ status: number; body: unknown }>;
|
||||
|
||||
export type AutumnEndpoint = ReturnType<typeof createAuthEndpoint>;
|
||||
|
||||
/** Get route config by name from routeConfigs */
|
||||
const getRouteConfig = (routeName: RouteName) => {
|
||||
const route = routeConfigs.find((r) => r.route === routeName);
|
||||
@@ -24,7 +26,7 @@ const getRouteConfig = (routeName: RouteName) => {
|
||||
export const createAutumnEndpoint = <T extends RouteName>(
|
||||
routeName: T,
|
||||
handleRoute: HandleBetterAuthRouteFn,
|
||||
) => {
|
||||
): AutumnEndpoint => {
|
||||
const config = getRouteConfig(routeName);
|
||||
return createAuthEndpoint(
|
||||
`/autumn/${routeName}` as `/autumn/${T}`,
|
||||
@@ -38,5 +40,5 @@ export const createAutumnEndpoint = <T extends RouteName>(
|
||||
status: result.status,
|
||||
});
|
||||
},
|
||||
);
|
||||
) as AutumnEndpoint;
|
||||
};
|
||||
|
||||
@@ -196,6 +196,7 @@ export const attachParamsOutboundSchema = z.object({
|
||||
.union([z.record(z.string(), z.string()), z.undefined()])
|
||||
.optional(),
|
||||
no_billing_changes: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
enable_plan_immediately: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
});
|
||||
|
||||
const closedEnumSchema = z.any();
|
||||
@@ -324,6 +325,7 @@ export const attachParamsSchema = z.object({
|
||||
.union([z.record(z.string(), z.string()), z.undefined()])
|
||||
.optional(),
|
||||
noBillingChanges: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
enablePlanImmediately: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
});
|
||||
|
||||
export const attachCodeSchema = openEnumSchema;
|
||||
|
||||
@@ -31,6 +31,10 @@ export const listPlansItemDisplaySchema = z.object({
|
||||
secondaryText: z.union([z.string(), z.undefined()]).optional(),
|
||||
});
|
||||
|
||||
export const listPlansConfigSchema = z.object({
|
||||
ignorePastDue: z.boolean(),
|
||||
});
|
||||
|
||||
export const listPlansParamsOutboundSchema = z.object({
|
||||
customer_id: z.union([z.string(), z.undefined()]).optional(),
|
||||
entity_id: z.union([z.string(), z.undefined()]).optional(),
|
||||
@@ -148,6 +152,7 @@ export const listPlansListSchema = z.object({
|
||||
env: listPlansEnvSchema,
|
||||
archived: z.boolean(),
|
||||
baseVariantId: z.string().nullable(),
|
||||
config: listPlansConfigSchema,
|
||||
customerEligibility: z
|
||||
.union([listPlansCustomerEligibilitySchema, z.undefined()])
|
||||
.optional(),
|
||||
|
||||
@@ -345,6 +345,7 @@ export const multiAttachParamsSchema = z.object({
|
||||
.union([multiAttachRedirectModeSchema, z.undefined()])
|
||||
.optional(),
|
||||
newBillingSubscription: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
enablePlanImmediately: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
customerData: z.union([customerDataSchema, z.undefined()]).optional(),
|
||||
entityData: z.union([multiAttachEntityDataSchema, z.undefined()]).optional(),
|
||||
});
|
||||
@@ -386,6 +387,7 @@ export const multiAttachParamsOutboundSchema = z.object({
|
||||
.optional(),
|
||||
redirect_mode: z.string(),
|
||||
new_billing_subscription: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
enable_plan_immediately: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
customer_data: z
|
||||
.union([customerDataOutboundSchema, z.undefined()])
|
||||
.optional(),
|
||||
|
||||
@@ -287,6 +287,7 @@ export const previewAttachParamsOutboundSchema = z.object({
|
||||
.union([z.record(z.string(), z.string()), z.undefined()])
|
||||
.optional(),
|
||||
no_billing_changes: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
enable_plan_immediately: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
});
|
||||
|
||||
const closedEnumSchema = z.any();
|
||||
@@ -432,6 +433,7 @@ export const previewAttachParamsSchema = z.object({
|
||||
.union([z.record(z.string(), z.string()), z.undefined()])
|
||||
.optional(),
|
||||
noBillingChanges: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
enablePlanImmediately: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
});
|
||||
|
||||
export const previewAttachIncomingSchema = z.object({
|
||||
@@ -454,6 +456,16 @@ export const previewAttachOutgoingSchema = z.object({
|
||||
|
||||
export const previewAttachCheckoutTypeSchema = openEnumSchema;
|
||||
|
||||
export const previewAttachStatusSchema = openEnumSchema;
|
||||
|
||||
export const previewAttachTaxSchema = z.object({
|
||||
total: z.number(),
|
||||
amountInclusive: z.number(),
|
||||
amountExclusive: z.number(),
|
||||
currency: z.string(),
|
||||
status: previewAttachStatusSchema,
|
||||
});
|
||||
|
||||
export const previewAttachResponseSchema = z.object({
|
||||
customerId: z.string(),
|
||||
lineItems: z.array(previewAttachLineItemSchema),
|
||||
@@ -466,4 +478,5 @@ export const previewAttachResponseSchema = z.object({
|
||||
outgoing: z.array(previewAttachOutgoingSchema),
|
||||
redirectToCheckout: z.boolean(),
|
||||
checkoutType: previewAttachCheckoutTypeSchema.nullable(),
|
||||
tax: z.union([previewAttachTaxSchema, z.undefined()]).optional(),
|
||||
});
|
||||
|
||||
@@ -451,6 +451,7 @@ export const previewMultiAttachParamsSchema = z.object({
|
||||
.union([previewMultiAttachRedirectModeSchema, z.undefined()])
|
||||
.optional(),
|
||||
newBillingSubscription: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
enablePlanImmediately: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
customerData: z.union([customerDataSchema, z.undefined()]).optional(),
|
||||
entityData: z
|
||||
.union([previewMultiAttachEntityDataSchema, z.undefined()])
|
||||
@@ -477,6 +478,16 @@ export const previewMultiAttachOutgoingSchema = z.object({
|
||||
|
||||
export const previewMultiAttachCheckoutTypeSchema = openEnumSchema;
|
||||
|
||||
export const previewMultiAttachStatusSchema = openEnumSchema;
|
||||
|
||||
export const previewMultiAttachTaxSchema = z.object({
|
||||
total: z.number(),
|
||||
amountInclusive: z.number(),
|
||||
amountExclusive: z.number(),
|
||||
currency: z.string(),
|
||||
status: previewMultiAttachStatusSchema,
|
||||
});
|
||||
|
||||
export const previewMultiAttachResponseSchema = z.object({
|
||||
customerId: z.string(),
|
||||
lineItems: z.array(previewMultiAttachLineItemSchema),
|
||||
@@ -491,6 +502,7 @@ export const previewMultiAttachResponseSchema = z.object({
|
||||
outgoing: z.array(previewMultiAttachOutgoingSchema),
|
||||
redirectToCheckout: z.boolean(),
|
||||
checkoutType: previewMultiAttachCheckoutTypeSchema.nullable(),
|
||||
tax: z.union([previewMultiAttachTaxSchema, z.undefined()]).optional(),
|
||||
});
|
||||
|
||||
export const previewMultiAttachParamsOutboundSchema = z.object({
|
||||
@@ -516,6 +528,7 @@ export const previewMultiAttachParamsOutboundSchema = z.object({
|
||||
.optional(),
|
||||
redirect_mode: z.string(),
|
||||
new_billing_subscription: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
enable_plan_immediately: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
customer_data: z
|
||||
.union([customerDataOutboundSchema, z.undefined()])
|
||||
.optional(),
|
||||
|
||||
@@ -184,6 +184,7 @@ export const setupPaymentParamsOutboundSchema = z.object({
|
||||
.union([z.record(z.string(), z.string()), z.undefined()])
|
||||
.optional(),
|
||||
no_billing_changes: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
enable_plan_immediately: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
});
|
||||
|
||||
const closedEnumSchema = z.any();
|
||||
@@ -311,4 +312,5 @@ export const setupPaymentParamsSchema = z.object({
|
||||
.union([z.record(z.string(), z.string()), z.undefined()])
|
||||
.optional(),
|
||||
noBillingChanges: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
enablePlanImmediately: z.union([z.boolean(), z.undefined()]).optional(),
|
||||
});
|
||||
|
||||