common

package
v0.0.0-...-63c74ad Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 23, 2026 License: MIT Imports: 41 Imported by: 1

Documentation

Overview

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

nolint:revive,godoclint

Index

Constants

View Source
const (

	// HeaderModeAppend appends the header to the request.
	HeaderModeAppend

	// HeaderModeOverwrite unconditionally overwrites the header in the request.
	HeaderModeOverwrite

	// HeaderModeSetIfMissing sets the header in the request if it is not already set.
	HeaderModeSetIfMissing
)
View Source
const (

	// QueryParamModeAppend appends the QueryParam to the request.
	QueryParamModeAppend

	// QueryParamModeOverwrite unconditionally overwrites the QueryParam in the request.
	QueryParamModeOverwrite

	// QueryParamModeSetIfMissing sets the QueryParam in the request if it is not already set.
	QueryParamModeSetIfMissing
)
View Source
const (
	ValueTypeString    = "string"
	ValueTypeReference = "reference"
	ValueTypeBoolean   = "boolean"
	ValueTypeFloat     = "float" // float is more preferred than int if provider doesn't differentiate.
	ValueTypeInt       = "int"

	ValueTypeDate     = "date"
	ValueTypeDateTime = "datetime"

	ValueTypeSingleSelect = "singleSelect"
	ValueTypeMultiSelect  = "multiSelect"

	ValueTypeOther = "other"
)
View Source
const AWSServiceContextKey ctxKey = "AWSService"

Variables

View Source
var (
	// ErrInvalidModuleDeclaration is returned when a module entry in the Modules map is incorrectly defined.
	// This may occur if the map key does not match the module's declared ID,
	// or if required provider/module metadata is missing or malformed.
	ErrInvalidModuleDeclaration = errors.New("supported modules are not correctly defined")

	// ErrMissingModule can be returned when connector cannot resolve ModuleID.
	ErrMissingModule = errors.New("module not found")

	// ErrUnsupportedModule returned when provided module is not supported.
	ErrUnsupportedModule = errors.New("provided module is not supported")
)
View Source
var (
	ErrValidationFailed        = errors.New("validation failed")
	ErrMissingAuthClient       = errors.New("authenticated client not given")
	ErrMissingMetadata         = errors.New("metadata not given")
	ErrMissingWorkspace        = errors.New("workspace not given")
	ErrMissingCustomAuthClient = errors.New("custom authenticated client not given")
)
View Source
var (
	// ErrAccessToken is a token which isn't valid.
	ErrAccessToken error = newClassedErr("access token invalid", ErrorClassAuthInvalidated)

	// ErrApiDisabled means a customer didn't enable this API on their SaaS instance.
	ErrApiDisabled error = newClassedErr("API disabled", ErrorClassAPIDisabled)

	// ErrForbidden means the user doesn't have access to this resource.
	ErrForbidden error = newClassedErr("forbidden", ErrorClassForbidden)

	// ErrInvalidSessionId means the session ID is invalid.
	ErrInvalidSessionId = errors.New("invalid session id")

	// ErrUnableToLockRow means the resource couldn't be locked.
	ErrUnableToLockRow = errors.New("unable to lock row")

	// ErrInvalidGrant means the OAuth grant is invalid.
	ErrInvalidGrant error = newClassedErr("invalid grant", ErrorClassAuthInvalidated)

	// ErrLimitExceeded means a quota limit was exceeded.
	ErrLimitExceeded error = newClassedErr("request limit exceeded", ErrorClassRateLimited)

	// ErrRetryable represents a temporary error. Can retry.
	ErrRetryable error = newClassedErr("retryable error", ErrorClassRetryable)

	// ErrCaller represents non-retryable errors caused by bad input from the caller.
	ErrCaller error = newClassedErr("caller error", ErrorClassBadRequest)

	// ErrServer represents non-retryable errors caused by something on the server.
	ErrServer error = newClassedErr("server error", ErrorClassProvider5xx)

	// ErrUnknown represents an unknown status code response.
	ErrUnknown error = newClassedErr("unknown error", ErrorClassUnknown)

	// ErrNotJSON is returned when a response is not JSON.
	ErrNotJSON = errors.New("response is not JSON")

	// ErrNotXML is returned when a response is not XML.
	ErrNotXML = errors.New("response is not XML")

	// ErrMissingOauthConfig is returned when the OAuth config is missing.
	ErrMissingOauthConfig = errors.New("missing OAuth config")

	// ErrMissingRefreshToken is returned when the refresh token is missing.
	ErrMissingRefreshToken = errors.New("missing refresh token")

	// ErrEmptyBaseURL is returned when the URL is relative, and the base URL is empty.
	ErrEmptyBaseURL = errors.New("empty base URL")

	// ErrNotImplemented is returned when a method is not implemented.
	ErrNotImplemented = errors.New("not implemented")

	// ErrRequestFailed is returned when the request failed.
	ErrRequestFailed = errors.New("request failed")

	// ErrParseError is returned data parsing failed.
	ErrParseError = errors.New("parse error")

	// ErrBadRequest is returned when we get a 400 response from the provider.
	ErrBadRequest error = newClassedErr("bad request", ErrorClassBadRequest)

	// ErrFieldNotFound is returned when a requested field was not found or is not
	// accessible on the object. It is a subset of ErrBadRequest.
	ErrFieldNotFound = errors.New("field not found or not accessible")

	// ErrConflict is returned when we get a 409 response from the provider.
	ErrConflict = errors.New("conflict")

	// ErrNotFound is returned when we get a 404 response from the provider.
	ErrNotFound = errors.New("not found")

	// ErrCursorGone is returned when a cursor used for pagination is no longer valid.
	ErrCursorGone error = newClassedErr("pagination cursor gone or expired", ErrorClassCursorGone)

	// ErrInvalidPaginationCursor is returned when the provider rejected a pagination cursor
	// as malformed/unparseable (e.g. HubSpot returning "Cannot deserialize value of type `int`
	// from String ...").
	ErrInvalidPaginationCursor error = errors.New("pagination cursor has an invalid format")

	// ErrResultsLimitExceeded is returned when a search query exceeds the provider's
	// maximum result limit (e.g., HubSpot's 10,000 record search limit).
	ErrResultsLimitExceeded error = newClassedErr("results limit exceeded", ErrorClassRateLimited)

	// ErrMissingExpectedValues is returned when response data doesn't have values expected for processing.
	ErrMissingExpectedValues = errors.New("response data is missing expected values")

	// ErrPreprocessingWritePayload is returned when request payload supplied to connector "Write" method
	// couldn't be processed. Likely, the issue is within provided WriteParams.RecordData or implementation.
	ErrPreprocessingWritePayload = errors.New("failed preprocessing write payload")

	// ErrEmptyJSONHTTPResponse is returned when the JSONHTTPResponse is nil.
	ErrEmptyJSONHTTPResponse = errors.New("empty json http response")

	// ErrFailedUnmarshalling is returned when the HTTP response cannot be unmarshalled.
	ErrFailedUnmarshalling = errors.New("json.Unmarshal failed")

	// ErrEmptyRecordIdResponse is returned when the response body doesn't have record id.
	ErrEmptyRecordIdResponse = errors.New("empty record id in response body")

	// ErrRecordDataNotJSON is returned when the record data in WriteParams is not JSON.
	ErrRecordDataNotJSON = errors.New("record data is not JSON")

	// ErrOperationNotSupportedForObject is returned when operation is not supported for this object.
	ErrOperationNotSupportedForObject = errors.New("operation is not supported for this object in this module")

	// ErrObjectNotSupported is returned when operation is not supported for this object.
	ErrObjectNotSupported = errors.New("operation is not supported for this object")

	// ErrResolvingURLPathForObject is returned when URL cannot be implied for object name.
	ErrResolvingURLPathForObject = errors.New("cannot resolve URL path for given object name")

	// ErrFailedToUnmarshalBody is returned when response body cannot be marshalled into some type.
	ErrFailedToUnmarshalBody = errors.New("failed to unmarshal response body")

	// ErrNextPageInvalid is returned when next page token provided in Read operation cannot be understood.
	ErrNextPageInvalid = errors.New("next page token is invalid")

	// ErrInvalidImplementation is returned when implementation assumption is broken.
	// This is not a client issue.
	ErrInvalidImplementation = errors.New("invalid implementation")

	// ErrPayloadNotURLForm is returned when payload is not string key-value pair
	// which could be encoded for POST with content type of application/x-www-form-urlencoded.
	ErrPayloadNotURLForm = errors.New("payload cannot be url-form encoded")

	// ErrResolvingCustomFields is returned when custom fields cannot be retrieved for Read or ListObjectMetadata.
	ErrResolvingCustomFields = errors.New("cannot resolve custom fields")

	ErrGetRecordNotSupportedForObject = errors.New("getRecord is not supported for the object")

	// ErrImplementation is returned when the code takes an unexpected or logically invalid execution path.
	// It should be used to explicitly catch cases that would otherwise lead to panics (e.g., nil pointer dereference).
	// This typically indicates a broken assumption or inconsistency in the implementation logic.
	ErrImplementation = errors.New("code took invalid execution path")

	// ErrBadProviderResponse is returned when the provider returns a response that doesn't match the expected format.
	// This can be used when the provider returns a 200 OK status,
	// but the body of the response indicates an error or is missing expected fields.
	ErrBadProviderResponse = errors.New("bad response from provider")

	// ErrProxyNotApplicable indicates that a proxy cannot be used in the given context.
	ErrProxyNotApplicable = errors.New("proxy is not applicable in this context")

	// ErrMissingField indicates that a required field is missing from a response body.
	// This error is returned during response body inspection when attempting to extract
	// important fields that are expected to be present but were not found.
	ErrMissingField = errors.New("missing field")

	// ErrSubscriptionEventList is returned by CollapsedSubscriptionEvent.SubscriptionEventList.
	ErrSubscriptionEventList = errors.New("failed creating []common.SubscriptionEvent")

	// ErrMissingHeader indicates that a required header is missing in HTTP response.
	ErrMissingHeader = errors.New("missing header")

	// ErrPrevSubscriptionResultInvalid is returned when the update subscription expects different shape of data
	// from previous SubscriptionResult. This should not happen and it points to issues with implementation.
	// Likely the result was not created properly by previous Create/Update step.
	ErrPrevSubscriptionResultInvalid = errors.New("previous SubscriptionResult does not match expectations")

	// ErrInvalidVirtualField is returned when Write cannot happen due to invalid virtual field.
	ErrInvalidVirtualField = errors.New("virtual field is invalid")
)
View Source
var (
	// ErrMissingObjects is returned when no objects are provided in the request.
	ErrMissingObjects = errors.New("no objects provided")

	// ErrEmptyObject is returned when empty string is used as an object name.
	// Some APIs, connectors could be strict about it.
	ErrEmptyObject = errors.New("object name is empty")

	// ErrMissingRecordID is returned when resource id is missing in the request.
	ErrMissingRecordID = errors.New("no object ID provided")

	// ErrMissingRecordData is returned when write data is missing in the request.
	ErrMissingRecordData = errors.New("no data provided")

	// ErrMissingFields is returned when no fields are provided for reading.
	ErrMissingFields = errors.New("no fields provided in ReadParams")

	// ErrSinceUntilChronOrder is returned when the 'since' timestamp is after the 'until' timestamp in ReadParams.
	ErrSinceUntilChronOrder = errors.New("since cannot come after until")

	// ErrMissingFieldsMetadata is returned when the list of fields to create via UpsertMetadata is empty.
	ErrMissingFieldsMetadata = errors.New("no fields metadata provided in UpsertMetadata")

	// ErrMissingSearchFilters is returned when no field filters are provided for the Search operation.
	ErrMissingSearchFilters = errors.New("no filters provided for Search operation")

	// ErrPaginationControl is returned when controlling page size is not supported by connector..
	ErrPaginationControl = errors.New("pagination cannot be controlled by page size")
)
View Source
var (
	// ErrUnknownWriteType is returned when enum option for the write type is invalid.
	ErrUnknownWriteType = errors.New("unknown write type")
	// ErrUnsupportedWriteType is returned when connector doesn't implement write type.
	ErrUnsupportedWriteType = errors.New("write type is not supported")
)
View Source
var (
	ErrNotXMLChildren = errors.New("children must be of type 'XMLData' or 'XMLString'")
	ErrNoSelfClosing  = errors.New("selfClosing cannot be true if children are not present")
	ErrNoParens       = errors.New("value cannot contain < or >")
)
View Source
var ErrBatchUnprocessedRecord = errors.New("record was not processed due to other records failures")

