@oxygen-agent/cli 1.1010.721 → 1.1010.950
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 +14 -0
- package/dist/contract-flags.d.ts +42 -0
- package/dist/contract-flags.js +220 -0
- 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/index.js +622 -325
- package/dist/run-wait.d.ts +3 -1
- package/dist/run-wait.js +19 -5
- package/dist/sender-limits-flags.d.ts +14 -0
- package/dist/sender-limits-flags.js +157 -0
- package/dist/streamed-file-import.d.ts +58 -0
- package/dist/streamed-file-import.js +115 -0
- package/dist/ugc-commands.js +16 -2
- 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 +6 -6
- package/node_modules/@oxygen/cli-ugc/dist/field-parser.d.ts +4 -0
- package/node_modules/@oxygen/cli-ugc/dist/field-parser.js +20 -8
- package/node_modules/@oxygen/cli-ugc/dist/index.d.ts +1 -0
- package/node_modules/@oxygen/cli-ugc/dist/index.js +1 -0
- package/node_modules/@oxygen/shared/dist/billing-anchors.d.ts +17 -0
- package/node_modules/@oxygen/shared/dist/billing-anchors.js +27 -0
- package/node_modules/@oxygen/shared/dist/billing.d.ts +191 -35
- package/node_modules/@oxygen/shared/dist/billing.js +333 -42
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +55 -5
- package/node_modules/@oxygen/shared/dist/contracts/operations.d.ts +39 -0
- package/node_modules/@oxygen/shared/dist/contracts/operations.js +11 -0
- package/node_modules/@oxygen/shared/dist/contracts/schema.d.ts +186 -0
- package/node_modules/@oxygen/shared/dist/contracts/schema.js +260 -0
- package/node_modules/@oxygen/shared/dist/contracts/sender-limits.d.ts +67 -0
- package/node_modules/@oxygen/shared/dist/contracts/sender-limits.js +88 -0
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.d.ts +2 -2
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.js +2 -2
- 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 +3 -1
- package/node_modules/@oxygen/shared/dist/email-hard-bounce.js +3 -3
- 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 +4 -0
- package/node_modules/@oxygen/shared/dist/feature-gates.js +5 -0
- 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 +2 -22
- package/node_modules/@oxygen/shared/dist/index.js +2 -42
- package/node_modules/@oxygen/shared/dist/linkedin-sequences.d.ts +11 -0
- package/node_modules/@oxygen/shared/dist/linkedin-sequences.js +41 -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/plan-band.d.ts +117 -1
- package/node_modules/@oxygen/shared/dist/plan-band.js +175 -10
- 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 +204 -6
- package/node_modules/@oxygen/shared/dist/plan-limits.js +197 -15
- package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +80 -36
- package/node_modules/@oxygen/shared/dist/pricing-sheet.js +80 -31
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.d.ts +38 -20
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.js +47 -34
- package/node_modules/@oxygen/shared/dist/product-briefing-rules.js +4 -2
- 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 +127 -0
- package/node_modules/@oxygen/shared/dist/repricing.js +407 -6
- 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 +5 -7
- package/node_modules/@oxygen/shared/dist/sending-limits.js +10 -16
- 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/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 +15 -7
- package/node_modules/@oxygen/shared/dist/stripe-price-catalog.js +18 -5
- package/node_modules/@oxygen/shared/dist/table-capacity.d.ts +35 -5
- package/node_modules/@oxygen/shared/dist/table-capacity.js +40 -8
- 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.js +5 -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 +17 -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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseField } from "./field-parser.js";
|
|
1
|
+
import { parseField, UgcUsageError } from "./field-parser.js";
|
|
2
2
|
export function registerUgcCommands(program, { request: requestOxygen, handle }) {
|
|
3
3
|
const ugc = program
|
|
4
4
|
.command("ugc")
|
|
@@ -1023,7 +1023,7 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
1023
1023
|
{
|
|
1024
1024
|
action: "sponsorship_cancel",
|
|
1025
1025
|
command: "sponsorship cancel",
|
|
1026
|
-
description: "Preview stopping renewal for one program sponsorship. Confirm with --approved and a signed-in master admin.
|
|
1026
|
+
description: "Preview stopping renewal for one program sponsorship. Confirm with --approved and a signed-in master admin. The paid period stays; a credit sponsorship stops without a card provider call.",
|
|
1027
1027
|
fields: [
|
|
1028
1028
|
{
|
|
1029
1029
|
name: "program_id",
|
|
@@ -1048,7 +1048,7 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
1048
1048
|
{
|
|
1049
1049
|
action: "sponsorship_preview",
|
|
1050
1050
|
command: "sponsorship preview",
|
|
1051
|
-
description: "Preview
|
|
1051
|
+
description: "Preview sponsoring creators as a signed-in master admin: funding is card (seat plus 10,000-credit grant) or credits (one LinkedIn reservation per creator). Org API keys cannot quote.",
|
|
1052
1052
|
fields: [
|
|
1053
1053
|
{
|
|
1054
1054
|
name: "program_id",
|
|
@@ -1067,7 +1067,7 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
1067
1067
|
{
|
|
1068
1068
|
action: "sponsorship_confirm",
|
|
1069
1069
|
command: "sponsorship confirm",
|
|
1070
|
-
description: "Confirm the exact sponsorship quote as the same signed-in master
|
|
1070
|
+
description: "Confirm the exact sponsorship quote as the same signed-in master admin. Card quotes return checkouts; credit quotes start the reservations or fail with insufficient_credits.",
|
|
1071
1071
|
fields: [
|
|
1072
1072
|
{
|
|
1073
1073
|
name: "program_id",
|
|
@@ -1316,10 +1316,10 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
1316
1316
|
}
|
|
1317
1317
|
if (spec.action === "invite_create") {
|
|
1318
1318
|
if ((body.email === undefined) === (body.emails === undefined))
|
|
1319
|
-
throw new
|
|
1319
|
+
throw new UgcUsageError("Pass exactly one of --email or --emails.");
|
|
1320
1320
|
body.send_email = options.linkOnly !== true;
|
|
1321
1321
|
if (options.linkOnly && (body.approved || body.preview_token))
|
|
1322
|
-
throw new
|
|
1322
|
+
throw new UgcUsageError("--link-only cannot be combined with --approved or --preview-token.");
|
|
1323
1323
|
}
|
|
1324
1324
|
return requestOxygen("/api/cli/ugc", {
|
|
1325
1325
|
method: "POST",
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/** A malformed flag value: the CLI reports it as `invalid_request`, not `unexpected_error`. */
|
|
2
|
+
export class UgcUsageError extends Error {
|
|
3
|
+
code = "invalid_request";
|
|
4
|
+
}
|
|
1
5
|
/** `2/week`, `4/month`, `10/total` or `none` (clears); a count of 1–100. */
|
|
2
6
|
export function parsePostingTarget(value) {
|
|
3
7
|
const text = value.trim().toLowerCase();
|
|
@@ -6,7 +10,7 @@ export function parsePostingTarget(value) {
|
|
|
6
10
|
const match = /^(\d{1,3})\s*\/\s*(week|month|total)$/.exec(text);
|
|
7
11
|
const count = match ? Number(match[1]) : 0;
|
|
8
12
|
if (!match || count < 1 || count > 100)
|
|
9
|
-
throw new
|
|
13
|
+
throw new UgcUsageError("--posting-target must be <n>/month, <n>/total or <n>/week with n from 1 to 100, or none.");
|
|
10
14
|
return { count, period: match[2] };
|
|
11
15
|
}
|
|
12
16
|
/** A JSON array of emails, or emails separated by commas, semicolons or whitespace. */
|
|
@@ -14,15 +18,15 @@ export function parseEmailList(value) {
|
|
|
14
18
|
const text = value.trim();
|
|
15
19
|
let items;
|
|
16
20
|
if (text.startsWith("[")) {
|
|
17
|
-
items =
|
|
21
|
+
items = parseJson(text, "--emails");
|
|
18
22
|
if (!Array.isArray(items) || !items.every((item) => typeof item === "string"))
|
|
19
|
-
throw new
|
|
23
|
+
throw new UgcUsageError("--emails must be a JSON array of strings or a comma-separated list.");
|
|
20
24
|
}
|
|
21
25
|
else
|
|
22
26
|
items = text.split(/[\s,;]+/);
|
|
23
27
|
const emails = items.map((item) => item.trim()).filter(Boolean);
|
|
24
28
|
if (!emails.length)
|
|
25
|
-
throw new
|
|
29
|
+
throw new UgcUsageError("--emails needs at least one email address.");
|
|
26
30
|
return emails;
|
|
27
31
|
}
|
|
28
32
|
export function parseField(value, field) {
|
|
@@ -34,18 +38,18 @@ export function parseField(value, field) {
|
|
|
34
38
|
if (field.kind === "text_list")
|
|
35
39
|
return String(value).split(",").map((item) => item.trim()).filter(Boolean);
|
|
36
40
|
if (field.kind === "array" || field.kind === "object") {
|
|
37
|
-
const parsed =
|
|
41
|
+
const parsed = parseJson(String(value), field.name);
|
|
38
42
|
if (field.kind === "array"
|
|
39
43
|
? !Array.isArray(parsed) ||
|
|
40
44
|
!parsed.every((item) => typeof item === "string")
|
|
41
45
|
: !parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
42
|
-
throw new
|
|
46
|
+
throw new UgcUsageError(`${field.name} must be a JSON ${field.kind === "array" ? "array of strings" : "object"}.`);
|
|
43
47
|
return parsed;
|
|
44
48
|
}
|
|
45
49
|
if (field.kind === "number") {
|
|
46
50
|
const parsed = Number(value);
|
|
47
51
|
if (!Number.isFinite(parsed) || parsed < 0)
|
|
48
|
-
throw new
|
|
52
|
+
throw new UgcUsageError(`${field.name} must be a nonnegative finite number.`);
|
|
49
53
|
return parsed;
|
|
50
54
|
}
|
|
51
55
|
if (field.kind === "boolean") {
|
|
@@ -53,7 +57,15 @@ export function parseField(value, field) {
|
|
|
53
57
|
return true;
|
|
54
58
|
if (value === false || value === "false")
|
|
55
59
|
return false;
|
|
56
|
-
throw new
|
|
60
|
+
throw new UgcUsageError(`${field.name} must be true or false.`);
|
|
57
61
|
}
|
|
58
62
|
return value;
|
|
59
63
|
}
|
|
64
|
+
function parseJson(text, name) {
|
|
65
|
+
try {
|
|
66
|
+
return JSON.parse(text);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
throw new UgcUsageError(`${name} must be valid JSON.`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { registerUgcCommands as registerCommands } from "./commands.js";
|
|
2
|
+
export { UgcUsageError } from "./field-parser.js";
|
|
2
3
|
/** Register the existing UGC command tree without performing requests. */
|
|
3
4
|
export function registerUgcCommands(program, dependencies) {
|
|
4
5
|
registerCommands(program, dependencies);
|
|
@@ -89,3 +89,20 @@ export declare function subscriptionGrantSlices(periodStart: Date, periodEnd: Da
|
|
|
89
89
|
export declare function dueSubscriptionGrantSlices(periodStart: Date, periodEnd: Date, now: Date): SubscriptionGrantSlice[];
|
|
90
90
|
/** The slice `now` falls in, or null outside the period. */
|
|
91
91
|
export declare function currentSubscriptionGrantSlice(periodStart: Date, periodEnd: Date, now: Date): SubscriptionGrantSlice | null;
|
|
92
|
+
/**
|
|
93
|
+
* When the next monthly credit grant of a paid plan arrives (repricing 2026-09,
|
|
94
|
+
* S13: "know when my credits arrive").
|
|
95
|
+
*
|
|
96
|
+
* A monthly plan grants with its renewal, at the period end. A yearly plan
|
|
97
|
+
* grants each slice at its start, so the next grant is the end of the slice
|
|
98
|
+
* `now` falls in; the last slice's end is the renewal. A grant that depends on
|
|
99
|
+
* the renewal is null when the renewal will not happen (`renews: false`: a
|
|
100
|
+
* scheduled cancellation, a lapsed or unpaid plan), because no grant follows.
|
|
101
|
+
*/
|
|
102
|
+
export declare function nextSubscriptionCreditGrantAt(input: {
|
|
103
|
+
periodStart: Date | null | undefined;
|
|
104
|
+
periodEnd: Date | null | undefined;
|
|
105
|
+
billingInterval: "month" | "year" | null | undefined;
|
|
106
|
+
renews: boolean;
|
|
107
|
+
now?: Date;
|
|
108
|
+
}): Date | null;
|
|
@@ -198,3 +198,30 @@ export function dueSubscriptionGrantSlices(periodStart, periodEnd, now) {
|
|
|
198
198
|
export function currentSubscriptionGrantSlice(periodStart, periodEnd, now) {
|
|
199
199
|
return (subscriptionGrantSlices(periodStart, periodEnd).find((slice) => slice.start.getTime() <= now.getTime() && now.getTime() < slice.end.getTime()) ?? null);
|
|
200
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;
|
|
@@ -75,7 +85,8 @@ 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
|
-
|
|
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;
|
|
79
90
|
/**
|
|
80
91
|
* Price of a custom top-up at an explicit rate. A checkout session records the
|
|
81
92
|
* rate it was quoted at (`CREDIT_TOPUP_RATE_METADATA_KEY`), and fulfillment
|
|
@@ -87,12 +98,17 @@ export declare function creditTopupUsdCentsAtRate(credits: number, usdCentsPer10
|
|
|
87
98
|
/** Checkout-session metadata key carrying the rate a top-up was quoted at. */
|
|
88
99
|
export declare const CREDIT_TOPUP_RATE_METADATA_KEY = "usd_cents_per_100";
|
|
89
100
|
/**
|
|
90
|
-
* Every top-up rate (US cents per 100 credits) a checkout has
|
|
91
|
-
* at. Append when the rate changes; never remove one, because an unpaid
|
|
92
|
-
* quoted at it can still be paid. The first entry is also the rate of
|
|
93
|
-
* created before the rate was written into their metadata.
|
|
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.
|
|
94
110
|
*/
|
|
95
|
-
export declare const CREDIT_TOPUP_SOLD_USD_CENTS_PER_100: readonly [125];
|
|
111
|
+
export declare const CREDIT_TOPUP_SOLD_USD_CENTS_PER_100: readonly [125, 130];
|
|
96
112
|
export declare const CREDIT_TOPUP_LEGACY_USD_CENTS_PER_100: number;
|
|
97
113
|
/**
|
|
98
114
|
* Whether fulfillment may price a session at `usdCentsPer100`: a rate OXYGEN has
|
|
@@ -100,7 +116,37 @@ export declare const CREDIT_TOPUP_LEGACY_USD_CENTS_PER_100: number;
|
|
|
100
116
|
* wrote, and it is refused rather than credited at a cheaper rate.
|
|
101
117
|
*/
|
|
102
118
|
export declare function isAcceptedCreditTopupRate(usdCentsPer100: number, currentUsdCentsPer100?: number): boolean;
|
|
103
|
-
|
|
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;
|
|
104
150
|
/** Kinds of resource that carry a fixed monthly credit commitment. */
|
|
105
151
|
export declare const CREDIT_COMMITMENT_KINDS: readonly ["sending_mailbox", "managed_mailbox", "mailbox_warmup", "deliverability_unit", "linkedin_account", "whatsapp_account", "x_account", "phone_number"];
|
|
106
152
|
export type CreditCommitmentKind = (typeof CREDIT_COMMITMENT_KINDS)[number];
|
|
@@ -113,11 +159,6 @@ export type CreditCommitmentKind = (typeof CREDIT_COMMITMENT_KINDS)[number];
|
|
|
113
159
|
* there is one definition of the price.
|
|
114
160
|
*/
|
|
115
161
|
export declare const SENDING_MAILBOX_MONTHLY_CREDITS = 100;
|
|
116
|
-
/**
|
|
117
|
-
* Oxygen-sold managed mailbox per month, in credits ($3.00). Flat, superseding
|
|
118
|
-
* the dynamic vendor-COGS x 1.25 quote for the recurring mailbox line.
|
|
119
|
-
*/
|
|
120
|
-
export declare const MANAGED_MAILBOX_MONTHLY_CREDITS = 300;
|
|
121
162
|
/**
|
|
122
163
|
* Grace window after a commitment goes past_due before the account disconnects.
|
|
123
164
|
* Repricing 2026-09 decision 2.8: sending from the account pauses at once, and
|
|
@@ -125,6 +166,25 @@ export declare const MANAGED_MAILBOX_MONTHLY_CREDITS = 300;
|
|
|
125
166
|
* days with no auto-cancel). The pause and the disconnect sweep are slice S23.
|
|
126
167
|
*/
|
|
127
168
|
export declare const COMMITMENT_PAST_DUE_GRACE_DAYS = 7;
|
|
169
|
+
/**
|
|
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.
|
|
174
|
+
*/
|
|
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;
|
|
128
188
|
/**
|
|
129
189
|
* Reconnect window in which an ENDED commitment resumes instead of starting a new
|
|
130
190
|
* one. The single most important anti-double-charge rule: a Unipile re-auth, a
|
|
@@ -157,26 +217,48 @@ export declare const COMMITMENT_GRACE_DAYS = 30;
|
|
|
157
217
|
* InboxPricingUnsignedError / WarmupPricingUnsignedError doctrine.
|
|
158
218
|
*/
|
|
159
219
|
export declare function ratifiedCommitmentCredits(kind: CreditCommitmentKind): number | null;
|
|
160
|
-
export
|
|
161
|
-
readonly id:
|
|
162
|
-
readonly usdCents:
|
|
163
|
-
readonly credits:
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
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
|
+
*/
|
|
179
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;
|
|
180
262
|
export declare const TRIAL_PERIOD_DAYS = 7;
|
|
181
263
|
export declare const TRIAL_CREDIT_GRANT = 2000;
|
|
182
264
|
/**
|
|
@@ -221,6 +303,54 @@ export declare const FREE_TIER_GRANTS_ENABLED_ENV_VAR = "OXYGEN_FREE_TIER_GRANTS
|
|
|
221
303
|
export declare function freeTierGrantsEnabled(env?: Record<string, string | undefined>): boolean;
|
|
222
304
|
export declare const WALKTHROUGH_COMPLETION_BONUS_CREDITS = 100;
|
|
223
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;
|
|
224
354
|
export declare const BASE_PRICING_PLANS: {
|
|
225
355
|
readonly free: {
|
|
226
356
|
readonly monthlyPriceCents: number | null;
|
|
@@ -233,9 +363,9 @@ export declare const BASE_PRICING_PLANS: {
|
|
|
233
363
|
readonly monthlyAutomationActions: null;
|
|
234
364
|
readonly automationOverageCentsPerMillion: null;
|
|
235
365
|
readonly automationOverageEnabledDefault: false;
|
|
236
|
-
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.";
|
|
237
367
|
readonly ctaLabel: "Upgrade";
|
|
238
|
-
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"];
|
|
239
369
|
};
|
|
240
370
|
readonly oxygen: {
|
|
241
371
|
readonly monthlyPriceCents: number | null;
|
|
@@ -365,12 +495,18 @@ export declare function resolveSubscriptionEntitlement(input: {
|
|
|
365
495
|
currentPeriodStart?: Date | null;
|
|
366
496
|
currentPeriodEnd?: Date | null;
|
|
367
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;
|
|
368
504
|
now?: Date;
|
|
369
505
|
/** Overrides the env switch. Injected by tests; production reads the flag. */
|
|
370
506
|
freeTierEntitled?: boolean;
|
|
371
507
|
}): SubscriptionEntitlement;
|
|
372
508
|
export type ResolvedPricingPlan = PricingPlanDefinition;
|
|
373
|
-
export declare function resolveBasePricingPlan(tier: string | null | undefined): ResolvedPricingPlan | null;
|
|
509
|
+
export declare function resolveBasePricingPlan(tier: string | null | undefined, options?: RepricingOptions): ResolvedPricingPlan | null;
|
|
374
510
|
export declare function applyPricingPlanMetadataOverrides(// skipcq: JS-R1005
|
|
375
511
|
plan: PricingPlanDefinition, metadata: PricingPlanMetadata): PricingPlanDefinition;
|
|
376
512
|
export declare function isSelfServePlanTier(value: string): value is SelfServePlanTier;
|
|
@@ -394,6 +530,26 @@ export declare const CREDIT_CYCLE_MAX_PERIOD_DAYS = 35;
|
|
|
394
530
|
export declare const ANNUAL_BILLING_MONTHS_CHARGED = 10;
|
|
395
531
|
/** The yearly price of a rung, in cents: ten times its monthly price. */
|
|
396
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;
|
|
397
553
|
export type CreditCycleSource = "subscription_period" | "calendar_month";
|
|
398
554
|
export type CreditCycleWindow = {
|
|
399
555
|
start: Date;
|