import { accounts } from './accounts.ts'
import { getAccount } from './account.ts'
import { inferOperationFromPath, oauthConnectUrl, scopeForOperation } from './setup.ts'
import { normalizeHubSpotPath } from './client.ts'
import { resolveObjectSpec } from './models.ts'
import type { HubSpotAuthInput } from './types.ts'
import { optionalString, requireRecord } from './types.ts'
import { requireAuthMode } from './auth.ts'
export type SmokeTestInput = HubSpotAuthInput & {
/** When true, skip the live portal query even if credentials exist. */
setupOnly?: boolean
}
/**
* Verify HubSpot auth without returning portal PII. Without credentials this
* still returns setup URLs so the package is forkable before anyone connects.
* @example
* import smokeTest from 'kody:@kody/hubspot/smoke-test'
* const result = await smokeTest()
*/
export async function smokeTest(params: SmokeTestInput = {}) {
const connectUrl = oauthConnectUrl('hubspot')
const selfCheck = {
ok: true as const,
pathKeepsCrmPrefix: normalizeHubSpotPath('/crm/v3/objects/contacts') === '/crm/v3/objects/contacts',
contactWriteScope: scopeForOperation('contacts.write') === 'crm.objects.contacts.write',
ticketWriteFromPath:
inferOperationFromPath('PATCH', '/crm/v3/objects/tickets/1') === 'tickets.write',
customReadFromPath:
inferOperationFromPath('GET', '/crm/v3/objects/p_listings') === 'custom.read',
searchIsCustomRead:
inferOperationFromPath('POST', '/crm/v3/objects/contacts/search') === 'contacts.read',
dealSpec: resolveObjectSpec('deals').writeOperation === 'deals.write',
connectUrlUsesHubSpotHost: connectUrl.includes('app.hubspot.com'),
connectUrlHasContactsScope: connectUrl.includes('crm.objects.contacts.read'),
}
const info = await accounts(params)
const canLive = Boolean(info.preferredAuth) && params.setupOnly !== true
if (!canLive) {
return {
ok: true,
live: false,
selfCheck,
authMode: info.preferredAuth,
integrationName: info.integrationName,
secretName: info.secretName,
oauthConnected: info.oauthConnected,
privateAppSaved: info.privateAppSaved,
hasPortalId: false,
setup: {
connectUrl: info.connectUrl,
privateAppUrl: info.privateAppUrl,
callbackUrl: info.callbackUrl,
requiredHosts: info.requiredHosts,
},
}
}
const account = await getAccount(params)
return {
ok: true,
live: true,
selfCheck,
authMode: info.preferredAuth,
integrationName: info.integrationName,
secretName: info.secretName,
oauthConnected: info.oauthConnected,
privateAppSaved: info.privateAppSaved,
hasPortalId: account.hasPortalId,
setup: {
connectUrl: info.connectUrl,
privateAppUrl: info.privateAppUrl,
callbackUrl: info.callbackUrl,
requiredHosts: info.requiredHosts,
},
}
}
/**
* Verify HubSpot auth without returning portal PII.
* @example
* import smokeTest from 'kody:@kody/hubspot/smoke-test'
* const result = await smokeTest({ setupOnly: true })
*/
export default async function smokeTestEntrypoint(
params: SmokeTestInput & Record<string, unknown> = {},
) {
const input = requireRecord(params, 'smoke-test')
return smokeTest({
integrationName: optionalString(input.integrationName, 'integrationName'),
integration: optionalString(input.integration, 'integration'),
account: optionalString(input.account, 'account'),
secretName: optionalString(input.secretName, 'secretName'),
auth: requireAuthMode(input.auth),
setupOnly: input.setupOnly === true,
})
}