ErrBatchUnprocessedRecord is returned when a record was skipped or not processed due to failures elsewhere in the batch.

View Source
var ErrFieldTypeUnknown = errors.New("unrecognized field type")
View Source
var ErrMissingAccessToken = errors.New("missing access token")

ErrMissingAccessToken returned when access token was not present in the context.Context.

View Source
var ErrMissingCSVData = errors.New("no CSV data provided")

ErrMissingCSVData is returned when no CSV data was given for the upload.

View Source
var ErrMissingContentType = errors.New("missing content type")
View Source
var ErrNumWriteResultExceedsTotalRecords = errors.New(
	"number of batch WriteResult entries exceeds total number of payload Records",
)
View Source
var ErrRequestAWSMissingService = errors.New("AWS request is missing Service name, supplied via context")

ErrRequestAWSMissingService is returned when deep connector implementation doesn't attach AWS service name into the context, therefore the request cannot be constructed for sending.

View Source
var HeaderFormURLEncoded = Header{
	Key:   "Content-Type",
	Value: "application/x-www-form-urlencoded",
}
View Source
var WithTrailingSlash = "/" //nolint:gochecknoglobals

Functions

func AddJSONContentTypeIfNotPresent

func AddJSONContentTypeIfNotPresent(req *http.Request) *http.Request

AddJSONContentTypeIfNotPresent adds the Content-Type header if it is not already present.

func AddSuffixIfNotExists

func AddSuffixIfNotExists(str string, suffix string) string

AddSuffixIfNotExists appends the suffix to the provided string.

func AssertType

func AssertType[T any](val any) (T, error)

func EnsureContentType

func EnsureContentType(pattern string, res *http.Response, errOnMissing bool) error

EnsureContentType ensures that the content type matches the given pattern. If errOnMissing is true, an error is returned if the content type is missing. Otherwise, the function returns nil.

func ExtractLowercaseFieldsFromRaw

func ExtractLowercaseFieldsFromRaw(fields []string, record map[string]any) map[string]any

ExtractLowercaseFieldsFromRaw returns a map of fields from a record. The fields are all returned in lowercase.

func GetResponseBodyOnce

func GetResponseBodyOnce(response *http.Response) []byte

func InterpretError

func InterpretError(res *http.Response, body []byte) error

InterpretError interprets the given HTTP response (in a fairly straightforward way) and returns an error that can be handled by the caller.

func MakeGetRequest

func MakeGetRequest(ctx context.Context, url string, headers []Header) (*http.Request, error)

MakeGetRequest creates a GET request with the given headers.

func MakeJSONGetRequest

func MakeJSONGetRequest(ctx context.Context, url string, headers []Header) (*http.Request, error)

MakeJSONGetRequest creates a GET request with the given headers and adds the Accept: application/json header. It then returns the request.

func NewEmptyObjectEvents

func NewEmptyObjectEvents(names []ObjectName) map[ObjectName]ObjectEvents

NewEmptyObjectEvents creates the subscription state where each object is not subscribed to any events.

func NewHTTPError

func NewHTTPError(status int, body []byte, headers Headers, err error) error

NewHTTPError creates a new error with the given HTTP status.

func PrintRequestAndResponse

func PrintRequestAndResponse(req *http.Request, rsp *http.Response)

func RecordDataToMap

func RecordDataToMap(recordData any) (map[string]any, error)

RecordDataToMap converts WriteParams.RecordData into a map[string]any.

When possible use WriteParams.GetRecord instead.

If RecordData is already a map, it is returned directly. Otherwise, it is serialized to JSON and then deserialized back into a map.

func RecordDataToStruct

func RecordDataToStruct[S any](params WriteParams) (payload S, err error)

RecordDataToStruct converts params.RecordData (any) into the concrete generic type S.

The conversion is performed by JSON round-trip: the function marshals params.RecordData to JSON and then unmarshals that JSON into the result value of type S.

Returns the zero value of S and a non-nil error if marshaling or unmarshaling fails.

func UnmarshalJSON

func UnmarshalJSON[T any](rsp *JSONHTTPResponse) (*T, error)

UnmarshalJSON deserializes the response body into the given type.

func ValidateParameters

func ValidateParameters(conn any, params ConnectorParams) error

ValidateParameters sees which interfaces conn implements, calls the relevant validation methods. nolint:cyclop

func WithAuthToken

func WithAuthToken(ctx context.Context, token AuthToken) context.Context

WithAuthToken returns a new context with the given auth token.

func WithRequestModifier

func WithRequestModifier(ctx context.Context, modifier RequestModifier) context.Context

WithRequestModifier adds a request modifier to the context. The request modifier will be called with the request before it is sent. This allows the caller to inject logic into the request, such as adding/removing headers or modifying the request body. Generally this should be used for debugging purposes only. Although there may be some use cases where it is useful to modify the request before it is sent. It can also double as an injectable observer function.

Types

type AWSClient

type AWSClient struct {
	// contains filtered or unexported fields
}

func (AWSClient) CloseIdleConnections

func (c AWSClient) CloseIdleConnections()

func (AWSClient) Do

func (c AWSClient) Do(req *http.Request) (*http.Response, error)

type Association

type Association struct {
	// ObjectID is the ID of the associated object.
	ObjectId string         `json:"objectId"`
	Raw      map[string]any `json:"raw,omitempty"`
	// ProviderAssociationMetadata holds provider-specific metadata about the association type.
	// For HubSpot, this includes category, typeId, and label from the associations API.
	ProviderAssociationMetadata map[string]any `json:"providerAssociationMetadata,omitempty"`
}

Association is a struct that represents an association between two objects. If you think of an association as a directed edge between two nodes, then the ObjectID is the target node. The source node is represented by ReadResultRow.

type AssociationCardinality

type AssociationCardinality string

AssociationCardinality represents the cardinality of an association/relationship.

const (

	// AssociationCardinalityManyToOne indicates that many records in the referencing object
	// can reference a single record in the target object.
	AssociationCardinalityManyToOne AssociationCardinality = "many-to-one"

	// AssociationCardinalityOneToOne indicates that each record in the referencing object
	// can reference only one record in the target object, and vice versa.
	AssociationCardinalityOneToOne AssociationCardinality = "one-to-one"
)

func (AssociationCardinality) IsValid

func (ac AssociationCardinality) IsValid() bool

IsValid checks if the AssociationCardinality is known.

type AssociationDefinition

type AssociationDefinition struct {
	// AssociationType is the high-level association variety (e.g., 'foreignKey', 'lookup', 'ref').
	// The provider determines the exact behavior.
	AssociationType string `json:"associationType"`
	// TargetObject is the name of the referenced/parent object.
	TargetObject string `json:"targetObject"`
	// TargetField is the name of the referenced field on the target object.
	// Defaults to the target's primary key when omitted.
	TargetField string `json:"targetField,omitempty"`
	// Association cardinality from the referencing field's perspective (e.g., 'many-to-one', 'one-to-one').
	Cardinality AssociationCardinality `json:"cardinality,omitempty"`
	// OnDelete defines the behavior upon foreign object deletion, where supported.
	// E.g., 'cascade', 'restrict', 'setNull'.
	OnDelete AssociationOnDeleteAction `json:"onDelete,omitempty"`
	// Required means that, if true, a referenced record must exist (i.e., NOT NULL foreign key).
	Required bool `json:"required,omitempty"`
	// ReverseLookupFieldName is an optional inverse relationship/property name exposed on the target object.
	ReverseLookupFieldName string `json:"reverseLookupFieldName,omitempty"`
	// Labels represents optional UI labels for the association
	Labels *AssociationLabels `json:"labels,omitempty"`
}

AssociationDefinition defines relationship information for a field to another object. Note that not all providers will support all aspects of the association. This is a best-effort attempt to create a common schema for associations across providers.

In the event that a provider doesn't support a particular aspect of the association, and assuming that the field has a value, then the value should be ignored, and a warning should be added to the UpsertMetadataResult.

type AssociationLabels

type AssociationLabels struct {
	Singular string `json:"singular"`
	Plural   string `json:"plural"`
}

AssociationLabels represents UI labels for an association.

type AssociationOnDeleteAction

type AssociationOnDeleteAction string
const (

	// AssociationOnDeleteActionCascade means that when the parent record is deleted,
	// all child records referencing it are also deleted.
	AssociationOnDeleteActionCascade AssociationOnDeleteAction = "cascade"

	// AssociationOnDeleteActionRestrict means that the parent record cannot be deleted
	// if there are any child records referencing it.
	AssociationOnDeleteActionRestrict AssociationOnDeleteAction = "restrict"

	// AssociationOnDeleteActionSetNull means that when the parent record is deleted,
	// the foreign key field in the child records is set to NULL.
	AssociationOnDeleteActionSetNull AssociationOnDeleteAction = "setNull"
)

func (AssociationOnDeleteAction) IsValid

func (a AssociationOnDeleteAction) IsValid() bool

type AuthToken

type AuthToken string

AuthToken is a type alias for a string representing an authentication token. This can be used to store the token in a context.

func GetAuthToken

func GetAuthToken(ctx context.Context) (AuthToken, bool)

GetAuthToken returns the auth token from the context, if it exists.

func (AuthToken) String

func (t AuthToken) String() string

type AuthenticatedHTTPClient

type AuthenticatedHTTPClient interface {
	Do(req *http.Request) (*http.Response, error)
	CloseIdleConnections()
}

AuthenticatedHTTPClient is an interface for an http client which can automatically authenticate itself. This is useful for OAuth authentication, where the access token needs to be refreshed automatically. The signatures are a subset of http.Client, so it can be used as a (mostly) drop-in replacement.

func NewAWSClient

func NewAWSClient(ctx context.Context, client *http.Client,
	accessKeyID, accessKeySecret, region string,
) (AuthenticatedHTTPClient, error)

NewAWSClient constructs an AWSClient using Access Key ID and Secret. Keys can be obtained as described here: https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/getting-started.html#get-your-aws-access-keys

The HTTP client is scoped to a single AWS region but supports multiple AWS services. The request context must pass service domain via context key AWSServiceContextKey.

Features: * SHA256 payload hashing * SigV4 request signing: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html

func NewApiKeyHeaderAuthHTTPClient

func NewApiKeyHeaderAuthHTTPClient(
	ctx context.Context,
	headerName, headerValue string,
	opts ...HeaderAuthClientOption,
) (AuthenticatedHTTPClient, error)

NewApiKeyHeaderAuthHTTPClient returns a new http client, with automatic API key authentication. Specifically this means that the client will automatically add the API key (as a header) to every request. HeaderValue must be in the correct format. This sometimes means adding prefix to the API Key.

func NewApiKeyQueryParamAuthHTTPClient

func NewApiKeyQueryParamAuthHTTPClient(
	ctx context.Context,
	queryParamName, apiKey string,
	opts ...QueryParamAuthClientOption,
) (AuthenticatedHTTPClient, error)

NewApiKeyQueryParamAuthHTTPClient returns a new http client, with automatic API key authentication. Specifically this means that the client will automatically add the API key (as a query param) to every request.

func NewBasicAuthHTTPClient

func NewBasicAuthHTTPClient(
	ctx context.Context,
	user, pass string,
	opts ...HeaderAuthClientOption,
) (AuthenticatedHTTPClient, error)

NewBasicAuthHTTPClient returns a new http client, with automatic Basic authentication. Specifically this means that the client will automatically add the Basic auth header to every request. The username and password are provided as arguments.

func NewCustomAuthHTTPClient

func NewCustomAuthHTTPClient(
	ctx context.Context,
	opts ...CustomAuthClientOption,
) (AuthenticatedHTTPClient, error)

NewCustomAuthHTTPClient returns a new http client, which will do generic header or query-param-based authentication. It does this by automatically adding the provided headers and/or query params to every request. There's no additional logic for refreshing tokens or anything like that. This is appropriate for APIs that require static but somewhat odd authentication mechanisms involving headers or query params.

func NewHeaderAuthHTTPClient

func NewHeaderAuthHTTPClient(
	ctx context.Context,
	opts ...HeaderAuthClientOption,
) (AuthenticatedHTTPClient, error)

NewHeaderAuthHTTPClient returns a new http client, which will do generic header-based authentication. It does this by automatically adding the provided headers to every request. There's no additional logic for refreshing tokens or anything like that. This is appropriate for APIs that use keys or basic auth.

func NewOAuthHTTPClient

func NewOAuthHTTPClient(ctx context.Context, opts ...OAuthOption) (AuthenticatedHTTPClient, error)

