@oxygen-agent/cli 1.1010.650 → 1.1010.905
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/auto-update.d.ts +129 -0
- package/dist/auto-update.js +392 -0
- package/dist/command-manifest.js +15 -1
- package/dist/credentials.d.ts +2 -0
- package/dist/credentials.js +6 -3
- package/dist/functions-commands.js +1 -1
- package/dist/http-client.js +28 -4
- package/dist/inbox-needs-reply-notice.d.ts +12 -0
- package/dist/inbox-needs-reply-notice.js +51 -0
- package/dist/index.js +756 -177
- package/dist/run-wait.d.ts +3 -1
- package/dist/run-wait.js +19 -5
- package/dist/skills.js +48 -22
- package/dist/streamed-file-import.d.ts +58 -0
- package/dist/streamed-file-import.js +115 -0
- package/dist/update.d.ts +29 -0
- package/dist/update.js +62 -16
- package/dist/workflow-plan-limit-notices.d.ts +8 -0
- package/dist/workflow-plan-limit-notices.js +28 -0
- package/node_modules/@oxygen/cli-ugc/dist/commands.js +3 -3
- package/node_modules/@oxygen/shared/dist/billing-anchors.d.ts +50 -2
- package/node_modules/@oxygen/shared/dist/billing-anchors.js +94 -2
- package/node_modules/@oxygen/shared/dist/billing.d.ts +247 -37
- package/node_modules/@oxygen/shared/dist/billing.js +418 -45
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +66 -6
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.d.ts +6 -6
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.js +6 -6
- package/node_modules/@oxygen/shared/dist/cost-estimate-view.d.ts +50 -0
- package/node_modules/@oxygen/shared/dist/cost-estimate-view.js +90 -0
- package/node_modules/@oxygen/shared/dist/cost-estimate.d.ts +167 -0
- package/node_modules/@oxygen/shared/dist/cost-estimate.js +361 -0
- package/node_modules/@oxygen/shared/dist/credit-gate.d.ts +26 -0
- package/node_modules/@oxygen/shared/dist/credit-gate.js +65 -0
- package/node_modules/@oxygen/shared/dist/email-deliverability-policy.d.ts +51 -0
- package/node_modules/@oxygen/shared/dist/email-deliverability-policy.js +101 -0
- package/node_modules/@oxygen/shared/dist/email-hard-bounce.d.ts +27 -0
- package/node_modules/@oxygen/shared/dist/email-hard-bounce.js +27 -0
- package/node_modules/@oxygen/shared/dist/error-redaction.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/error-redaction.js +1 -1
- package/node_modules/@oxygen/shared/dist/feature-gates.d.ts +10 -1
- package/node_modules/@oxygen/shared/dist/feature-gates.js +12 -1
- package/node_modules/@oxygen/shared/dist/file-import.d.ts +13 -1
- package/node_modules/@oxygen/shared/dist/file-import.js +33 -6
- package/node_modules/@oxygen/shared/dist/hosted-ai.d.ts +73 -3
- package/node_modules/@oxygen/shared/dist/hosted-ai.js +246 -24
- package/node_modules/@oxygen/shared/dist/import-limits.d.ts +25 -1
- package/node_modules/@oxygen/shared/dist/import-limits.js +35 -2
- package/node_modules/@oxygen/shared/dist/index.d.ts +4 -23
- package/node_modules/@oxygen/shared/dist/index.js +4 -43
- package/node_modules/@oxygen/shared/dist/linkedin-sequences.d.ts +114 -0
- package/node_modules/@oxygen/shared/dist/linkedin-sequences.js +150 -0
- package/node_modules/@oxygen/shared/dist/object-storage.d.ts +9 -0
- package/node_modules/@oxygen/shared/dist/object-storage.js +17 -0
- package/node_modules/@oxygen/shared/dist/operational-telemetry.d.ts +41 -0
- package/node_modules/@oxygen/shared/dist/operational-telemetry.js +55 -0
- package/node_modules/@oxygen/shared/dist/otlp-log-sink.js +19 -2
- package/node_modules/@oxygen/shared/dist/plan-band.d.ts +234 -0
- package/node_modules/@oxygen/shared/dist/plan-band.js +312 -0
- package/node_modules/@oxygen/shared/dist/plan-capabilities.d.ts +77 -7
- package/node_modules/@oxygen/shared/dist/plan-capabilities.js +87 -7
- package/node_modules/@oxygen/shared/dist/plan-limits-view.d.ts +219 -0
- package/node_modules/@oxygen/shared/dist/plan-limits-view.js +330 -0
- package/node_modules/@oxygen/shared/dist/plan-limits.d.ts +335 -126
- package/node_modules/@oxygen/shared/dist/plan-limits.js +277 -86
- package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +158 -49
- package/node_modules/@oxygen/shared/dist/pricing-sheet.js +139 -41
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.d.ts +42 -23
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.js +56 -37
- package/node_modules/@oxygen/shared/dist/process-resource.d.ts +4 -0
- package/node_modules/@oxygen/shared/dist/process-resource.js +25 -0
- package/node_modules/@oxygen/shared/dist/provider-http-error.d.ts +10 -0
- package/node_modules/@oxygen/shared/dist/provider-http-error.js +27 -0
- package/node_modules/@oxygen/shared/dist/repricing.d.ts +257 -0
- package/node_modules/@oxygen/shared/dist/repricing.js +721 -0
- package/node_modules/@oxygen/shared/dist/semver.d.ts +21 -0
- package/node_modules/@oxygen/shared/dist/semver.js +41 -0
- package/node_modules/@oxygen/shared/dist/sending-limits.d.ts +30 -0
- package/node_modules/@oxygen/shared/dist/sending-limits.js +43 -0
- package/node_modules/@oxygen/shared/dist/sending-seats.d.ts +18 -15
- package/node_modules/@oxygen/shared/dist/sending-seats.js +22 -17
- package/node_modules/@oxygen/shared/dist/sequence-failures.js +4 -1
- package/node_modules/@oxygen/shared/dist/spend-safety.d.ts +57 -8
- package/node_modules/@oxygen/shared/dist/spend-safety.js +64 -11
- package/node_modules/@oxygen/shared/dist/stripe-price-catalog.d.ts +33 -1
- package/node_modules/@oxygen/shared/dist/stripe-price-catalog.js +71 -1
- package/node_modules/@oxygen/shared/dist/table-capacity.d.ts +68 -10
- package/node_modules/@oxygen/shared/dist/table-capacity.js +85 -4
- package/node_modules/@oxygen/shared/dist/telemetry-export-observer.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/telemetry-export-observer.js +13 -5
- package/node_modules/@oxygen/shared/dist/telemetry-resource.d.ts +40 -0
- package/node_modules/@oxygen/shared/dist/telemetry-resource.js +35 -0
- package/node_modules/@oxygen/shared/dist/telemetry.d.ts +9 -0
- package/node_modules/@oxygen/shared/dist/telemetry.js +41 -2
- package/node_modules/@oxygen/shared/dist/trace-context.d.ts +29 -0
- package/node_modules/@oxygen/shared/dist/trace-context.js +88 -0
- package/node_modules/@oxygen/shared/dist/ugc.d.ts +15 -0
- package/node_modules/@oxygen/shared/dist/ugc.js +29 -0
- package/node_modules/@oxygen/shared/dist/version.d.ts +1 -3
- package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
- package/node_modules/@oxygen/shared/dist/version.js +14 -27
- package/node_modules/@oxygen/shared/dist/workspace-file-storage.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/workspace-file-storage.js +5 -0
- package/node_modules/@oxygen/workflows/dist/graph/manifest-schema.d.ts +3 -3
- package/node_modules/@oxygen/workflows/dist/graph/types.d.ts +15 -1
- package/node_modules/@oxygen/workflows/dist/graph/types.js +15 -1
- package/node_modules/@oxygen/workflows/dist/index.d.ts +45 -0
- package/node_modules/@oxygen/workflows/dist/index.js +152 -2
- package/node_modules/@oxygen/workflows/dist/usage-estimate.d.ts +10 -1
- package/node_modules/@oxygen/workflows/dist/usage-estimate.js +33 -29
- package/package.json +1 -1
- package/node_modules/@oxygen/shared/dist/email-warmup-readiness.d.ts +0 -64
- package/node_modules/@oxygen/shared/dist/email-warmup-readiness.js +0 -90
|
@@ -108,8 +108,10 @@ export function occurrencesInPeriod(from, to, anchorDay) {
|
|
|
108
108
|
* The block is a STANDING one-month-per-resource reserve (see
|
|
109
109
|
* credit-commitments.ts): because every anchor is at most one month out, holding
|
|
110
110
|
* one month per active resource always covers every fixed charge falling due
|
|
111
|
-
* inside any coming subscription period of <= 1 month. Longer periods
|
|
112
|
-
*
|
|
111
|
+
* inside any coming subscription period of <= 1 month. Longer periods need
|
|
112
|
+
* proportionally more held, or the block runs dry mid-term. A yearly plan is
|
|
113
|
+
* not such a period: it grants monthly slices, so its caller passes the current
|
|
114
|
+
* slice's length (see recomputeOrgCommitmentBlock, P-23).
|
|
113
115
|
*
|
|
114
116
|
* Returns at least 1 — a missing/zero/garbage period length must never collapse
|
|
115
117
|
* the block to nothing, which would silently disable the whole feature.
|
|
@@ -133,3 +135,93 @@ export function periodLengthDays(start, end) {
|
|
|
133
135
|
return null;
|
|
134
136
|
return Math.floor(ms / DAY_MS);
|
|
135
137
|
}
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
// Monthly credit slices of a longer (annual) subscription period
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
//
|
|
142
|
+
// Repricing 2026-09, decision 1.2: every plan size can be paid annually, and the
|
|
143
|
+
// credits are STILL granted monthly. One paid annual period therefore funds a
|
|
144
|
+
// sequence of monthly grant slices. P-8 (PROPOSED default) anchors the slices to
|
|
145
|
+
// the subscription period start, walked with the same immutable-anchor clamp as
|
|
146
|
+
// the commitment anchors above: a period starting 31 Jan slices at 28 Feb,
|
|
147
|
+
// 31 Mar, 30 Apr ... and never decays to the 28th.
|
|
148
|
+
/** Average Gregorian month length in days: 365.2425 / 12. */
|
|
149
|
+
const AVERAGE_MONTH_DAYS = 365.2425 / 12;
|
|
150
|
+
/** Longest period that is still ONE monthly grant (matches the allowance-bar guard). */
|
|
151
|
+
export const SINGLE_GRANT_PERIOD_MAX_DAYS = 35;
|
|
152
|
+
/**
|
|
153
|
+
* The monthly grant slices of one paid subscription period.
|
|
154
|
+
*
|
|
155
|
+
* A period of at most {@link SINGLE_GRANT_PERIOD_MAX_DAYS} days is a single
|
|
156
|
+
* slice covering the whole period, which is exactly today's monthly grant. A
|
|
157
|
+
* longer period is cut on its start's anchor day. The slice count is bounded by
|
|
158
|
+
* the period's length in average months (12 for a year, including leap years
|
|
159
|
+
* and clamped anchors), and the last slice absorbs any remainder, so a period
|
|
160
|
+
* end whose time of day differs from its start by seconds can never produce a
|
|
161
|
+
* thirteenth sliver.
|
|
162
|
+
*/
|
|
163
|
+
export function subscriptionGrantSlices(periodStart, periodEnd) {
|
|
164
|
+
if (!(periodStart instanceof Date) || !(periodEnd instanceof Date))
|
|
165
|
+
return [];
|
|
166
|
+
if (Number.isNaN(periodStart.getTime()) || Number.isNaN(periodEnd.getTime()))
|
|
167
|
+
return [];
|
|
168
|
+
if (periodEnd <= periodStart)
|
|
169
|
+
return [];
|
|
170
|
+
const periodDays = (periodEnd.getTime() - periodStart.getTime()) / DAY_MS;
|
|
171
|
+
if (periodDays <= SINGLE_GRANT_PERIOD_MAX_DAYS) {
|
|
172
|
+
return [{ index: 0, start: periodStart, end: periodEnd }];
|
|
173
|
+
}
|
|
174
|
+
const maxSlices = Math.max(1, Math.round(periodDays / AVERAGE_MONTH_DAYS));
|
|
175
|
+
const anchorDay = anchorDayOf(periodStart);
|
|
176
|
+
const slices = [];
|
|
177
|
+
let cursor = periodStart;
|
|
178
|
+
for (let index = 0; index < maxSlices; index += 1) {
|
|
179
|
+
const next = nextAnchorDueAt(cursor, anchorDay);
|
|
180
|
+
if (index === maxSlices - 1 || next >= periodEnd) {
|
|
181
|
+
slices.push({ index, start: cursor, end: periodEnd });
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
slices.push({ index, start: cursor, end: next });
|
|
185
|
+
cursor = next;
|
|
186
|
+
}
|
|
187
|
+
return slices;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* The slices of a period that have started by `now`, in order. Nothing after the
|
|
191
|
+
* period end is ever due: a subscription set to cancel at period end, or a row
|
|
192
|
+
* whose renewal webhook has not arrived yet, stops at its last paid slice.
|
|
193
|
+
*/
|
|
194
|
+
export function dueSubscriptionGrantSlices(periodStart, periodEnd, now) {
|
|
195
|
+
return subscriptionGrantSlices(periodStart, periodEnd).filter((slice) => slice.start.getTime() <= now.getTime());
|
|
196
|
+
}
|
|
197
|
+
/** The slice `now` falls in, or null outside the period. */
|
|
198
|
+
export function currentSubscriptionGrantSlice(periodStart, periodEnd, now) {
|
|
199
|
+
return (subscriptionGrantSlices(periodStart, periodEnd).find((slice) => slice.start.getTime() <= now.getTime() && now.getTime() < slice.end.getTime()) ?? null);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* When the next monthly credit grant of a paid plan arrives (repricing 2026-09,
|
|
203
|
+
* S13: "know when my credits arrive").
|
|
204
|
+
*
|
|
205
|
+
* A monthly plan grants with its renewal, at the period end. A yearly plan
|
|
206
|
+
* grants each slice at its start, so the next grant is the end of the slice
|
|
207
|
+
* `now` falls in; the last slice's end is the renewal. A grant that depends on
|
|
208
|
+
* the renewal is null when the renewal will not happen (`renews: false`: a
|
|
209
|
+
* scheduled cancellation, a lapsed or unpaid plan), because no grant follows.
|
|
210
|
+
*/
|
|
211
|
+
export function nextSubscriptionCreditGrantAt(input) {
|
|
212
|
+
const now = input.now ?? new Date();
|
|
213
|
+
const end = input.periodEnd;
|
|
214
|
+
if (!(end instanceof Date) || Number.isNaN(end.getTime()))
|
|
215
|
+
return null;
|
|
216
|
+
if (end.getTime() <= now.getTime())
|
|
217
|
+
return null;
|
|
218
|
+
const start = input.periodStart;
|
|
219
|
+
if (input.billingInterval === "year"
|
|
220
|
+
&& start instanceof Date
|
|
221
|
+
&& !Number.isNaN(start.getTime())) {
|
|
222
|
+
const slice = currentSubscriptionGrantSlice(start, end, now);
|
|
223
|
+
if (slice && slice.end.getTime() < end.getTime())
|
|
224
|
+
return slice.end;
|
|
225
|
+
}
|
|
226
|
+
return input.renews ? end : null;
|
|
227
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type RepricingOptions } from "./repricing.js";
|
|
1
2
|
export declare const WEEKLY_USAGE_WINDOW_DAYS = 7;
|
|
2
3
|
export declare const BILLING_CURRENCIES: readonly ["usd"];
|
|
3
4
|
export type BillingCurrency = (typeof BILLING_CURRENCIES)[number];
|
|
@@ -52,7 +53,16 @@ export type PricingPlanDefinition = {
|
|
|
52
53
|
export type PricingPlanMetadata = Record<string, unknown> | null | undefined;
|
|
53
54
|
export declare const CONTACT_SALES_URL = "mailto:priority@oxygen-agent.com";
|
|
54
55
|
export declare const CREDITS_PER_USD = 100;
|
|
55
|
-
|
|
56
|
+
/**
|
|
57
|
+
* US cents per 100 on-demand top-up credits right now. The rate rises from 125
|
|
58
|
+
* ($1.25) to the seed's 130 ($1.30) at the 2026-09 repricing's effective instant
|
|
59
|
+
* (decision 1.5, slice S10), so it is read per call through the switch and never
|
|
60
|
+
* from the snapshot: plan credits are then at least 23% cheaper (1 - 1.00/1.30),
|
|
61
|
+
* where they were 20% cheaper at $1.25. A page that shows it resolves it on the
|
|
62
|
+
* server and passes the number down, because a client bundle cannot read the
|
|
63
|
+
* switch.
|
|
64
|
+
*/
|
|
65
|
+
export declare function creditTopupUsdCentsPer100(options?: RepricingOptions): number;
|
|
56
66
|
export declare const CREDIT_TOPUP_MIN_CREDITS = 800;
|
|
57
67
|
export declare const CREDIT_TOPUP_MAX_CREDITS = 100000;
|
|
58
68
|
export declare const CREDIT_TOPUP_STEP_CREDITS = 100;
|
|
@@ -60,8 +70,8 @@ export declare const CREDIT_TOPUP_DEFAULT_CREDITS = 2000;
|
|
|
60
70
|
export declare function isValidCreditTopupCredits(credits: number): boolean;
|
|
61
71
|
/**
|
|
62
72
|
* A shortfall expressed as an amount `oxygen billing topup` will actually SELL:
|
|
63
|
-
* rounded up onto
|
|
64
|
-
* [
|
|
73
|
+
* rounded up onto CREDIT_TOPUP_STEP_CREDITS (100) and clamped into the purchasable
|
|
74
|
+
* [CREDIT_TOPUP_MIN_CREDITS .. CREDIT_TOPUP_MAX_CREDITS] band (800 .. 100,000). A next_action (or an alert email) naming a number the
|
|
65
75
|
* top-up route refuses with `invalid_topup_amount` is not a next action, it is a
|
|
66
76
|
* second dead end during the incident it exists to end.
|
|
67
77
|
*
|
|
@@ -75,30 +85,106 @@ export declare function isValidCreditTopupCredits(credits: number): boolean;
|
|
|
75
85
|
* second rounding formula is how two customer-facing figures drift apart.
|
|
76
86
|
*/
|
|
77
87
|
export declare function creditTopupAmountForShortfall(credits: number): number;
|
|
78
|
-
|
|
79
|
-
export declare
|
|
88
|
+
/** Price of a custom top-up at the rate in force now (`creditTopupUsdCentsPer100`). */
|
|
89
|
+
export declare function creditTopupUsdCents(credits: number, options?: RepricingOptions): number | null;
|
|
90
|
+
/**
|
|
91
|
+
* Price of a custom top-up at an explicit rate. A checkout session records the
|
|
92
|
+
* rate it was quoted at (`CREDIT_TOPUP_RATE_METADATA_KEY`), and fulfillment
|
|
93
|
+
* re-prices it at THAT rate, never the rate in force when Stripe confirms the
|
|
94
|
+
* payment: a session opened before a rate change and paid after it must still
|
|
95
|
+
* be credited.
|
|
96
|
+
*/
|
|
97
|
+
export declare function creditTopupUsdCentsAtRate(credits: number, usdCentsPer100: number): number | null;
|
|
98
|
+
/** Checkout-session metadata key carrying the rate a top-up was quoted at. */
|
|
99
|
+
export declare const CREDIT_TOPUP_RATE_METADATA_KEY = "usd_cents_per_100";
|
|
100
|
+
/**
|
|
101
|
+
* Every top-up rate (US cents per 100 credits) a checkout has been or can be
|
|
102
|
+
* minted at. Append when the rate changes; never remove one, because an unpaid
|
|
103
|
+
* session quoted at it can still be paid. The first entry is also the rate of
|
|
104
|
+
* sessions created before the rate was written into their metadata.
|
|
105
|
+
*
|
|
106
|
+
* 130 is the 2026-09 rate (decision 1.5). It is listed before the switch's
|
|
107
|
+
* instant as well, so a session minted after the instant is still credited if
|
|
108
|
+
* an operator rolls the switch back before the customer pays. Accepting a rate
|
|
109
|
+
* higher than the one in force can never credit a purchase cheaply.
|
|
110
|
+
*/
|
|
111
|
+
export declare const CREDIT_TOPUP_SOLD_USD_CENTS_PER_100: readonly [125, 130];
|
|
112
|
+
export declare const CREDIT_TOPUP_LEGACY_USD_CENTS_PER_100: number;
|
|
113
|
+
/**
|
|
114
|
+
* Whether fulfillment may price a session at `usdCentsPer100`: a rate OXYGEN has
|
|
115
|
+
* sold at, or the rate in force now. Anything else is metadata no OXYGEN server
|
|
116
|
+
* wrote, and it is refused rather than credited at a cheaper rate.
|
|
117
|
+
*/
|
|
118
|
+
export declare function isAcceptedCreditTopupRate(usdCentsPer100: number, currentUsdCentsPer100?: number): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Credits one workflow step costs right now. Every step a live run executes
|
|
121
|
+
* (a manifest step, a billable graph node, a recipe checkpoint, the durable
|
|
122
|
+
* recipe runtime) draws this from the one credit pool; rows written inside a run
|
|
123
|
+
* are free (repricing 2026-09, decisions 6.1 and 6.2). Seed key:
|
|
124
|
+
* charge.automation.action.
|
|
125
|
+
*
|
|
126
|
+
* The step price rises 0.001 → 0.05 at the repricing's effective instant (S07),
|
|
127
|
+
* so it is read per call through the switch and never from the snapshot. A page
|
|
128
|
+
* that shows it resolves it on the server and passes the number down.
|
|
129
|
+
*/
|
|
130
|
+
export declare function automationStepCredits(options?: RepricingOptions): number;
|
|
131
|
+
/**
|
|
132
|
+
* Credits one provider call made with the customer's own API key (BYOK) costs
|
|
133
|
+
* right now: the platform fee of decision 6.3. The vendor bills the call to the
|
|
134
|
+
* customer's own account; this is OXYGEN's fee for running it. Seed key:
|
|
135
|
+
* charge.byok.platform_fee.
|
|
136
|
+
*
|
|
137
|
+
* 0 until the repricing's effective instant (S07), then 0.05, so it is read per
|
|
138
|
+
* call through the switch and never from the snapshot. Every BYOK provider call
|
|
139
|
+
* is admitted and captured at this price by `chargeByokCall`
|
|
140
|
+
* (`@oxygen/integrations`).
|
|
141
|
+
*/
|
|
142
|
+
export declare function byokPlatformFeeCredits(options?: RepricingOptions): number;
|
|
143
|
+
/**
|
|
144
|
+
* Whether the step credits a live run executes count toward its approved
|
|
145
|
+
* `max_credits` and a trigger's per-delivery ceiling (proposal P-45). Dark until
|
|
146
|
+
* the step price rises with it: counting 0.001 steps would only tighten ceilings
|
|
147
|
+
* customers already approved.
|
|
148
|
+
*/
|
|
149
|
+
export declare function automationStepsCountTowardRunCap(options?: RepricingOptions): boolean;
|
|
80
150
|
/** Kinds of resource that carry a fixed monthly credit commitment. */
|
|
81
|
-
export declare const CREDIT_COMMITMENT_KINDS: readonly ["sending_mailbox", "managed_mailbox", "mailbox_warmup", "deliverability_unit", "linkedin_account", "whatsapp_account"];
|
|
151
|
+
export declare const CREDIT_COMMITMENT_KINDS: readonly ["sending_mailbox", "managed_mailbox", "mailbox_warmup", "deliverability_unit", "linkedin_account", "whatsapp_account", "x_account", "phone_number"];
|
|
82
152
|
export type CreditCommitmentKind = (typeof CREDIT_COMMITMENT_KINDS)[number];
|
|
83
153
|
/**
|
|
84
154
|
* Sequencer platform fee per CONNECTED SENDING MAILBOX per month, in credits
|
|
85
155
|
* ($1.00). Charged on EVERY mailbox wired to the sequencer — BYOK/self-connected
|
|
86
156
|
* Gmail and Microsoft inboxes included — and it STACKS on Oxygen-sold mailboxes,
|
|
87
|
-
* which additionally pay their own mailbox/warmup/placement lines.
|
|
157
|
+
* which additionally pay their own mailbox/warmup/placement lines. Read from the
|
|
158
|
+
* pricing seed (`commitment.sending_mailbox`) through the generated snapshot, so
|
|
159
|
+
* there is one definition of the price.
|
|
88
160
|
*/
|
|
89
161
|
export declare const SENDING_MAILBOX_MONTHLY_CREDITS = 100;
|
|
90
162
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
163
|
+
* Grace window after a commitment goes past_due before the account disconnects.
|
|
164
|
+
* Repricing 2026-09 decision 2.8: sending from the account pauses at once, and
|
|
165
|
+
* after 7 days without funds the account disconnects (replacing the earlier 14
|
|
166
|
+
* days with no auto-cancel). The pause and the disconnect sweep are slice S23.
|
|
93
167
|
*/
|
|
94
|
-
export declare const
|
|
168
|
+
export declare const COMMITMENT_PAST_DUE_GRACE_DAYS = 7;
|
|
95
169
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
170
|
+
* P-15 (PROPOSED default, awaiting ratification): what "disconnect" means for a
|
|
171
|
+
* rented phone number. Releasing a number at the carrier is irreversible, so it is
|
|
172
|
+
* suspended at COMMITMENT_PAST_DUE_GRACE_DAYS (it already cannot dial while past
|
|
173
|
+
* due) and released only after this many days without funds.
|
|
100
174
|
*/
|
|
101
|
-
export declare const
|
|
175
|
+
export declare const PHONE_NUMBER_PAST_DUE_RELEASE_DAYS = 30;
|
|
176
|
+
/**
|
|
177
|
+
* What happens to a connected account whose reservation renewal was refused, and
|
|
178
|
+
* when (decision 2.8 and P-15). `teardown` is the one irreversible-or-disconnecting
|
|
179
|
+
* step and `teardownAt` its instant; `suspendedAt` marks the day-7 rung for a kind
|
|
180
|
+
* whose teardown waits longer (a phone number).
|
|
181
|
+
*/
|
|
182
|
+
export type CommitmentGraceSchedule = {
|
|
183
|
+
teardown: "disconnect" | "release";
|
|
184
|
+
teardownAt: Date;
|
|
185
|
+
suspendedAt: Date | null;
|
|
186
|
+
};
|
|
187
|
+
export declare function commitmentGraceSchedule(kind: CreditCommitmentKind, pastDueSince: Date): CommitmentGraceSchedule;
|
|
102
188
|
/**
|
|
103
189
|
* Reconnect window in which an ENDED commitment resumes instead of starting a new
|
|
104
190
|
* one. The single most important anti-double-charge rule: a Unipile re-auth, a
|
|
@@ -131,26 +217,48 @@ export declare const COMMITMENT_GRACE_DAYS = 30;
|
|
|
131
217
|
* InboxPricingUnsignedError / WarmupPricingUnsignedError doctrine.
|
|
132
218
|
*/
|
|
133
219
|
export declare function ratifiedCommitmentCredits(kind: CreditCommitmentKind): number | null;
|
|
134
|
-
export
|
|
135
|
-
readonly id:
|
|
136
|
-
readonly usdCents:
|
|
137
|
-
readonly credits:
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
export
|
|
220
|
+
export type CreditTopupPack = {
|
|
221
|
+
readonly id: string;
|
|
222
|
+
readonly usdCents: number;
|
|
223
|
+
readonly credits: number;
|
|
224
|
+
};
|
|
225
|
+
/**
|
|
226
|
+
* The dollar packs sold at $1.25 per 100 credits, on offer until the 2026-09
|
|
227
|
+
* repricing's effective instant. The id is the pack's price in dollars.
|
|
228
|
+
*/
|
|
229
|
+
export declare const CREDIT_TOPUP_LEGACY_PACKS: readonly CreditTopupPack[];
|
|
230
|
+
/**
|
|
231
|
+
* The credit-first packs on offer from the 2026-09 repricing's instant, at $1.30
|
|
232
|
+
* per 100 credits (decision 1.5; the pack set is PROPOSED P-7). Dollar packs at
|
|
233
|
+
* $1.30 would buy fractional credits ($10 → 769.2), so these fix the credits and
|
|
234
|
+
* the id names them. The ids are new on purpose: fulfillment credits a pack
|
|
235
|
+
* session `pack.credits` without re-checking its amount, so reusing '10' or '25'
|
|
236
|
+
* with a new price would credit an old unpaid session from the new table.
|
|
237
|
+
*/
|
|
238
|
+
export declare const CREDIT_TOPUP_PACKS_2026_09: readonly CreditTopupPack[];
|
|
239
|
+
/** Every pack id a checkout session may carry, whichever table sold it. */
|
|
240
|
+
export declare const CREDIT_TOPUP_KNOWN_PACKS: readonly CreditTopupPack[];
|
|
241
|
+
/** The packs on offer now: the dollar packs until the switch, the credit-first packs from it. */
|
|
242
|
+
export declare function creditTopupPacks(options?: RepricingOptions): readonly CreditTopupPack[];
|
|
243
|
+
/**
|
|
244
|
+
* Any pack a session may name, with the credits and price it was SOLD at. Used by
|
|
245
|
+
* fulfillment, which must credit an old session its original credits whichever
|
|
246
|
+
* packs are on offer when Stripe confirms the payment.
|
|
247
|
+
*/
|
|
153
248
|
export declare function resolveCreditTopupPack(id: string | null | undefined): CreditTopupPack | null;
|
|
249
|
+
/**
|
|
250
|
+
* How the top-up route sells a pack id right now. A pack on offer sells at its
|
|
251
|
+
* own price. Any other known id (a dollar pack after the switch from an older
|
|
252
|
+
* CLI, or a credit-first pack before it) still works and buys the pack's credits
|
|
253
|
+
* as a custom amount at the rate in force, so an old client sees the current
|
|
254
|
+
* quote and never an old price. Null for an unknown id.
|
|
255
|
+
*/
|
|
256
|
+
export declare function quoteCreditTopupPack(id: string | null | undefined, options?: RepricingOptions): {
|
|
257
|
+
pack: CreditTopupPack;
|
|
258
|
+
offered: boolean;
|
|
259
|
+
credits: number;
|
|
260
|
+
usdCents: number;
|
|
261
|
+
} | null;
|
|
154
262
|
export declare const TRIAL_PERIOD_DAYS = 7;
|
|
155
263
|
export declare const TRIAL_CREDIT_GRANT = 2000;
|
|
156
264
|
/**
|
|
@@ -195,6 +303,54 @@ export declare const FREE_TIER_GRANTS_ENABLED_ENV_VAR = "OXYGEN_FREE_TIER_GRANTS
|
|
|
195
303
|
export declare function freeTierGrantsEnabled(env?: Record<string, string | undefined>): boolean;
|
|
196
304
|
export declare const WALKTHROUGH_COMPLETION_BONUS_CREDITS = 100;
|
|
197
305
|
export declare const WALKTHROUGH_SCRAPE_MAX_CREDITS = 200;
|
|
306
|
+
/**
|
|
307
|
+
* The volume bonus of a plan (repricing 2026-09, decision 1.3): the monthly
|
|
308
|
+
* credits it grants above face value ($1 = 100 credits). +5% on $499 (52,395),
|
|
309
|
+
* +10% on $999 (109,890), +15% on $1,999 (229,885); $49-$199 stay flat.
|
|
310
|
+
*
|
|
311
|
+
* DERIVED from the seeded monthlyCredits rather than declared, so the schedule
|
|
312
|
+
* lives in one place (packages/control-db/src/pricing/seed.ts). Only the
|
|
313
|
+
* purchasable Oxygen rungs carry a bonus: a legacy plan whose credits exceed its
|
|
314
|
+
* price (launch_50 bought 20,000 credits for $50 under the old unit) is not a
|
|
315
|
+
* volume bonus, and a contact-sales plan has no face value.
|
|
316
|
+
*/
|
|
317
|
+
export declare function planVolumeBonusCredits(planKey: string | null | undefined): number;
|
|
318
|
+
/**
|
|
319
|
+
* The volume bonus inside one subscription grant of `monthlyCredits` on
|
|
320
|
+
* `planKey`: the plan's bonus when the grant is the plan's seeded allowance, and
|
|
321
|
+
* 0 when a metadata override replaced it (a custom allowance carries no
|
|
322
|
+
* schedule to defer). Grant writers pass this to grantSubscriptionCredits.
|
|
323
|
+
*/
|
|
324
|
+
export declare function subscriptionGrantVolumeBonusCredits(planKey: string | null | undefined, monthlyCredits: number | null | undefined): number;
|
|
325
|
+
/** The volume bonus as a whole percentage of face value: 5, 10, 15, or 0. */
|
|
326
|
+
export declare function planVolumeBonusPercent(planKey: string | null | undefined): number;
|
|
327
|
+
/**
|
|
328
|
+
* Agency partner bonus (repricing 2026-09, decision 9.1): a partner earns
|
|
329
|
+
* +15% of its plan's face value in bonus credits every month, on every Oxygen
|
|
330
|
+
* size from $99, on top of the volume bonus. The two percentages ADD (spec
|
|
331
|
+
* PROPOSED default P-1, option A of the agency-partner benchmark): the $1,999
|
|
332
|
+
* plan grants 229,885 + 29,985 = 259,870, never 229,885 x 1.15.
|
|
333
|
+
*
|
|
334
|
+
* The bonus is its own ledger line (category `partner_bonus`), never part of
|
|
335
|
+
* the plan's monthlyCredits, so it stays out of every limit or guard derived
|
|
336
|
+
* from the plan allowance (P-3, P-54, P-61).
|
|
337
|
+
*/
|
|
338
|
+
export declare const PARTNER_BONUS_PERCENT = 15;
|
|
339
|
+
/** The smallest plan that earns the partner bonus: $99 a month. */
|
|
340
|
+
export declare const PARTNER_BONUS_MINIMUM_MONTHLY_PRICE_CENTS = 9900;
|
|
341
|
+
/**
|
|
342
|
+
* The monthly partner bonus of a plan: 15% of face value ($1 = 100 credits),
|
|
343
|
+
* rounded half up to a whole credit (section 2's rounding rule). 0 for Free,
|
|
344
|
+
* $49, the grandfathered Starter/Pro/Team and older legacy plans, and the
|
|
345
|
+
* contact-sales plans (P-3: Oxygen sizes only).
|
|
346
|
+
*/
|
|
347
|
+
export declare function planPartnerBonusCredits(planKey: string | null | undefined): number;
|
|
348
|
+
/**
|
|
349
|
+
* The partner bonus that rides with one subscription grant of `monthlyCredits`
|
|
350
|
+
* on `planKey`: the plan's bonus when the grant is the plan's seeded allowance,
|
|
351
|
+
* 0 when a metadata override replaced it (a custom contract is priced by hand).
|
|
352
|
+
*/
|
|
353
|
+
export declare function subscriptionGrantPartnerBonusCredits(planKey: string | null | undefined, monthlyCredits: number | null | undefined): number;
|
|
198
354
|
export declare const BASE_PRICING_PLANS: {
|
|
199
355
|
readonly free: {
|
|
200
356
|
readonly monthlyPriceCents: number | null;
|
|
@@ -207,9 +363,9 @@ export declare const BASE_PRICING_PLANS: {
|
|
|
207
363
|
readonly monthlyAutomationActions: null;
|
|
208
364
|
readonly automationOverageCentsPerMillion: null;
|
|
209
365
|
readonly automationOverageEnabledDefault: false;
|
|
210
|
-
readonly description: "Your CRM
|
|
366
|
+
readonly description: "Your CRM and tables — free forever. Credits pay for enrichment, AI and workflow steps; your own provider keys need a paid plan.";
|
|
211
367
|
readonly ctaLabel: "Upgrade";
|
|
212
|
-
readonly features: readonly ["CRM, Tables,
|
|
368
|
+
readonly features: readonly ["CRM, Tables, and Knowledge — unmetered; workflows pay per step", "Sequences: author, preview, and enroll", "Agents and Workspace Copilot", "Credits for enrichment and AI, topped up any time"];
|
|
213
369
|
};
|
|
214
370
|
readonly oxygen: {
|
|
215
371
|
readonly monthlyPriceCents: number | null;
|
|
@@ -339,12 +495,18 @@ export declare function resolveSubscriptionEntitlement(input: {
|
|
|
339
495
|
currentPeriodStart?: Date | null;
|
|
340
496
|
currentPeriodEnd?: Date | null;
|
|
341
497
|
trialEnd?: Date | null;
|
|
498
|
+
/**
|
|
499
|
+
* `subscriptions.past_due_since`: when this unpaid streak was first seen.
|
|
500
|
+
* The past-due grace counts from here, never from a period start that a
|
|
501
|
+
* yearly plan may have set months ago.
|
|
502
|
+
*/
|
|
503
|
+
pastDueSince?: Date | null;
|
|
342
504
|
now?: Date;
|
|
343
505
|
/** Overrides the env switch. Injected by tests; production reads the flag. */
|
|
344
506
|
freeTierEntitled?: boolean;
|
|
345
507
|
}): SubscriptionEntitlement;
|
|
346
508
|
export type ResolvedPricingPlan = PricingPlanDefinition;
|
|
347
|
-
export declare function resolveBasePricingPlan(tier: string | null | undefined): ResolvedPricingPlan | null;
|
|
509
|
+
export declare function resolveBasePricingPlan(tier: string | null | undefined, options?: RepricingOptions): ResolvedPricingPlan | null;
|
|
348
510
|
export declare function applyPricingPlanMetadataOverrides(// skipcq: JS-R1005
|
|
349
511
|
plan: PricingPlanDefinition, metadata: PricingPlanMetadata): PricingPlanDefinition;
|
|
350
512
|
export declare function isSelfServePlanTier(value: string): value is SelfServePlanTier;
|
|
@@ -361,6 +523,33 @@ export declare function getCurrentBillingCycleKey(date?: Date): string;
|
|
|
361
523
|
* billing-anchor shift without admitting a quarterly or annual period.
|
|
362
524
|
*/
|
|
363
525
|
export declare const CREDIT_CYCLE_MAX_PERIOD_DAYS = 35;
|
|
526
|
+
/**
|
|
527
|
+
* Annual billing (Repricing 2026-09, decision 1.2): a year costs ten months of
|
|
528
|
+
* the monthly price, and the credits are still granted monthly.
|
|
529
|
+
*/
|
|
530
|
+
export declare const ANNUAL_BILLING_MONTHS_CHARGED = 10;
|
|
531
|
+
/** The yearly price of a rung, in cents: ten times its monthly price. */
|
|
532
|
+
export declare function annualPlanPriceCents(monthlyPriceCents: number): number;
|
|
533
|
+
/** How often a plan Price bills. Credits are granted monthly on both. */
|
|
534
|
+
export type PlanBillingInterval = "month" | "year";
|
|
535
|
+
export declare const PLAN_BILLING_INTERVALS: readonly PlanBillingInterval[];
|
|
536
|
+
/**
|
|
537
|
+
* A billing interval as a customer or an agent types it. `month`/`monthly` and
|
|
538
|
+
* `year`/`yearly`/`annual`/`annually` are accepted; anything else is null so the
|
|
539
|
+
* caller can refuse it by name instead of silently billing monthly.
|
|
540
|
+
*/
|
|
541
|
+
export declare function parsePlanBillingInterval(value: unknown): PlanBillingInterval | null;
|
|
542
|
+
/**
|
|
543
|
+
* What one charge of a rung costs on an interval, in cents: the monthly price,
|
|
544
|
+
* or ten months' price for a year.
|
|
545
|
+
*/
|
|
546
|
+
export declare function planChargeCents(monthlyPriceCents: number, interval: PlanBillingInterval): number;
|
|
547
|
+
/**
|
|
548
|
+
* The per-month equivalent of one charge, in cents, rounded to the cent: $990 a
|
|
549
|
+
* year is $82.50 a month. This is what `recurring_monthly` reports, so a yearly
|
|
550
|
+
* plan is never compared as if it cost $990 a month.
|
|
551
|
+
*/
|
|
552
|
+
export declare function planMonthlyEquivalentCents(chargeCents: number, interval: PlanBillingInterval): number;
|
|
364
553
|
export type CreditCycleSource = "subscription_period" | "calendar_month";
|
|
365
554
|
export type CreditCycleWindow = {
|
|
366
555
|
start: Date;
|
|
@@ -389,6 +578,21 @@ export declare function isStripeManagedSubscription(subscription: {
|
|
|
389
578
|
stripeSubscriptionId?: string | null;
|
|
390
579
|
metadata?: Record<string, unknown> | null;
|
|
391
580
|
}): boolean;
|
|
581
|
+
/**
|
|
582
|
+
* Whether a Stripe subscription is scheduled to end. A classic-billing-mode
|
|
583
|
+
* period-end cancel sets `cancel_at_period_end`; a Billing Portal cancel on a
|
|
584
|
+
* flexible-billing-mode subscription sets only `cancel_at` (to the period end)
|
|
585
|
+
* and leaves `cancel_at_period_end` false (Stripe billing-mode comparison docs;
|
|
586
|
+
* reproduced in test mode 2026-09-26). Reading the boolean alone showed a
|
|
587
|
+
* Portal-cancelled plan as renewing. `cancel_at` on a subscription that has
|
|
588
|
+
* already ended records when it ended, not a pending cancellation, so it only
|
|
589
|
+
* counts while the subscription is still live.
|
|
590
|
+
*/
|
|
591
|
+
export declare function stripeSubscriptionCancellationScheduled(subscription: {
|
|
592
|
+
status: string;
|
|
593
|
+
cancel_at_period_end?: boolean | null;
|
|
594
|
+
cancel_at?: number | null;
|
|
595
|
+
}): boolean;
|
|
392
596
|
/**
|
|
393
597
|
* The window the credit-allowance bar measures: "this month's credits", resolved
|
|
394
598
|
* to the boundary at which the plan's grant actually renews.
|
|
@@ -412,6 +616,12 @@ export declare function resolveCreditCycleWindow(input: {
|
|
|
412
616
|
currentPeriodEnd: Date | null;
|
|
413
617
|
/** isOffStripeSubscription(subscription.metadata) — resolved by the caller. */
|
|
414
618
|
offStripe: boolean;
|
|
619
|
+
/**
|
|
620
|
+
* planBillingIntervalForPriceId(subscription.stripePriceId). A yearly
|
|
621
|
+
* period grants its credits in monthly slices, so the cycle the bar measures
|
|
622
|
+
* is the current slice, anchored to the period start (P-8).
|
|
623
|
+
*/
|
|
624
|
+
billingInterval?: "month" | "year" | null;
|
|
415
625
|
} | null;
|
|
416
626
|
now?: Date;
|
|
417
627
|
}): CreditCycleWindow;
|