import { hubspotRequest, hubspotUrl, inferOperationFromPath, isMutatingMethod } from './client.ts'
import { HUBSPOT_API_BASE_URL } from './setup.ts'
import type { HubSpotAuthInput, JsonRecord } from './types.ts'
import {
optionalBoolean,
optionalString,
requireRecord,
requireString,
} from './types.ts'
import { requireAuthMode } from './auth.ts'
export type HubSpotRawRequestInput = HubSpotAuthInput & {
path: string
method?: string
query?: JsonRecord
body?: JsonRecord
confirm?: boolean
dryRun?: boolean
}
/**
* Call the HubSpot REST API with a saved OAuth integration or private-app token.
* Search POST `/crm/v3/objects/{type}/search` is treated as a read. Other
* mutating methods require `confirm: true`; use `dryRun: true` to preview.
* @example
* import request from 'kody:@kody/hubspot/request'
* const result = await request({ path: '/crm/v3/objects/contacts', query: { limit: 5 } })
*/
export async function request(input: HubSpotRawRequestInput) {
const path = requireString(input.path, 'path')
const method = (input.method ?? 'GET').toUpperCase()
const operation = inferOperationFromPath(method, path)
const integrationName =
optionalString(input.integrationName, 'integrationName') ??
optionalString(input.integration, 'integration')
const secretName = optionalString(input.secretName, 'secretName')
const account = optionalString(input.account, 'account')
const isSearch = /\/search(?:\/|$)/.test(path) && method === 'POST'
const mutating = isMutatingMethod(method) && !isSearch
if (input.dryRun) {
return {
dryRun: true,
url: hubspotUrl(path, input.query),
apiBaseUrl: HUBSPOT_API_BASE_URL,
method,
operation,
path,
query: input.query ?? {},
body: input.body ?? null,
integrationName: integrationName ?? null,
secretName: secretName ?? null,
account: account ?? null,
readOnly: !mutating,
}
}
if (mutating && input.confirm !== true) {
throw new Error(
'This HubSpot request may mutate CRM data. Pass confirm: true only after explicit user approval, or use dryRun: true.',
)
}
return hubspotRequest({
path,
method,
query: input.query,
body: input.body,
operation,
integrationName,
integration: input.integration,
account,
secretName,
auth: input.auth,
})
}
/**
* Call the HubSpot REST API with a saved OAuth integration or private-app token.
* @example
* import request from 'kody:@kody/hubspot/request'
* const result = await request({ path: '/account-info/v3/details' })
*/
export default async function requestEntrypoint(
params: Partial<HubSpotRawRequestInput> & Record<string, unknown> = {},
) {
const input = requireRecord(params, 'request')
return request({
path: requireString(input.path, 'path'),
method: optionalString(input.method, 'method'),
query: input.query as JsonRecord | undefined,
body: input.body as JsonRecord | undefined,
integrationName: optionalString(input.integrationName, 'integrationName'),
integration: optionalString(input.integration, 'integration'),
account: optionalString(input.account, 'account'),
secretName: optionalString(input.secretName, 'secretName'),
auth: requireAuthMode(input.auth),
confirm: optionalBoolean(input.confirm, 'confirm'),
dryRun: optionalBoolean(input.dryRun, 'dryRun'),
})
}