NewOAuthHTTPClient returns a new http client, with automatic OAuth authentication. Specifically this means that the client will automatically refresh the access token whenever it expires.

func NewQueryParamAuthHTTPClient

func NewQueryParamAuthHTTPClient(
	ctx context.Context,
	opts ...QueryParamAuthClientOption,
) (AuthenticatedHTTPClient, error)

NewQueryParamAuthHTTPClient returns a new http client, which will do generic query-param-based authentication. It does this by automatically adding the provided query params to every request. There's no additional logic for refreshing tokens or anything like that. This is appropriate for APIs that use keys encoded in the query params.

type BatchItem

type BatchItem struct {
	Record       map[string]any
	Associations any
}

func (BatchItem) GetRecord

func (i BatchItem) GetRecord() (Record, error)

type BatchItems

type BatchItems []BatchItem

type BatchPolicy

type BatchPolicy struct {
	// AllOrNone controls whether partial success is allowed.
	// When true, if any record fails, the entire batch is rolled back.
	// When false (default), successful records are committed even if others fail.
	// If nil, defaults to false (partial success allowed).
	AllOrNone *bool `json:"allOrNone,omitempty"`
}

BatchPolicy configures the behavior of batch write operations. This struct is extensible for future batch configuration options.

func (*BatchPolicy) GetAllOrNone

func (p *BatchPolicy) GetAllOrNone() bool

GetAllOrNone returns the AllOrNone value, defaulting to false if nil.

type BatchStatus

type BatchStatus string

BatchStatus describes the aggregate outcome of a batch operation.

const (
	BatchStatusSuccess BatchStatus = "success"
	BatchStatusFailure BatchStatus = "failure"
	BatchStatusPartial BatchStatus = "partial"
)

type BatchWriteParam

type BatchWriteParam struct {
	// ObjectName identifies the target object for the write operation.
	ObjectName ObjectName
	// Type defines how the records should be processed: create, update, or upsert.
	Type WriteType
	// Batch contains the collection of record payloads to be written.
	Batch BatchItems
	// Headers contains additional headers to be added to the request.
	Headers []WriteHeader // optional
	// Policy configures batch write behavior (partial success, etc.)
	Policy *BatchPolicy
	// Deprecated: Use Policy.AllOrNone instead.
	AllOrNone *bool
}

BatchWriteParam defines the input required to execute a batch write operation. It allows creating, updating, or upserting multiple records in a single request.

func (BatchWriteParam) GetAllOrNone

func (p BatchWriteParam) GetAllOrNone() bool

GetAllOrNone returns the effective AllOrNone value. Prefers Policy.AllOrNone if set, falls back to deprecated AllOrNone field, defaults to false (partial success allowed) if neither is set.

func (BatchWriteParam) GetRecords

func (p BatchWriteParam) GetRecords() ([]Record, error)

func (BatchWriteParam) IsCreate

func (p BatchWriteParam) IsCreate() bool

func (BatchWriteParam) IsUpdate

func (p BatchWriteParam) IsUpdate() bool

func (BatchWriteParam) ValidateParams

func (p BatchWriteParam) ValidateParams() error

type BatchWriteResponseMatcher

type BatchWriteResponseMatcher[P, R any] func(index int, payloadItem P) *R

BatchWriteResponseMatcher matches a single payload item from the request to its corresponding provider response item.

Implementations may match items by inspecting payload data or by using the index, depending on how the provider structures its response. For providers that return responses in the same order as the request, the index allows a straightforward positional lookup.

The function must be deterministic and fast — given a payload item (and its index), it should return the corresponding response item or nil if none exists.

type BatchWriteResponseTransformer

type BatchWriteResponseTransformer[P, R any] func(payloadItem P, respItem *R) (*WriteResult, error)

BatchWriteResponseTransformer converts a payload item and its matched provider response into a standardized WriteResult.

Responsibilities of the transformer:

  • Determine success vs failure for the item (WriteResult.Success).
  • Populate WriteResult.RecordId when the provider returns an identifier for the affected record.
  • Attach errors describing what went wrong at WriteResult.Errors
  • In case of successful create/update set the response item to WriteResult.Data.

Type parameters:

P — payload item type.
R — provider response item type.

type BatchWriteResult

type BatchWriteResult struct {
	// Status summarizes the batch outcome (success, failure, or partial).
	Status BatchStatus
	// Errors lists top-level errors that are not tied to specific records.
	// While errors that are specific to certain records are found in Results[i].Errors
	Errors []any
	// Results contains the detailed outcomes for each record in the batch.
	Results []WriteResult
	// SuccessCount is the number of successfully written records.
	SuccessCount int `json:"successCount"`
	// FailureCount is the number of failed records.
	FailureCount int `json:"failureCount"`
}

BatchWriteResult represents the outcome of a provider batch write operation.

It contains both a high-level summary of the batch and detailed per-record results.

Providers may return more errors than there are payload items, or omit identifiers that would allow matching errors to specific records. In such cases, unmatched or batch-level issues are collected in the top-level Errors slice.

Each identifiable record—matched by reference ID or record ID—produces a WriteResult entry in Results. If multiple identifiable errors occurred for the same record, they are grouped under WriteResult.Errors.

Top-level Errors represent issues that apply to the batch as a whole or to records that could not be reliably matched to payload items.

func NewBatchWriteResult

func NewBatchWriteResult(
	results []WriteResult, successCounter, totalNumRecords int, unmatchedErrors []any,
) (*BatchWriteResult, error)

NewBatchWriteResult constructs a new BatchWriteResult summarizing the outcome of a batch write operation. It validates input consistency, computes success/failure counts, and derives the BatchStatus based on those counts.

Rules and assumptions:

  • len(results) must not exceed totalNumRecords. If it does, the constructor returns a joined error containing ErrInvalidImplementation and ErrNumWriteResultExceedsTotalRecords.

  • successCounter < 0 triggers automatic counting of successes from the results slice. This is a convenience for callers that did not precompute successes. However, providing an explicit success count is preferred.

  • successCounter cannot exceed totalNumRecords. If it does, the counter is recomputed defensively.

  • failureCounter is computed as totalNumRecords - successCounter.

  • A BatchWriteResult always satisfies: SuccessCount + FailureCount == totalNumRecords and len(Results) ≤ totalNumRecords.

  • unmatchedErrors represent provider responses that could not be associated with specific payload items — for example, schema validation issues or general API errors returned alongside per-record results.

Constructors may return an error to signal invalid or inconsistent usage rather than to represent runtime provider failures.

func NewBatchWriteResultFailed

func NewBatchWriteResultFailed(
	results []WriteResult, totalNumRecords int, unmatchedErrors []any,
) (*BatchWriteResult, error)

NewBatchWriteResultFailed constructs a BatchWriteResult representing a fully failed batch operation. It assumes zero successful records and marks the BatchStatus as failure. The constructor still validates that the number of WriteResult entries does not exceed totalNumRecords.

unmatchedErrors may include provider-level issues explaining the failure that cannot be tied to specific records.

func ParseBatchWrite

func ParseBatchWrite[P, R any](
	payloadItems []P,
	responseMatcher BatchWriteResponseMatcher[P, R],
	responseToResult BatchWriteResponseTransformer[P, R],
	unmatchedErrors []any,
) (*BatchWriteResult, error)

ParseBatchWrite converts a provider's overall batch response into a consolidated BatchWriteResult.

A Record is a domain-agnostic map/struct that models fields you want to persist. An Item is the wire representation (payload item) the provider expects for a single Record. Connectors must make an explicit mapping Record -> Item (payload item) when constructing the overall payload. When responses arrive, connectors must match each payload item to its response item and produce a WriteResult. This separation ensures consistent handling of ID mapping, reference IDs, partial successes, and errors.

-------------------------- The function is intentionally generic:

P is the payload item type (what was sent),
R is the provider response item type (what was received).

Arguments: payloadItems - list of items that are part of payload to create/update each record. responseMatcher - list of items that are part of payload to create/update each record. responseToResult - a transformer that converts a matched item pair (payload P, response R) into a WriteResult. unmatchedErrors – top-level errors not tied to individual records,

such as validation failures detected before response matching.

type Classifier

type Classifier interface {
	ErrorClass() ErrorClass
}

Classifier is implemented by error types that know their own ErrorClass. Callers should prefer `ClassOf(err)` over direct `errors.As` checks because ClassOf walks the error chain and applies fallbacks.

type CollapsedSubscriptionEvent

type CollapsedSubscriptionEvent interface {
	Event

	// SubscriptionEventList collapses the event response into the list of messages.
	// In case of an error returns ErrSubscriptionEventList.
	SubscriptionEventList() ([]SubscriptionEvent, error)
}

CollapsedSubscriptionEvent some providers send multiple events in a single webhook payload. This interface is used to extract individual events to SubscriptionEvent type from a collapsed event for webhook parsing and processing.

type ConnectorParams

type ConnectorParams struct {
	Module ModuleID

	// AuthenticatedClient is an HTTP client for the connector that knows how to handle authentication for the provider.
	AuthenticatedClient AuthenticatedHTTPClient

	// Workspace is the provider workspace that the connector is connecting to. It could be a part of the metadata
	// map, but it is a common enough field that it is included here.
	Workspace string

	// Metadata is a map of key-value pairs that can be used to pass in additional information to the connector.
	// Generally this is used to substitute placeholders in the providerInfo, like workspace, server, etc, which is
	// information that is specific to the connection.
	Metadata map[string]string

	// CustomAuthenticatedClient [optional] is useful for connectors that work over non-http protocols or want
	// to use custom non-http clients. Connectors that need this will know to check for it & use it if available.
	CustomAuthenticatedClient any
}

ConnectorParams can be used to pass input parameters to the connector.

type CustomAuthClientOption

type CustomAuthClientOption func(params *customClientParams)

func WithCustomClient

func WithCustomClient(client *http.Client) CustomAuthClientOption

WithCustomClient sets the http client to use for the connector. Its usage is optional.

func WithCustomDebug

func WithCustomDebug(f func(req *http.Request, rsp *http.Response)) CustomAuthClientOption

WithCustomDebug sets a debug function to be called on every request and response, after the response has been received from the downstream API.

func WithCustomDynamicHeaders

func WithCustomDynamicHeaders(f DynamicHeadersGenerator) CustomAuthClientOption

WithCustomDynamicHeaders sets a function that will be called on every request to get additional headers to use. Use this for things like time-based tokens or loading headers from some external authority. The function can access a copy of the request object to use its metadata for generating headers.

func WithCustomDynamicQueryParams

func WithCustomDynamicQueryParams(f DynamicQueryParamsGenerator) CustomAuthClientOption

WithCustomDynamicQueryParams sets a function that will be called on every request to get additional query params to use. Use this for things like time-based tokens or loading query params from some external authority. The function can access a copy of the request object to use its metadata for generating query params.

func WithCustomHeaders

func WithCustomHeaders(headers ...Header) CustomAuthClientOption

WithCustomHeaders sets the headers to use for the connector. Its usage is optional.

func WithCustomIsUnauthorizedHandler

func WithCustomIsUnauthorizedHandler(
	f func(rsp *http.Response) (bool, error),
) CustomAuthClientOption

WithCustomIsUnauthorizedHandler sets the function to call whenever the response is unauthorized (not necessarily 401). This is useful for handling the case where the server has invalidated the token, and the client needs to forcefully refresh. It's optional.

func WithCustomQueryParams

func WithCustomQueryParams(ps ...QueryParam) CustomAuthClientOption

WithCustomQueryParams sets the query params to use for the connector. Its usage is optional.

func WithCustomUnauthorizedHandler

func WithCustomUnauthorizedHandler(
	f func(hdrs []Header, params []QueryParam, req *http.Request, rsp *http.Response) (*http.Response, error),
) CustomAuthClientOption

WithCustomUnauthorizedHandler sets the function to call whenever the response is 401 unauthorized. This is useful for handling the case where the server has invalidated the credentials, and the client needs to refresh. It's optional.

type DeleteMetadataParams

type DeleteMetadataParams struct {
	// Maps object names to field names to delete.
	// For example: {"Account": ["My_Custom_Field__c", "Another_Field__c"]}
	Fields map[ObjectName][]string `json:"fields"`
}

DeleteMetadataParams represents parameters for deleting custom field metadata.

func (*DeleteMetadataParams) ValidateParams

func (p *DeleteMetadataParams) ValidateParams() error

type DeleteMetadataResult

