@oxygen-agent/cli 1.1011.855 → 1.1011.1091
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/admin-lead-magnet-commands.d.ts +7 -0
- package/dist/admin-lead-magnet-commands.js +128 -0
- package/dist/command-manifest.js +29 -0
- package/dist/crm-support-flags.d.ts +1 -0
- package/dist/crm-support-flags.js +5 -1
- package/dist/customer-operation-commands.js +30 -1
- package/dist/functions-commands.js +1 -1
- package/dist/help.js +10 -2
- package/dist/http-client.d.ts +4 -0
- package/dist/http-client.js +21 -10
- package/dist/index.js +444 -208
- package/dist/sender-limits-flags.d.ts +7 -0
- package/dist/sender-limits-flags.js +13 -0
- package/dist/workspace-utility-flags.d.ts +7 -0
- package/dist/workspace-utility-flags.js +45 -0
- package/node_modules/@oxygen/shared/dist/attempt-provenance.d.ts +22 -0
- package/node_modules/@oxygen/shared/dist/attempt-provenance.js +83 -0
- package/node_modules/@oxygen/shared/dist/billing-anchors.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/billing-anchors.js +7 -1
- package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +279 -13
- package/node_modules/@oxygen/shared/dist/cli-result.js +6 -0
- package/node_modules/@oxygen/shared/dist/contracts/browser-operations.js +21 -9
- package/node_modules/@oxygen/shared/dist/contracts/crm-attributes.d.ts +7 -1
- package/node_modules/@oxygen/shared/dist/contracts/crm-attributes.js +5 -1
- package/node_modules/@oxygen/shared/dist/contracts/crm-support.d.ts +14 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-support.js +4 -0
- package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +13 -11
- package/node_modules/@oxygen/shared/dist/contracts/limits-read.js +11 -1
- package/node_modules/@oxygen/shared/dist/contracts/operations.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/contracts/publishing-reads.js +1 -0
- package/node_modules/@oxygen/shared/dist/contracts/schema.js +10 -6
- package/node_modules/@oxygen/shared/dist/contracts/spintax.d.ts +18 -0
- package/node_modules/@oxygen/shared/dist/contracts/spintax.js +11 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-row-removal.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-row-removal.js +21 -0
- package/node_modules/@oxygen/shared/dist/contracts/workspace-utilities.d.ts +162 -0
- package/node_modules/@oxygen/shared/dist/contracts/workspace-utilities.js +46 -0
- package/node_modules/@oxygen/shared/dist/credit-topup-review.d.ts +11 -0
- package/node_modules/@oxygen/shared/dist/credit-topup-review.js +3 -0
- package/node_modules/@oxygen/shared/dist/emailguard-placement-probe.d.ts +70 -0
- package/node_modules/@oxygen/shared/dist/emailguard-placement-probe.js +161 -0
- package/node_modules/@oxygen/shared/dist/future-signup-events.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/future-signup-events.js +4 -0
- package/node_modules/@oxygen/shared/dist/knowledge-seed-content.js +2 -2
- package/node_modules/@oxygen/shared/dist/linkedin-quota-denial.d.ts +48 -0
- package/node_modules/@oxygen/shared/dist/linkedin-quota-denial.js +94 -0
- package/node_modules/@oxygen/shared/dist/partner-coupon-bonus.d.ts +45 -0
- package/node_modules/@oxygen/shared/dist/partner-coupon-bonus.js +57 -0
- package/node_modules/@oxygen/shared/dist/provider-balance-signal.js +3 -2
- package/node_modules/@oxygen/shared/dist/table-filter-operators.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/table-filter-operators.js +50 -0
- package/node_modules/@oxygen/shared/dist/telemetry.js +4 -0
- package/node_modules/@oxygen/shared/dist/version.d.ts +1 -1
- 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 +1 -1
- package/node_modules/@oxygen/shared/dist/whatsapp-sender-limits.d.ts +42 -0
- package/node_modules/@oxygen/shared/dist/whatsapp-sender-limits.js +68 -0
- package/node_modules/@oxygen/shared/dist/workflow-trigger-metadata.d.ts +15 -0
- package/node_modules/@oxygen/shared/dist/workflow-trigger-metadata.js +33 -0
- package/node_modules/@oxygen/shared/package.json +5 -5
- package/node_modules/@oxygen/workflows/dist/index.d.ts +1 -0
- package/node_modules/@oxygen/workflows/dist/index.js +1 -0
- package/node_modules/@oxygen/workflows/dist/recipe-timestamp.d.ts +22 -0
- package/node_modules/@oxygen/workflows/dist/recipe-timestamp.js +72 -0
- package/node_modules/@oxygen/workflows/dist/usage-estimate.js +9 -5
- package/package.json +1 -1
- package/node_modules/@oxygen/shared/dist/vercel-sandbox-fetch.d.ts +0 -9
- package/node_modules/@oxygen/shared/dist/vercel-sandbox-fetch.js +0 -33
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
/** Browser resource operations, using the same scoped handlers on every surface. */
|
|
2
2
|
import { arr, bool, enumOf, int, nullable, num, obj, str } from "./schema.js";
|
|
3
3
|
import { TABLE_ROW_READ_WINDOW_FIELDS } from "./table-row-read.js";
|
|
4
|
+
import { TABLE_ROW_REMOVAL_FIELDS } from "./table-row-removal.js";
|
|
4
5
|
const text = (description) => str(description ? { description } : {});
|
|
6
|
+
// The grid's own URL state (Sequence lead/contact grids reuse the Table grid): copying f / s from a
|
|
7
|
+
// filtered, sorted browser view is the supported way to build them.
|
|
8
|
+
const FILTER_PARAM = "Filter tree as the grid URL's f parameter (base64url JSON); copy it from a filtered browser view.";
|
|
9
|
+
const SORT_PARAM = "Sort list as the grid URL's s parameter (base64url JSON); copy it from a sorted browser view.";
|
|
10
|
+
// Sequence lead/contact rows: one row can carry ~100 KB of research and
|
|
11
|
+
// enrichment values, so these reads select columns and compact values (OXP-1.11.67).
|
|
12
|
+
const sequenceRowsProjection = {
|
|
13
|
+
fields: text("Comma-separated column keys to return, e.g. full_name,company,__seq_status; omit for every column."),
|
|
14
|
+
projection: enumOf(["grid", "values"], { description: "values: compact {id, values} rows, long values capped; grid (default): the full grid payload." }),
|
|
15
|
+
};
|
|
16
|
+
const SEQUENCE_ROWS_TRUNCATION_HINT = "Result trimmed for context size. Pass projection=values (values over 2,000 characters are capped) and fields=<column keys>; a smaller limit cannot shrink one row.";
|
|
5
17
|
const json = { type: "object", additionalProperties: true };
|
|
6
18
|
const strings = () => arr(str());
|
|
7
19
|
const objects = () => arr(json);
|
|
@@ -15,12 +27,12 @@ const selection = obj({
|
|
|
15
27
|
const actions = arr(obj({ type: enumOf(["tool_column"]), column: text(), definition: json }, { required: ["column"] }));
|
|
16
28
|
const viewFields = { name: text(), view_type: text(), config: json, group_by: text(), is_default: bool(), position: int({ minimum: 0 }) };
|
|
17
29
|
const crmLinks = arr(obj({ object: text(), row_id: text(), role: text() }, { required: ["object", "row_id"] }));
|
|
18
|
-
function operation(id, route, method, cli, mcp, pack, summary, fields = {}, required = [], options = {}) {
|
|
30
|
+
function operation(id, route, method, cli, mcp, pack, summary, fields = {}, required = [], options = {}, annotations) {
|
|
19
31
|
return {
|
|
20
32
|
id, route, method, parameters: [...route.matchAll(/\{(\w+)\}/g)].map((match) => match[1]),
|
|
21
33
|
contract: obj(fields, { required }),
|
|
22
34
|
cli: { path: cli.split(" "), summary },
|
|
23
|
-
mcp: { name: mcp, title: `Oxygen: ${cli}`, description: summary, pack },
|
|
35
|
+
mcp: { name: mcp, title: `Oxygen: ${cli}`, description: summary, pack, ...(annotations ? { annotations } : {}) },
|
|
24
36
|
mutates: method !== "GET", spends: false, ...options,
|
|
25
37
|
};
|
|
26
38
|
}
|
|
@@ -33,18 +45,18 @@ const multipart = { contentField: "content_base64", nameField: "file_name", type
|
|
|
33
45
|
const nativeCli = { generated: { cli: false, mcp: false } };
|
|
34
46
|
export const BROWSER_OPERATIONS = [
|
|
35
47
|
operation("tables.resource.export_csv", `${table}/export/csv`, "GET", "tables export-csv", "oxygen_table_export_csv", "tables", "Download every row in the exact filtered Table view as streamed CSV. CLI writes --output; MCP returns an authenticated download resource link. Unsupported live lookup filters fail before download; rows and bytes are not capped or truncated.", { f: text("Serialized filter tree."), s: text("Serialized sort state."), q: text(), fields: text("Comma-separated exact column keys.") }, [], { binary: { stream: true, resourceParameter: "table" } }),
|
|
36
|
-
operation("billing.allowance.view", "/api/cli/billing/allowance/view", "GET", "billing allowance view", "oxygen_billing_allowance_view", "billing", "
|
|
48
|
+
operation("billing.allowance.view", "/api/cli/billing/allowance/view", "GET", "billing allowance view", "oxygen_billing_allowance_view", "billing", "Inspect the current-cycle allowance, billing owner and partner-bonus eligibility. 0 credits; reserves nothing. Due plan grants or credit expiry may apply."),
|
|
37
49
|
operation("billing.commitments.view", "/api/cli/billing/commitments/view", "GET", "billing commitments view", "oxygen_billing_commitments_view", "billing", "Read the complete fixed-credit commitment view and linked billing-owner display, without enumerating a child's sibling resources."),
|
|
38
50
|
operation("billing.invoices.view", "/api/cli/billing/invoices/view", "GET", "billing invoices view", "oxygen_billing_invoices_view", "billing", "Read the browser invoice-history projection, including exact native timestamps, amounts and signed Stripe invoice links."),
|
|
39
51
|
operation("billing.summary", "/api/cli/billing/summary", "GET", "billing summary", "oxygen_billing_summary", "billing", "Read the complete non-writing wallet, plan, seat-capacity and billing-owner summary."),
|
|
40
|
-
operation("billing.usage.view", "/api/cli/billing/usage/view", "GET", "billing usage view", "oxygen_billing_usage_view", "billing", "
|
|
52
|
+
operation("billing.usage.view", "/api/cli/billing/usage/view", "GET", "billing usage view", "oxygen_billing_usage_view", "billing", "Credit spend over 7, 30 or 90 days by category and provider, each with its share, plus permitted linked-workspace rollups. totalSpent is reserved minus released; billing usage managed_credits_used counts captured credits only. Other windows or groupings: billing audit.", { days: enumOf(["7", "30", "90"]), workspace: text() }),
|
|
41
53
|
operation("integrations.managed_endpoints", "/api/cli/integrations/composio/endpoints", "GET", "integrations managed-endpoints", "oxygen_integration_managed_endpoints", "integrations", "Read a managed integration's full action catalog and parameter schemas.", { integration_id: text() }, ["integration_id"]),
|
|
42
54
|
operation("integrations.openrouter_models", "/api/cli/integrations/openrouter/models", "GET", "integrations openrouter-models", "oxygen_openrouter_models", "integrations", "Read model and pricing metadata using this workspace's connected OpenRouter account; credentials are never returned."),
|
|
43
55
|
operation("integrations.status", "/api/cli/integrations/status", "GET", "integrations status", "oxygen_integration_status", "integrations", "Read active connection counts, sender connection state and the workspace's usable BYOK plan entitlement."),
|
|
44
56
|
operation("pricing.customer_credit_prices", "/api/cli/pricing/customer-credit-prices", "GET", "pricing customer-credit-prices", "oxygen_customer_credit_prices", "workspace", "Read the customer credit-price catalog, quantity decisions and price provenance used by the Table picker."),
|
|
45
|
-
operation("sequences.contacts.rows", "/api/cli/sequences/{sequence}/contacts/rows", "GET", "sequences contacts rows", "oxygen_sequence_contacts_rows", "sequences", "Read the full contact grid projection with exact contact-state filter and native synthetic status columns.", { contact_state: enumOf(["all", "not_contacted", "contacted", "connected", "replied", "positive_reply"]), limit: int({ minimum: 1, maximum: 2000 }), cursor: text(), offset: int({ minimum: 0 }), f: text(), s: text() }),
|
|
46
|
-
operation("sequences.leads.rows", "/api/cli/sequences/{sequence}/leads/rows", "GET", "sequences leads rows", "oxygen_sequence_leads_rows", "sequences", "Read the complete enrolled-lead grid projection, including sequence status, step, action and failure columns.", { limit: int({ minimum: 1, maximum: 2000 }), cursor: text(), offset: int({ minimum: 0 }), f: text(), s: text() }),
|
|
47
|
-
operation("unibox.metadata", "/api/cli/unibox/metadata", "GET", "unibox metadata", "oxygen_unibox_metadata", "inbox", "Read the complete authenticated inbox account, filter and tag metadata."),
|
|
57
|
+
operation("sequences.contacts.rows", "/api/cli/sequences/{sequence}/contacts/rows", "GET", "sequences contacts rows", "oxygen_sequence_contacts_rows", "sequences", "Read the full contact grid projection with exact contact-state filter and native synthetic status columns.", { contact_state: enumOf(["all", "not_contacted", "contacted", "connected", "replied", "positive_reply"]), limit: int({ minimum: 1, maximum: 2000 }), cursor: text(), offset: int({ minimum: 0 }), f: text(FILTER_PARAM), s: text(SORT_PARAM), ...sequenceRowsProjection }, [], { truncationHint: SEQUENCE_ROWS_TRUNCATION_HINT }),
|
|
58
|
+
operation("sequences.leads.rows", "/api/cli/sequences/{sequence}/leads/rows", "GET", "sequences leads rows", "oxygen_sequence_leads_rows", "sequences", "Read the complete enrolled-lead grid projection, including sequence status, step, action and failure columns.", { limit: int({ minimum: 1, maximum: 2000 }), cursor: text(), offset: int({ minimum: 0 }), f: text(FILTER_PARAM), s: text(SORT_PARAM), ...sequenceRowsProjection }, [], { truncationHint: SEQUENCE_ROWS_TRUNCATION_HINT }),
|
|
59
|
+
operation("unibox.metadata", "/api/cli/unibox/metadata", "GET", "unibox metadata", "oxygen_unibox_metadata", "inbox", "Read the complete authenticated inbox account, filter and tag metadata, including each sender profile (person) and its id."),
|
|
48
60
|
operation("workflows.observed_output", "/api/cli/workflows/{workflow}/observed-output", "GET", "workflows observed-output", "oxygen_workflow_observed_output", "workflows", "Inspect observed output paths and bounded samples from an exact run or recent matching workflow revision.", { run_id: text(), source_hash: text() }),
|
|
49
61
|
operation("workflows.run.events", "/api/cli/workflows/{workflow}/runs/{run}/events", "GET", "workflows runs events", "oxygen_workflow_run_events", "workflows", "Read the exact Workflow run's bounded event history and whether it is still active.", { limit: int({ minimum: 1, maximum: 1000 }) }),
|
|
50
62
|
operation("workflows.run.step_statuses", "/api/cli/workflows/{workflow}/runs/{run}/step-statuses", "GET", "workflows runs step-statuses", "oxygen_workflow_run_step_statuses", "workflows", "Read the current Workflow run status and every step status for immediate execution readback."),
|
|
@@ -52,7 +64,7 @@ export const BROWSER_OPERATIONS = [
|
|
|
52
64
|
operation("tables.resource.edit", table, "PATCH", "tables edit", "oxygen_table_resource_edit", "tables", "Rename a Table or move it to a workspace project; returns the saved Table.", { name: text(), project_id: text() }),
|
|
53
65
|
operation("tables.resource.archive", table, "DELETE", "tables archive", "oxygen_tables_archive", "tables", "Archive a Table indefinitely without dropping its physical data or scheduling a purge.", {}, [], nativeCli),
|
|
54
66
|
operation("tables.resource.duplicate", `${table}/duplicate`, "POST", "tables duplicate", "oxygen_tables_duplicate", "tables", "Duplicate a Table with its columns and optionally its row values.", { name: text(), include_rows: bool() }, [], nativeCli),
|
|
55
|
-
operation("tables.resource.activity", `${table}/activity`, "GET", "tables changes", "oxygen_table_resource_activity", "tables", "Read a Table's
|
|
67
|
+
operation("tables.resource.activity", `${table}/activity`, "GET", "tables changes", "oxygen_table_resource_activity", "tables", "Read a Table's live runs and queue health.", { limit: int({ minimum: 1 }) }),
|
|
56
68
|
operation("tables.resource.column_stats", `${table}/column-stats`, "GET", "tables column-stats", "oxygen_table_column_stats", "tables", "Read per-column completion and provider statistics; large Tables use labeled samples."),
|
|
57
69
|
operation("tables.resource.fill_progress", `${table}/fill-progress`, "GET", "tables fill-progress", "oxygen_table_fill_progress", "tables", "Read hosted Table fill progress and any actionable ingestion failure."),
|
|
58
70
|
operation("tables.resource.kind_estimates", "/api/cli/tables/column-kind-estimates", "GET", "columns kind-estimates", "oxygen_column_kind_estimates", "tables", "Read managed credit estimates for available Table column kinds."),
|
|
@@ -70,7 +82,7 @@ export const BROWSER_OPERATIONS = [
|
|
|
70
82
|
operation("tables.resource.rows.get", `${table}/rows/{row}`, "GET", "tables rows inspect", "oxygen_table_row_inspect", "tables", "Read one row; field selects column keys and hydrate_relations=1 includes relations. projection=value returns lossless JSON fragments; resume value_cursor with identical table/row/field/path.", { hydrate_relations: enumOf(["1"]), field: strings(), ...TABLE_ROW_READ_WINDOW_FIELDS }, [], { repeatedQueryFields: ["field"] }),
|
|
71
83
|
operation("tables.resource.rows.edit", `${table}/rows/{row}`, "PATCH", "tables rows edit", "oxygen_table_row_edit", "tables", "Patch one row's values and return the committed row.", { values: json }, ["values"]),
|
|
72
84
|
operation("tables.resource.rows.delete", `${table}/rows/{row}`, "DELETE", "tables rows remove", "oxygen_table_row_remove", "tables", "Remove one row from a workspace Table."),
|
|
73
|
-
operation("tables.resource.rows.bulk_delete", `${table}/rows/delete`, "POST", "tables rows remove-selection", "oxygen_table_rows_remove_selection", "tables", "
|
|
85
|
+
operation("tables.resource.rows.bulk_delete", `${table}/rows/delete`, "POST", "tables rows remove-selection", "oxygen_table_rows_remove_selection", "tables", "Permanently delete Table rows by exact ids or a matching filtered selection. Unsupported scope fields are refused.", TABLE_ROW_REMOVAL_FIELDS, [], {}, { destructiveHint: true }),
|
|
74
86
|
operation("tables.resource.rows.ids", `${table}/rows/ids`, "GET", "tables rows range-ids", "oxygen_table_rows_range_ids", "tables", "Resolve a bounded row range into exact ids, preserving the current filter, search, sort and CRM scope.", { offset: int({ minimum: 0 }), limit: int({ minimum: 1 }), filter: text(), search: text(), sort: text(), crm_object: text() }, ["offset", "limit"]),
|
|
75
87
|
operation("tables.resource.relationships.get", `${table}/records/{row}/relationships`, "GET", "tables rows relationships", "oxygen_table_row_relationships", "crm", "Read a CRM-backed Table row's relationship links and available targets."),
|
|
76
88
|
operation("tables.resource.relationships.set", `${table}/records/{row}/relationships`, "POST", "tables rows relationship-set", "oxygen_table_row_relationship_set", "crm", "Set one CRM-backed Table row's relationship and return the saved links.", { relationship: text(), target_row_id: text() }, ["relationship", "target_row_id"]),
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { ObjectProperty } from "./schema.js";
|
|
2
2
|
/** Custom CRM column writes accept both canonical snake_case and legacy aliases. */
|
|
3
|
-
export declare const CRM_CUSTOM_COLUMN_SCHEMA: ObjectProperty
|
|
3
|
+
export declare const CRM_CUSTOM_COLUMN_SCHEMA: ObjectProperty & {
|
|
4
|
+
allOf: Array<{
|
|
5
|
+
anyOf: Array<{
|
|
6
|
+
required: string[];
|
|
7
|
+
}>;
|
|
8
|
+
}>;
|
|
9
|
+
};
|
|
4
10
|
export declare const CRM_CUSTOM_IDENTITY_SCHEMA: ObjectProperty;
|
|
@@ -5,7 +5,7 @@ export const CRM_CUSTOM_COLUMN_SCHEMA = {
|
|
|
5
5
|
key: { type: "string" }, label: { type: "string" },
|
|
6
6
|
data_type: { type: "string", enum: ["text", "numeric", "boolean", "jsonb", "timestamptz"] },
|
|
7
7
|
dataType: { type: "string", enum: ["text", "numeric", "boolean", "jsonb", "timestamptz"] },
|
|
8
|
-
semantic_type: { type: "string" }, semanticType: { type: "string" },
|
|
8
|
+
semantic_type: { type: "string", minLength: 1, description: "Required with data_type; text for a generic field, or a semantic such as company.name, company.domain or email." }, semanticType: { type: "string", minLength: 1, description: "Alias of semantic_type." },
|
|
9
9
|
kind: { type: "string" }, attribute_kind: { type: "string" }, attributeKind: { type: "string" },
|
|
10
10
|
option_model_type: { type: "string" }, optionModelType: { type: "string" },
|
|
11
11
|
is_required: { type: "boolean" }, isRequired: { type: "boolean" },
|
|
@@ -21,6 +21,10 @@ export const CRM_CUSTOM_COLUMN_SCHEMA = {
|
|
|
21
21
|
attributeMetadata: { type: "object", additionalProperties: true },
|
|
22
22
|
},
|
|
23
23
|
required: ["key", "label"],
|
|
24
|
+
allOf: [
|
|
25
|
+
{ anyOf: [{ required: ["data_type"] }, { required: ["dataType"] }] },
|
|
26
|
+
{ anyOf: [{ required: ["semantic_type"] }, { required: ["semanticType"] }] },
|
|
27
|
+
],
|
|
24
28
|
additionalProperties: false,
|
|
25
29
|
};
|
|
26
30
|
export const CRM_CUSTOM_IDENTITY_SCHEMA = {
|
|
@@ -72,6 +72,20 @@ export declare const CRM_OBJECTS_QUERY_CONTRACT: import("./schema.js").ContractO
|
|
|
72
72
|
"x-clamp"?: true;
|
|
73
73
|
};
|
|
74
74
|
}, never>;
|
|
75
|
+
export declare const CRM_RECORD_QUERY_CONTRACT: import("./schema.js").ContractObject<{
|
|
76
|
+
readonly projection: {
|
|
77
|
+
type: "string";
|
|
78
|
+
enum: readonly ("compact" | "full")[];
|
|
79
|
+
description?: string;
|
|
80
|
+
};
|
|
81
|
+
readonly max_chars: {
|
|
82
|
+
type: "integer";
|
|
83
|
+
description?: string;
|
|
84
|
+
minimum?: number;
|
|
85
|
+
maximum?: number;
|
|
86
|
+
"x-clamp"?: true;
|
|
87
|
+
};
|
|
88
|
+
}, never>;
|
|
75
89
|
export declare const CRM_CONNECTIONS_QUERY_CONTRACT: import("./schema.js").ContractObject<{
|
|
76
90
|
readonly projection: {
|
|
77
91
|
type: "string";
|
|
@@ -30,6 +30,10 @@ export const CRM_OBJECTS_QUERY_CONTRACT = obj({
|
|
|
30
30
|
limit: int({ minimum: 1, maximum: 100, description: "Objects in one batch; default 20 for bounded reads." }),
|
|
31
31
|
max_chars: int({ minimum: 2000, maximum: 40_000, description: "Complete response window; oversized objects refuse without advancing." }),
|
|
32
32
|
});
|
|
33
|
+
export const CRM_RECORD_QUERY_CONTRACT = obj({
|
|
34
|
+
projection: enumOf(["compact", "full"], { description: "compact omits object configuration and oversized row fields, naming omissions. HTTP/CLI default full; MCP default compact." }),
|
|
35
|
+
max_chars: int({ minimum: 2000, maximum: 40_000, description: "Complete receipt window. Omitted cells remain available through the Table row inspector." }),
|
|
36
|
+
});
|
|
33
37
|
export const CRM_CONNECTIONS_QUERY_CONTRACT = obj({
|
|
34
38
|
projection: enumOf(["compact", "full"], { description: "Compact returns identifiers and short communication previews. HTTP default full." }),
|
|
35
39
|
max_chars: int({ minimum: 2000, maximum: 40_000, description: "Complete recent-window response; hasMore includes omitted links." }),
|
|
@@ -6,6 +6,8 @@ import { TABLE_FAVORITE_CONTRACT, TABLE_FAVORITES_LIST_CONTRACT, TABLE_ITEM_RESO
|
|
|
6
6
|
import { BILLING_OWNER_READ_CONTRACT } from "./billing-owner-read.js";
|
|
7
7
|
import { COPILOT_SESSIONS_LIST_CONTRACT } from "./copilot-sessions.js";
|
|
8
8
|
import { CRM_FILE_ATTACH_CONTRACT, CRM_FILE_ATTACH_DESCRIPTION } from "./crm-support.js";
|
|
9
|
+
import { spintaxContract } from "./spintax.js";
|
|
10
|
+
import { betaFeaturesUpdateContract, emailDomainSuppressionListContract, emailDomainSuppressionRemoveContract, emailSuppressionRemoveContract, providerLimitListContract, providerLimitSelectorContract, providerLimitUpdateContract } from "./workspace-utilities.js";
|
|
9
11
|
const text = (description) => str(description === undefined ? {} : { description });
|
|
10
12
|
const list = () => arr(str());
|
|
11
13
|
const json = { type: "object", additionalProperties: true };
|
|
@@ -41,7 +43,7 @@ export const CUSTOMER_OPERATIONS = [
|
|
|
41
43
|
operation("copilot.attachments.delete", "/api/cli/copilot/sessions/{session_id}/attachments/{attachment_id}", "DELETE", "copilot attachments delete", "oxygen_copilot_attachment_delete", "agents", "Detach an unsent Copilot attachment; attachments already quoted by a turn cannot be removed."),
|
|
42
44
|
operation("copilot.feedback", "/api/cli/copilot/sessions/{session_id}/turns/{turn_id}/feedback", "POST", "copilot feedback", "oxygen_copilot_feedback", "agents", "Rate one attended Copilot turn and optionally explain the rating.", { rating: enumOf(["up", "down"]), comment: text() }, ["rating"]),
|
|
43
45
|
operation("copilot.interrupt", "/api/cli/copilot/sessions/{session_id}/turns/{turn_id}/interrupt", "POST", "copilot interrupt", "oxygen_copilot_interrupt", "agents", "Request cancellation of one Copilot turn. Read the session again to confirm it stopped.", {}, [], mcpOnly),
|
|
44
|
-
operation("context.canonical.get", "/api/cli/context/canonical/get", "POST", "context canonical get", "oxygen_context_canonical_get", "knowledge", "Read the pinned
|
|
46
|
+
operation("context.canonical.get", "/api/cli/context/canonical/get", "POST", "context canonical get", "oxygen_context_canonical_get", "knowledge", "Read the current canonical (pinned) voice, brand or positioning that AI copy uses, or any type's pinned asset. present=false means none is pinned; grounding_when_absent says what AI copy uses instead.", { type: text("Type to read: voice, brand or positioning (the canonical copy AI uses), or another context type such as playbook or persona.") }, ["type"], { mutates: false }),
|
|
45
47
|
operation("crm.notes.update", "/api/cli/crm/notes/{note_id}", "PATCH", "crm notes update", "oxygen_crm_note_update", "crm", "Edit a CRM note's body, title or pinned state; an empty title clears it.", { body: text(), title: nullable(text()), pinned: bool() }, [], mcpOnly),
|
|
46
48
|
operation("crm.notes.delete", "/api/cli/crm/notes/{note_id}", "DELETE", "crm notes delete", "oxygen_crm_note_delete", "crm", "Delete one CRM note in this workspace.", {}, [], mcpOnly),
|
|
47
49
|
operation("crm.files.attach_inline", "/api/cli/crm/objects/{object}/records/{row_id}/files", "POST", "crm files attach-inline", "oxygen_crm_file_attach", "crm", CRM_FILE_ATTACH_DESCRIPTION, CRM_FILE_ATTACH_CONTRACT.properties, [...(CRM_FILE_ATTACH_CONTRACT.required ?? [])]),
|
|
@@ -60,12 +62,12 @@ export const CUSTOMER_OPERATIONS = [
|
|
|
60
62
|
operation("directory.apply", "/api/cli/directory/apply", "POST", "directory apply", "oxygen_directory_apply", "crm", "Apply for an agency-directory listing for this workspace; reuses an existing open application.", { message: text(), website: text() }, [], mcpOnly),
|
|
61
63
|
operation("directory.logo", "/api/cli/directory/listing/logo", "POST", "directory logo upload", "oxygen_directory_logo_upload", "crm", "Upload a public agency-directory logo and read back the updated listing; PNG, JPEG, WebP or SVG, at most 2 MB.", { content_base64: text(), file_name: text(), content_type: enumOf(["image/png", "image/jpeg", "image/webp", "image/svg+xml"]) }, ["content_base64", "file_name", "content_type"], { multipart: { contentField: "content_base64", nameField: "file_name", typeField: "content_type", fileField: "file" } }),
|
|
62
64
|
operation("domains.delete", "/api/cli/domains/delete", "POST", "domains delete", "oxygen_domains_delete", "deliverability", "Preview domain removal and renewal cancellation; execute only with the exact plan hash and confirmation.", { domains: list(), approved: bool(), plan_hash: text(), confirmation: text() }, ["domains"], mcpOnly),
|
|
63
|
-
operation("knowledge.pages.archive", "/api/cli/knowledge/pages/archive", "POST", "knowledge page archive", "oxygen_knowledge_page_archive", "knowledge", "Archive a knowledge page
|
|
65
|
+
operation("knowledge.pages.archive", "/api/cli/knowledge/pages/archive", "POST", "knowledge page archive", "oxygen_knowledge_page_archive", "knowledge", "Archive a knowledge page; content/history remain, links become unresolved. Pass expected_revision for the version you reviewed.", { slug: text(), id: text(), expected_revision: int({ minimum: 1 }) }, [], mcpOnly),
|
|
64
66
|
operation("knowledge.sync.manifest", "/api/cli/knowledge/sync/manifest", "POST", "knowledge sync-manifest", "oxygen_knowledge_sync_manifest", "knowledge", "Read the wiki revision and content-hash inventory without downloading instruction bodies.", {}, [], { mutates: false }),
|
|
65
67
|
operation("knowledge.sync.delta", "/api/cli/knowledge/sync/delta", "POST", "knowledge sync", "oxygen_knowledge_sync_delta", "knowledge", "Read one resumable batch of wiki pages and tombstones, bounded by the server's byte budget.", { cursor: text(), limit: int({ minimum: 1, maximum: 200 }) }, [], { ...mcpOnly, mutates: false }),
|
|
66
|
-
operation("limits.provider.get", "/api/cli/limits/provider", "GET", "limits provider list", "oxygen_provider_limits_list", "billing", "Read
|
|
67
|
-
operation("limits.provider.set", "/api/cli/limits/provider", "POST", "limits provider set", "oxygen_provider_limits_set", "billing", "Set
|
|
68
|
-
operation("limits.provider.delete", "/api/cli/limits/provider", "DELETE", "limits provider delete", "oxygen_provider_limits_delete", "billing", "Clear
|
|
68
|
+
operation("limits.provider.get", "/api/cli/limits/provider", "GET", "limits provider list", "oxygen_provider_limits_list", "billing", "Read provider request limits and BYOK warning defaults. MCP defaults to bounded summary pages; follow paging.next_offset with the same filter. HTTP/CLI omit pagination for the full legacy list. 0 credits.", {}, [], { contract: providerLimitListContract, generated: { cli: false, mcp: false } }),
|
|
69
|
+
operation("limits.provider.set", "/api/cli/limits/provider", "POST", "limits provider set", "oxygen_provider_limits_set", "billing", "Set an enforced provider request limit; admin or owner only. Approve the exact provider, operation and window: raising a cap may permit more provider use. 0 credits.", {}, [], { ...mcpOnly, contract: providerLimitUpdateContract }),
|
|
70
|
+
operation("limits.provider.delete", "/api/cli/limits/provider", "DELETE", "limits provider delete", "oxygen_provider_limits_delete", "billing", "Clear one provider request-limit override; admin or owner only. Approve the exact selector. Other operation overrides remain; the provider returns to its defaults, whose BYOK threshold may be observe-only. 0 credits.", {}, [], { ...mcpOnly, contract: providerLimitSelectorContract, queryFields: ["provider", "operation"] }),
|
|
69
71
|
operation("mailboxes.emailguard.auto_enroll.get", "/api/cli/mailboxes/emailguard/auto-enroll", "GET", "mailboxes emailguard auto-enroll", "oxygen_mailboxes_emailguard_auto_enroll_get", "deliverability", "Read the workspace's automatic monitoring enrollment grant and last sweep.", {}, [], mcpOnly),
|
|
70
72
|
operation("mailboxes.emailguard.auto_enroll.set", "/api/cli/mailboxes/emailguard/auto-enroll", "POST", "mailboxes emailguard auto-enroll", "oxygen_mailboxes_emailguard_auto_enroll_set", "deliverability", "Preview, arm or disarm automatic mailbox monitoring. Arming recurring spend requires approved=true and max_credits_per_cycle.", { enabled: bool(), approved: bool(), max_credits_per_cycle: num({ minimum: 0 }), run: bool(), dry_run: bool() }, [], { ...mcpOnly, spends: true }),
|
|
71
73
|
operation("mailboxes.warmup_profiles.get", "/api/cli/mailboxes/warmup-profile", "GET", "mailboxes warmup profile", "oxygen_mailboxes_warmup_profiles", "deliverability", "Read available OXYGEN Warm-up profiles and current bindings.", {}, [], mcpOnly),
|
|
@@ -76,8 +78,8 @@ export const CUSTOMER_OPERATIONS = [
|
|
|
76
78
|
operation("publishing.drafts.update", "/api/cli/publishing/drafts/{draft_id}", "PATCH", "publishing drafts edit", "oxygen_publishing_draft_update", "publishing", "Edit a queued publishing draft's text without publishing it.", { text: text(), variant_index: int({ minimum: 0 }) }, ["text"], mcpOnly),
|
|
77
79
|
operation("publishing.mentions.search", "/api/cli/publishing/mentions/search", "POST", "publishing mentions search", "oxygen_publishing_mentions_search", "publishing", "Find LinkedIn company or person identities for a mention; free, subject to the connected account's read quota.", { query: text(), kind: enumOf(["company", "person"]), connection_id: text() }, ["query"], { mutates: false }),
|
|
78
80
|
operation("settings.beta.get", "/api/cli/settings/beta-features", "GET", "settings beta-features get", "oxygen_settings_beta_features_get", "workspace", "Read this workspace's beta-navigation opt-in."),
|
|
79
|
-
operation("settings.beta.set", "/api/cli/settings/beta-features", "POST", "settings beta-features set", "oxygen_settings_beta_features_set", "workspace", "Enable or disable beta navigation for
|
|
80
|
-
operation("spintax.generate", "/api/cli/spintax", "POST", "spintax generate", "oxygen_spintax_generate", "sequences", "Generate spintax
|
|
81
|
+
operation("settings.beta.set", "/api/cli/settings/beta-features", "POST", "settings beta-features set", "oxygen_settings_beta_features_set", "workspace", "Enable or disable beta navigation for every workspace member; admin or owner only. Approve the preference change. This does not disable routes. 0 credits.", {}, [], { contract: betaFeaturesUpdateContract }),
|
|
82
|
+
operation("spintax.generate", "/api/cli/spintax", "POST", "spintax generate", "oxygen_spintax_generate", "sequences", "Generate wording or copy variations as spintax: live (default) costs 3 credits and requires approval and a credit ceiling; explicit dry_run is a free preview. Preserve merge variables; send nothing. Live requires approved:true and max_credits>=3 after preview; failed generation refunds the reservation.", {}, [], { contract: spintaxContract, defaults: { mode: "live" }, spends: true }),
|
|
81
83
|
operation("table_action_items.resolve", "/api/cli/table-action-items/{item_id}/resolve", "POST", "table-actions resolve", "oxygen_table_action_item_resolve", "tables", "Record a human-verified uncertain Table action outcome without repeating it. Use cells resolve for row/column coordinates.", TABLE_ITEM_RESOLVE_CONTRACT.properties, ["outcome"]),
|
|
82
84
|
operation("table_ingestions.append", "/api/cli/table-ingestion-runs/{ingestion_run_id}/items", "POST", "table-ingestions append", "oxygen_table_ingestions_append_items", "runs", "Append bounded ingestion items to an existing run; preserves the run's approved scope.", { items: rows(), max_attempts: int({ minimum: 1 }) }, ["items"], cliOnly),
|
|
83
85
|
operation("tables.favorites.get", "/api/cli/tables/favorite", "GET", "tables favorites", "oxygen_tables_favorites", "tables", "Read starred Tables/folders (per-member preference; free (0 credits)); next_cursor. Catalog stars differ.", TABLE_FAVORITES_LIST_CONTRACT.properties, [], { generated: { cli: true, mcp: false } }),
|
|
@@ -100,7 +102,7 @@ export const CUSTOMER_OPERATIONS = [
|
|
|
100
102
|
operation("db.provision", "/api/cli/db/provision", "POST", "db provision", "oxygen_workspace_database_provision", "workspace", "Provision or retry this workspace database immediately; already-ready workspaces retain it. No preview or confirmation field; native workspace write access applies. May outlast the connector deadline: read oxygen_workspace_database_status before retrying. Hosting is plan-included; 0 credits.", {}, [], mcpOnly),
|
|
101
103
|
operation("sessions.list", "/api/cli/sessions", "GET", "sessions list", "oxygen_sessions_list", "workspace", "List your personal CLI sessions across workspaces; OAuth or personal user session required, organization API keys are refused."),
|
|
102
104
|
operation("sessions.revoke", "/api/cli/sessions/{session_id}", "DELETE", "sessions revoke", "oxygen_sessions_revoke", "workspace", "Revoke one of your personal CLI sessions; OAuth or personal user session required, organization API keys are refused."),
|
|
103
|
-
operation("billing.allowance", "/api/cli/billing/allowance", "GET", "billing allowance", "oxygen_billing_allowance", "billing", "
|
|
105
|
+
operation("billing.allowance", "/api/cli/billing/allowance", "GET", "billing allowance", "oxygen_billing_allowance", "billing", "Inspect this workspace's recurring credit allowance and period. 0 credits; reserves nothing. Due plan grants or credit expiry may apply.", {}, [], mcpOnly),
|
|
104
106
|
operation("billing.invoices", "/api/cli/billing/invoices", "GET", "billing invoices", "oxygen_billing_invoices", "billing", "Read this workspace's billing invoices and their hosted payment links.", {}, [], mcpOnly),
|
|
105
107
|
operation("billing.seats.set", "/api/cli/billing/seats", "POST", "billing seats set", "oxygen_billing_seats_set", "billing", "Set purchased legacy sending-seat quantity. Retired seats cannot increase; reducing existing seats lowers the next renewal charge.", { seat_key: enumOf(["linkedin", "whatsapp", "phone_number", "email_sender"]), quantity: int({ minimum: 0 }) }, ["seat_key", "quantity"], mcpOnly),
|
|
106
108
|
operation("collaboration.gates.list", "/api/cli/collab/gates", "GET", "approvals gate list", "oxygen_approval_gates_list", "collaboration", "Read this workspace's approval gates, optionally for one exact subject.", { subject: text() }, [], mcpOnly),
|
|
@@ -118,9 +120,9 @@ export const CUSTOMER_OPERATIONS = [
|
|
|
118
120
|
operation("orgs.billing_owners", "/api/cli/orgs/billing-owners", "GET", "orgs billing-owners", "oxygen_workspace_billing_owners", "workspace", "Read the current workspace's billing owner, entitlement and payer candidates, including ineligibility reasons. Optional organization asserts the current workspace. Free.", BILLING_OWNER_READ_CONTRACT.properties, [], mcpOnly),
|
|
119
121
|
operation("search.runs.items", "/api/cli/search/runs/{search_run_id}/items", "GET", "search runs items", "oxygen_search_run_items", "enrichment", "Read durable search ingestion items by run id and optional status.", { status: text(), limit: int({ minimum: 1 }) }, [], mcpOnly),
|
|
120
122
|
operation("senders.checkpoints", "/api/cli/senders/checkpoints", "GET", "senders checkpoints", "oxygen_sender_checkpoints", "sequences", "Read connected sender authentication checkpoints that need human completion.", {}, [], mcpOnly),
|
|
121
|
-
operation("suppressions.domains.list", "/api/cli/suppressions/domains", "GET", "suppressions domains", "oxygen_suppressed_domains_list", "sequences", "Read domain-wide
|
|
122
|
-
operation("suppressions.domains.remove", "/api/cli/suppressions/domains", "DELETE", "suppressions remove-domain", "oxygen_suppressed_domains_remove", "sequences", "Remove one domain-wide
|
|
123
|
-
operation("suppressions.addresses.remove", "/api/cli/suppressions/addresses", "DELETE", "suppressions remove-address", "oxygen_suppressed_addresses_remove", "sequences", "Remove one email-address
|
|
123
|
+
operation("suppressions.domains.list", "/api/cli/suppressions/domains", "GET", "suppressions domains", "oxygen_suppressed_domains_list", "sequences", "Read domain-wide sending blocks, newest first. Domain reasons differ from address reasons. MCP defaults to bounded summary pages; follow paging.next_offset with the same filters. 0 credits.", {}, [], { contract: emailDomainSuppressionListContract, generated: { cli: false, mcp: false } }),
|
|
124
|
+
operation("suppressions.domains.remove", "/api/cli/suppressions/domains", "DELETE", "suppressions remove-domain", "oxygen_suppressed_domains_remove", "sequences", "Remove one domain-wide sending block or up to 500 exact domains after approval of the keys. Can restore future sending eligibility; other suppression ledgers still apply. This does not resume enrollments automatically. 0 credits.", {}, [], { ...mcpOnly, contract: emailDomainSuppressionRemoveContract }),
|
|
125
|
+
operation("suppressions.addresses.remove", "/api/cli/suppressions/addresses", "DELETE", "suppressions remove-address", "oxygen_suppressed_addresses_remove", "sequences", "Remove one email-address sending block or up to 500 exact addresses after approval of the keys. Can restore future sending eligibility; other suppression ledgers still apply. This does not resume enrollments automatically. 0 credits.", {}, [], { ...mcpOnly, contract: emailSuppressionRemoveContract }),
|
|
124
126
|
operation("table_action_runs.list", "/api/cli/table-action-runs", "GET", "table-runs list", "oxygen_table_action_runs_list", "runs", "Read durable Table action runs, optionally filtered by status or trace.", { table: text(), status: text(), trace_id: text(), limit: int({ minimum: 1 }) }, ["table"], mcpOnly),
|
|
125
127
|
operation("tables.columns.fields", "/api/cli/tables/columns/fields", "GET", "columns fields", "oxygen_table_column_fields", "tables", "Read the output fields available from one hosted Table column.", { table: text(), column: text() }, ["table", "column"], mcpOnly),
|
|
126
128
|
operation("tools.favorites", "/api/cli/tools/favorites", "GET", "tools favorites", "oxygen_tool_favorites", "enrichment", "Read this member's favorite tool catalog entries in the active workspace.", {}, [], mcpOnly),
|
|
@@ -12,7 +12,7 @@ export function limitsReadQueryIssue(query) {
|
|
|
12
12
|
}
|
|
13
13
|
const record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
14
14
|
const pick = (value, keys) => Object.fromEntries(keys.filter(key => Object.hasOwn(value, key)).map(key => [key, value[key]]));
|
|
15
|
-
const COMMON = ["organization_id", "plan_band", "plan_band_label", "plan_tier", "limits_tier", "source", "entitled", "shared_billing", "web_url", "deepLink"];
|
|
15
|
+
const COMMON = ["organization_id", "plan_band", "plan_band_label", "plan_tier", "limits_tier", "source", "entitled", "plan_resolution", "shared_billing", "web_url", "deepLink"];
|
|
16
16
|
const SECTION_FIELDS = { api: "api_rate_limits", webhooks: "webhook_ingress", spend: "spend_safety_defaults", sending: "sending_limits", workflow: "workflow_limits" };
|
|
17
17
|
function capacityProjection(value) {
|
|
18
18
|
const capacity = record(value), usage = record(capacity.usage), reconciled = usage.row_usage_reconciled === true;
|
|
@@ -119,5 +119,15 @@ export function projectLimitsRead(data, query) {
|
|
|
119
119
|
delete bounded[key];
|
|
120
120
|
markOmitted(key);
|
|
121
121
|
}
|
|
122
|
+
// Both links open the limits page. Drop duplicate navigation last when a
|
|
123
|
+
// long app URL crowds out the protected workspace and plan scope.
|
|
124
|
+
for (const key of ["deepLink", "web_url"]) {
|
|
125
|
+
if (JSON.stringify(bounded).length <= maxChars)
|
|
126
|
+
break;
|
|
127
|
+
if (Object.hasOwn(bounded, key)) {
|
|
128
|
+
delete bounded[key];
|
|
129
|
+
markOmitted(key);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
122
132
|
return bounded;
|
|
123
133
|
}
|
|
@@ -61,6 +61,12 @@ export type OperationSpec<C extends ContractObject = ContractObject> = {
|
|
|
61
61
|
};
|
|
62
62
|
mutates: boolean;
|
|
63
63
|
spends: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* MCP only: what a trimmed result should advise instead of the generic
|
|
66
|
+
* "smaller limit / a cursor", for a read whose single row can exceed the
|
|
67
|
+
* result ceiling (OXP-1.11.67).
|
|
68
|
+
*/
|
|
69
|
+
truncationHint?: string;
|
|
64
70
|
};
|
|
65
71
|
/** The route with its `{param}` segments filled in, each URL-encoded. */
|
|
66
72
|
export declare function operationPath(spec: Pick<OperationSpec, "route">, params: Readonly<Record<string, string>>): string;
|
|
@@ -12,6 +12,7 @@ export const PUBLISHING_AMPLIFICATION_SCOPE_KINDS = ["all", "tag", "post", "ugc_
|
|
|
12
12
|
* closed. Coarse tool annotations remain mixed; native identity/schema checks
|
|
13
13
|
* still run after this call-level classification. */
|
|
14
14
|
export const PUBLISHING_STORED_READ_SELECTORS = {
|
|
15
|
+
oxygen_publishing_comments: { argument: "action", values: ["list", "get"] },
|
|
15
16
|
oxygen_publishing_notes: { argument: "action", values: ["list"] },
|
|
16
17
|
oxygen_publishing_revisions: { argument: "action", values: ["list"] },
|
|
17
18
|
oxygen_publishing_analytics: { argument: "scope", values: ["summary", "timeseries", "post", "account"] },
|
|
@@ -118,18 +118,22 @@ function childPath(parent, key) {
|
|
|
118
118
|
}
|
|
119
119
|
function walkObject(schema, value, path, walk) {
|
|
120
120
|
const out = {};
|
|
121
|
+
const set = (key, entry) => {
|
|
122
|
+
// JSON keys remain own data properties, including an explicit __proto__.
|
|
123
|
+
Object.defineProperty(out, key, { value: entry, enumerable: true, writable: true, configurable: true });
|
|
124
|
+
};
|
|
121
125
|
const properties = schema.properties ?? {};
|
|
122
126
|
for (const key of schema.required ?? []) {
|
|
123
|
-
if (value[key] === undefined)
|
|
127
|
+
if (!Object.hasOwn(value, key) || value[key] === undefined)
|
|
124
128
|
walk.issues.push({ path: childPath(path, key), message: `${childPath(path, key)} is required.` });
|
|
125
129
|
}
|
|
126
130
|
for (const [key, entry] of Object.entries(value)) {
|
|
127
131
|
if (entry === undefined)
|
|
128
132
|
continue;
|
|
129
133
|
const at = childPath(path, key);
|
|
130
|
-
const property = properties[key];
|
|
134
|
+
const property = Object.hasOwn(properties, key) ? properties[key] : undefined;
|
|
131
135
|
if (property !== undefined) {
|
|
132
|
-
|
|
136
|
+
set(key, walkValue(property, entry, at, walk));
|
|
133
137
|
continue;
|
|
134
138
|
}
|
|
135
139
|
const extra = schema.additionalProperties;
|
|
@@ -139,14 +143,14 @@ function walkObject(schema, value, path, walk) {
|
|
|
139
143
|
}
|
|
140
144
|
else {
|
|
141
145
|
walk.unknownKeys.push(at);
|
|
142
|
-
|
|
146
|
+
set(key, entry);
|
|
143
147
|
}
|
|
144
148
|
}
|
|
145
149
|
else if (extra && typeof extra === "object") {
|
|
146
|
-
|
|
150
|
+
set(key, walkValue(extra, entry, at, walk));
|
|
147
151
|
}
|
|
148
152
|
else {
|
|
149
|
-
|
|
153
|
+
set(key, entry);
|
|
150
154
|
}
|
|
151
155
|
}
|
|
152
156
|
return out;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const SPINTAX_GENERATION_CREDITS = 3;
|
|
2
|
+
export declare const spintaxContract: import("./schema.js").ContractObject<{
|
|
3
|
+
readonly text: import("./schema.js").StringProperty;
|
|
4
|
+
readonly section: import("./schema.js").StringProperty;
|
|
5
|
+
readonly mode: {
|
|
6
|
+
type: "string";
|
|
7
|
+
enum: readonly ("dry_run" | "live")[];
|
|
8
|
+
description?: string;
|
|
9
|
+
};
|
|
10
|
+
readonly approved: import("./schema.js").BooleanProperty;
|
|
11
|
+
readonly max_credits: {
|
|
12
|
+
type: "number";
|
|
13
|
+
description?: string;
|
|
14
|
+
minimum?: number;
|
|
15
|
+
maximum?: number;
|
|
16
|
+
"x-clamp"?: true;
|
|
17
|
+
};
|
|
18
|
+
}, "text">;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { bool, enumOf, num, obj, str } from "./schema.js";
|
|
2
|
+
// The native managed service charges this fixed amount for a usable spin.
|
|
3
|
+
// Preview, reservation, settlement and agent-visible schemas share this owner.
|
|
4
|
+
export const SPINTAX_GENERATION_CREDITS = 3;
|
|
5
|
+
export const spintaxContract = obj({
|
|
6
|
+
text: str({ minLength: 1, maxLength: 4000, description: "Outreach copy to vary; merge variables are preserved." }),
|
|
7
|
+
section: str({ maxLength: 80, description: "Optional section label, e.g. Subject." }),
|
|
8
|
+
mode: enumOf(["dry_run", "live"], { description: `Omitted mode is live. Explicit dry_run previews the fixed ${SPINTAX_GENERATION_CREDITS}-credit cost without generation; live requires approval and a ceiling.` }),
|
|
9
|
+
approved: bool({ description: `True only after approval of the exact text and ${SPINTAX_GENERATION_CREDITS}-credit cost.` }),
|
|
10
|
+
max_credits: num({ minimum: 0, description: `Live ceiling must cover the fixed ${SPINTAX_GENERATION_CREDITS}-credit cost.` }),
|
|
11
|
+
}, { required: ["text"] });
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const TABLE_ROW_REMOVAL_FIELDS: {
|
|
2
|
+
row_ids: import("./schema.js").ArrayProperty<import("./schema.js").StringProperty>;
|
|
3
|
+
selection: import("./schema.js").OneOfProperty;
|
|
4
|
+
};
|
|
5
|
+
export declare const TABLE_ROW_REMOVAL_CONTRACT: import("./schema.js").ContractObject<{
|
|
6
|
+
row_ids: import("./schema.js").ArrayProperty<import("./schema.js").StringProperty>;
|
|
7
|
+
selection: import("./schema.js").OneOfProperty;
|
|
8
|
+
}, never>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { arr, enumOf, int, obj, str } from "./schema.js";
|
|
2
|
+
const rowIds = () => arr(str({ minLength: 1 }), { minItems: 1 });
|
|
3
|
+
// Removal uses the grid's scope, not the broader execution selection. In
|
|
4
|
+
// particular, execution's `filters` array is not a serialized browser filter.
|
|
5
|
+
const selection = {
|
|
6
|
+
description: '{"mode":"row_ids","row_ids":["id"]} or {"mode":"all_matching","filter":"<grid f>"}. Optional search, sort, range {offset,limit}, excluded_row_ids, crm_object. filter is base64url grid JSON; filters/limit are refused. Unqualified all_matching removes every row. Encoding guide: oxygen_skills_get({name:"oxygen-tables"}) or oxygen skills get oxygen-tables --json.',
|
|
7
|
+
oneOf: [
|
|
8
|
+
obj({ mode: enumOf(["row_ids"]), row_ids: rowIds() }, { required: ["mode", "row_ids"] }),
|
|
9
|
+
obj({
|
|
10
|
+
mode: enumOf(["all_matching"]),
|
|
11
|
+
filter: str({ description: "Serialized browser filter tree." }),
|
|
12
|
+
search: str(),
|
|
13
|
+
sort: str(),
|
|
14
|
+
range: obj({ offset: int({ minimum: 0 }), limit: int({ minimum: 1 }) }, { required: ["offset", "limit"] }),
|
|
15
|
+
excluded_row_ids: arr(str({ minLength: 1 })),
|
|
16
|
+
crm_object: str(),
|
|
17
|
+
}, { required: ["mode"] }),
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
export const TABLE_ROW_REMOVAL_FIELDS = { row_ids: rowIds(), selection };
|
|
21
|
+
export const TABLE_ROW_REMOVAL_CONTRACT = obj(TABLE_ROW_REMOVAL_FIELDS);
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
export declare const betaFeaturesUpdateContract: import("./schema.js").ContractObject<{
|
|
2
|
+
readonly enabled: import("./schema.js").BooleanProperty;
|
|
3
|
+
}, "enabled">;
|
|
4
|
+
export declare const providerLimitSelectorContract: import("./schema.js").ContractObject<{
|
|
5
|
+
readonly provider: import("./schema.js").StringProperty;
|
|
6
|
+
readonly operation: import("./schema.js").StringProperty;
|
|
7
|
+
}, "provider">;
|
|
8
|
+
export declare const providerLimitUpdateContract: import("./schema.js").ContractObject<{
|
|
9
|
+
readonly provider: import("./schema.js").StringProperty;
|
|
10
|
+
readonly operation: {
|
|
11
|
+
oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
|
|
12
|
+
description?: string;
|
|
13
|
+
};
|
|
14
|
+
readonly limit: {
|
|
15
|
+
type: "integer";
|
|
16
|
+
description?: string;
|
|
17
|
+
minimum?: number;
|
|
18
|
+
maximum?: number;
|
|
19
|
+
"x-clamp"?: true;
|
|
20
|
+
};
|
|
21
|
+
readonly window_seconds: {
|
|
22
|
+
type: "integer";
|
|
23
|
+
description?: string;
|
|
24
|
+
minimum?: number;
|
|
25
|
+
maximum?: number;
|
|
26
|
+
"x-clamp"?: true;
|
|
27
|
+
};
|
|
28
|
+
}, "limit" | "provider" | "window_seconds">;
|
|
29
|
+
export declare const SUPPRESSION_BULK_MAX_KEYS = 500;
|
|
30
|
+
export declare const utilityListWindowProperties: {
|
|
31
|
+
view: {
|
|
32
|
+
type: "string";
|
|
33
|
+
enum: readonly ("full" | "summary")[];
|
|
34
|
+
description?: string;
|
|
35
|
+
};
|
|
36
|
+
max_chars: {
|
|
37
|
+
type: "integer";
|
|
38
|
+
description?: string;
|
|
39
|
+
minimum?: number;
|
|
40
|
+
maximum?: number;
|
|
41
|
+
"x-clamp"?: true;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export declare const utilityListWindowContract: import("./schema.js").ContractObject<{
|
|
45
|
+
view: {
|
|
46
|
+
type: "string";
|
|
47
|
+
enum: readonly ("full" | "summary")[];
|
|
48
|
+
description?: string;
|
|
49
|
+
};
|
|
50
|
+
max_chars: {
|
|
51
|
+
type: "integer";
|
|
52
|
+
description?: string;
|
|
53
|
+
minimum?: number;
|
|
54
|
+
maximum?: number;
|
|
55
|
+
"x-clamp"?: true;
|
|
56
|
+
};
|
|
57
|
+
}, never>;
|
|
58
|
+
export declare const providerLimitListContract: import("./schema.js").ContractObject<{
|
|
59
|
+
readonly view: {
|
|
60
|
+
type: "string";
|
|
61
|
+
enum: readonly ("full" | "summary")[];
|
|
62
|
+
description?: string;
|
|
63
|
+
};
|
|
64
|
+
readonly max_chars: {
|
|
65
|
+
type: "integer";
|
|
66
|
+
description?: string;
|
|
67
|
+
minimum?: number;
|
|
68
|
+
maximum?: number;
|
|
69
|
+
"x-clamp"?: true;
|
|
70
|
+
};
|
|
71
|
+
readonly provider: import("./schema.js").StringProperty;
|
|
72
|
+
readonly limit: {
|
|
73
|
+
type: "integer";
|
|
74
|
+
description?: string;
|
|
75
|
+
minimum?: number;
|
|
76
|
+
maximum?: number;
|
|
77
|
+
"x-clamp"?: true;
|
|
78
|
+
};
|
|
79
|
+
readonly offset: {
|
|
80
|
+
type: "integer";
|
|
81
|
+
description?: string;
|
|
82
|
+
minimum?: number;
|
|
83
|
+
maximum?: number;
|
|
84
|
+
"x-clamp"?: true;
|
|
85
|
+
};
|
|
86
|
+
}, never>;
|
|
87
|
+
export declare const emailSuppressionListContract: import("./schema.js").ContractObject<{
|
|
88
|
+
readonly view: {
|
|
89
|
+
type: "string";
|
|
90
|
+
enum: readonly ("full" | "summary")[];
|
|
91
|
+
description?: string;
|
|
92
|
+
};
|
|
93
|
+
readonly max_chars: {
|
|
94
|
+
type: "integer";
|
|
95
|
+
description?: string;
|
|
96
|
+
minimum?: number;
|
|
97
|
+
maximum?: number;
|
|
98
|
+
"x-clamp"?: true;
|
|
99
|
+
};
|
|
100
|
+
readonly reason: {
|
|
101
|
+
type: "string";
|
|
102
|
+
enum: readonly ("complaint" | "hard_bounce" | "manual" | "unsubscribe")[];
|
|
103
|
+
description?: string;
|
|
104
|
+
};
|
|
105
|
+
readonly search: import("./schema.js").StringProperty;
|
|
106
|
+
readonly limit: {
|
|
107
|
+
type: "integer";
|
|
108
|
+
description?: string;
|
|
109
|
+
minimum?: number;
|
|
110
|
+
maximum?: number;
|
|
111
|
+
"x-clamp"?: true;
|
|
112
|
+
};
|
|
113
|
+
readonly offset: {
|
|
114
|
+
type: "integer";
|
|
115
|
+
description?: string;
|
|
116
|
+
minimum?: number;
|
|
117
|
+
maximum?: number;
|
|
118
|
+
"x-clamp"?: true;
|
|
119
|
+
};
|
|
120
|
+
}, never>;
|
|
121
|
+
export declare const emailDomainSuppressionListContract: import("./schema.js").ContractObject<{
|
|
122
|
+
readonly view: {
|
|
123
|
+
type: "string";
|
|
124
|
+
enum: readonly ("full" | "summary")[];
|
|
125
|
+
description?: string;
|
|
126
|
+
};
|
|
127
|
+
readonly max_chars: {
|
|
128
|
+
type: "integer";
|
|
129
|
+
description?: string;
|
|
130
|
+
minimum?: number;
|
|
131
|
+
maximum?: number;
|
|
132
|
+
"x-clamp"?: true;
|
|
133
|
+
};
|
|
134
|
+
readonly limit: {
|
|
135
|
+
type: "integer";
|
|
136
|
+
description?: string;
|
|
137
|
+
minimum?: number;
|
|
138
|
+
maximum?: number;
|
|
139
|
+
"x-clamp"?: true;
|
|
140
|
+
};
|
|
141
|
+
readonly offset: {
|
|
142
|
+
type: "integer";
|
|
143
|
+
description?: string;
|
|
144
|
+
minimum?: number;
|
|
145
|
+
maximum?: number;
|
|
146
|
+
"x-clamp"?: true;
|
|
147
|
+
};
|
|
148
|
+
readonly reason: {
|
|
149
|
+
type: "string";
|
|
150
|
+
enum: readonly ("complaint" | "manual" | "policy")[];
|
|
151
|
+
description?: string;
|
|
152
|
+
};
|
|
153
|
+
readonly search: import("./schema.js").StringProperty;
|
|
154
|
+
}, never>;
|
|
155
|
+
export declare const emailSuppressionRemoveContract: import("./schema.js").ContractObject<{
|
|
156
|
+
readonly email: import("./schema.js").StringProperty;
|
|
157
|
+
readonly emails: import("./schema.js").ArrayProperty<import("./schema.js").StringProperty>;
|
|
158
|
+
}, never>;
|
|
159
|
+
export declare const emailDomainSuppressionRemoveContract: import("./schema.js").ContractObject<{
|
|
160
|
+
readonly domain: import("./schema.js").StringProperty;
|
|
161
|
+
readonly domains: import("./schema.js").ArrayProperty<import("./schema.js").StringProperty>;
|
|
162
|
+
}, never>;
|