@planet-a/affinity-node
Advanced tools
Comparing version 0.0.1-test.10 to 0.0.1-test.11
@@ -0,3 +1,3 @@ | ||
import { defaultTransformers } from './axios_default_transformers.js'; | ||
import { fieldValueChangesUrl } from './urls.js'; | ||
import { defaultTransformers } from './axios_default_transformers.js'; | ||
/** | ||
@@ -4,0 +4,0 @@ * Enum for Action Type. |
@@ -9,2 +9,3 @@ import axios from 'axios'; | ||
import { Organizations } from './organizations.js'; | ||
import { Persons } from './persons.js'; | ||
export { EntityType, FieldValueType, RoleId } from './lists.js'; | ||
@@ -71,2 +72,8 @@ export { AffinityApiError } from './errors.js'; | ||
}); | ||
Object.defineProperty(this, "persons", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
this.axios = axiosInstance || axios.create(); | ||
@@ -87,3 +94,4 @@ this.axios.defaults.headers.common['X-Requested-With'] = | ||
this.organizations = new Organizations(this.axios); | ||
this.persons = new Persons(this.axios); | ||
} | ||
} |
import { listEntriesUrl } from './urls.js'; | ||
import { defaultTransformers } from './axios_default_transformers.js'; | ||
import { transformListEntryReference } from './transform_list_entry_reference.js'; | ||
/** | ||
@@ -35,7 +36,7 @@ * @module | ||
...json, | ||
list_entries: json.list_entries.map(ListEntries.transformEntry), | ||
list_entries: json.list_entries.map(transformListEntryReference), | ||
}; | ||
} | ||
else { | ||
return json.map(ListEntries.transformEntry); | ||
return json.map(transformListEntryReference); | ||
} | ||
@@ -63,5 +64,3 @@ }, | ||
...defaultTransformers(), | ||
(json) => { | ||
return ListEntries.transformEntry(json); | ||
}, | ||
transformListEntryReference, | ||
], | ||
@@ -145,5 +144,3 @@ }); | ||
...defaultTransformers(), | ||
(json) => { | ||
return ListEntries.transformEntry(json); | ||
}, | ||
transformListEntryReference, | ||
], | ||
@@ -154,12 +151,1 @@ }); | ||
} | ||
Object.defineProperty(ListEntries, "transformEntry", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: (entry) => { | ||
return { | ||
...entry, | ||
created_at: new Date(entry.created_at), | ||
}; | ||
} | ||
}); |
@@ -0,3 +1,6 @@ | ||
import { defaultTransformers } from './axios_default_transformers.js'; | ||
import { createSearchIteratorFn } from './create_search_iterator_fn.js'; | ||
import { organizationFieldsUrl, organizationsUrl } from './urls.js'; | ||
import { defaultTransformers } from './axios_default_transformers.js'; | ||
import { transformInteractionDateResponseRaw } from './transform_interaction_date_response_raw.js'; | ||
import { transformListEntryReference } from './transform_list_entry_reference.js'; | ||
/** | ||
@@ -24,2 +27,26 @@ * @module | ||
}); | ||
/** | ||
* Returns an async iterator that yields all organization entries matching the given search terms | ||
* Each yielded array contains up to the number specified in {@link SearchOrganizationsRequest.page_size} of organizations. | ||
* Use this method if you want to process the organizations in a streaming fashion. | ||
* | ||
* *Please note:* the yielded organizations array may be empty on the last page. | ||
* | ||
* @example | ||
* ```typescript | ||
* let page = 0 | ||
* for await (const entries of affinity.organizations.searchIterator({ | ||
* term: 'Ltd', | ||
* page_size: 10 | ||
* })) { | ||
* console.log(`Page ${++page} of entries:`, entries) | ||
* } | ||
* ``` | ||
*/ | ||
Object.defineProperty(this, "searchIterator", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: createSearchIteratorFn(this.search.bind(this), 'organizations') | ||
}); | ||
} | ||
@@ -54,9 +81,4 @@ static transformSearchOrganizationsRequest(data) { | ||
return { | ||
...Organizations.transformOrganization(organization), | ||
list_entries: json.list_entries.map((entry) => { | ||
return { | ||
...entry, | ||
created_at: new Date(entry.created_at), | ||
}; | ||
}), | ||
...transformInteractionDateResponseRaw(organization), | ||
list_entries: json.list_entries.map(transformListEntryReference), | ||
}; | ||
@@ -89,3 +111,3 @@ }, | ||
...json, | ||
organizations: json.organizations.map(Organizations.transformOrganization), | ||
organizations: json.organizations.map(transformInteractionDateResponseRaw), | ||
}; | ||
@@ -97,51 +119,3 @@ }, | ||
} | ||
static transformOrganization(organization) { | ||
const { interaction_dates, interactions, ...rest } = organization; | ||
const ret = { | ||
...rest, | ||
}; | ||
if (interaction_dates) { | ||
ret.interaction_dates = Object.fromEntries(Object.entries(interaction_dates).map(([key, value]) => [key, new Date(value)])); | ||
} | ||
if (interactions) { | ||
ret.interactions = Object.fromEntries(Object.entries(interactions).map(([key, value]) => [key, { | ||
...value, | ||
date: new Date(value.date), | ||
}])); | ||
} | ||
return ret; | ||
} | ||
/** | ||
* Returns an async iterator that yields all organization entries matching the given search terms | ||
* Each yielded array contains up to the number specified in {@link SearchOrganizationsRequest.page_size} of organizations. | ||
* Use this method if you want to process the organizations in a streaming fashion. | ||
* | ||
* *Please note:* the yielded organizations array may be empty on the last page. | ||
* | ||
* @example | ||
* ```typescript | ||
* let page = 0 | ||
* for await (const entries of affinity.organizations.searchIterator({ | ||
* term: 'Ltd', | ||
* page_size: 10 | ||
* })) { | ||
* console.log(`Page ${++page} of entries:`, entries) | ||
* } | ||
* ``` | ||
*/ | ||
async *searchIterator(params) { | ||
let page_token = undefined; | ||
while (true) { | ||
const response = await this.search(page_token ? { ...params, page_token } : params); | ||
yield response.organizations; | ||
if (response.next_page_token === null) { | ||
// no more pages to fetch | ||
return; | ||
} | ||
else { | ||
page_token = response.next_page_token; | ||
} | ||
} | ||
} | ||
/** | ||
* Creates a new organization with the supplied parameters. | ||
@@ -148,0 +122,0 @@ * |
@@ -0,1 +1,6 @@ | ||
import { defaultTransformers } from './axios_default_transformers.js'; | ||
import { createSearchIteratorFn } from './create_search_iterator_fn.js'; | ||
import { transformInteractionDateResponseRaw } from './transform_interaction_date_response_raw.js'; | ||
import { transformListEntryReference } from './transform_list_entry_reference.js'; | ||
import { personFieldsUrl, personsUrl } from './urls.js'; | ||
/** | ||
@@ -15,1 +20,189 @@ * The type of person. | ||
})(PersonType || (PersonType = {})); | ||
/** | ||
* @module | ||
* The persons API allows you to manage all the contacts of your organization. | ||
* These people include anyone your team has ever been in email communications or meetings with, and all the people that your team has added to Affinity either manually or through the API. Affinity's data model also guarantees that only one person in your team's shared contact list has a given email address. | ||
* | ||
* *Notes*: | ||
* - If you are looking to add or remove a person from a list, please check out the {@link ListEntries} section of the API. | ||
* - If you are looking to modify a person's field values (one of the cells on Affinity's spreadsheet), please check out the {@link FieldValues} section of the API. | ||
*/ | ||
export class Persons { | ||
/** @hidden */ | ||
constructor(axios) { | ||
Object.defineProperty(this, "axios", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: axios | ||
}); | ||
/** | ||
* Returns an async iterator that yields all person entries matching the given search terms | ||
* Each yielded array contains up to the number specified in {@link SearchPersonsRequest.page_size} of persons. | ||
* Use this method if you want to process the persons in a streaming fashion. | ||
* | ||
* *Please note:* the yielded persons array may be empty on the last page. | ||
* | ||
* @example | ||
* ```typescript | ||
* let page = 0 | ||
* for await (const entries of affinity.persons.searchIterator({ | ||
* term: 'Alice', | ||
* page_size: 10 | ||
* })) { | ||
* console.log(`Page ${++page} of entries:`, entries) | ||
* } | ||
* ``` | ||
*/ | ||
Object.defineProperty(this, "searchIterator", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: createSearchIteratorFn(this.search.bind(this), 'persons') | ||
}); | ||
} | ||
static transformSearchPersonsRequest(data) { | ||
return Object.fromEntries(Object.entries(data).map(([key, value]) => [ | ||
key, | ||
value instanceof Date ? value.toISOString() : value, | ||
])); | ||
} | ||
/** | ||
* Fetches an person with a specified `person_id`. | ||
* | ||
* @returns The person object corresponding to the `person_id`. | ||
* | ||
* @example | ||
* ```typescript | ||
* const person = await affinity.persons.get({ | ||
* person_id: 12345 | ||
* }) | ||
* console.log(person) | ||
* ``` | ||
*/ | ||
async get(params) { | ||
const { person_id, ...rest } = params; | ||
const response = await this.axios.get(personsUrl(person_id), { | ||
params: rest, | ||
transformResponse: [ | ||
...defaultTransformers(), | ||
(json) => { | ||
const { list_entries, ...person } = json; | ||
return { | ||
...transformInteractionDateResponseRaw(person), | ||
list_entries: json.list_entries.map(transformListEntryReference), | ||
}; | ||
}, | ||
], | ||
}); | ||
return response.data; | ||
} | ||
/** | ||
* Searches your teams data and fetches all the persons that meet the search criteria. | ||
* | ||
* This result is paginated. An initial request returns an object with two fields: `persons` and {@link PagedResponse.next_page_token}. `persons` contains an array of person resources. The value of {@link PagedResponse.next_page_token} should be sent as the query parameter `page_token` in another request to retrieve the next page of results. While paginating through results, each request must have identical query parameters other than the changing `page_token`. Otherwise, an `Invalid page_token variable` error will be returned. | ||
* | ||
* The absence of a {@link PagedResponse.next_page_token} indicates that all the records have been fetched, though its presence does not necessarily indicate that there are *more* resources to be fetched. The next page may be empty (but then {@link PagedResponse.next_page_token} would be `null` to confirm that there are no more resources). | ||
* Pass `{@link InteractionDatesQueryParams.with_interaction_dates}=true` as a query parameter to include dates of the most recent and upcoming interactions with persons. When this parameter is included, persons with no interactions will not be returned in the response. Pass `with_interaction_persons=true` as a query parameter if `with_interaction_dates=true` to also get the internal persons associated with the interaction. | ||
* You can filter by interaction dates by providing additional query parameters like `min_last_email_date` or `max_next_event_date`. The value of these query parameters should be ISO 8601 formatted date strings. | ||
* | ||
* @param request - Object containing the data for the request | ||
* | ||
* @example | ||
* ```typescript | ||
* const { persons: allAlices } = await affinity.persons.search({ | ||
* term: 'Alice' | ||
* }) | ||
* console.log(allAlices) | ||
* ``` | ||
*/ | ||
async search(request) { | ||
const response = await this.axios.get(personsUrl(), { | ||
params: Persons.transformSearchPersonsRequest(request), | ||
transformResponse: [ | ||
...defaultTransformers(), | ||
(json) => { | ||
return { | ||
...json, | ||
persons: json.persons.map(transformInteractionDateResponseRaw), | ||
}; | ||
}, | ||
], | ||
}); | ||
return response.data; | ||
} | ||
/** | ||
* Creates a new person with the supplied parameters. | ||
* | ||
* @param data - Object containing the data for creating a new person | ||
* @returns The person resource that was just created. | ||
* | ||
* @example | ||
* ```typescript | ||
* const newPerson = await affinity.persons.create({ | ||
* first_name: 'Alice', | ||
* last_name: 'Doe', | ||
* emails: ['alice@doe.com'], | ||
* organization_ids: [123456] | ||
* }) | ||
* console.log(newPerson) | ||
* ``` | ||
*/ | ||
async create(data) { | ||
const response = await this.axios.post(personsUrl(), data); | ||
return response.data; | ||
} | ||
/** | ||
* Updates an existing person with `person_id` with the supplied parameters. | ||
* | ||
* @param data - Object containing the data for updating an person | ||
* @returns The person resource that was just updated. | ||
* | ||
* @example | ||
* ```typescript | ||
* const updatedPerson = await affinity.persons.update({ | ||
* person_id: 12345, | ||
* name: 'Acme Corp.', | ||
* person_ids: [38706, 89734] | ||
* }) | ||
* console.log(updatedPerson) | ||
* ``` | ||
*/ | ||
async update(data) { | ||
const { person_id, ...rest } = data; | ||
const response = await this.axios.put(personsUrl(person_id), rest); | ||
return response.data; | ||
} | ||
/** | ||
* Deletes an person with a specified `person_id`. | ||
* @returns true if the deletion was successful | ||
* | ||
* @example | ||
* ```typescript | ||
* const success = await affinity.persons.delete({ | ||
* person_id: 12345 | ||
* }) | ||
* console.log(success ? 'Person deleted': 'Person not deleted') | ||
* ``` | ||
*/ | ||
async delete(request) { | ||
const { person_id } = request; | ||
const response = await this.axios.delete(personsUrl(person_id)); | ||
return response.data.success === true; | ||
} | ||
/** | ||
* Fetches an array of all the global fields that exist on persons. | ||
* | ||
* @returns An array of the fields that exist on all persons for your team. | ||
* | ||
* @example | ||
* ```typescript | ||
* const personFields = await affinity.persons.getFields() | ||
* console.log(personFields) | ||
* ``` | ||
*/ | ||
async getFields() { | ||
const response = await this.axios.get(personFieldsUrl()); | ||
return response.data; | ||
} | ||
} |
@@ -56,1 +56,13 @@ /** | ||
export const organizationFieldsUrl = () => organizationsUrl('fields'); | ||
/** | ||
* @hidden | ||
* See [here](https://api-docs.affinity.co/#persons) for more info. | ||
*/ | ||
export const personsUrl = (person_id) => { | ||
return person_id ? `/persons/${encodeURIComponent(person_id)}` : '/persons'; | ||
}; | ||
/** | ||
* @hidden | ||
* See [here](https://api-docs.affinity.co/#get-global-person-fields) for more info. | ||
*/ | ||
export const personFieldsUrl = () => personsUrl('fields'); |
{ | ||
"name": "@planet-a/affinity-node", | ||
"version": "0.0.1-test.10", | ||
"version": "0.0.1-test.11", | ||
"description": "API wrapper for the affinity.co API", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -35,3 +35,3 @@ # [![Test, Lint & Deploy](https://github.com/planet-a-ventures/affinity-node/actions/workflows/main.yml/badge.svg)](https://github.com/planet-a-ventures/affinity-node/actions/workflows/main.yml) affinity-node | ||
- ✅ [Field Value Changes](src/v1/field_value_changes.ts) | ||
- ❌ [Persons](src/v1/persons.ts) | ||
- ✅ [Persons](src/v1/persons.ts) | ||
- ✅ [Organizations](src/v1/organizations.ts) | ||
@@ -38,0 +38,0 @@ - ❌ [Opportunities](src/v1/opportunities.ts) |
import { AxiosInstance } from 'axios'; | ||
import type { DateTime, Replace } from './types.js'; | ||
/** | ||
@@ -31,3 +32,8 @@ * TODO(@joscha): Enum is most likely incomplete | ||
}; | ||
export type WhoAmIResponse = { | ||
type GrantRaw = { | ||
type: string; | ||
scope: string; | ||
createdAt: DateTime; | ||
}; | ||
type WhoAmIResponseRaw = { | ||
/** | ||
@@ -44,2 +50,5 @@ * Information about the Affinity instance the user belongs to. | ||
*/ | ||
grant: GrantRaw; | ||
}; | ||
export type WhoAmIResponse = Replace<WhoAmIResponseRaw, { | ||
grant: { | ||
@@ -50,3 +59,3 @@ type: GrantType; | ||
}; | ||
}; | ||
}>; | ||
/** | ||
@@ -67,1 +76,2 @@ * @module | ||
} | ||
export {}; |
import type { AxiosInstance } from 'axios'; | ||
import type { ValueRaw } from './field_values.js'; | ||
import type { Person } from './list_entries.js'; | ||
import type { DateTime } from './types.js'; | ||
import type { ValueRaw } from './field_values.js'; | ||
import type { DateTime, Replace, RequireOnlyOne } from './types.js'; | ||
/** | ||
* Via https://stackoverflow.com/questions/40510611 | ||
*/ | ||
export type RequireOnlyOne<T, Keys extends keyof T = keyof T> = Pick<T, Exclude<keyof T, Keys>> & { | ||
[K in Keys]-?: Required<Pick<T, K>> & Partial<Record<Exclude<Keys, K>, never>>; | ||
}[Keys]; | ||
/** | ||
* Enum for Action Type. | ||
@@ -77,5 +71,5 @@ */ | ||
export type FieldValueChangeResponseRaw = FieldValueChangeRaw[]; | ||
export type FieldValueChange = Omit<FieldValueChangeRaw, 'changed_at'> & { | ||
export type FieldValueChange = Replace<FieldValueChangeRaw, { | ||
changed_at: Date; | ||
}; | ||
}>; | ||
export type FieldValueChangeResponse = FieldValueChange[]; | ||
@@ -82,0 +76,0 @@ /** |
import type { AxiosInstance } from 'axios'; | ||
import { FieldValueType } from './lists.js'; | ||
import type { DateTime } from './types.js'; | ||
import type { DateTime, Replace } from './types.js'; | ||
import { FieldBase } from './fields.js'; | ||
@@ -123,6 +123,6 @@ export type { DateTime } from './types.js'; | ||
export type FieldValueResponseRaw = FieldValueRaw[]; | ||
export type FieldValue = Omit<FieldValueRaw, 'value' | 'updated_at' | 'created_at' | 'value_type'> & { | ||
export type FieldValue = Replace<FieldValueRaw, { | ||
updated_at: Date | null; | ||
created_at: Date; | ||
} & ValueTypeMixin<FieldValueValues>; | ||
} & ValueTypeMixin<FieldValueValues>>; | ||
export type FieldValueResponse = FieldValue[]; | ||
@@ -129,0 +129,0 @@ export type CreateFieldValueRequest = { |
@@ -9,2 +9,3 @@ import { type AxiosInstance } from 'axios'; | ||
import { Organizations } from './organizations.js'; | ||
import { Persons } from './persons.js'; | ||
export type * as ListEntries from './list_entries.js'; | ||
@@ -41,2 +42,3 @@ export type * as Lists from './lists.js'; | ||
readonly organizations: Organizations; | ||
readonly persons: Persons; | ||
} |
import type { AxiosInstance } from 'axios'; | ||
import type { EntityType, GetQuery } from './lists.js'; | ||
import type { DateTime } from './types.js'; | ||
import type { DateTime, Replace } from './types.js'; | ||
import { PersonType } from './persons.js'; | ||
@@ -44,3 +44,3 @@ import { Organization } from './organizations.js'; | ||
}; | ||
export type ListEntryResponseRaw = ListEntryReferenceRaw & { | ||
export type ListEntryResponseRaw = { | ||
/** | ||
@@ -54,17 +54,17 @@ * The type of the entity corresponding to the list entry. | ||
entity: Entity; | ||
}; | ||
} & ListEntryReferenceRaw; | ||
export type PagedListEntryResponseRaw = { | ||
list_entries: ListEntryResponseRaw[]; | ||
/** | ||
* The absence of a `next_page_token` indicates that all the records have been fetched, though its presence does not necessarily indicate that there are more resources to be fetched. | ||
* The next page may be empty (but then `next_page_token` would be `null` to confirm that there are no more resources). | ||
* The absence of a {@link PagedResponse.next_page_token} indicates that all the records have been fetched, though its presence does not necessarily indicate that there are more resources to be fetched. | ||
* The next page may be empty (but then {@link PagedResponse.next_page_token} would be `null` to confirm that there are no more resources). | ||
*/ | ||
next_page_token: string | null; | ||
}; | ||
export type ListEntryResponse = Omit<ListEntryResponseRaw, 'created_at'> & { | ||
export type ListEntryResponse = Replace<ListEntryResponseRaw, { | ||
created_at: Date; | ||
}; | ||
export type PagedListEntryResponse = Omit<PagedListEntryResponseRaw, 'list_entries'> & { | ||
}>; | ||
export type PagedListEntryResponse = Replace<PagedListEntryResponseRaw, { | ||
list_entries: ListEntryResponse[]; | ||
}; | ||
}>; | ||
/** | ||
@@ -126,3 +126,2 @@ * Paging parameters for retrieving list entries. | ||
constructor(axios: AxiosInstance); | ||
private static transformEntry; | ||
/** | ||
@@ -129,0 +128,0 @@ * Fetches all list entries in the list with the supplied list id. |
@@ -5,2 +5,5 @@ import type { AxiosInstance } from 'axios'; | ||
import type { Field } from './lists.js'; | ||
import type { PagedRequest } from './paged_request.js'; | ||
import type { PagedResponse } from './paged_response.js'; | ||
import type { Replace } from './types.js'; | ||
export type InteractionOccurrenceQuantifier = 'first' | 'last'; | ||
@@ -33,28 +36,23 @@ export type InteractionType = `${InteractionOccurrenceQuantifier}_email` | `${InteractionOccurrenceQuantifier}_event` | 'next_event' | 'last_chat_message' | 'last_interaction'; | ||
}; | ||
/** | ||
* Each organization object has a unique id. It also has a name, domain (the website of the organization), and persons associated with it. | ||
* The domain is an important attribute from an automation perspective, as it helps Affinity automatically link all the appropriate person objects to the organization. | ||
* | ||
* Each organization also has a flag determining whether it's global or not. | ||
* As mentioned above, Affinity maintains its own database of global organizations that each customer has access to. | ||
* Note that you cannot change the name or the domain of a global organization. | ||
* You also cannot delete a global organization. | ||
* | ||
* Of course, if an organization is manually created by your team, all fields can be modified and the organization can be deleted. | ||
* | ||
* Dates of the most recent and upcoming interactions with an organization are available in the interaction_dates field. | ||
* This data is only included when passing `with_interaction_dates=true` as a query parameter to the `GET /organizations` or the `GET /organizations/{organization_id}` endpoints. | ||
*/ | ||
export type OrganizationResponseRaw = Organization & { | ||
export type OpportunityIdResponseRaw = { | ||
/** | ||
* An array of unique identifiers of people ({@link Person.id}) that are associated with the organization. | ||
* An array of unique identifiers of opportunities ({@link Opportunity.id}) that are associated with the entity. | ||
* Only returned when passing `{@link OpportunitiesQueryParams.with_opportunities}=true`. | ||
* | ||
* TODO(@joscha): model this in the type system, so the return type is based on the query parameter type. | ||
*/ | ||
person_ids?: number[]; | ||
/** | ||
* An array of unique identifiers of opportunities ({@link Opportunity.id}) that are associated with the organization. | ||
*/ | ||
opportunity_ids?: number[]; | ||
}; | ||
export type InteractionDateResponseBase = { | ||
interaction_dates?: { | ||
[key in InteractionDateKey]: never; | ||
}; | ||
interactions?: { | ||
[key in InteractionType]: never; | ||
}; | ||
}; | ||
export type InteractionDateResponseRaw = Replace<InteractionDateResponseBase, { | ||
/** | ||
* An object with string date fields representing the most recent and upcoming interactions with this organization. | ||
* Only returned when passing with_interaction_dates=true. | ||
* An object with string date fields representing the most recent and upcoming interactions with this entity. | ||
* Only returned when passing `{@link InteractionDatesQueryParams.with_interaction_dates}=true`. | ||
* | ||
@@ -69,3 +67,3 @@ * TODO(@joscha): model this in the type system, so the return type is based on the query parameter type. | ||
* Each field corresponds to one of the seven interactions, and includes nested fields for date and person_ids which indicates the internal people associated with that event (people only returned if passing `{@link InteractionDatesQueryParams.with_interaction_persons}=true`). | ||
* Only returned when passing `with_interaction_dates=true`. | ||
* Only returned when passing `{@link InteractionDatesQueryParams.with_interaction_dates}=true`. | ||
* | ||
@@ -77,2 +75,43 @@ * TODO(@joscha): model this in the type system, so the return type is based on the query parameter type. | ||
}; | ||
}>; | ||
export type InteractionDateResponse = Replace<InteractionDateResponseRaw, { | ||
/** | ||
* An object with string date fields representing the most recent and upcoming interactions with this entity. | ||
* Only returned when passing `{@link InteractionDatesQueryParams.with_interaction_dates}=true`. | ||
* | ||
* TODO(@joscha): model this in the type system, so the return type is based on the query parameter type. | ||
*/ | ||
interaction_dates?: { | ||
[key in InteractionDateKey]: Date; | ||
}; | ||
/** | ||
* An object with seven fields nested underneath. | ||
* Each field corresponds to one of the seven interactions, and includes nested fields for date and person_ids which indicates the internal people associated with that event (people only returned if passing `{@link InteractionDatesQueryParams.with_interaction_persons}=true`). | ||
* Only returned when passing `{@link InteractionDatesQueryParams.with_interaction_dates}=true`. | ||
* | ||
* TODO(@joscha): model this in the type system, so the return type is based on the query parameter type. | ||
*/ | ||
interactions?: { | ||
[key in InteractionType]: InteractionDate; | ||
}; | ||
}>; | ||
/** | ||
* Each organization object has a unique id. It also has a name, domain (the website of the organization), and persons associated with it. | ||
* The domain is an important attribute from an automation perspective, as it helps Affinity automatically link all the appropriate person objects to the organization. | ||
* | ||
* Each organization also has a flag determining whether it's global or not. | ||
* As mentioned above, Affinity maintains its own database of global organizations that each customer has access to. | ||
* Note that you cannot change the name or the domain of a global organization. | ||
* You also cannot delete a global organization. | ||
* | ||
* Of course, if an organization is manually created by your team, all fields can be modified and the organization can be deleted. | ||
* | ||
* Dates of the most recent and upcoming interactions with an organization are available in the interaction_dates field. | ||
* This data is only included when passing `{@link InteractionDatesQueryParams.with_interaction_dates}=true` as a query parameter to the `GET /organizations` or the `GET /organizations/{organization_id}` endpoints. | ||
*/ | ||
export type OrganizationResponseRaw = Organization & OpportunityIdResponseRaw & InteractionDateResponseRaw & { | ||
/** | ||
* An array of unique identifiers of people ({@link Person.id}) that are associated with the organization. | ||
*/ | ||
person_ids?: number[]; | ||
}; | ||
@@ -87,21 +126,16 @@ export type SimpleOrganizationResponse = Organization & Pick<OrganizationResponse, 'person_ids'>; | ||
}; | ||
export type InteractionDate = Omit<InteractionDateRaw, 'date'> & { | ||
export type InteractionDate = Replace<InteractionDateRaw, { | ||
date: Date; | ||
}; | ||
export type OrganizationResponse = Omit<OrganizationResponseRaw, 'interaction_dates' | 'interactions'> & { | ||
interaction_dates?: { | ||
[key in InteractionDateKey]: Date; | ||
}; | ||
interactions?: { | ||
[key in InteractionType]: InteractionDate; | ||
}; | ||
}; | ||
}>; | ||
export type OrganizationResponse = Replace<OrganizationResponseRaw, InteractionDateResponse>; | ||
export type ListEntryReference = Replace<ListEntryReferenceRaw, { | ||
created_at: Date; | ||
}>; | ||
export type PagedOrganizationResponseRaw = { | ||
organizations: OrganizationResponseRaw[]; | ||
next_page_token: string | null; | ||
}; | ||
export type PagedOrganizationResponse = Omit<PagedOrganizationResponseRaw, 'organizations'> & { | ||
} & PagedResponse; | ||
export type PagedOrganizationResponse = Replace<PagedOrganizationResponseRaw, { | ||
organizations: OrganizationResponse[]; | ||
}; | ||
export type SingleOrganizationResponseRaw = OrganizationResponseRaw & { | ||
}>; | ||
export type SingleOrganizationResponseRaw = { | ||
/** | ||
@@ -111,9 +145,6 @@ * An array of list entry resources associated with the organization, only returned as part of the {@link Organizations.get} a specific organization endpoint. | ||
list_entries: ListEntryReferenceRaw[]; | ||
}; | ||
export type ListEntryReference = Omit<ListEntryReferenceRaw, 'created_at'> & { | ||
created_at: Date; | ||
}; | ||
export type SingleOrganizationResponse = OrganizationResponse & { | ||
} & OrganizationResponseRaw; | ||
export type SingleOrganizationResponse = { | ||
list_entries: ListEntryReference[]; | ||
}; | ||
} & OrganizationResponse; | ||
export type CreateOrganizationRequest = { | ||
@@ -133,3 +164,3 @@ /** | ||
}; | ||
export type UpdateOrganizationRequest = OrganizationReference & { | ||
export type UpdateOrganizationRequest = { | ||
/** | ||
@@ -148,3 +179,3 @@ * The name of the organization. | ||
person_ids?: number[]; | ||
}; | ||
} & OrganizationReference; | ||
export type InteractionTypeWithoutChat = Exclude<InteractionType, 'last_chat_message'>; | ||
@@ -163,3 +194,3 @@ export type OptionalMinQueryParams = { | ||
/** | ||
* When true, persons for each interaction will be returned. Used in conjunction with `with_interaction_dates` | ||
* When true, persons for each interaction will be returned. Used in conjunction with {@link InteractionDatesQueryParams.with_interaction_dates} | ||
*/ | ||
@@ -179,14 +210,3 @@ with_interaction_persons: true; | ||
term?: string; | ||
/** | ||
* The number of organizations to return per page. | ||
* | ||
* Default is the maximum value of 500. | ||
*/ | ||
page_size?: number; | ||
/** | ||
* The page token to retrieve the next page of organizations. | ||
* if you do not pass the `page_size` parameter, the next page will have the default page size of 500. | ||
*/ | ||
page_token?: string; | ||
} & OpportunitiesQueryParams & OptionalMinQueryParams & OptionalMaxQueryParams & InteractionDatesQueryParams; | ||
} & PagedRequest & OpportunitiesQueryParams & OptionalMinQueryParams & OptionalMaxQueryParams & InteractionDatesQueryParams; | ||
export type GetOrganizationRequest = OrganizationReference & OpportunitiesQueryParams & InteractionDatesQueryParams; | ||
@@ -197,3 +217,3 @@ export type OrganizationReference = { | ||
}; | ||
export type OrganizationField = Pick<Field, 'id' | 'name' | 'value_type' | 'allows_multiple' | 'dropdown_options'>; | ||
export type EntityField = Pick<Field, 'id' | 'name' | 'value_type' | 'allows_multiple' | 'dropdown_options'>; | ||
/** | ||
@@ -244,3 +264,2 @@ * @module | ||
search(request: SearchOrganizationsRequest): Promise<PagedOrganizationResponse>; | ||
private static transformOrganization; | ||
/** | ||
@@ -264,3 +283,3 @@ * Returns an async iterator that yields all organization entries matching the given search terms | ||
*/ | ||
searchIterator(params: Omit<SearchOrganizationsRequest, 'page_token'>): AsyncGenerator<OrganizationResponse[]>; | ||
searchIterator: (params: Omit<PagedRequest, "page_token">) => AsyncGenerator<(PagedResponse & Record<"organizations", object[]>)[], any, unknown>; | ||
/** | ||
@@ -324,3 +343,3 @@ * Creates a new organization with the supplied parameters. | ||
*/ | ||
getFields(): Promise<OrganizationField[]>; | ||
getFields(): Promise<EntityField[]>; | ||
} |
@@ -0,1 +1,7 @@ | ||
import type { AxiosInstance } from 'axios'; | ||
import type { ListEntryReferenceRaw } from './list_entries.js'; | ||
import { EntityField, InteractionDateResponse, type InteractionDateResponseRaw, InteractionDatesQueryParams, type ListEntryReference, OpportunitiesQueryParams, type OpportunityIdResponseRaw, OptionalMaxQueryParams, OptionalMinQueryParams } from './organizations.js'; | ||
import type { PagedRequest } from './paged_request.js'; | ||
import type { PagedResponse } from './paged_response.js'; | ||
import type { Replace } from './types.js'; | ||
/** | ||
@@ -15,3 +21,239 @@ * The type of person. | ||
export type Person = { | ||
/** The unique identifier of the person object. */ | ||
id: number; | ||
/** The type of person. */ | ||
type: PersonType; | ||
/** The first name of the person. */ | ||
first_name: string; | ||
/** The last name of the person. */ | ||
last_name: string; | ||
/** The email addresses of the person. */ | ||
emails: string[]; | ||
/** The email (automatically computed) that is most likely to the current active email address of the person. */ | ||
primary_email: string; | ||
/** An array of unique identifiers of organizations that the person is associated with. */ | ||
organization_ids: number[]; | ||
}; | ||
/** | ||
* Each person resource is assigned a unique `id` and stores the name, type, and email addresses of the person. A person resource also has access to a smart attribute called `primary_email`. The value of `primary_email` is automatically computed by Affinity's proprietary algorithms and refers to the email that is most likely to be the current active email address of a person. | ||
* The person resource `organization_ids` is a collection of unique identifiers to the person's associated organizations. Note that a person can be associated with multiple organizations. For example, say your team has talked with organizations A and B. Person X used to work at A and was your point of contact, but then changed jobs and started emailing you from a new email address (corresponding to organization B). In this case, Affinity will automatically associate person X with both organization A and organization B. | ||
* The person resource `type` indicates whether a person is internal or external to your team. Every internal person is a user of Affinity on your team, and all other people are externals. | ||
* Dates of the most recent and upcoming interactions with a person are available in the `interaction_dates` field. This data is only included when passing `{@link InteractionDatesQueryParams.with_interaction_dates}=true` as a query parameter to the `/persons` or the `/persons/{person_id}` endpoints. | ||
*/ | ||
export type PersonResponseRaw = { | ||
/** An array of unique identifiers of organizations that the person is currently associated with according to the Affinity Data: Current Organization in-app column. | ||
* Only returned when `{@link WithCurrentOrganizatonParams.with_current_organizations}=true`. | ||
* | ||
* TODO(@joscha): model this in the type system, so the return type is based on the query parameter type. | ||
*/ | ||
current_organization_ids?: number[]; | ||
} & Person & InteractionDateResponseRaw & OpportunityIdResponseRaw; | ||
export type PersonResponse = Replace<PersonResponseRaw, InteractionDateResponse>; | ||
export type WithCurrentOrganizatonParams = { | ||
/** | ||
* When true, the organization IDs of each person's current organizations (according to the Affinity Data: Current Organizations column) will be returned. | ||
*/ | ||
with_current_organizations?: boolean; | ||
}; | ||
export type SearchPersonsRequest = { | ||
/** | ||
* The search term to filter persons. | ||
* The search term can be part of an email address, a first name or a last name. | ||
*/ | ||
term?: string; | ||
} & PagedRequest & OpportunitiesQueryParams & OptionalMinQueryParams & OptionalMaxQueryParams & InteractionDatesQueryParams & WithCurrentOrganizatonParams; | ||
export type PagedPersonResponseRaw = { | ||
persons: PersonResponseRaw[]; | ||
} & PagedResponse; | ||
export type PagedPersonResponse = Replace<PagedPersonResponseRaw, { | ||
persons: PersonResponse[]; | ||
}>; | ||
export type SinglePersonResponseRaw = { | ||
list_entries: ListEntryReferenceRaw[]; | ||
} & PersonResponseRaw; | ||
export type SinglePersonResponse = { | ||
/** | ||
* An array of list entry resources associated with the person, only returned as part of the {@link Persons.get} a specific person endpoint. | ||
*/ | ||
list_entries: ListEntryReference[]; | ||
} & PersonResponse; | ||
export type GetPersonRequest = PersonReference & OpportunitiesQueryParams & InteractionDatesQueryParams & WithCurrentOrganizatonParams; | ||
export type PersonReference = { | ||
/** The unique ID of the person */ | ||
person_id: number; | ||
}; | ||
/** | ||
* The request object for creating an organization. | ||
*/ | ||
export type CreatePersonRequest = { | ||
/** | ||
* The first name of the person. | ||
*/ | ||
first_name: string; | ||
/** | ||
* The last name of the person. | ||
*/ | ||
last_name: string; | ||
/** | ||
* The email addresses of the person. If there are no email addresses, please specify an empty array. | ||
*/ | ||
emails: string[]; | ||
/** | ||
* An array of unique identifiers of organizations that the person is associated with. | ||
*/ | ||
organization_ids?: number[]; | ||
}; | ||
/** | ||
* The request object for updating an organization. | ||
*/ | ||
export type UpdatePersonRequest = { | ||
/** | ||
* The first name of the person. | ||
*/ | ||
first_name?: string; | ||
/** | ||
* The last name of the person. | ||
*/ | ||
last_name?: string; | ||
/** | ||
* The email addresses of the person. If there are no email addresses, please specify an empty array. | ||
* | ||
* *Hint*: If you are trying to add a new email to a person, the existing values for `emails` must also be supplied as parameters. | ||
*/ | ||
emails?: string[]; | ||
/** | ||
* An array of unique identifiers of organizations that the person is associated with. | ||
* | ||
* *Hint*: If you are trying to add a new organization to a person, the existing values for `organization_ids` must also be supplied as parameters. | ||
*/ | ||
organization_ids?: number[]; | ||
} & PersonReference; | ||
export type SimplePersonResponse = Person & Pick<PersonResponse, 'organization_ids'>; | ||
/** | ||
* @module | ||
* The persons API allows you to manage all the contacts of your organization. | ||
* These people include anyone your team has ever been in email communications or meetings with, and all the people that your team has added to Affinity either manually or through the API. Affinity's data model also guarantees that only one person in your team's shared contact list has a given email address. | ||
* | ||
* *Notes*: | ||
* - If you are looking to add or remove a person from a list, please check out the {@link ListEntries} section of the API. | ||
* - If you are looking to modify a person's field values (one of the cells on Affinity's spreadsheet), please check out the {@link FieldValues} section of the API. | ||
*/ | ||
export declare class Persons { | ||
private readonly axios; | ||
/** @hidden */ | ||
constructor(axios: AxiosInstance); | ||
private static transformSearchPersonsRequest; | ||
/** | ||
* Fetches an person with a specified `person_id`. | ||
* | ||
* @returns The person object corresponding to the `person_id`. | ||
* | ||
* @example | ||
* ```typescript | ||
* const person = await affinity.persons.get({ | ||
* person_id: 12345 | ||
* }) | ||
* console.log(person) | ||
* ``` | ||
*/ | ||
get(params: GetPersonRequest): Promise<SinglePersonResponse>; | ||
/** | ||
* Searches your teams data and fetches all the persons that meet the search criteria. | ||
* | ||
* This result is paginated. An initial request returns an object with two fields: `persons` and {@link PagedResponse.next_page_token}. `persons` contains an array of person resources. The value of {@link PagedResponse.next_page_token} should be sent as the query parameter `page_token` in another request to retrieve the next page of results. While paginating through results, each request must have identical query parameters other than the changing `page_token`. Otherwise, an `Invalid page_token variable` error will be returned. | ||
* | ||
* The absence of a {@link PagedResponse.next_page_token} indicates that all the records have been fetched, though its presence does not necessarily indicate that there are *more* resources to be fetched. The next page may be empty (but then {@link PagedResponse.next_page_token} would be `null` to confirm that there are no more resources). | ||
* Pass `{@link InteractionDatesQueryParams.with_interaction_dates}=true` as a query parameter to include dates of the most recent and upcoming interactions with persons. When this parameter is included, persons with no interactions will not be returned in the response. Pass `with_interaction_persons=true` as a query parameter if `with_interaction_dates=true` to also get the internal persons associated with the interaction. | ||
* You can filter by interaction dates by providing additional query parameters like `min_last_email_date` or `max_next_event_date`. The value of these query parameters should be ISO 8601 formatted date strings. | ||
* | ||
* @param request - Object containing the data for the request | ||
* | ||
* @example | ||
* ```typescript | ||
* const { persons: allAlices } = await affinity.persons.search({ | ||
* term: 'Alice' | ||
* }) | ||
* console.log(allAlices) | ||
* ``` | ||
*/ | ||
search(request: SearchPersonsRequest): Promise<PagedPersonResponse>; | ||
/** | ||
* Returns an async iterator that yields all person entries matching the given search terms | ||
* Each yielded array contains up to the number specified in {@link SearchPersonsRequest.page_size} of persons. | ||
* Use this method if you want to process the persons in a streaming fashion. | ||
* | ||
* *Please note:* the yielded persons array may be empty on the last page. | ||
* | ||
* @example | ||
* ```typescript | ||
* let page = 0 | ||
* for await (const entries of affinity.persons.searchIterator({ | ||
* term: 'Alice', | ||
* page_size: 10 | ||
* })) { | ||
* console.log(`Page ${++page} of entries:`, entries) | ||
* } | ||
* ``` | ||
*/ | ||
searchIterator: (params: Omit<PagedRequest, "page_token">) => AsyncGenerator<(PagedResponse & Record<"persons", object[]>)[], any, unknown>; | ||
/** | ||
* Creates a new person with the supplied parameters. | ||
* | ||
* @param data - Object containing the data for creating a new person | ||
* @returns The person resource that was just created. | ||
* | ||
* @example | ||
* ```typescript | ||
* const newPerson = await affinity.persons.create({ | ||
* first_name: 'Alice', | ||
* last_name: 'Doe', | ||
* emails: ['alice@doe.com'], | ||
* organization_ids: [123456] | ||
* }) | ||
* console.log(newPerson) | ||
* ``` | ||
*/ | ||
create(data: CreatePersonRequest): Promise<SimplePersonResponse>; | ||
/** | ||
* Updates an existing person with `person_id` with the supplied parameters. | ||
* | ||
* @param data - Object containing the data for updating an person | ||
* @returns The person resource that was just updated. | ||
* | ||
* @example | ||
* ```typescript | ||
* const updatedPerson = await affinity.persons.update({ | ||
* person_id: 12345, | ||
* name: 'Acme Corp.', | ||
* person_ids: [38706, 89734] | ||
* }) | ||
* console.log(updatedPerson) | ||
* ``` | ||
*/ | ||
update(data: UpdatePersonRequest): Promise<SimplePersonResponse>; | ||
/** | ||
* Deletes an person with a specified `person_id`. | ||
* @returns true if the deletion was successful | ||
* | ||
* @example | ||
* ```typescript | ||
* const success = await affinity.persons.delete({ | ||
* person_id: 12345 | ||
* }) | ||
* console.log(success ? 'Person deleted': 'Person not deleted') | ||
* ``` | ||
*/ | ||
delete(request: PersonReference): Promise<boolean>; | ||
/** | ||
* Fetches an array of all the global fields that exist on persons. | ||
* | ||
* @returns An array of the fields that exist on all persons for your team. | ||
* | ||
* @example | ||
* ```typescript | ||
* const personFields = await affinity.persons.getFields() | ||
* console.log(personFields) | ||
* ``` | ||
*/ | ||
getFields(): Promise<EntityField[]>; | ||
} |
@@ -7,1 +7,8 @@ /** | ||
}; | ||
export type Replace<S, T> = Omit<S, keyof T> & T; | ||
/** | ||
* Via https://stackoverflow.com/questions/40510611 | ||
*/ | ||
export type RequireOnlyOne<T, Keys extends keyof T = keyof T> = Pick<T, Exclude<keyof T, Keys>> & { | ||
[K in Keys]-?: Required<Pick<T, K>> & Partial<Record<Exclude<Keys, K>, never>>; | ||
}[Keys]; |
@@ -46,1 +46,11 @@ /** | ||
export declare const organizationFieldsUrl: () => string; | ||
/** | ||
* @hidden | ||
* See [here](https://api-docs.affinity.co/#persons) for more info. | ||
*/ | ||
export declare const personsUrl: (person_id?: number | 'fields') => string; | ||
/** | ||
* @hidden | ||
* See [here](https://api-docs.affinity.co/#get-global-person-fields) for more info. | ||
*/ | ||
export declare const personFieldsUrl: () => string; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
131871
50
3291