type DeleteMetadataResult struct {
	// Indicates if the delete operation was successful.
	Success bool `json:"success"`
}

DeleteMetadataResult contains results for all deleted fields.

type DeleteParams

type DeleteParams struct {
	// The name of the object we are deleting, e.g. "Account"
	ObjectName string // required

	// The external ID of the object instance we are removing.
	RecordId string // required

	// Headers contains additional headers to be added to the delete request.
	Headers []WriteHeader // optional
}

DeleteParams defines how we are deleting data in SaaS API.

func (DeleteParams) ValidateParams

func (p DeleteParams) ValidateParams() error

type DeleteResult

type DeleteResult struct {
	// Success is true if deletion succeeded.
	Success bool `json:"success"`
}

DeleteResult represents the outcome of a single record delete operation.

type DynamicHeadersGenerator

type DynamicHeadersGenerator func(*http.Request) ([]Header, error)

type DynamicQueryParamsGenerator

type DynamicQueryParamsGenerator func(*http.Request) (QueryParams, error)

type ErrorClass

type ErrorClass string

ErrorClass is a stable, coarse category for an error. It is designed to be consumed by observability tooling (Sentry tags, alert routing, dashboards) and by callers that need to react to broad classes of failure without coupling to specific sentinel values.

New classes should be added here rather than invented at a call site so that downstream systems (Sentry saved searches, alert rules) can stay in sync with the set of possible values.

const (
	// ErrorClassNone is used when there is no error (err == nil).
	ErrorClassNone ErrorClass = "none"

	// ErrorClassUnknown means no classifier matched. Treat as "needs triage".
	ErrorClassUnknown ErrorClass = "unknown"

	// ErrorClassAuthInvalidated — credentials rejected; needs reconnect.
	ErrorClassAuthInvalidated ErrorClass = "auth_invalidated"

	// ErrorClassForbidden — authenticated but not authorized for this resource.
	ErrorClassForbidden ErrorClass = "forbidden"

	// ErrorClassAPIDisabled — the provider-side feature/API is disabled for
	// this customer's instance (e.g. NetSuite REST Web Services off).
	ErrorClassAPIDisabled ErrorClass = "api_disabled"

	// ErrorClassCursorGone — pagination cursor expired or invalidated.
	ErrorClassCursorGone ErrorClass = "cursor_gone"

	// ErrorClassRateLimited — 429 or provider-specific quota error.
	ErrorClassRateLimited ErrorClass = "rate_limited"

	// ErrorClassBadRequest — 4xx caller error that won't succeed on retry.
	ErrorClassBadRequest ErrorClass = "bad_request"

	// ErrorClassSchemaDriftField — provider rejected a known field name
	// (custom field removed, standard field gated by FLS, typo, etc.).
	ErrorClassSchemaDriftField ErrorClass = "schema_drift_missing_field"

	// ErrorClassSchemaDriftObject — provider rejected a known object name.
	ErrorClassSchemaDriftObject ErrorClass = "schema_drift_missing_object"

	// ErrorClassProviderMigration — the provider is transiently unavailable
	// due to an internal migration (e.g. HubSpot hub data-center move).
	// Usually self-heals within hours.
	ErrorClassProviderMigration ErrorClass = "provider_migration"

	// ErrorClassProvider5xx — 5xx server error on the provider side. Retryable.
	ErrorClassProvider5xx ErrorClass = "provider_5xx"

	// ErrorClassRetryable — generic retryable error where a finer class isn't known.
	ErrorClassRetryable ErrorClass = "retryable"
)

func ClassOf

func ClassOf(err error) ErrorClass

ClassOf returns the ErrorClass for an error, walking the error chain.

Resolution order:

  1. Any error in the chain implementing Classifier wins (sentinels declared with newClassedErr implement it automatically).
  2. String-content heuristics for cases where Temporal or another layer has flattened the chain into a raw string and lost the typed sentinel.

Returns ErrorClassNone for nil; never panics.

type ErrorHandler

type ErrorHandler func(rsp *http.Response, body []byte) error

ErrorHandler allows the caller to inject their own HTTP error handling logic. All non-2xx responses will be passed to the error handler. If the error handler returns nil, then the error is ignored and the caller is responsible for handling the error. If the error handler returns an error, then that error is returned to the caller, as-is. Both the response and the response body are passed to the error handler as arguments.

type ErrorPostProcessor

type ErrorPostProcessor struct {
	Process func(err error) error
}

type Event

type Event interface {
	RawMap() (map[string]any, error)
}

Event represents a raw webhook payload and serves as the common abstraction across all event types in the system. Implementations are expected to provide access to the underlying payload in a normalized map form.

The following higher-level event interfaces build on top of Event and should be considered during implementation:

  • SubscriptionEvent: core interface for all subscription-related events
  • SubscriptionUpdateEvent: specialization for update/change events
  • CollapsedSubscriptionEvent: for payloads containing multiple events

A concrete provider event type may implement one or more of these interfaces depending on the structure of the incoming webhook payload.

type FieldDefinition

type FieldDefinition struct {
	// FieldName is the identifier of the field, e.g. "My_Custom_Field".
	FieldName string `json:"fieldName"`
	// DisplayName is the human-readable name of the field, e.g. "My Custom Field".
	DisplayName string `json:"displayName"`
	// Description is an optional description of the field.
	Description string `json:"description,omitempty"`
	// ValueType is the data type of the field.
	ValueType FieldType `json:"valueType"`
	// Required indicates if the field is required.
	Required bool `json:"required,omitempty"`
	// Unique indicates if the field must be unique across all records.
	Unique bool `json:"unique,omitempty"`
	// Indexed indicates if the field should be indexed for faster search.
	Indexed bool `json:"indexed,omitempty"`
	// StringOptions contains additional options for string fields (if any).
	StringOptions *StringFieldOptions `json:"stringOptions,omitempty"`
	// NumericOptions contains additional options for numeric fields (if any).
	NumericOptions *NumericFieldOptions `json:"numericOptions,omitempty"`
	// Association defines association/relationship information for the field (if any).
	Association *AssociationDefinition `json:"association,omitempty"`
}

FieldDefinition represents a field definition. Note that not all providers will support all fields. This is a best-effort attempt to create a common schema for custom fields across providers.

In the event that a provider doesn't support a particular field, and assuming that the field has a value, then the value should be ignored, and a warning should be added to the UpsertMetadataResult.

type FieldFilter

type FieldFilter struct {
	FieldName string         `json:"fieldName" validate:"required"`
	Operator  FilterOperator `json:"operator"  validate:"required"`
	Value     any            `json:"value"     validate:"required"`
}

type FieldMetadata

type FieldMetadata struct {
	// DisplayName is a human-readable field name.
	DisplayName string

	// ValueType is a set of Ampersand defined field types.
	ValueType ValueType

	// ProviderType is the raw type, a term used by provider API.
	// Each is mapped to an Ampersand ValueType.
	ProviderType string

	// ReadOnly would indicate if field can be modified or only read.
	ReadOnly *bool

	// IsCustom indicates whether the field is user-defined or custom.
	// True means the field was added by the user, false means it is native to the provider.
	IsCustom *bool

	// IsRequired indicates whether a value for the field is mandatory
	// when creating or updating the object.
	// True means the field must have a value, false means it is optional.
	IsRequired *bool

	// FieldId is the provider's unique identifier for this field.
	// It is nil when the provider does not expose field identifiers.
	FieldId *string //nolint:revive

	// Values is a list of possible values for this field.
	// It is applicable only if the type is either singleSelect or multiSelect, otherwise slice is nil.
	Values []FieldValue

	// ReferenceTo is the list of object types this field references.
	// It is applicable only if the ProviderType is "reference" (i.e. a lookup field), otherwise nil.
	ReferenceTo []string
}

type FieldType

type FieldType string

FieldType represents the data type of a field.

const (
	FieldTypeString       FieldType = "string"
	FieldTypeBoolean      FieldType = "boolean"
	FieldTypeDate         FieldType = "date"
	FieldTypeDateTime     FieldType = "datetime"
	FieldTypeSingleSelect FieldType = "singleSelect"
	FieldTypeMultiSelect  FieldType = "multiSelect"
	FieldTypeInt          FieldType = "int"
	FieldTypeFloat        FieldType = "float"
)

func (FieldType) IsSelectionType

func (ft FieldType) IsSelectionType() bool

func (FieldType) IsValid

func (ft FieldType) IsValid() bool

IsValid checks if the FieldType is known.

type FieldUpsertResult

type FieldUpsertResult struct {
	// FieldName is the name of the field.
	FieldName string `json:"fieldName"`
	// Action indicates what action was taken (create, update, none).
	Action UpsertMetadataAction `json:"action"`
	// Metadata contains provider-specific metadata about the field (if any).
	// Specific keys/values will vary by provider. Considered strictly informational.
	Metadata map[string]any `json:"metadata,omitempty"`
	// Warnings contains any warnings that occurred during the upsert operation,
	// such as unsupported field attributes.
	Warnings []string `json:"warnings,omitempty"`
}

FieldUpsertResult is the result of an upsert operation for a single field. It indicates what action was taken (create, update, none) and any provider-specific metadata or warnings.

type FieldValue

type FieldValue struct {
	Value        string
	DisplayValue string
}

type FieldValues

type FieldValues []FieldValue

type FieldsMetadata

type FieldsMetadata map[string]FieldMetadata

func (FieldsMetadata) AddFieldWithDisplayOnly

func (f FieldsMetadata) AddFieldWithDisplayOnly(fieldName string, displayName string)

type FilterOperator

type FilterOperator string
const (
	FilterOperatorEQ FilterOperator = "eq"
)

type HTTPClient

type HTTPClient struct {
	// [Deprecated] URL endpoints are not the responsibility of HTTPClient.
	// NOTE: to avoid linter errors the deprecation comment is not of correct golang formatting.
	// Optional base URL. If unset, all request URLs must be absolute.
	Base string
	// Underlying HTTP client. Required.
	Client AuthenticatedHTTPClient
	// Optional ErrorHandler. If not set, then the default error handler is used.
	ErrorHandler ErrorHandler
	// Optional ResponseHandler, allowing mutation of the http.Response returned by the SaaS API.
	ResponseHandler ResponseHandler
	// Optional predicate deciding whether the ErrorHandler should be invoked.
	ShouldHandleError ShouldHandleError
}

HTTPClient is an HTTP client that handles OAuth access token refreshes and provides hooks for custom error and response handling.

func (*HTTPClient) Delete

func (h *HTTPClient) Delete(ctx context.Context,
	url string, headers ...Header,
) (*http.Response, []byte, error)

func (*HTTPClient) Get

func (h *HTTPClient) Get(ctx context.Context, url string, headers ...Header) (*http.Response, []byte, error)

Get makes a GET request to the given URL and returns the response. If the response is not a 2xx, an error is returned. If the response is a 401, the caller should refresh the access token and retry the request. If errorHandler is nil, then the default error handler is used. If not, the caller can inject their own error handling logic.

func (*HTTPClient) Patch

func (h *HTTPClient) Patch(ctx context.Context,
	url string, reqBody []byte, headers ...Header,
) (*http.Response, []byte, error)

Patch makes a PATCH request to the given URL and returns the response & response body. If the response is not a 2xx, an error is returned. If the response is a 401, the caller should refresh the access token and retry the request. If errorHandler is nil, then the default error handler is used. If not, the caller can inject their own error handling logic.

func (*HTTPClient) Post

func (h *HTTPClient) Post(ctx context.Context,
	url string, reqBody []byte, headers ...Header,
) (*http.Response, []byte, error)

Post makes a POST request to the given URL and returns the response & response body. If the response is not a 2xx, an error is returned. If the response is a 401, the caller should refresh the access token and retry the request. If errorHandler is nil, then the default error handler is used. If not, the caller can inject their own error handling logic.

func (*HTTPClient) Put

func (h *HTTPClient) Put(ctx context.Context,
	url string, reqBody []byte, headers ...Header,
) (*http.Response, []byte, error)

type HTTPError

type HTTPError struct {
	// Status is the original HTTP status.
	Status int

	// Headers are the HTTP headers of the response, if available.
	Headers Headers // optional

	// Body is the raw response body, if available.
	Body []byte // optional
	// contains filtered or unexported fields
}

HTTPError is an error that contains both an error and details about the HTTP response that caused the error. It includes the HTTP status code, headers, and body of the response. Body and Headers are optional and may be nil if not available.

func (HTTPError) Error

func (r HTTPError) Error() string

func (HTTPError) ErrorClass

func (r HTTPError) ErrorClass() ErrorClass

