lumnisai 0.5.50 → 0.5.52
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/dist/index.cjs +136 -12
- package/dist/index.d.cts +444 -71
- package/dist/index.d.mts +444 -71
- package/dist/index.d.ts +444 -71
- package/dist/index.mjs +136 -12
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -970,6 +970,7 @@ class ContactRelationshipsResource {
|
|
|
970
970
|
}
|
|
971
971
|
}
|
|
972
972
|
|
|
973
|
+
const COMPANY_SEARCH_PASSTHROUGH_KEYS = ["filters", "properties"];
|
|
973
974
|
class CrmResource {
|
|
974
975
|
constructor(http) {
|
|
975
976
|
this.http = http;
|
|
@@ -1069,6 +1070,118 @@ class CrmResource {
|
|
|
1069
1070
|
data
|
|
1070
1071
|
);
|
|
1071
1072
|
}
|
|
1073
|
+
/**
|
|
1074
|
+
* List the company fields the connected CRM exposes, with the operators each
|
|
1075
|
+
* one accepts — what a filter builder needs before calling
|
|
1076
|
+
* {@link searchCompanies}. A live, read-only provider call: nothing is
|
|
1077
|
+
* written to the CRM and nothing is served from the `crm_contacts` ledger.
|
|
1078
|
+
*
|
|
1079
|
+
* Pass `propertyName` to narrow to a single field. Attio returns
|
|
1080
|
+
* `select`/`status` choices only that way; HubSpot already includes
|
|
1081
|
+
* enumeration choices in the full listing, except for externally-sourced
|
|
1082
|
+
* ones, which come back as `options: null, optionsComplete: false`.
|
|
1083
|
+
*
|
|
1084
|
+
* Field metadata is provider-shaped, so the return type narrows on the
|
|
1085
|
+
* `provider` you pass.
|
|
1086
|
+
*
|
|
1087
|
+
* Failure modes: `403 crm_access_denied` and `503 crm_access_unavailable`
|
|
1088
|
+
* (the `crmUserId` grant), `409 crm_not_connected` (no single active
|
|
1089
|
+
* connection for the owner), `404 crm_property_not_found`,
|
|
1090
|
+
* `429 crm_rate_limited`, `504 crm_read_timeout`, `502 crm_read_failed`.
|
|
1091
|
+
*
|
|
1092
|
+
* @example
|
|
1093
|
+
* ```typescript
|
|
1094
|
+
* const { properties } = await client.crm.getCompanyProperties({
|
|
1095
|
+
* userId: 'user@example.com',
|
|
1096
|
+
* provider: 'hubspot',
|
|
1097
|
+
* })
|
|
1098
|
+
* const filterable = properties.filter(p => p.operators.length > 0)
|
|
1099
|
+
*
|
|
1100
|
+
* // Attio choices need the field named explicitly.
|
|
1101
|
+
* const tier = await client.crm.getCompanyProperties({
|
|
1102
|
+
* userId: 'user@example.com',
|
|
1103
|
+
* provider: 'attio',
|
|
1104
|
+
* propertyName: 'employee_range',
|
|
1105
|
+
* })
|
|
1106
|
+
* console.log(tier.properties[0].options)
|
|
1107
|
+
* ```
|
|
1108
|
+
*/
|
|
1109
|
+
async getCompanyProperties(params) {
|
|
1110
|
+
const response = await this.http.get(
|
|
1111
|
+
"/crm/companies/properties",
|
|
1112
|
+
{
|
|
1113
|
+
// Backend requires snake_case query params (see getContactsSyncStatus).
|
|
1114
|
+
params: {
|
|
1115
|
+
user_id: params.userId,
|
|
1116
|
+
provider: params.provider,
|
|
1117
|
+
property_name: params.propertyName,
|
|
1118
|
+
crm_user_id: params.crmUserId
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
);
|
|
1122
|
+
return response;
|
|
1123
|
+
}
|
|
1124
|
+
/**
|
|
1125
|
+
* Read one page of companies from the connected CRM using that provider's
|
|
1126
|
+
* own filter syntax. Read-only: no CRM writes, no local persistence, so the
|
|
1127
|
+
* same request can be replayed to refresh a preview.
|
|
1128
|
+
*
|
|
1129
|
+
* Filters are never translated. HubSpot takes `filterGroups` (AND within a
|
|
1130
|
+
* group, OR between groups) with string comparison values; Attio takes its
|
|
1131
|
+
* record-query object with `$`-prefixed operators. Both cross the wire
|
|
1132
|
+
* verbatim — the SDK's camelCase ↔ snake_case conversion is switched off for
|
|
1133
|
+
* `filters` and for each company's `properties` map, whose keys are CRM
|
|
1134
|
+
* property names. Discover valid names and operators with
|
|
1135
|
+
* {@link getCompanyProperties}.
|
|
1136
|
+
*
|
|
1137
|
+
* Paging is cursor-based: pass the previous page's `nextCursor` back as
|
|
1138
|
+
* `cursor` and keep every other field identical, because HubSpot pages by
|
|
1139
|
+
* record id inside the original query. `nextCursor: null` is the last page.
|
|
1140
|
+
* `total` is reported on the first HubSpot page only, and is always null for
|
|
1141
|
+
* Attio.
|
|
1142
|
+
*
|
|
1143
|
+
* An empty `companies` array is a real "no matches" result — provider
|
|
1144
|
+
* failures raise instead. Failure modes: `403 crm_access_denied` and
|
|
1145
|
+
* `503 crm_access_unavailable` (the `crmUserId` grant),
|
|
1146
|
+
* `409 crm_not_connected`, `400 invalid_crm_filter` (the provider rejected
|
|
1147
|
+
* the query), `422 invalid_crm_request` (filter/limit/cursor budgets,
|
|
1148
|
+
* checked before the provider call), `429 crm_rate_limited`,
|
|
1149
|
+
* `504 crm_read_timeout`, `502 crm_read_failed`.
|
|
1150
|
+
*
|
|
1151
|
+
* @example
|
|
1152
|
+
* ```typescript
|
|
1153
|
+
* const request: CrmHubspotCompanySearchRequest = {
|
|
1154
|
+
* userId: 'user@example.com',
|
|
1155
|
+
* provider: 'hubspot',
|
|
1156
|
+
* filters: {
|
|
1157
|
+
* filterGroups: [{
|
|
1158
|
+
* filters: [
|
|
1159
|
+
* { propertyName: 'domain', operator: 'CONTAINS_TOKEN', value: 'acme' },
|
|
1160
|
+
* { propertyName: 'numberofemployees', operator: 'GT', value: '50' },
|
|
1161
|
+
* ],
|
|
1162
|
+
* }],
|
|
1163
|
+
* },
|
|
1164
|
+
* properties: ['numberofemployees', 'industry'],
|
|
1165
|
+
* limit: 50,
|
|
1166
|
+
* }
|
|
1167
|
+
*
|
|
1168
|
+
* const page = await client.crm.searchCompanies(request)
|
|
1169
|
+
* for (const company of page.companies)
|
|
1170
|
+
* console.log(company.name, company.properties.industry)
|
|
1171
|
+
*
|
|
1172
|
+
* // Same query, next page.
|
|
1173
|
+
* if (page.nextCursor)
|
|
1174
|
+
* await client.crm.searchCompanies({ ...request, cursor: page.nextCursor })
|
|
1175
|
+
* ```
|
|
1176
|
+
*/
|
|
1177
|
+
async searchCompanies(data) {
|
|
1178
|
+
const response = await this.http.post(
|
|
1179
|
+
"/crm/companies/search",
|
|
1180
|
+
data,
|
|
1181
|
+
{ passthroughKeys: COMPANY_SEARCH_PASSTHROUGH_KEYS }
|
|
1182
|
+
);
|
|
1183
|
+
return response;
|
|
1184
|
+
}
|
|
1072
1185
|
/**
|
|
1073
1186
|
* Trigger a full mirror of the owner's CRM contact book into the local
|
|
1074
1187
|
* `crm_contacts` ledger. Returns immediately (`202`); poll
|
|
@@ -1950,23 +2063,28 @@ const PASSTHROUGH_VALUE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1950
2063
|
// those would rename the customer's own groups.
|
|
1951
2064
|
"committee"
|
|
1952
2065
|
]);
|
|
1953
|
-
function convertCase(obj, converter) {
|
|
2066
|
+
function convertCase(obj, converter, passthroughKeys) {
|
|
1954
2067
|
if (Array.isArray(obj)) {
|
|
1955
|
-
return obj.map((v) => convertCase(v, converter));
|
|
2068
|
+
return obj.map((v) => convertCase(v, converter, passthroughKeys));
|
|
1956
2069
|
} else if (obj !== null && typeof obj === "object") {
|
|
1957
2070
|
return Object.keys(obj).reduce((acc, key) => {
|
|
1958
|
-
const value =
|
|
2071
|
+
const value = passthroughKeys.has(key) ? obj[key] : convertCase(obj[key], converter, passthroughKeys);
|
|
1959
2072
|
acc[converter(key)] = value;
|
|
1960
2073
|
return acc;
|
|
1961
2074
|
}, {});
|
|
1962
2075
|
}
|
|
1963
2076
|
return obj;
|
|
1964
2077
|
}
|
|
1965
|
-
function
|
|
1966
|
-
|
|
2078
|
+
function passthroughSet(extraKeys) {
|
|
2079
|
+
if (!extraKeys || extraKeys.length === 0)
|
|
2080
|
+
return PASSTHROUGH_VALUE_KEYS;
|
|
2081
|
+
return /* @__PURE__ */ new Set([...PASSTHROUGH_VALUE_KEYS, ...extraKeys]);
|
|
1967
2082
|
}
|
|
1968
|
-
function
|
|
1969
|
-
return convertCase(obj,
|
|
2083
|
+
function toCamelCase(obj, extraPassthroughKeys) {
|
|
2084
|
+
return convertCase(obj, toCamel, passthroughSet(extraPassthroughKeys));
|
|
2085
|
+
}
|
|
2086
|
+
function toSnakeCase(obj, extraPassthroughKeys) {
|
|
2087
|
+
return convertCase(obj, toSnake, passthroughSet(extraPassthroughKeys));
|
|
1970
2088
|
}
|
|
1971
2089
|
|
|
1972
2090
|
class MessagingResource {
|
|
@@ -5990,7 +6108,7 @@ class Http {
|
|
|
5990
6108
|
backoffFactor: options.backoffFactor || DEFAULT_BACKOFF_FACTOR
|
|
5991
6109
|
};
|
|
5992
6110
|
}
|
|
5993
|
-
async _handleResponse(response) {
|
|
6111
|
+
async _handleResponse(response, passthroughKeys) {
|
|
5994
6112
|
const requestId = response.headers.get("x-request-id");
|
|
5995
6113
|
if (response.ok) {
|
|
5996
6114
|
if (response.status === 204)
|
|
@@ -5998,7 +6116,7 @@ class Http {
|
|
|
5998
6116
|
const contentType = response.headers.get("content-type") || "";
|
|
5999
6117
|
if (contentType.includes("application/json")) {
|
|
6000
6118
|
const json = await response.json();
|
|
6001
|
-
return toCamelCase(json);
|
|
6119
|
+
return toCamelCase(json, passthroughKeys);
|
|
6002
6120
|
}
|
|
6003
6121
|
return await response.text();
|
|
6004
6122
|
}
|
|
@@ -6028,7 +6146,13 @@ class Http {
|
|
|
6028
6146
|
}
|
|
6029
6147
|
}
|
|
6030
6148
|
async request(path, init = {}) {
|
|
6031
|
-
const {
|
|
6149
|
+
const {
|
|
6150
|
+
body,
|
|
6151
|
+
params,
|
|
6152
|
+
idempotencyKey: idempotencyKeyOption,
|
|
6153
|
+
passthroughKeys,
|
|
6154
|
+
...fetchOptions
|
|
6155
|
+
} = init;
|
|
6032
6156
|
const method = fetchOptions.method || "GET";
|
|
6033
6157
|
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
6034
6158
|
const fullPath = this.options.apiPrefix ? `${this.options.apiPrefix}${normalizedPath}` : normalizedPath;
|
|
@@ -6057,10 +6181,10 @@ class Http {
|
|
|
6057
6181
|
...fetchOptions,
|
|
6058
6182
|
method,
|
|
6059
6183
|
headers,
|
|
6060
|
-
body: body ? JSON.stringify(toSnakeCase(body)) : void 0,
|
|
6184
|
+
body: body ? JSON.stringify(toSnakeCase(body, passthroughKeys)) : void 0,
|
|
6061
6185
|
signal: controller.signal
|
|
6062
6186
|
});
|
|
6063
|
-
return await this._handleResponse(response);
|
|
6187
|
+
return await this._handleResponse(response, passthroughKeys);
|
|
6064
6188
|
} catch (error) {
|
|
6065
6189
|
lastError = error;
|
|
6066
6190
|
if (error instanceof RateLimitError) {
|