@oxygen-agent/cli 1.177.1 → 1.209.6
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/http-client.js +6 -4
- package/dist/index.d.ts +0 -1
- package/dist/index.js +1144 -24
- package/node_modules/@oxygen/recipe-sdk/dist/index.d.ts +41 -0
- package/node_modules/@oxygen/shared/dist/billing.d.ts +28 -6
- package/node_modules/@oxygen/shared/dist/billing.js +41 -0
- package/node_modules/@oxygen/shared/dist/budget-scopes.d.ts +4 -0
- package/node_modules/@oxygen/shared/dist/budget-scopes.js +9 -0
- package/node_modules/@oxygen/shared/dist/cell-format.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/cell-format.js +26 -0
- package/node_modules/@oxygen/shared/dist/index.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/index.js +2 -0
- package/node_modules/@oxygen/shared/dist/networks.d.ts +21 -0
- package/node_modules/@oxygen/shared/dist/networks.js +25 -0
- package/node_modules/@oxygen/shared/dist/search-vocab.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/select-options.d.ts +7 -0
- package/node_modules/@oxygen/shared/dist/select-options.js +9 -0
- package/node_modules/@oxygen/shared/dist/sequences.d.ts +91 -1
- package/node_modules/@oxygen/shared/dist/sequences.js +288 -15
- package/node_modules/@oxygen/shared/dist/signup-lead-webhook.d.ts +39 -0
- package/node_modules/@oxygen/shared/dist/signup-lead-webhook.js +78 -0
- package/node_modules/@oxygen/shared/dist/sql-error.d.ts +12 -0
- package/node_modules/@oxygen/shared/dist/sql-error.js +15 -0
- package/node_modules/@oxygen/shared/dist/version.d.ts +2 -2
- package/node_modules/@oxygen/shared/dist/version.js +4 -2
- package/node_modules/@oxygen/shared/dist/workflow-trigger-metadata.js +2 -5
- package/node_modules/@oxygen/workflows/dist/index.d.ts +23 -0
- package/node_modules/@oxygen/workflows/dist/index.js +199 -24
- package/oxygen.js +2 -0
- package/package.json +2 -2
|
@@ -78,6 +78,46 @@ export type RecipeContextProfileApi = {
|
|
|
78
78
|
export type RecipeContextApi = {
|
|
79
79
|
profile: RecipeContextProfileApi;
|
|
80
80
|
};
|
|
81
|
+
export type RecipeCrmIdentity = {
|
|
82
|
+
key: string;
|
|
83
|
+
value: unknown;
|
|
84
|
+
};
|
|
85
|
+
export type RecipeCrmActivityLink = {
|
|
86
|
+
object: string;
|
|
87
|
+
row_id: string;
|
|
88
|
+
role?: string;
|
|
89
|
+
};
|
|
90
|
+
export type RecipeCrmActivityInput = {
|
|
91
|
+
type: string;
|
|
92
|
+
links: RecipeCrmActivityLink[];
|
|
93
|
+
summary?: string | null;
|
|
94
|
+
body?: string | null;
|
|
95
|
+
channel?: string | null;
|
|
96
|
+
direction?: "inbound" | "outbound" | "internal" | "system" | null;
|
|
97
|
+
occurred_at?: string | null;
|
|
98
|
+
source_provider?: string | null;
|
|
99
|
+
provider_event_id?: string | null;
|
|
100
|
+
metadata?: Record<string, unknown>;
|
|
101
|
+
};
|
|
102
|
+
export type RecipeCrmExternalRef = {
|
|
103
|
+
provider: string;
|
|
104
|
+
object: string;
|
|
105
|
+
external_id: string;
|
|
106
|
+
pulled_at?: string | null;
|
|
107
|
+
provider_event_id?: string | null;
|
|
108
|
+
confidence?: number | null;
|
|
109
|
+
};
|
|
110
|
+
export type RecipeCrmApi = {
|
|
111
|
+
assert: <T = unknown>(object: string, identity: RecipeCrmIdentity, values: Record<string, unknown> | undefined, options: {
|
|
112
|
+
key: string;
|
|
113
|
+
}) => Promise<T>;
|
|
114
|
+
assertFromProvider: <T = unknown>(object: string, identity: RecipeCrmIdentity, values: Record<string, unknown> | undefined, external: RecipeCrmExternalRef, options: {
|
|
115
|
+
key: string;
|
|
116
|
+
}) => Promise<T>;
|
|
117
|
+
logActivity: <T = unknown>(input: RecipeCrmActivityInput, options: {
|
|
118
|
+
key: string;
|
|
119
|
+
}) => Promise<T>;
|
|
120
|
+
};
|
|
81
121
|
export type RecipeApprovalApi = {
|
|
82
122
|
require: <T = {
|
|
83
123
|
approved: boolean;
|
|
@@ -97,6 +137,7 @@ export type RecipeContext = {
|
|
|
97
137
|
rows: RecipeRowsApi;
|
|
98
138
|
columns: RecipeColumnsApi;
|
|
99
139
|
context: RecipeContextApi;
|
|
140
|
+
crm: RecipeCrmApi;
|
|
100
141
|
approvals: RecipeApprovalApi;
|
|
101
142
|
log: (level: RecipeLogLevel, message: string, payload?: Record<string, unknown>) => void;
|
|
102
143
|
step: <T = unknown>(key: string, options: RecipeStepOptions<T>) => Promise<T>;
|
|
@@ -13,6 +13,9 @@ export type PricingPlanDefinition = {
|
|
|
13
13
|
monthlyCredits: number | null;
|
|
14
14
|
weeklyCreditsLimit: number | null;
|
|
15
15
|
rolloverCap: number | null;
|
|
16
|
+
monthlyAutomationActions: number | null;
|
|
17
|
+
automationOverageCentsPerMillion: number | null;
|
|
18
|
+
automationOverageEnabledDefault: boolean;
|
|
16
19
|
byokEnabled: boolean;
|
|
17
20
|
description: string;
|
|
18
21
|
badge?: string;
|
|
@@ -31,10 +34,13 @@ export declare const BASE_PRICING_PLANS: {
|
|
|
31
34
|
readonly monthlyCredits: 500;
|
|
32
35
|
readonly weeklyCreditsLimit: 500;
|
|
33
36
|
readonly rolloverCap: 500;
|
|
37
|
+
readonly monthlyAutomationActions: 10000;
|
|
38
|
+
readonly automationOverageCentsPerMillion: null;
|
|
39
|
+
readonly automationOverageEnabledDefault: false;
|
|
34
40
|
readonly byokEnabled: false;
|
|
35
41
|
readonly description: "Get $10 in credits on us every month — try OXYGEN with managed email, phone enrichment, and AI credits.";
|
|
36
42
|
readonly ctaLabel: "Start free";
|
|
37
|
-
readonly features: readonly ["$10 in credits every month", "All integrations", "Workflows", "No card required"];
|
|
43
|
+
readonly features: readonly ["$10 in credits every month", "10,000 automation actions / month", "All integrations", "Workflows", "No card required"];
|
|
38
44
|
};
|
|
39
45
|
readonly starter: {
|
|
40
46
|
readonly tier: "starter";
|
|
@@ -43,10 +49,13 @@ export declare const BASE_PRICING_PLANS: {
|
|
|
43
49
|
readonly monthlyCredits: 5000;
|
|
44
50
|
readonly weeklyCreditsLimit: 2000;
|
|
45
51
|
readonly rolloverCap: 5000;
|
|
52
|
+
readonly monthlyAutomationActions: 250000;
|
|
53
|
+
readonly automationOverageCentsPerMillion: 1000;
|
|
54
|
+
readonly automationOverageEnabledDefault: false;
|
|
46
55
|
readonly byokEnabled: true;
|
|
47
56
|
readonly description: "For founders running focused managed enrichment and AI columns.";
|
|
48
57
|
readonly ctaLabel: "Choose Starter";
|
|
49
|
-
readonly features: readonly ["All integrations", "Bring your own keys", "Workflows", "Standard support"];
|
|
58
|
+
readonly features: readonly ["All integrations", "250,000 automation actions / month", "Bring your own keys", "Workflows", "Standard support"];
|
|
50
59
|
};
|
|
51
60
|
readonly pro: {
|
|
52
61
|
readonly tier: "pro";
|
|
@@ -55,12 +64,15 @@ export declare const BASE_PRICING_PLANS: {
|
|
|
55
64
|
readonly monthlyCredits: 12500;
|
|
56
65
|
readonly weeklyCreditsLimit: 5000;
|
|
57
66
|
readonly rolloverCap: 12500;
|
|
67
|
+
readonly monthlyAutomationActions: 2000000;
|
|
68
|
+
readonly automationOverageCentsPerMillion: 1000;
|
|
69
|
+
readonly automationOverageEnabledDefault: false;
|
|
58
70
|
readonly byokEnabled: true;
|
|
59
71
|
readonly description: "For recurring GTM enrichment and AI-column workflows on managed credits.";
|
|
60
72
|
readonly badge: "Most popular";
|
|
61
73
|
readonly highlighted: true;
|
|
62
74
|
readonly ctaLabel: "Choose Pro";
|
|
63
|
-
readonly features: readonly ["All integrations", "Bring your own keys", "Workflows", "Standard support"];
|
|
75
|
+
readonly features: readonly ["All integrations", "2,000,000 automation actions / month", "Bring your own keys", "Workflows", "Standard support"];
|
|
64
76
|
};
|
|
65
77
|
readonly team: {
|
|
66
78
|
readonly tier: "team";
|
|
@@ -69,10 +81,13 @@ export declare const BASE_PRICING_PLANS: {
|
|
|
69
81
|
readonly monthlyCredits: 37500;
|
|
70
82
|
readonly weeklyCreditsLimit: 15000;
|
|
71
83
|
readonly rolloverCap: 37500;
|
|
84
|
+
readonly monthlyAutomationActions: 10000000;
|
|
85
|
+
readonly automationOverageCentsPerMillion: 500;
|
|
86
|
+
readonly automationOverageEnabledDefault: false;
|
|
72
87
|
readonly byokEnabled: true;
|
|
73
88
|
readonly description: "For small GTM teams and agencies running shared workflows with their own AI keys.";
|
|
74
89
|
readonly ctaLabel: "Choose Team";
|
|
75
|
-
readonly features: readonly ["All integrations", "Bring your own keys", "Workflows", "Premium support"];
|
|
90
|
+
readonly features: readonly ["All integrations", "10,000,000 automation actions / month", "Bring your own keys", "Workflows", "Premium support"];
|
|
76
91
|
};
|
|
77
92
|
readonly scale: {
|
|
78
93
|
readonly tier: "scale";
|
|
@@ -81,11 +96,14 @@ export declare const BASE_PRICING_PLANS: {
|
|
|
81
96
|
readonly monthlyCredits: 500000;
|
|
82
97
|
readonly weeklyCreditsLimit: 500000;
|
|
83
98
|
readonly rolloverCap: 500000;
|
|
99
|
+
readonly monthlyAutomationActions: 50000000;
|
|
100
|
+
readonly automationOverageCentsPerMillion: null;
|
|
101
|
+
readonly automationOverageEnabledDefault: false;
|
|
84
102
|
readonly byokEnabled: true;
|
|
85
103
|
readonly description: "For high-volume GTM teams that need custom limits and rollout support.";
|
|
86
104
|
readonly ctaLabel: "Contact sales";
|
|
87
105
|
readonly contactHref: "https://cal.com/tim-scheuer-mxbib9/45";
|
|
88
|
-
readonly features: readonly ["500,000+ managed credits / month", "Phone number enrichment on managed credits", "Custom provider routing and BYOK policies", "Dedicated onboarding"];
|
|
106
|
+
readonly features: readonly ["500,000+ managed credits / month", "50,000,000+ automation actions / month", "Phone number enrichment on managed credits", "Custom provider routing and BYOK policies", "Dedicated onboarding"];
|
|
89
107
|
};
|
|
90
108
|
readonly enterprise: {
|
|
91
109
|
readonly tier: "enterprise";
|
|
@@ -94,11 +112,14 @@ export declare const BASE_PRICING_PLANS: {
|
|
|
94
112
|
readonly monthlyCredits: null;
|
|
95
113
|
readonly weeklyCreditsLimit: null;
|
|
96
114
|
readonly rolloverCap: null;
|
|
115
|
+
readonly monthlyAutomationActions: null;
|
|
116
|
+
readonly automationOverageCentsPerMillion: null;
|
|
117
|
+
readonly automationOverageEnabledDefault: false;
|
|
97
118
|
readonly byokEnabled: true;
|
|
98
119
|
readonly description: "Custom procurement, invoicing, limits, and rollout support.";
|
|
99
120
|
readonly ctaLabel: "Talk to us";
|
|
100
121
|
readonly contactHref: "https://cal.com/tim-scheuer-mxbib9/45";
|
|
101
|
-
readonly features: readonly ["Custom monthly usage pool", "Phone number enrichment", "Custom AI-key and provider routing policies", "SSO, invoicing, and procurement support"];
|
|
122
|
+
readonly features: readonly ["Custom monthly usage pool", "Custom automation action allowance", "Phone number enrichment", "Custom AI-key and provider routing policies", "SSO, invoicing, and procurement support"];
|
|
102
123
|
};
|
|
103
124
|
};
|
|
104
125
|
export declare const PUBLIC_PLAN_ORDER: readonly PlanTier[];
|
|
@@ -114,6 +135,7 @@ export declare function isSelfServePlanTier(value: string): value is SelfServePl
|
|
|
114
135
|
export declare function isBillingCurrency(value: string): value is BillingCurrency;
|
|
115
136
|
export declare function normalizeBillingCurrency(value: string | null | undefined): BillingCurrency;
|
|
116
137
|
export declare function getCurrentFreeTierCycleKey(date?: Date): string;
|
|
138
|
+
export declare function getCurrentBillingCycleKey(date?: Date): string;
|
|
117
139
|
export declare function evaluateWeeklyQuota(usedCredits: number, requestedCredits: number, weeklyCreditsLimit: number): {
|
|
118
140
|
usedCredits: number;
|
|
119
141
|
requestedCredits: number;
|
|
@@ -10,11 +10,15 @@ export const BASE_PRICING_PLANS = {
|
|
|
10
10
|
monthlyCredits: 500,
|
|
11
11
|
weeklyCreditsLimit: 500,
|
|
12
12
|
rolloverCap: 500,
|
|
13
|
+
monthlyAutomationActions: 10_000,
|
|
14
|
+
automationOverageCentsPerMillion: null,
|
|
15
|
+
automationOverageEnabledDefault: false,
|
|
13
16
|
byokEnabled: false,
|
|
14
17
|
description: "Get $10 in credits on us every month — try OXYGEN with managed email, phone enrichment, and AI credits.",
|
|
15
18
|
ctaLabel: "Start free",
|
|
16
19
|
features: [
|
|
17
20
|
"$10 in credits every month",
|
|
21
|
+
"10,000 automation actions / month",
|
|
18
22
|
"All integrations",
|
|
19
23
|
"Workflows",
|
|
20
24
|
"No card required",
|
|
@@ -27,11 +31,15 @@ export const BASE_PRICING_PLANS = {
|
|
|
27
31
|
monthlyCredits: 5_000,
|
|
28
32
|
weeklyCreditsLimit: 2_000,
|
|
29
33
|
rolloverCap: 5_000,
|
|
34
|
+
monthlyAutomationActions: 250_000,
|
|
35
|
+
automationOverageCentsPerMillion: 1_000,
|
|
36
|
+
automationOverageEnabledDefault: false,
|
|
30
37
|
byokEnabled: true,
|
|
31
38
|
description: "For founders running focused managed enrichment and AI columns.",
|
|
32
39
|
ctaLabel: "Choose Starter",
|
|
33
40
|
features: [
|
|
34
41
|
"All integrations",
|
|
42
|
+
"250,000 automation actions / month",
|
|
35
43
|
"Bring your own keys",
|
|
36
44
|
"Workflows",
|
|
37
45
|
"Standard support",
|
|
@@ -44,6 +52,9 @@ export const BASE_PRICING_PLANS = {
|
|
|
44
52
|
monthlyCredits: 12_500,
|
|
45
53
|
weeklyCreditsLimit: 5_000,
|
|
46
54
|
rolloverCap: 12_500,
|
|
55
|
+
monthlyAutomationActions: 2_000_000,
|
|
56
|
+
automationOverageCentsPerMillion: 1_000,
|
|
57
|
+
automationOverageEnabledDefault: false,
|
|
47
58
|
byokEnabled: true,
|
|
48
59
|
description: "For recurring GTM enrichment and AI-column workflows on managed credits.",
|
|
49
60
|
badge: "Most popular",
|
|
@@ -51,6 +62,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
51
62
|
ctaLabel: "Choose Pro",
|
|
52
63
|
features: [
|
|
53
64
|
"All integrations",
|
|
65
|
+
"2,000,000 automation actions / month",
|
|
54
66
|
"Bring your own keys",
|
|
55
67
|
"Workflows",
|
|
56
68
|
"Standard support",
|
|
@@ -63,11 +75,15 @@ export const BASE_PRICING_PLANS = {
|
|
|
63
75
|
monthlyCredits: 37_500,
|
|
64
76
|
weeklyCreditsLimit: 15_000,
|
|
65
77
|
rolloverCap: 37_500,
|
|
78
|
+
monthlyAutomationActions: 10_000_000,
|
|
79
|
+
automationOverageCentsPerMillion: 500,
|
|
80
|
+
automationOverageEnabledDefault: false,
|
|
66
81
|
byokEnabled: true,
|
|
67
82
|
description: "For small GTM teams and agencies running shared workflows with their own AI keys.",
|
|
68
83
|
ctaLabel: "Choose Team",
|
|
69
84
|
features: [
|
|
70
85
|
"All integrations",
|
|
86
|
+
"10,000,000 automation actions / month",
|
|
71
87
|
"Bring your own keys",
|
|
72
88
|
"Workflows",
|
|
73
89
|
"Premium support",
|
|
@@ -80,12 +96,16 @@ export const BASE_PRICING_PLANS = {
|
|
|
80
96
|
monthlyCredits: 500_000,
|
|
81
97
|
weeklyCreditsLimit: 500_000,
|
|
82
98
|
rolloverCap: 500_000,
|
|
99
|
+
monthlyAutomationActions: 50_000_000,
|
|
100
|
+
automationOverageCentsPerMillion: null,
|
|
101
|
+
automationOverageEnabledDefault: false,
|
|
83
102
|
byokEnabled: true,
|
|
84
103
|
description: "For high-volume GTM teams that need custom limits and rollout support.",
|
|
85
104
|
ctaLabel: "Contact sales",
|
|
86
105
|
contactHref: CONTACT_SALES_URL,
|
|
87
106
|
features: [
|
|
88
107
|
"500,000+ managed credits / month",
|
|
108
|
+
"50,000,000+ automation actions / month",
|
|
89
109
|
"Phone number enrichment on managed credits",
|
|
90
110
|
"Custom provider routing and BYOK policies",
|
|
91
111
|
"Dedicated onboarding",
|
|
@@ -98,12 +118,16 @@ export const BASE_PRICING_PLANS = {
|
|
|
98
118
|
monthlyCredits: null,
|
|
99
119
|
weeklyCreditsLimit: null,
|
|
100
120
|
rolloverCap: null,
|
|
121
|
+
monthlyAutomationActions: null,
|
|
122
|
+
automationOverageCentsPerMillion: null,
|
|
123
|
+
automationOverageEnabledDefault: false,
|
|
101
124
|
byokEnabled: true,
|
|
102
125
|
description: "Custom procurement, invoicing, limits, and rollout support.",
|
|
103
126
|
ctaLabel: "Talk to us",
|
|
104
127
|
contactHref: CONTACT_SALES_URL,
|
|
105
128
|
features: [
|
|
106
129
|
"Custom monthly usage pool",
|
|
130
|
+
"Custom automation action allowance",
|
|
107
131
|
"Phone number enrichment",
|
|
108
132
|
"Custom AI-key and provider routing policies",
|
|
109
133
|
"SSO, invoicing, and procurement support",
|
|
@@ -229,6 +253,11 @@ plan, metadata) {
|
|
|
229
253
|
const monthlyCredits = readCreditLimit(config, "monthlyCredits", "monthly_credits", "monthly_credit_limit");
|
|
230
254
|
const weeklyCreditsLimit = readCreditLimit(config, "weeklyCreditsLimit", "weekly_credits_limit", "weekly_credit_limit");
|
|
231
255
|
const rolloverCap = readCreditLimit(config, "rolloverCap", "rollover_cap", "rollover_credits");
|
|
256
|
+
const monthlyAutomationActions = readCreditLimit(config, "monthlyAutomationActions", "monthly_automation_actions", "automation_actions", "automation_action_limit");
|
|
257
|
+
const automationOverageCentsPerMillion = readCreditLimit(config, "automationOverageCentsPerMillion", "automation_overage_cents_per_million", "automation_action_overage_cents_per_million");
|
|
258
|
+
const automationOverageEnabledDefault = readBoolean(config, "automationOverageEnabledDefault")
|
|
259
|
+
?? readBoolean(config, "automation_overage_enabled_default")
|
|
260
|
+
?? readBoolean(config, "automation_overage_enabled");
|
|
232
261
|
const byokEnabled = readBoolean(config, "byokEnabled")
|
|
233
262
|
?? readBoolean(config, "byok_enabled");
|
|
234
263
|
return {
|
|
@@ -237,6 +266,9 @@ plan, metadata) {
|
|
|
237
266
|
monthlyCredits: monthlyCredits ?? plan.monthlyCredits,
|
|
238
267
|
weeklyCreditsLimit: weeklyCreditsLimit ?? plan.weeklyCreditsLimit,
|
|
239
268
|
rolloverCap: rolloverCap ?? plan.rolloverCap,
|
|
269
|
+
monthlyAutomationActions: monthlyAutomationActions ?? plan.monthlyAutomationActions,
|
|
270
|
+
automationOverageCentsPerMillion: automationOverageCentsPerMillion ?? plan.automationOverageCentsPerMillion,
|
|
271
|
+
automationOverageEnabledDefault: automationOverageEnabledDefault ?? plan.automationOverageEnabledDefault,
|
|
240
272
|
byokEnabled: byokEnabled ?? plan.byokEnabled,
|
|
241
273
|
description: description ?? plan.description,
|
|
242
274
|
};
|
|
@@ -284,6 +316,15 @@ export function getCurrentFreeTierCycleKey(date = new Date()) {
|
|
|
284
316
|
const month = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
285
317
|
return `free:${year}-${month}`;
|
|
286
318
|
}
|
|
319
|
+
// Calendar-month cycle key (UTC `YYYY-MM`) for off-Stripe custom plans. Stripe
|
|
320
|
+
// subscriptions advance their billing period via webhooks; manual/invoiced
|
|
321
|
+
// plans never do, so we renew their monthly credit grant by calendar month
|
|
322
|
+
// instead of by Stripe period boundary.
|
|
323
|
+
export function getCurrentBillingCycleKey(date = new Date()) {
|
|
324
|
+
const year = date.getUTCFullYear();
|
|
325
|
+
const month = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
326
|
+
return `${year}-${month}`;
|
|
327
|
+
}
|
|
287
328
|
export function evaluateWeeklyQuota(usedCredits, requestedCredits, weeklyCreditsLimit) {
|
|
288
329
|
const projectedCredits = usedCredits + requestedCredits;
|
|
289
330
|
return {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const PUBLIC_BUDGET_SCOPES: readonly ["org", "table", "workflow_trigger", "monitor"];
|
|
2
|
+
export type PublicBudgetScope = (typeof PUBLIC_BUDGET_SCOPES)[number];
|
|
3
|
+
export declare function formatPublicBudgetScopes(): string;
|
|
4
|
+
export declare const PUBLIC_BUDGET_SCOPE_DESCRIPTION = "Cap scope: org (whole workspace), table (a single table), workflow_trigger (one workflow trigger), or monitor (one scheduled workflow).";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const PUBLIC_BUDGET_SCOPES = ["org", "table", "workflow_trigger", "monitor"];
|
|
2
|
+
export function formatPublicBudgetScopes() {
|
|
3
|
+
const scopes = [...PUBLIC_BUDGET_SCOPES];
|
|
4
|
+
const last = scopes.pop();
|
|
5
|
+
if (!last)
|
|
6
|
+
return "";
|
|
7
|
+
return scopes.length === 0 ? last : `${scopes.join(", ")}, or ${last}`;
|
|
8
|
+
}
|
|
9
|
+
export const PUBLIC_BUDGET_SCOPE_DESCRIPTION = "Cap scope: org (whole workspace), table (a single table), workflow_trigger (one workflow trigger), or monitor (one scheduled workflow).";
|
|
@@ -39,6 +39,12 @@ export type CellFormatOptions = {
|
|
|
39
39
|
* escaping, ellipsis budgets) belong outside this function.
|
|
40
40
|
*/
|
|
41
41
|
export declare function formatCellForDisplay(value: unknown, column: CellColumnLike | null | undefined, options: CellFormatOptions): string;
|
|
42
|
+
/**
|
|
43
|
+
* Flatten markdown into a single line of readable plain text — for grid cells,
|
|
44
|
+
* CLI tables, and MCP previews where the rendered markdown would be noise.
|
|
45
|
+
* Drops syntax markers; keeps the words.
|
|
46
|
+
*/
|
|
47
|
+
export declare function markdownToPlainText(markdown: string): string;
|
|
42
48
|
/**
|
|
43
49
|
* Decide whether the same value-level + column-level guards used inside
|
|
44
50
|
* `formatCellForDisplay`'s text path should rescue this string. Exposed so
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* version strings, phone numbers, URLs): {@link rescueNumericText} returns
|
|
15
15
|
* null for those.
|
|
16
16
|
*/
|
|
17
|
+
import { isMarkdownColumnSemantic } from "./select-options.js";
|
|
17
18
|
const DEFAULT_LOCALE = "en-US";
|
|
18
19
|
const INTEGER_RE = /^-?\d{1,15}$/;
|
|
19
20
|
const DECIMAL_RE = /^-?\d{1,15}(?:\.\d{1,9})?$/;
|
|
@@ -65,6 +66,11 @@ export function formatCellForDisplay(value, column, options) {
|
|
|
65
66
|
return formatTimestamp(value, options.surface);
|
|
66
67
|
if (dataType === "numeric")
|
|
67
68
|
return formatNumeric(value, locale, options.surface);
|
|
69
|
+
// Markdown cells collapse to a single-line plain-text preview for the grid,
|
|
70
|
+
// CLI, and MCP. The web record view renders the full markdown separately.
|
|
71
|
+
if (isMarkdownColumnSemantic(column?.semanticType ?? column?.semantic_type)) {
|
|
72
|
+
return markdownToPlainText(typeof value === "string" ? value : String(value));
|
|
73
|
+
}
|
|
68
74
|
if (isEnrichmentPayload(value) && columnHasWrapperKind(column)) {
|
|
69
75
|
const wrapped = readEnrichmentValue(value);
|
|
70
76
|
if (wrapped !== undefined) {
|
|
@@ -94,6 +100,26 @@ export function formatCellForDisplay(value, column, options) {
|
|
|
94
100
|
}
|
|
95
101
|
return String(value);
|
|
96
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Flatten markdown into a single line of readable plain text — for grid cells,
|
|
105
|
+
* CLI tables, and MCP previews where the rendered markdown would be noise.
|
|
106
|
+
* Drops syntax markers; keeps the words.
|
|
107
|
+
*/
|
|
108
|
+
export function markdownToPlainText(markdown) {
|
|
109
|
+
return markdown
|
|
110
|
+
.replace(/```[\s\S]*?```/g, " ") // fenced code blocks
|
|
111
|
+
.replace(/`([^`]+)`/g, "$1") // inline code
|
|
112
|
+
.replace(/!\[[^\]]*\]\([^)]*\)/g, " ") // images
|
|
113
|
+
.replace(/\[([^\]]+)\]\([^)]*\)/g, "$1") // links → label
|
|
114
|
+
.replace(/^\s{0,3}#{1,6}\s+/gm, "") // headings
|
|
115
|
+
.replace(/^\s*>\s?/gm, "") // blockquotes
|
|
116
|
+
.replace(/^\s*[-*+]\s+/gm, "") // bullet markers
|
|
117
|
+
.replace(/^\s*\d+\.\s+/gm, "") // ordered markers
|
|
118
|
+
.replace(/^\s*[-*_]{3,}\s*$/gm, " ") // horizontal rules
|
|
119
|
+
.replace(/[*_~]{1,3}([^*_~]+)[*_~]{1,3}/g, "$1") // bold / italic / strike
|
|
120
|
+
.replace(/\s+/g, " ")
|
|
121
|
+
.trim();
|
|
122
|
+
}
|
|
97
123
|
/**
|
|
98
124
|
* Best-effort parse of a string that looks numeric (with or without thousands
|
|
99
125
|
* grouping, with or without dotted IP-style separators) into a finite number.
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
export { OXYGEN_MINIMUM_CLI_VERSION, OXYGEN_VERSION } from "./version.js";
|
|
2
2
|
export { WORKFLOW_TRIGGER_AUTO_PAUSE_METADATA_KEYS, clearWorkflowTriggerAutoPauseMetadata, } from "./workflow-trigger-metadata.js";
|
|
3
3
|
export * from "./billing.js";
|
|
4
|
+
export * from "./budget-scopes.js";
|
|
4
5
|
export * from "./cell-format.js";
|
|
5
6
|
export * from "./cli-envelope.js";
|
|
6
7
|
export * from "./cli-result.js";
|
|
7
8
|
export * from "./column-types.js";
|
|
8
9
|
export * from "./credit-guidance.js";
|
|
9
10
|
export * from "./linkedin-sequences.js";
|
|
11
|
+
export * from "./networks.js";
|
|
10
12
|
export * from "./sequences.js";
|
|
11
13
|
export * from "./log.js";
|
|
12
14
|
export * from "./provider-request-outcomes.js";
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
export { OXYGEN_MINIMUM_CLI_VERSION, OXYGEN_VERSION } from "./version.js";
|
|
2
2
|
export { WORKFLOW_TRIGGER_AUTO_PAUSE_METADATA_KEYS, clearWorkflowTriggerAutoPauseMetadata, } from "./workflow-trigger-metadata.js";
|
|
3
3
|
export * from "./billing.js";
|
|
4
|
+
export * from "./budget-scopes.js";
|
|
4
5
|
export * from "./cell-format.js";
|
|
5
6
|
export * from "./cli-envelope.js";
|
|
6
7
|
export * from "./cli-result.js";
|
|
7
8
|
export * from "./column-types.js";
|
|
8
9
|
export * from "./credit-guidance.js";
|
|
9
10
|
export * from "./linkedin-sequences.js";
|
|
11
|
+
export * from "./networks.js";
|
|
10
12
|
export * from "./sequences.js";
|
|
11
13
|
export * from "./log.js";
|
|
12
14
|
export * from "./provider-request-outcomes.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sequencer networks — the channel discriminator for the Unipile-backed sender
|
|
3
|
+
* pool, unibox, and per-account daily quota ledger (schema `ox_sequencer`).
|
|
4
|
+
*
|
|
5
|
+
* The sequencer primitives (sender_accounts, conversations, messages,
|
|
6
|
+
* sender_action_counts) are channel-agnostic; `network` tells one Unipile
|
|
7
|
+
* network from another. LinkedIn is the original network and the default for
|
|
8
|
+
* every row/call site that predates the discriminator, so a missing/unknown
|
|
9
|
+
* value always resolves to `"linkedin"` (zero behaviour change). WhatsApp is the
|
|
10
|
+
* second network and is warm-only (no cold sequencer dispatch).
|
|
11
|
+
*
|
|
12
|
+
* Email is intentionally NOT a sequencer network: it has its own mailbox and
|
|
13
|
+
* conversation tables (`email_mailboxes`, `email_conversations`, …).
|
|
14
|
+
*/
|
|
15
|
+
export declare const SEQUENCER_NETWORKS: readonly ["linkedin", "whatsapp"];
|
|
16
|
+
export type SequencerNetwork = (typeof SEQUENCER_NETWORKS)[number];
|
|
17
|
+
/** The network assumed for any row/call site that predates the discriminator. */
|
|
18
|
+
export declare const DEFAULT_SEQUENCER_NETWORK: SequencerNetwork;
|
|
19
|
+
export declare function isSequencerNetwork(value: unknown): value is SequencerNetwork;
|
|
20
|
+
/** Coerce an unknown/null DB value to a network, defaulting to LinkedIn. */
|
|
21
|
+
export declare function coerceSequencerNetwork(value: unknown): SequencerNetwork;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sequencer networks — the channel discriminator for the Unipile-backed sender
|
|
3
|
+
* pool, unibox, and per-account daily quota ledger (schema `ox_sequencer`).
|
|
4
|
+
*
|
|
5
|
+
* The sequencer primitives (sender_accounts, conversations, messages,
|
|
6
|
+
* sender_action_counts) are channel-agnostic; `network` tells one Unipile
|
|
7
|
+
* network from another. LinkedIn is the original network and the default for
|
|
8
|
+
* every row/call site that predates the discriminator, so a missing/unknown
|
|
9
|
+
* value always resolves to `"linkedin"` (zero behaviour change). WhatsApp is the
|
|
10
|
+
* second network and is warm-only (no cold sequencer dispatch).
|
|
11
|
+
*
|
|
12
|
+
* Email is intentionally NOT a sequencer network: it has its own mailbox and
|
|
13
|
+
* conversation tables (`email_mailboxes`, `email_conversations`, …).
|
|
14
|
+
*/
|
|
15
|
+
export const SEQUENCER_NETWORKS = ["linkedin", "whatsapp"];
|
|
16
|
+
/** The network assumed for any row/call site that predates the discriminator. */
|
|
17
|
+
export const DEFAULT_SEQUENCER_NETWORK = "linkedin";
|
|
18
|
+
export function isSequencerNetwork(value) {
|
|
19
|
+
return (typeof value === "string" &&
|
|
20
|
+
SEQUENCER_NETWORKS.includes(value));
|
|
21
|
+
}
|
|
22
|
+
/** Coerce an unknown/null DB value to a network, defaulting to LinkedIn. */
|
|
23
|
+
export function coerceSequencerNetwork(value) {
|
|
24
|
+
return isSequencerNetwork(value) ? value : DEFAULT_SEQUENCER_NETWORK;
|
|
25
|
+
}
|
|
@@ -2,7 +2,7 @@ export declare function normalizeText(value: string): string;
|
|
|
2
2
|
export declare function escapeRegExp(value: string): string;
|
|
3
3
|
export declare function extractUrls(value: string): string[];
|
|
4
4
|
export declare function extractDomains(value: string): string[];
|
|
5
|
-
export declare function parseMoney(amount: string, unit
|
|
5
|
+
export declare function parseMoney(amount: string, unit?: string): number;
|
|
6
6
|
export declare function regionDisplayName(code: string): string | null;
|
|
7
7
|
export declare const COUNTRY_NAME_TO_ISO: Map<string, string>;
|
|
8
8
|
export declare const COUNTRY_ALIAS_TO_ISO: Record<string, string>;
|
|
@@ -8,6 +8,13 @@ export type SelectColumnSemantic = (typeof SELECT_COLUMN_SEMANTICS)[number];
|
|
|
8
8
|
export declare function isSelectColumnSemantic(semanticType: string | null | undefined): boolean;
|
|
9
9
|
export declare function isMultiSelectSemantic(semanticType: string | null | undefined): boolean;
|
|
10
10
|
export declare function isStatusSemantic(semanticType: string | null | undefined): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* `markdown` is a semantic over the `text` dataType (storage stays text): the
|
|
13
|
+
* cell holds a long markdown body that renders as a "page" in the record view
|
|
14
|
+
* and as a compact plain-text preview in the grid. Notes, summaries, and call
|
|
15
|
+
* transcripts all use this.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isMarkdownColumnSemantic(semanticType: string | null | undefined): boolean;
|
|
11
18
|
export type SelectOption = {
|
|
12
19
|
id: string;
|
|
13
20
|
value: string;
|
|
@@ -46,6 +46,15 @@ export function isMultiSelectSemantic(semanticType) {
|
|
|
46
46
|
export function isStatusSemantic(semanticType) {
|
|
47
47
|
return semanticType === "status";
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* `markdown` is a semantic over the `text` dataType (storage stays text): the
|
|
51
|
+
* cell holds a long markdown body that renders as a "page" in the record view
|
|
52
|
+
* and as a compact plain-text preview in the grid. Notes, summaries, and call
|
|
53
|
+
* transcripts all use this.
|
|
54
|
+
*/
|
|
55
|
+
export function isMarkdownColumnSemantic(semanticType) {
|
|
56
|
+
return semanticType === "markdown";
|
|
57
|
+
}
|
|
49
58
|
const MAX_OPTIONS = 200;
|
|
50
59
|
// Normalize a raw options array (from a column `definition.options`, CLI/MCP, or
|
|
51
60
|
// the editor) into canonical SelectOptions: dedupe by value, default colors,
|
|
@@ -35,8 +35,12 @@ export type SequenceChannel = (typeof SEQUENCE_CHANNELS)[number];
|
|
|
35
35
|
* a signal — it's resolved on demand by the dispatcher via a connection branch,
|
|
36
36
|
* `condition: "already_connected"`.)
|
|
37
37
|
*/
|
|
38
|
-
export declare const SEQUENCE_SIGNALS: readonly ["linkedin_connected", "linkedin_replied", "email_sent", "email_opened", "email_clicked", "email_replied", "email_bounced"];
|
|
38
|
+
export declare const SEQUENCE_SIGNALS: readonly ["linkedin_connected", "linkedin_replied", "email_sent", "email_opened", "email_clicked", "email_replied", "email_bounced", "company_hiring", "company_raised_funds", "job_change", "new_hire", "web_visit", "intent"];
|
|
39
39
|
export type SequenceSignal = (typeof SEQUENCE_SIGNALS)[number];
|
|
40
|
+
/** External GTM signals (the non-engagement subset of SEQUENCE_SIGNALS). */
|
|
41
|
+
export declare const SEQUENCE_EXTERNAL_SIGNALS: readonly ["company_hiring", "company_raised_funds", "job_change", "new_hire", "web_visit", "intent"];
|
|
42
|
+
export type SequenceExternalSignal = (typeof SEQUENCE_EXTERNAL_SIGNALS)[number];
|
|
43
|
+
export declare function isExternalSequenceSignal(value: string): value is SequenceExternalSignal;
|
|
40
44
|
/**
|
|
41
45
|
* row_values keys an enrollment's email may live under, in send-precedence order.
|
|
42
46
|
* The dispatcher picks the FIRST present key as the recipient address; the
|
|
@@ -44,6 +48,31 @@ export type SequenceSignal = (typeof SEQUENCE_SIGNALS)[number];
|
|
|
44
48
|
* Single source of truth so the send path and the lookup path can't drift.
|
|
45
49
|
*/
|
|
46
50
|
export declare const SEQUENCE_EMAIL_COLUMN_KEYS: readonly ["email", "email_address", "work_email", "primary_email", "Email"];
|
|
51
|
+
/**
|
|
52
|
+
* A per-step / per-sequence send window. `days` are ISO weekdays (1=Mon … 7=Sun)
|
|
53
|
+
* on which sends are allowed; `start`/`end` are "HH:MM" local times. The window
|
|
54
|
+
* is evaluated in `timezone` by default; when `timezone_mode === "recipient"`
|
|
55
|
+
* the dispatcher reads the lead's IANA timezone from
|
|
56
|
+
* `recipient_timezone_column` in the enrolled row (falling back to `timezone`
|
|
57
|
+
* when the column is missing/invalid), so a 9-5 window lands in each
|
|
58
|
+
* recipient's local morning rather than the operator's. Unlike the LinkedIn
|
|
59
|
+
* per-account working hours, this gate also governs the native + Instantly email
|
|
60
|
+
* track (which otherwise has no send window at all).
|
|
61
|
+
*/
|
|
62
|
+
export type SequenceSendWindow = {
|
|
63
|
+
timezone: string;
|
|
64
|
+
/** Allowed ISO weekdays, 1=Mon … 7=Sun. Empty/absent → all days. */
|
|
65
|
+
days?: number[];
|
|
66
|
+
/** "HH:MM" inclusive start of the daily window. */
|
|
67
|
+
start: string;
|
|
68
|
+
/** "HH:MM" exclusive end of the daily window. */
|
|
69
|
+
end: string;
|
|
70
|
+
timezone_mode?: "fixed" | "recipient";
|
|
71
|
+
/** row_values key holding the lead's IANA timezone (timezone_mode="recipient"). */
|
|
72
|
+
recipient_timezone_column?: string;
|
|
73
|
+
};
|
|
74
|
+
/** Base content + up to this many alternates per A/B step (base counts as variant "a"). */
|
|
75
|
+
export declare const MAX_STEP_VARIANTS = 5;
|
|
47
76
|
export declare const SEQUENCE_STEP_KINDS: readonly ["visit_profile", "invite", "wait_for_connection", "message", "inmail", "email_send", "email_reply", "email_enroll", "email_move", "email_stop", "wait", "wait_for_signal", "branch", "stop"];
|
|
48
77
|
export type SequenceStepKind = (typeof SEQUENCE_STEP_KINDS)[number];
|
|
49
78
|
export type SequenceLinkedInVisitProfileStep = {
|
|
@@ -70,6 +99,10 @@ export type SequenceLinkedInMessageStep = {
|
|
|
70
99
|
channel: "linkedin";
|
|
71
100
|
kind: "message";
|
|
72
101
|
template: string;
|
|
102
|
+
/** A/B alternates. Each overrides the base `template`; the base is variant "a". */
|
|
103
|
+
variants?: {
|
|
104
|
+
template?: string;
|
|
105
|
+
}[];
|
|
73
106
|
};
|
|
74
107
|
export type SequenceLinkedInInMailStep = {
|
|
75
108
|
id: string;
|
|
@@ -77,6 +110,11 @@ export type SequenceLinkedInInMailStep = {
|
|
|
77
110
|
kind: "inmail";
|
|
78
111
|
subject_template: string;
|
|
79
112
|
template: string;
|
|
113
|
+
/** A/B alternates over subject/body; the base is variant "a". */
|
|
114
|
+
variants?: {
|
|
115
|
+
subject_template?: string;
|
|
116
|
+
template?: string;
|
|
117
|
+
}[];
|
|
80
118
|
};
|
|
81
119
|
export type SequenceEmailEnrollStep = {
|
|
82
120
|
id: string;
|
|
@@ -109,6 +147,13 @@ export type SequenceEmailSendStep = {
|
|
|
109
147
|
subject_template: string;
|
|
110
148
|
/** Body. Supports {{column}} interpolation. */
|
|
111
149
|
body_template: string;
|
|
150
|
+
/** A/B alternates over subject/body; the base is variant "a". */
|
|
151
|
+
variants?: {
|
|
152
|
+
subject_template?: string;
|
|
153
|
+
body_template?: string;
|
|
154
|
+
}[];
|
|
155
|
+
/** Per-step send window (overrides the sequence-level email_send_window). */
|
|
156
|
+
send_window?: SequenceSendWindow;
|
|
112
157
|
};
|
|
113
158
|
/** Threaded follow-up in the same email thread as the lead's prior email_send. */
|
|
114
159
|
export type SequenceEmailReplyStep = {
|
|
@@ -117,6 +162,12 @@ export type SequenceEmailReplyStep = {
|
|
|
117
162
|
kind: "email_reply";
|
|
118
163
|
/** Reply body. Supports {{column}} interpolation. */
|
|
119
164
|
body_template: string;
|
|
165
|
+
/** A/B alternates over the reply body; the base is variant "a". */
|
|
166
|
+
variants?: {
|
|
167
|
+
body_template?: string;
|
|
168
|
+
}[];
|
|
169
|
+
/** Per-step send window (overrides the sequence-level email_send_window). */
|
|
170
|
+
send_window?: SequenceSendWindow;
|
|
120
171
|
};
|
|
121
172
|
export type SequenceWaitStep = {
|
|
122
173
|
id: string;
|
|
@@ -236,3 +287,42 @@ export declare function sequenceTemplateVariables(definition: SequenceDefinition
|
|
|
236
287
|
* Used by the dispatch planner for branch steps. Pure.
|
|
237
288
|
*/
|
|
238
289
|
export declare function evaluateSequenceCondition(condition: SequenceSignalCondition, firedSignals: Iterable<string>): boolean;
|
|
290
|
+
/** Variant label for an index: 0 → "a" (the base step), 1 → "b", … */
|
|
291
|
+
export declare function sequenceVariantLabel(index: number): string;
|
|
292
|
+
type StepVariantContent = Record<string, string>;
|
|
293
|
+
/**
|
|
294
|
+
* The ordered list of fully-resolved content variants for a step: index 0 is the
|
|
295
|
+
* base step ("a"); each declared alternate is merged OVER the base (so a variant
|
|
296
|
+
* that sets only `subject_template` keeps the base body). Returns [] for steps
|
|
297
|
+
* with no copy.
|
|
298
|
+
*/
|
|
299
|
+
export declare function sequenceStepVariantContents(step: SequenceStep): StepVariantContent[];
|
|
300
|
+
/** Number of A/B variants a step carries (1 = no test). */
|
|
301
|
+
export declare function sequenceStepVariantCount(step: SequenceStep): number;
|
|
302
|
+
/**
|
|
303
|
+
* Deterministically assign one variant to an enrollment for a step. The same
|
|
304
|
+
* (key, step) always resolves to the same variant — replayable, evenly
|
|
305
|
+
* distributed, and previewable in a dry run before any send. `key` is the
|
|
306
|
+
* enrollment id.
|
|
307
|
+
*/
|
|
308
|
+
export declare function selectStepVariant(step: SequenceStep, key: string): {
|
|
309
|
+
variantId: string;
|
|
310
|
+
index: number;
|
|
311
|
+
content: StepVariantContent;
|
|
312
|
+
};
|
|
313
|
+
/**
|
|
314
|
+
* Resolve which IANA timezone a send window evaluates in for a given lead row.
|
|
315
|
+
* "recipient" mode reads the lead's tz from `recipient_timezone_column`, falling
|
|
316
|
+
* back to the window's fixed `timezone` when the column is absent/blank.
|
|
317
|
+
*/
|
|
318
|
+
export declare function resolveSendWindowTimezone(window: SequenceSendWindow, rowValues?: Record<string, unknown> | null): string;
|
|
319
|
+
/**
|
|
320
|
+
* Is `now` inside the send window, evaluated in `timezone` (already resolved for
|
|
321
|
+
* recipient mode via resolveSendWindowTimezone)? Pure; Intl only
|
|
322
|
+
* (client-bundle-safe). An unresolvable timezone or malformed window fails OPEN
|
|
323
|
+
* (returns true) so a bad tz never permanently strands an enrollment — the hard
|
|
324
|
+
* send caps still bound it. A window with no `days` allows every weekday;
|
|
325
|
+
* start>end wraps past midnight.
|
|
326
|
+
*/
|
|
327
|
+
export declare function isWithinSendWindow(window: SequenceSendWindow, now: Date, timezone?: string): boolean;
|
|
328
|
+
export {};
|