ErrorClass derives a stable class for this HTTP error. The status code is the primary signal (e.g. 401 → auth_invalidated, 477 → provider_migration, 5xx → provider_5xx); if the status doesn't map cleanly, we defer to the wrapped error, which self-classifies via the Classifier interface.

func (HTTPError) Unwrap

func (r HTTPError) Unwrap() error
type Header struct {
	Key   string     `json:"key"`
	Value string     `json:"value"`
	Mode  HeaderMode `json:"mode"`
}

Header is a key/value pair that can be added to a request.

func TransformWriteHeaders

func TransformWriteHeaders(headers []WriteHeader, mode HeaderMode) []Header

func (Header) ApplyToRequest

func (h Header) ApplyToRequest(req *http.Request)

func (Header) String

func (h Header) String() string

type HeaderAuthClientOption

type HeaderAuthClientOption func(params *headerClientParams)

func WithDynamicHeaders

func WithDynamicHeaders(f DynamicHeadersGenerator) HeaderAuthClientOption

WithDynamicHeaders sets a function that will be called on every request to get additional headers to use. Use this for things like time-based tokens or loading headers from some external authority. The function can access a copy of the request object to use its metadata for generating headers.

func WithHeaderClient

func WithHeaderClient(client *http.Client) HeaderAuthClientOption

WithHeaderClient sets the http client to use for the connector. Its usage is optional.

func WithHeaderDebug

func WithHeaderDebug(f func(req *http.Request, rsp *http.Response)) HeaderAuthClientOption

WithHeaderDebug sets a debug function to be called on every request and response, after the response has been received from the downstream API.

func WithHeaderIsUnauthorizedHandler

func WithHeaderIsUnauthorizedHandler(
	f func(rsp *http.Response) (bool, error),
) HeaderAuthClientOption

WithHeaderIsUnauthorizedHandler sets the function to call whenever the response is unauthorized (not necessarily 401). This is useful for handling the case where the server has invalidated the token, and the client needs to forcefully refresh. It's optional.

func WithHeaderUnauthorizedHandler

func WithHeaderUnauthorizedHandler(
	f func(hdrs []Header, req *http.Request, rsp *http.Response) (*http.Response, error),
) HeaderAuthClientOption

WithHeaderUnauthorizedHandler sets the function to call whenever the response is 401 unauthorized. This is useful for handling the case where the server has invalidated the credentials, and the client needs to refresh. It's optional.

func WithHeaders

func WithHeaders(headers ...Header) HeaderAuthClientOption

WithHeaders sets the headers to use for the connector. Its usage is optional.

type HeaderMode

type HeaderMode int

HeaderMode determines how the header should be applied to the request.

type Headers

type Headers []Header

func GetRequestHeaders

func GetRequestHeaders(request *http.Request) Headers

func GetResponseHeaders

func GetResponseHeaders(response *http.Response) Headers

func (Headers) ApplyToRequest

func (h Headers) ApplyToRequest(req *http.Request)

func (Headers) Has

func (h Headers) Has(target Header) bool

func (Headers) LogValue

func (h Headers) LogValue() slog.Value

type JSONHTTPClient

type JSONHTTPClient struct {
	HTTPClient         *HTTPClient        // underlying HTTP client. Required.
	ErrorPostProcessor ErrorPostProcessor // Errors returned from CRUD methods will go via this method. Optional.
}

JSONHTTPClient is an HTTP client which makes certain assumptions, such as that the response body is JSON. It also handles OAuth access token refreshes.

func (*JSONHTTPClient) Delete

func (j *JSONHTTPClient) Delete(ctx context.Context, url string, headers ...Header) (*JSONHTTPResponse, error)

func (*JSONHTTPClient) Get

func (j *JSONHTTPClient) Get(ctx context.Context, url string, headers ...Header) (*JSONHTTPResponse, error)

Get makes a GET request to the given URL and returns the response body as a JSON object. If the response is not a 2xx, an error is returned. If the response is a 401, the caller should refresh the access token and retry the request. If errorHandler is nil, then the default error handler is used. If not, the caller can inject their own error handling logic.

func (*JSONHTTPClient) Patch

func (j *JSONHTTPClient) Patch(
	ctx context.Context,
	url string, reqBody any, headers ...Header,
) (*JSONHTTPResponse, error)

func (*JSONHTTPClient) Post

func (j *JSONHTTPClient) Post(
	ctx context.Context,
	url string, reqBody any, headers ...Header,
) (*JSONHTTPResponse, error)

Post makes a POST request to the given URL and returns the response body as a JSON object. ReqBody must be JSON-serializable. If it is not, an error is returned. If the response is not a 2xx, an error is returned. If the response is a 401, the caller should refresh the access token and retry the request. If errorHandler is nil, then the default error handler is used. If not, the caller can inject their own error handling logic.

func (*JSONHTTPClient) Put

func (j *JSONHTTPClient) Put(
	ctx context.Context,
	url string, reqBody any, headers ...Header,
) (*JSONHTTPResponse, error)

func (*JSONHTTPClient) PutCSV

func (j *JSONHTTPClient) PutCSV(ctx context.Context, url string, reqBody []byte, headers ...Header) ([]byte, error)

type JSONHTTPResponse

type JSONHTTPResponse struct {

	// Code is the HTTP status code of the response.
	Code int

	// Headers are the HTTP headers of the response.
	Headers http.Header
	// contains filtered or unexported fields
}

JSONHTTPResponse is a JSON response from an HTTP request. Consider using Body to operate on ajson.Node or Unmarshal into the struct of your choosing via UnmarshalJSON.

func ParseJSONResponse

func ParseJSONResponse(ctx context.Context, res *http.Response, body []byte) (*JSONHTTPResponse, error)

ParseJSONResponse parses the given HTTP response and returns a JSONHTTPResponse.

func (*JSONHTTPResponse) Body

func (j *JSONHTTPResponse) Body() (*ajson.Node, bool)

Body returns JSON node. If it is empty the flag will indicate so. Empty response body is a special case and should be handled explicitly.

type ListObjectMetadataResult

type ListObjectMetadataResult struct {
	// Result is a map of object names to object metadata
	Result map[string]ObjectMetadata

	// Errors is a map of object names to errors
	Errors map[string]error
}

func NewListObjectMetadataResult

func NewListObjectMetadataResult() *ListObjectMetadataResult

func (ListObjectMetadataResult) AppendError

func (r ListObjectMetadataResult) AppendError(objectName string, err error)

AppendError will associate an error with the object. It is possible that single object may have multiple errors.

func (ListObjectMetadataResult) GetObjectMetadata

func (r ListObjectMetadataResult) GetObjectMetadata(objectName string) *ObjectMetadata

type MarshalFromNodeFunc

type MarshalFromNodeFunc func(records []*ajson.Node, fields []string) ([]ReadResultRow, error)

MarshalFromNodeFunc converts a list of ajson.Node records into ReadResultRow format.

func MakeMarshaledDataFunc deprecated

func MakeMarshaledDataFunc(nodeRecordFunc RecordTransformer) MarshalFromNodeFunc

MakeMarshaledDataFunc constructs a MarshalFromNodeFunc that converts records into ReadResultRow slices. It applies an optional RecordTransformer to each record; if nil, it defaults to ajson-to-map conversion. Typically used to flatten, normalize records or enhance them with custom fields.

Deprecated: For new connectors, prefer readhelper.MakeMarshaledDataFuncWithId to ensure the ReadResultRow.Id field is properly populated.

type MarshalFunc

type MarshalFunc func(records []map[string]any, fields []string) ([]ReadResultRow, error)

MarshalFunc converts a list of map[string]any records into ReadResultRow format.

type Module

type Module struct {
	ID      ModuleID
	Label   string // e.g. "crm"
	Version string // e.g. "v3"
}

Module represents a set of endpoints and functionality available by provider. Single provider may support multiple modules, requiring the user to choose a module before making requests. Modules may differ by version or by theme, covering different systems or functionalities.

func (Module) Path

func (a Module) Path() string

type ModuleID

type ModuleID = string
const ModuleRoot ModuleID = "root"

type ModuleObjectNameToFieldName

type ModuleObjectNameToFieldName map[ModuleID]datautils.DefaultMap[string, string]

ModuleObjectNameToFieldName is a grouping of ObjectName to response field name mappings defined for each Module.

Explanation: modules have objects, each object is located under certain field name in the response body. This mapping stores the general relationship between the said ObjectName and FieldName. Those objects that do not follow the pattern described in the fallback method are hard code as exceptions.

Ex:

Given:	Connector has 2 modules -- Commerce, Messaging.
		Commerce module has objects stored under "data" field name, except "carts".
		Messaging module has objects stored under the same name as object, except "chats".
Then:	It will be represented as follows:

	ModuleObjectNameToFieldName{
		ModuleCommerce: datautils.NewDefaultMap(map[string]string{
			"carts": "carts",
		},
			func(objectName string) string {
				return "data" // always under "data" field {"data": [{},{},...]}
			},
		),
		ModuleHelpCenter: datautils.NewDefaultMap(map[string]string{
			"chats":        "active_chats",
		}, func(objectName string) string {
			fieldName := objectName // Object "messages" is stored under {"messages": [{},{},...]}
			return fieldName
		}),
	}

type Modules

type Modules = datautils.Map[ModuleID, Module]

type NextPageFunc

type NextPageFunc func(*ajson.Node) (string, error)

NextPageFunc extracts the next page token/URL from the response body.

type NextPageToken

type NextPageToken string

NextPageToken is an opaque token that can be used to get the next page of results. Callers are encouraged to treat this as an opaque string, and not attempt to parse it. And although each provider will be different, callers should expect that this token will expire after some period of time. So long-term storage of this token is not recommended.

func (NextPageToken) String

func (t NextPageToken) String() string

type NodeRecordsFunc

type NodeRecordsFunc func(*ajson.Node) ([]*ajson.Node, error)

NodeRecordsFunc extracts a list of records as ajson.Node from the response body.

func MakeRecordsFunc

func MakeRecordsFunc(jsonPath string, nestedPath ...string) NodeRecordsFunc

MakeRecordsFunc returns a function that extracts an array of record nodes from a JSON document. The jsonPath defines where the records array resides. The optional nestedPath specifies a traversal prefix to locate nested arrays.

type NumericFieldOptions

type NumericFieldOptions struct {
	// Precision is the total number of digits (for decimal types).
	Precision *int `json:"precision,omitempty"`
	// Scale is the number of digits to the right of the decimal point (for decimal types).
	Scale *int `json:"scale,omitempty"`
	// Min is the minimum value for numeric fields (if any).
	Min *float64 `json:"min,omitempty"`
	// Max is the maximum value for numeric fields (if any).
	Max *float64 `json:"max,omitempty"`
	// DefaultValue is the default value for the field (if any).
	DefaultValue *float64 `json:"defaultValue,omitempty"`
}

NumericFieldOptions contains additional options for numeric fields. Note that not all providers will support all options. This is a best-effort attempt to create a common schema for numeric field options across providers.

In the event that a provider doesn't support a particular option, and assuming that the option has a value, then the value should be ignored, and a warning should be added to the UpsertMetadataResult.

type OAuthOption

type OAuthOption func(*oauthClientParams)

func WithOAuthClient

func WithOAuthClient(client *http.Client) OAuthOption

WithOAuthClient sets the http client to use for the connector. Its usage is optional.

func WithOAuthConfig

func WithOAuthConfig(config *oauth2.Config) OAuthOption

WithOAuthConfig sets the oauth config to use for the connector. It's required, unless a token source is provided.

func WithOAuthDebug

func WithOAuthDebug(f func(req *http.Request, rsp *http.Response)) OAuthOption

WithOAuthDebug sets a debug function to be called on every request and response, after the response has been received from the downstream API.

func WithOAuthIsUnauthorizedHandler

func WithOAuthIsUnauthorizedHandler(
	f func(rsp *http.Response) (bool, error),
) OAuthOption

WithOAuthIsUnauthorizedHandler sets the function to call whenever the response is unauthorized (not necessarily 401). This is useful for handling the case where the server has invalidated the token, and the client needs to forcefully refresh. It's optional.

func WithOAuthToken

func WithOAuthToken(token *oauth2.Token) OAuthOption

WithOAuthToken sets the oauth token to use for the connector. It's required, unless a token source is provided.

func WithOAuthUnauthorizedHandler

func WithOAuthUnauthorizedHandler(
	f func(token *oauth2.Token, req *http.Request, rsp *http.Response) (*http.Response, error),
) OAuthOption

