Connector lifecycle
The lifecycle from the SDK source runs in this order: package registration, factory implementation, factory registration, authorized runs, contract-test verification, operation.

1. Register the package
Section titled “1. Register the package”Register the integration package (lib/integrations/packages/types.ts, managed at /automations/connectors/[packageKey]). For Field mapping UI support, set mappingTemplate: 'crm'. That is what wires the package to the shared object-mapping editor (components/integrations/package-object-mappings.tsx).
- Package registered with
mappingTemplate: 'crm' - Field-mapping UI renders for the package via the Admin API (
/api/v1/integration-packages/[packageKey]/object-mappings)
2. Implement ConnectorProviderFactory
Section titled “2. Implement ConnectorProviderFactory”Build the adapter behind the source contract (provider-types.ts): a factory returning a refreshed, tenant/connection-scoped client exposing exactly three operations: objects(), properties(objectKey), records(objectKey, properties, after). Skeleton in Examples.
- Client is tenant- and connection-scoped with refresh (no cross-tenant leakage, no stale credentials)
objects(),properties(),records()match the contract inprovider-types.ts- Record paging honors the
aftercursor (watermarks depend on it)
3. Register the factory in crm-sync/provider.ts
Section titled “3. Register the factory in crm-sync/provider.ts”Registration is code-owned and fail-closed: unregistered providers do not run, period.
- Factory registered in
lib/integrations/crm-sync/provider.ts - Unknown-provider path verified fail-closed (no fallback import)
- Adapter follows the registered-adapter convention (HubSpot:
lib/integrations/hubspot/sync-provider.ts; ConnectWise PSA: provider underlib/integrations/connectwise/)
4. Run authorized: syncConnectorObjectMappings
Section titled “4. Run authorized: syncConnectorObjectMappings”Invoke syncConnectorObjectMappings({ orgId, connectionId, packageKey }) from an authorized runner:
- New scheduling goes through Inngest via function-catalog (register the new function there).
- Do NOT revive
connector-sync-runner. It stays dead; new work uses the catalog path. - Only advance the watermark when
failed === 0. Partial success re-runs from the same watermark and never skips failed records.
5. Verify: adapter contract tests
Section titled “5. Verify: adapter contract tests”Every adapter proves this sequence in order: create, update, retry, pause.
- Create: new source records arrive as mapped records
- Update: changed source records update (see
upsertConnectorCrmRecord) - Retry: failed runs re-run from the held watermark without loss or duplication
- Pause: pausing stops scheduling cleanly; resume continues correctly
6. Operate
Section titled “6. Operate”- Watch run outcomes and denial patterns as design feedback.
- Track binding health per org, package, and connection (
settings.object_mappings). - Changes go through the lifecycle again. Never edited live under tenants.
- Retirement: remove from
provider.ts, migrate or freeze bindings, revoke grants, preserve audit history. Exact retirement mechanics: not in pasted sources.
Never rules (from source)
Section titled “Never rules (from source)”- Never expose
applyConnectorMappedRecordunauthenticated. Authorized runners only. - Never revive
connector-sync-runnerfor new scheduling. - Never advance the watermark when
failed !== 0. - Never present Salesforce scaffolds as implementations; never promise outbound HubSpot writes.

