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 = {}, ) { 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, }) }