WithOAuthUnauthorizedHandler sets the function to call whenever the response is 401 unauthorized. This is useful for handling the case where the server has invalidated the token, and the client needs to forcefully refresh. It's optional.

func WithTokenHeaderAttachment

func WithTokenHeaderAttachment(tokenHeader *TokenHeaderAttachment) OAuthOption

WithTokenHeaderAttachment configures the HTTP header used to attach the OAuth 2.0 access token to outbound API requests.

func WithTokenSource

func WithTokenSource(tokenSource oauth2.TokenSource) OAuthOption

WithTokenSource sets the oauth token source to use for the connector. Whenever the token expires, this will be called to refresh it.

func WithTokenUpdated

func WithTokenUpdated(onTokenUpdated func(oldToken, newToken *oauth2.Token) error) OAuthOption

WithTokenUpdated this is useful for persisting the refreshed tokens somewhere, so that it can be used later. It's optional.

type ObjectEvents

type ObjectEvents struct {
	// ["create", "update", "delete"] our regular CRUD operation events
	// we translate to provider-specific names contact.creation
	Events SubscriptionEventTypes
	// ["email", "fax"] fields to watch for an update subscription
	WatchFields []string
	// true if all fields should be watched for an update subscription
	// this is provider specific, and not all providers support this.
	WatchFieldsAll bool
	// any non CRUD operations with provider specific event names
	// eg)  ["contact.merged"] for hubspot or ["jira_issue:restored", "jira_issue:archived"] for jira.
	PassThroughEvents []string
}

func (ObjectEvents) Equals

func (o ObjectEvents) Equals(other ObjectEvents) bool

Equals checks if two ObjectEvents configurations are identical. All fields must match: WatchFieldsAll, Events, WatchFields, and PassThroughEvents.

type ObjectMetadata

type ObjectMetadata struct {
	// Provider's display name for the object.
	DisplayName string

	// Fields is a map of field names to FieldMetadata.
	// Some legacy connectors do not populate this, but only populates FieldsMap.
	Fields FieldsMetadata

	// Deprecated: for new connectors, please only populate and read `ObjectMetadata.Fields`.
	// FieldsMap is a map of field names to field display names.
	// TODO: Remove this field once all connectors populate Fields.
	FieldsMap map[string]string
}

func NewObjectMetadata

func NewObjectMetadata(displayName string, fields FieldsMetadata) *ObjectMetadata

NewObjectMetadata constructs ObjectMetadata. This will automatically infer fields map from field metadata map. This construct exists for such convenience.

func (*ObjectMetadata) AddFieldMetadata

func (m *ObjectMetadata) AddFieldMetadata(fieldName string, fieldMetadata FieldMetadata)

AddFieldMetadata updates Fields and FieldsMap fields ensuring data consistency.

func (*ObjectMetadata) RemoveFieldMetadata

func (m *ObjectMetadata) RemoveFieldMetadata(fieldName string)

type ObjectName

type ObjectName string

func (ObjectName) String

func (n ObjectName) String() string

type PostAuthInfo

type PostAuthInfo struct {
	CatalogVars          *map[string]string
	RawResponse          *JSONHTTPResponse
	ProviderWorkspaceRef string
}

type PrintablePayload

type PrintablePayload struct {
	Base64          bool   `json:"base64,omitempty"`
	Content         string `json:"content"`
	Length          int64  `json:"length"`
	TruncatedLength int64  `json:"truncatedLength,omitempty"`
}

PrintablePayload represents a payload that can be printed or displayed. It contains the content, its length, and whether it is base64 encoded. It also includes a truncated length for cases where the content is too large.

func PrintableRequest

func PrintableRequest(req *http.Request, body []byte) (*PrintablePayload, error)

PrintableRequest creates a PrintablePayload from an HTTP request. The body parameter can be nil, in which case it will read the request body.

func PrintableResponse

func PrintableResponse(resp *http.Response, body []byte) (*PrintablePayload, error)

PrintableResponse creates a PrintablePayload from an HTTP response. The body parameter can be nil, in which case it will read the response body.

func (*PrintablePayload) Clone

func (p *PrintablePayload) Clone() *PrintablePayload

func (*PrintablePayload) GetContent

func (p *PrintablePayload) GetContent() string

func (*PrintablePayload) GetContentBytes

func (p *PrintablePayload) GetContentBytes() ([]byte, error)

func (*PrintablePayload) GetLength

func (p *PrintablePayload) GetLength() int64

func (*PrintablePayload) GetTruncatedLength

func (p *PrintablePayload) GetTruncatedLength() int64

func (*PrintablePayload) IsBase64

func (p *PrintablePayload) IsBase64() bool

func (*PrintablePayload) IsEmpty

func (p *PrintablePayload) IsEmpty() bool

func (*PrintablePayload) IsJSON

func (p *PrintablePayload) IsJSON() (bool, error)

func (*PrintablePayload) IsTruncated

func (p *PrintablePayload) IsTruncated() bool

func (*PrintablePayload) LogValue

func (p *PrintablePayload) LogValue() slog.Value

func (*PrintablePayload) String

func (p *PrintablePayload) String() string

func (*PrintablePayload) Truncate

func (p *PrintablePayload) Truncate(size int64) (*PrintablePayload, error)

type ProviderReadResponseType

type ProviderReadResponseType interface {
	map[string]any | *ajson.Node
}

ProviderReadResponseType defines the types of records that ParseResult can process. It determines which callback function is used for parsing.

type QueryParam

type QueryParam struct {
	Key   string         `json:"key"`
	Value string         `json:"value"`
	Mode  QueryParamMode `json:"mode"`
}

func (QueryParam) ApplyToRequest

func (q QueryParam) ApplyToRequest(vals *url.Values)

func (QueryParam) String

func (q QueryParam) String() string

type QueryParamAuthClientOption

type QueryParamAuthClientOption func(params *queryParamClientParams)

func WithQueryParamClient

func WithQueryParamClient(client *http.Client) QueryParamAuthClientOption

WithQueryParamClient sets the http client to use for the connector. Its usage is optional.

func WithQueryParamDebug

func WithQueryParamDebug(f func(req *http.Request, rsp *http.Response)) QueryParamAuthClientOption

WithQueryParamDebug sets a debug function to be called on every request and response, after the response has been received from the downstream API.

func WithQueryParamIsUnauthorizedHandler

func WithQueryParamIsUnauthorizedHandler(
	f func(rsp *http.Response) (bool, error),
) QueryParamAuthClientOption

WithQueryParamIsUnauthorizedHandler sets the function to call whenever the response is unauthorized (not necessarily 401). This is useful for handling the case where the server has invalidated the token, and the client needs to forcefully refresh. It's optional.

func WithQueryParamUnauthorizedHandler

func WithQueryParamUnauthorizedHandler(
	f func(params []QueryParam, req *http.Request, rsp *http.Response) (*http.Response, error),
) QueryParamAuthClientOption

WithQueryParamUnauthorizedHandler sets the function to call whenever the response is 401 unauthorized. This is useful for handling the case where the server has invalidated the credentials, and the client needs to refresh. It's optional.

func WithQueryParams

func WithQueryParams(ps ...QueryParam) QueryParamAuthClientOption

type QueryParamMode

type QueryParamMode int

QueryParamMode determines how the query param should be applied to the request.

type QueryParams

type QueryParams []QueryParam

func (QueryParams) ApplyToRequest

func (q QueryParams) ApplyToRequest(req *http.Request)

func (QueryParams) Has

func (q QueryParams) Has(target QueryParam) bool

type ReadParams

type ReadParams struct {
	// The name of the object we are reading, e.g. "Account"
	ObjectName string // required

	// The fields we are reading from the object, e.g. ["Id", "Name", "BillingCity"]
	Fields datautils.StringSet // required, at least one field needed

	// NextPage is an opaque token that can be used to get the next page of results.
	NextPage NextPageToken // optional, only set this if you want to read the next page of results

	// Since is an optional timestamp to fetch only records updated **after** this time.
	// Used for incremental reads.
	Since time.Time

	// Until is an optional timestamp to fetch only records updated **up to and including** this time.
	// Pagination stops when records exceed this timestamp.
	Until time.Time

	// Deleted is true if we want to read deleted records instead of active records.
	Deleted bool // optional, defaults to false

	// Filter defines the filtering criteria for supported connectors.
	// It is optional and behaves differently depending on the connector:
	//	* Salesforce: It is a SOQL string that comes after the WHERE clause which will be used to filter the records.
	//		Reference: https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql.htm
	//	* Klaviyo: Comma separated methods following JSON:API filtering syntax.
	//		Note: timing is already handled by Since argument.
	//		Reference: https://developers.klaviyo.com/en/docs/filtering_
	//	* Marketo: Comma-separated activityTypeIds for filtering lead activities.
	//		Note: Only supported when reading Lead Activities (not other endpoints).
	//		Example: "1,6,12" (for visitWebpage, fillOutForm, emailClicked)
	//		Reference: https://developer.adobe.com/marketo-apis/api/mapi/#tag/Activities
	//  * GetResponse: An ampersand-style filter string that maps directly to GetResponse's
	//      bracket-notation query parameters. Supports both `query[...]` and `sort[...]`.
	//      Multiple filters can be separated by '&'.
	//      Examples:
	//          - "query[name]=campaign_name"
	//          - "query[isDefault]=true"
	//          - "sort[name]=ASC"
	//          - "sort[createdOn]=DESC"
	//          - "query[name]=test&sort[createdOn]=DESC"
	//      Reference: https://apireference.getresponse.com/#operation/getCampaignList
	Filter string // optional

	// BuilderFilter is an optional Ampersand-style structured filter for read actions.
	// Multiple field filters are joined by AND. Only the "eq" operator is supported.
	BuilderFilter *SearchFilter // optional

	// AssociatedObjects specifies a list of related objects to fetch along with the main object.
	// It is optional and supported by the following connectors:
	//	* HubSpot: Supported in Read operation, but not Search.
	//	* Stripe: Only nested objects can be expanded. Specify a dot-separated path
	//		to the property to fetch and expand those objects.
	//		Reference: https://docs.stripe.com/expand#how-it-works
	//	* Capsule: Embeds objects in response.
	//		Reference: https://developer.capsulecrm.com/v2/overview/reading-from-the-api
	AssociatedObjects []string // optional

	// PageSize specifies the # of records to request when making a read request.
	PageSize int // optional

	// Additional options for the read operation that the connector may support.
	// This optional map is used for bespoke connector-specific parameters.
	Opts ReadParamsOpts // optional
}

ReadParams defines how we are reading data from a SaaS API.

func (ReadParams) IsFirstPage

func (p ReadParams) IsFirstPage() bool

func (ReadParams) ValidateParams

func (p ReadParams) ValidateParams(withRequiredFields bool) error

type ReadParamsOpts

type ReadParamsOpts any

Each connector that supports ReadParams.Opts should define its own type and assert it. e.g. gong.ReadParamOpts.

type ReadResult

type ReadResult struct {
	// Rows is the number of total rows in the result.
	Rows int64 `json:"rows"`
	// Data is an array where each element represents a ReadResultRow.
	Data []ReadResultRow `json:"data"`
	// NextPage is an opaque token that can be used to get the next page of results.
	NextPage NextPageToken `json:"nextPage,omitempty"`
	// Done is true if there are no more pages to read.
	Done bool `json:"done,omitempty"`
}

ReadResult is what's returned from reading data via the Read call.

func ParseResult

func ParseResult[R ProviderReadResponseType](
	resp *JSONHTTPResponse,
	extractRecords func(*ajson.Node) ([]R, error),
	extractNextPage func(*ajson.Node) (string, error),
	marshalFunc func([]R, []string) ([]ReadResultRow, error),
	fields datautils.Set[string],
) (*ReadResult, error)

ParseResult parses the response from a provider into a ReadResult. A 2xx return type is assumed. The sizeFunc returns the total number of records in the response. The extractRecords returns the records in the response. The extractNextPage returns the URL for the next page of results. The marshalFunc is used to structure the data into an array of ReadResultRows. The fields are used to populate ReadResultRow.Fields.

func ParseResultFiltered

func ParseResultFiltered(
	params ReadParams,
	resp *JSONHTTPResponse,
	extractRecords func(*ajson.Node) ([]*ajson.Node, error),
	filterRecords func(ReadParams, *ajson.Node, []*ajson.Node) ([]*ajson.Node, string, error),
	marshalFunc func([]*ajson.Node, []string) ([]ReadResultRow, error),
	fields datautils.Set[string],
) (*ReadResult, error)

ParseResultFiltered parses the response from a provider into a ReadResult. A 2xx return type is assumed. The sizeFunc returns the total number of records in the response. The extractRecords returns the records in the response. The filterRecords acts as a sieve based on ReadParams since and until properties. The marshalFunc is used to structure the data into an array of ReadResultRows. The fields are used to populate ReadResultRow.Fields.

type ReadResultRow

type ReadResultRow struct {
	// Fields is a map of requested provider field names to values.
	// All field names are in lowercase (eg: accountid, name, billingcityid)
	Fields map[string]any `json:"fields"`
	// Associations is a map of associated objects to the main object.
	// The key is the associated object name, and the value is an array of associated object ids.
	Associations map[string][]Association `json:"associations,omitempty"`
	// Raw is the raw JSON response from the provider.
	Raw map[string]any `json:"raw"`
	// RecordId is the ID of the record.
	Id string `json:"id,omitempty"`
}

ReadResultRow is a single row of data returned from a Read call, which contains the requested fields, as well as the raw JSON response from the provider.

func GetMarshaledData deprecated

func GetMarshaledData(records []map[string]any, fields []string) ([]ReadResultRow, error)

GetMarshaledData converts records into ReadResultRow slices without populating the Id field.

Deprecated: For new connectors, prefer readhelper.MakeGetMarshaledDataWithId to ensure the ReadResultRow.Id field is properly populated.

type Record

type Record map[string]any

type RecordCountParams

type RecordCountParams struct {
	// ObjectName is the name of the object to count records for.
	ObjectName string

	// SinceTimestamp is an optional timestamp to count only records updated after this time.
	SinceTimestamp *time.Time

	// UntilTimestamp is an optional timestamp to count only records updated up to this time.
	UntilTimestamp *time.Time
}

RecordCountParams contains parameters for getting record counts.

type RecordCountResult

type RecordCountResult struct {
	// Count is the number of records matching the query.
	Count int
}

RecordCountResult contains the result of a record count operation.

type RecordTransformer

type RecordTransformer func(node *ajson.Node) (map[string]any, error)

RecordTransformer is a function that processes a JSON node and transforms it into a map representation, potentially applying structural modifications.

Common use cases include: - Flattening nested objects (see FlattenNestedFields) - Filtering out unwanted fields - Converting field formats - Renaming fields - Adding computed fields

Example usage: - FlattenNestedFields("attributes") - Replacing GUIDs with human-readable fields - Enhancing fields with custom data from the API response. - Adding a relationships property to the root level from a nested object.

func FlattenNestedFields

func FlattenNestedFields(nestedKey string) RecordTransformer

FlattenNestedFields returns a procedure which copies fields of a nested object to the top level.

Ex: Every object has special field "attributes" which holds all the object specific fields. Therefore, nested "attributes" will be removed and fields will be moved to the top level of the object.

Example accounts(shortened response):

 "data": [
    {
        "type": "",
        "id": "",
        "attributes": {
            "test_account": false,
            "contact_information": {},
            "locale": ""
        },
        "links": {}
    }
],

The resulting fields for the above will be: [ type, id, test_account, contact_information, locale, links ].

type RecordsFilterFunc

type RecordsFilterFunc func(ReadParams, *ajson.Node, []*ajson.Node) ([]*ajson.Node, string, error)

RecordsFilterFunc filters records based on ReadParams (e.g., Since/Until ranges). It returns:

  • A filtered slice of records
  • A next page token (which may be empty if no more records are available using deduction)
  • An error, if filtering fails

type RecordsFunc

type RecordsFunc func(*ajson.Node) ([]map[string]any, error)

RecordsFunc extracts a list of records as map[string]any from the response body.

func ExtractOptionalRecordsFromPath

func ExtractOptionalRecordsFromPath(jsonPath string, nestedPath ...string) RecordsFunc

func ExtractRecordsFromPath

func ExtractRecordsFromPath(jsonPath string, nestedPath ...string) RecordsFunc

type RegistrationResult

type RegistrationResult struct {
	RegistrationRef string
	Result          any // struct depends on the provider
	Status          RegistrationStatus
}

type RegistrationStatus

type RegistrationStatus string
const (
	// RegistrationStatusPending registration is pending and not yet complete.
	RegistrationStatusPending RegistrationStatus = "pending"
	// RegistrationStatusFailed registration returned error, and all intermittent steps are rolled back.
	RegistrationStatusFailed RegistrationStatus = "failed"
	// RegistrationStatusSuccess successful registration.
	RegistrationStatusSuccess RegistrationStatus = "success"
	// RegistrationStatusFailedToRollback registration returned error, and failed to rollback some intermittent steps.
	RegistrationStatusFailedToRollback RegistrationStatus = "failed_to_rollback"
)

type RequestModifier

type RequestModifier func(req *http.Request)

type RequireAuthenticatedClient

type RequireAuthenticatedClient struct{}

type RequireCustomAuthenticatedClient

type RequireCustomAuthenticatedClient struct{}

type RequireMetadata

type RequireMetadata struct {
	ExpectedMetadataKeys []string
}

RequireMetadata defines required metadata for validation. Metadata keys are case-insensitive.

type RequireModule

type RequireModule struct {
	ExpectedModules []ModuleID
}

type RequireWorkspace

type RequireWorkspace struct{}

type ResponseHandler

type ResponseHandler func(rsp *http.Response) (*http.Response, error)

type SearchFilter

type SearchFilter struct {
	// multiple filters are joined by `and` by default.
	FieldFilters []FieldFilter `json:"fieldFilters" validate:"required,dive"`
}

func (SearchFilter) FilterBy

func (s SearchFilter) FilterBy(fieldName string, operator FilterOperator, value any) SearchFilter

FilterBy returns a new SearchFilter with an additional FieldFilter appended.

The receiver is treated as immutable: FilterBy does not modify the original SearchFilter. Instead, it creates a copy of the underlying FieldFilters slice before appending the new filter. This avoids slice aliasing and allows safe chaining of FilterBy calls without unintended side effects.

Example:

filter := SearchFilter{}.
	FilterBy("status", Eq, "active").
	FilterBy("age", Gt, 18)

type SearchParams

type SearchParams struct {
	ObjectName string `json:"objectName" validate:"required"`

	// Fields to return in the search result.
	Fields   datautils.StringSet `json:"fields"             validate:"required"`
	Filter   SearchFilter        `json:"filter"             validate:"required"`
	NextPage NextPageToken       `json:"nextPage,omitempty"`

	// Page Limit for the search. If omitted, return provider's default limit.
	Limit int64 `json:"limit,omitempty"`

	// AssociatedObjects specifies a list of related objects to fetch along with the main object.
	// Optional.
	AssociatedObjects []string `json:"associatedObjects,omitempty"`
}

func (SearchParams) ValidateParams

func (p SearchParams) ValidateParams(withRequiredFields bool) error

type SearchResult

type SearchResult = ReadResult

type ShouldHandleError

type ShouldHandleError func(response *http.Response) bool

ShouldHandleError determines whether the default or custom ErrorHandler should be invoked for a given HTTP response. Returning true indicates that the response represents an error that requires handling.

type StringFieldOptions

type StringFieldOptions struct {
	// Length is the maximum length of the string field.
	Length *int `json:"length,omitempty"`
	// Pattern is a regex pattern that the string field value must match (if any).
	Pattern string `json:"pattern,omitempty"`
	// Values is a list of allowed values for enum fields (if any).
	Values []string `json:"values,omitempty"`
	// ValuesRestricted indicates if the field value must be limited to what's in Values.
	ValuesRestricted bool `json:"valuesRestricted,omitempty"`
	// DefaultValue is the default value for the field (if any).
	DefaultValue *string `json:"defaultValue,omitempty"`
	// NumDisplayLines defines how many lines of text are shown in the UI.
	// If the text exceeds this number, it will be truncated.
	NumDisplayLines *int `json:"lines,omitempty"`
}

StringFieldOptions contains additional options for string fields. Note that not all providers will support all options. This is a best-effort attempt to create a common schema for string field options across providers.

In the event that a provider doesn't support a particular option, and assuming that the option has a value, then the value should be ignored, and a warning should be added to the UpsertMetadataResult.

type StringMap

type StringMap map[string]any

func ToStringMap

func ToStringMap(m map[string]any) StringMap

func (StringMap) AsFloat

func (m StringMap) AsFloat(key string) (float64, error)

AsFloat is a helper function that extracts a float from the map. This function will convert number values such as int, uint, and float to float64. By doing so, it may lose precision for large numbers. This is helpful when you are not sure about the type of the number.

func (StringMap) AsInt

func (m StringMap) AsInt(key string) (int64, error)

AsInt is a helper function that extracts an integer from the map. This function will convert number values such as int, uint, and float to int64. By doing so, it may lose precision for large numbers. This is helpful when you are not sure about the type of the number.

func (StringMap) Get

func (m StringMap) Get(key string) (any, error)

func (StringMap) GetBool

func (m StringMap) GetBool(key string) (bool, error)

func (StringMap) GetCaseInsensitive

func (m StringMap) GetCaseInsensitive(key string) (any, bool)

func (StringMap) GetFloat

func (m StringMap) GetFloat(key string) (float64, error)

GetFloat extracts a float from the map.

func (StringMap) GetInt

func (m StringMap) GetInt(key string) (int64, error)

GetInt extracts an integer from the map.

func (StringMap) GetNumber

func (m StringMap) GetNumber(key string) (float64, error)

func (StringMap) GetString

func (m StringMap) GetString(key string) (string, error)

func (StringMap) Has

func (m StringMap) Has(key string) bool

func (StringMap) Keys

func (m StringMap) Keys() []string

func (StringMap) Len

func (m StringMap) Len() int

func (StringMap) Values

func (m StringMap) Values() []any

type SubscribeParams

type SubscribeParams struct {
	// Request contains provider-specific parameters that are unique to each subscription.
	// These parameters can be either optional or required depending on the provider's API requirements.
	// Each provider defines its own request structure (e.g., webhook URL, secret, unique reference, etc.)
	// that must be provided when creating subscriptions. The structure is provider-specific and should
	// match the provider's expected request format for subscription operations.
	Request any
	// RegistrationResult is the result of the Connector.Register call.
	// Connector.Subscribe requires information from the registration.
	// Not all providers require registration, so this is optional.
	// eg) Salesforce and HubSpot require registration because
	RegistrationResult *RegistrationResult
	// SubscriptionEvents is a normalized view representing the exact subscription state
	// that should be maintained in the provider's system. This field specifies which
	// objects and events the caller wants to subscribe to, using a provider-agnostic
	// format. Connector.Subscribe method will translate these normalized events to its own event
	// naming conventions when creating subscriptions. This represents the desired
	// state, which may differ from the actual state returned in SubscriptionResult.ObjectEvents
	// if some subscription operations fail or are rolled back.
	SubscriptionEvents map[ObjectName]ObjectEvents
}

func (SubscribeParams) ValidateParams

func (p SubscribeParams) ValidateParams() error

type SubscriptionEvent

type SubscriptionEvent interface {
	Event

	EventType() (SubscriptionEventType, error)
	RawEventName() (string, error)
	ObjectName() (string, error)
	Workspace() (string, error)
	RecordId() (string, error)
	EventTimeStampNano() (int64, error)

	// PreLoadData is used to preload data into the subscription event.
	// Assume that the data will include the entire request body in case it is needed for the event processing.
	// This method will be called for every event as the first step in the event processing.
	PreLoadData(data *SubscriptionEventPreLoadData) error
}

SubscriptionEvent is an interface for webhook events coming from the provider. This interface defines methods to extract information from the webhook event.

type SubscriptionEventPreLoadData

type SubscriptionEventPreLoadData struct {
	RequestHeaders *http.Header
}

type SubscriptionEventType

type SubscriptionEventType string
const (
	SubscriptionEventTypeCreate            SubscriptionEventType = "create"
	SubscriptionEventTypeUpdate            SubscriptionEventType = "update"
	SubscriptionEventTypeDelete            SubscriptionEventType = "delete"
	SubscriptionEventTypeAssociationUpdate SubscriptionEventType = "associationUpdate"
	SubscriptionEventTypeOther             SubscriptionEventType = "other"
)

type SubscriptionEventTypes

type SubscriptionEventTypes []SubscriptionEventType

SubscriptionEventTypes is a list of subscription event types representing the operations to subscribe to.

func (SubscriptionEventTypes) Equals

func (t SubscriptionEventTypes) Equals(otherTypes SubscriptionEventTypes) bool

Equals checks if two SubscriptionEventTypes lists contain the same event types. The comparison is order-independent.

type SubscriptionEventWithRecord

type SubscriptionEventWithRecord interface {
	SubscriptionEvent

	// Record returns the single record carried inline in the webhook payload as a
	// ReadResultRow, marshaled the same way a read returns it: Raw holds the full
	// provider record and Fields holds the requested subset (lowercased), selected
	// from the given fields. This lets callers map the inline record exactly like a
	// fetched read, without a GetRecordsByIds call.
	Record(fields []string) (ReadResultRow, error)
}

SubscriptionEventWithRecord is an optional interface implemented by providers whose webhook payload already carries the full provider record inline (e.g. ConnectWise ships it as the "Entity" field). When implemented, the record can be field-mapped downstream without a separate GetRecordsByIds fetch.

type SubscriptionRegistrationParams

type SubscriptionRegistrationParams struct {
	Request any `json:"request" validate:"required"`
}

type SubscriptionResult

type SubscriptionResult struct {
	// Result contains the provider's original response data in its raw form.
	// This field preserves the complete, unmodified response from the provider's API,
	// allowing callers to access all original metadata, IDs, timestamps, and other
	// provider-specific information that may not be represented in the transformed ObjectEvents.
	// The structure of Result is provider-specific and should match the provider's actual API response format.
	Result any
	// ObjectEvents represents the transformed view of the subscription state after the operation.
	// This field contains a normalized, provider-agnostic representation of which objects and events
	// are currently subscribed in the provider's system. It reflects the exact state after
	// creating, updating, or deleting subscriptions, and may differ from the requested subscriptions
	// if some operations failed or were rolled back. This transformed view is useful for tracking
	// the actual subscription state without needing to parse provider-specific response formats.
	ObjectEvents map[ObjectName]ObjectEvents
	Status       SubscriptionStatus

	// Below fields are soon to be DEPRECATED, and will be removed in a future release.
	// Use ObjectEvents instead.
	Objects []ObjectName
	Events  []SubscriptionEventType
	// ["create", "update", "delete"]
	// our regular CRUD operation events we translate to provider-specific names contact.creation
	UpdateFields []string
	// ["email", "fax"]
	PassThroughEvents []string
}

func (SubscriptionResult) ObjectNames

func (r SubscriptionResult) ObjectNames() []ObjectName

type SubscriptionStatus

type SubscriptionStatus string
const (
	// SubscriptionStatusPending registration is pending and not yet complete.
	SubscriptionStatusPending SubscriptionStatus = "pending"
	// SubscriptionStatusFailed registration returned error, and all intermittent steps are rolled back.
	SubscriptionStatusFailed SubscriptionStatus = "failed"
	// SubscriptionStatusSuccess successful registration.
	SubscriptionStatusSuccess SubscriptionStatus = "success"
	// SubscriptionStatusFailedToRollback registration returned error, and failed to rollback some intermittent steps.
	SubscriptionStatusFailedToRollback SubscriptionStatus = "failed_to_rollback"
)

func (SubscriptionStatus) Resolve

Resolve combines multiple subscription statuses and returns the most severe status. The priority order (from worst to best) is:

  1. failed_to_rollback (worst - error occurred AND cleanup failed)
  2. failed (error occurred but cleanup succeeded)
  3. pending (registration in progress)
  4. success (best - registration completed successfully)

If any status in the input is failed_to_rollback, the result is failed_to_rollback. If any status is failed (and no failed_to_rollback), the result is failed. If all statuses are pending, the result is pending. Only if all statuses are success, the result is success.

Parameters:

  • others: One or more additional subscription statuses to merge with the current status

Returns:

  • The most severe status among all inputs

Example:

status := SubscriptionStatusSuccess
status.Merge(SubscriptionStatusSuccess, SubscriptionStatusFailed) // returns SubscriptionStatusFailed

type SubscriptionUpdateEvent

type SubscriptionUpdateEvent interface {
	SubscriptionEvent

	// UpdatedFields returns the fields that were updated in the event.
	UpdatedFields() ([]string, error)
}

type TokenHeaderAttachment

type TokenHeaderAttachment struct {
	Name   string
	Prefix string
}

TokenHeaderAttachment defines an HTTP header channel used to convey an access token in outbound API requests.

The access token is attached by setting the specified header name to the token value, optionally prefixed with a static string (for example, "Bearer " or "Token ").

This attachment is typically used for providers that require access tokens to be supplied through custom HTTP headers rather than the standard OAuth 2.0 Authorization header.

type TokenSourceWithContext

type TokenSourceWithContext interface {
	oauth2.TokenSource

	// TokenWithContext returns a token or an error.
	// Token must be safe for concurrent use by multiple goroutines.
	// The returned Token must not be modified.
	// Similar semantics to oauth2.TokenSource, but with a context.
	TokenWithContext(ctx context.Context) (*oauth2.Token, error)
}

TokenSourceWithContext is an interface that extends the oauth2.TokenSource interface with a context. This is useful for token sources that need to be aware of the context in which they are being called. The use of this interface is optional, but if the token source conforms to it, then the context version of the Token method will be called instead of the normal one.

type UpsertMetadataAction

type UpsertMetadataAction string

UpsertMetadataAction represents the action taken during an upsert operation.

const (
	// UpsertMetadataActionCreate indicates that the object/field was created.
	UpsertMetadataActionCreate UpsertMetadataAction = "create"
	// UpsertMetadataActionUpdate indicates that the object/field was updated.
	UpsertMetadataActionUpdate UpsertMetadataAction = "update"
	// UpsertMetadataActionNone indicates that the object/field was not changed.
	UpsertMetadataActionNone UpsertMetadataAction = "none"
)

func (UpsertMetadataAction) IsValid

func (a UpsertMetadataAction) IsValid() bool

IsValid checks if the UpsertMetadataAction is known.

type UpsertMetadataParams

type UpsertMetadataParams struct {
	// Maps object names to field definitions.
	Fields map[string][]FieldDefinition `json:"fields"`
}

UpsertMetadataParams represents parameters for upserting metadata.

func (*UpsertMetadataParams) ValidateParams

func (p *UpsertMetadataParams) ValidateParams() error

type UpsertMetadataResult

type UpsertMetadataResult struct {
	// Indicates if the upsert operation was successful.
	Success bool `json:"success"`

	// Maps object name -> field name -> upsert result.
	Fields map[string]map[string]FieldUpsertResult `json:"fields"`
}

UpsertMetadataResult contains results for all created/updated objects and fields.

type ValueType

type ValueType string

func InferValueTypeFromData

func InferValueTypeFromData(value any) ValueType

type VerificationParams

type VerificationParams struct {
	Param any
}

VerificationParams is a struct that contains the parameters specific to the provider.

type WebhookRequest

type WebhookRequest struct {
	Headers http.Header
	Body    []byte
	URL     string
	Method  string
}

WebhookRequest is a struct that contains the request parameters for a webhook.

type WriteHeader

type WriteHeader struct {
	Key   string
	Value string
}

type WriteMethod

type WriteMethod func(context.Context, string, any, ...Header) (*JSONHTTPResponse, error)

WriteMethod is signature for any HTTP method that performs write modifications. Ex: Post/Put/Patch.

type WriteParams

type WriteParams struct {
	// The name of the object we are writing, e.g. "Account"
	ObjectName string // required

	// The external ID of the object instance we are updating. Provided in the case of UPDATE, but not CREATE.
	RecordId string // optional

	// RecordData is a JSON node representing the record of data we want to insert in the case of CREATE
	// or fields of data we want to modify in case of an update
	RecordData any // required

	// Associations contains associations between the object and other objects.
	Associations any // optional

	Headers []WriteHeader // optional
}

WriteParams defines how we are writing data to a SaaS API.

func (WriteParams) GetRecord

func (p WriteParams) GetRecord() (Record, error)

GetRecord converts WriteParams.RecordData into a map-based Record.

If RecordData is already a map[string]any, it is returned directly. Otherwise, the value is serialized to JSON and deserialized back into a map.

func (WriteParams) GetRecordReader

func (p WriteParams) GetRecordReader() (*bytes.Reader, error)

func (WriteParams) IsCreate

func (p WriteParams) IsCreate() bool

IsCreate reports whether the Write is creating a new record.

Write is considered a Create when no record identifier is provided. Callers should prefer IsCreate over negating IsUpdate for clarity.

func (WriteParams) IsUpdate

func (p WriteParams) IsUpdate() bool

IsUpdate reports whether the write operation is an update rather than a Create.

Write is considered an update when a non-empty RecordId is provided. Callers should prefer IsUpdate over negating IsCreate for clarity.

func (WriteParams) ValidateParams

func (p WriteParams) ValidateParams() error

type WriteResult

type WriteResult struct {
	// Success is true if write succeeded.
	Success bool `json:"success"`
	// RecordId is the ID of the written record.
	RecordId string `json:"recordId,omitempty"` // optional
	// Errors is list of error record returned by the API.
	Errors []any `json:"errors,omitempty"` // optional
	// Data is a JSON node containing data about the properties that were updated.
	Data map[string]any `json:"data,omitempty"` // optional
}

WriteResult represents the outcome of a single record write operation.

type WriteType

type WriteType string

WriteType specifies the type of write operation (create, update, delete, upsert).

const (
	WriteTypeCreate WriteType = "create"
	WriteTypeUpdate WriteType = "update"
	WriteTypeDelete WriteType = "delete"
	WriteTypeUpsert WriteType = "upsert"
)

type XMLAttributes

type XMLAttributes struct {
	Key   string `json:"key"   validate:"required,excludesall=<>,excludesrune=<>"`
	Value string `json:"value" validate:"excludesall=<>,excludesrune=<>"`
}

func (*XMLAttributes) String

func (attr *XMLAttributes) String() string

func (*XMLAttributes) Validate

func (attr *XMLAttributes) Validate() error

type XMLData

type XMLData struct {
	XMLName     string           `json:"xmlName,omitempty"     validate:"required,excludesall=<>"`
	Attributes  []*XMLAttributes `json:"attributes,omitempty"`
	Children    []XMLSchema      `json:"children,omitempty"`
	SelfClosing bool             `json:"selfClosing,omitempty"`
}

func (*XMLData) String

func (x *XMLData) String() string

func (*XMLData) UnmarshalJSON

func (x *XMLData) UnmarshalJSON(b []byte) error

func (*XMLData) Validate

func (x *XMLData) Validate() error

type XMLHTTPClient

type XMLHTTPClient struct {
	HTTPClient         *HTTPClient        // underlying HTTP client. Required.
	ErrorPostProcessor ErrorPostProcessor // Errors returned from CRUD methods will go via this method. Optional.
}

XMLHTTPClient is an HTTP client that can parse XML response.

func (*XMLHTTPClient) Get

func (c *XMLHTTPClient) Get(ctx context.Context, url string, headers ...Header) (*XMLHTTPResponse, error)

Get makes a GET request to the given URL and returns the response body as a XML object. If the response is not a 2xx, an error is returned. If the response is a 401, the caller should refresh the access token and retry the request. If errorHandler is nil, then the default error handler is used. If not, the caller can inject their own error handling logic.

func (*XMLHTTPClient) Post

func (c *XMLHTTPClient) Post(ctx context.Context,
	url string, node *xquery.XML, headers ...Header,
) (*XMLHTTPResponse, error)

Post sends XML request and receives XML as a response.

type XMLHTTPResponse

type XMLHTTPResponse struct {

	// Code is the HTTP status code of the response.
	Code int

	// Headers are the HTTP headers of the response.
	Headers http.Header

	// Body is the unmarshalled response body in XML form. Content is the same as bodyBytes
	Body *xquery.XML
	// contains filtered or unexported fields
}

type XMLSchema

type XMLSchema interface {
	String() string
	Validate() error
}

type XMLString

type XMLString string

func (XMLString) String

func (str XMLString) String() string

func (XMLString) Validate

func (str XMLString) Validate() error

Directories

Path Synopsis
Package paramsbuilder provides common parameters used to initialize connectors.
Package paramsbuilder provides common parameters used to initialize connectors.
credscanning
Package credscanning is a wrapper for scanning package.
Package credscanning is a wrapper for scanning package.
Package subscriptionhelper provides utilities for categorizing object subscription events based on their existing and desired states.
Package subscriptionhelper provides utilities for categorizing object subscription events based on their existing and desired states.
Package try provides a Result type for error handling in Go.
Package try provides a Result type for error handling in Go.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL