Merge PostHog self-hosted into a single PostHog provider

Fold POSTHOG_SELF_HOSTED into POSTHOG: one provider now covers Cloud (OAuth + region-pinned API key) and self-hosted (API key + instance URL), since both already share the driver, name resolver, and PostHogConnectorSettings{BaseURL}. The API-key form picks a deployment (Cloud US/EU or self-hosted URL); the resolver requires exactly one of region/instanceUrl.

Drop the POSTHOG_SELF_HOSTED enum value, registration, migration, and logo mapping. Extract the deployment selector into a dedicated PostHogDeploymentField component. Point the driver tests at us.posthog.com instead of the legacy app.posthog.com host.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
This commit is contained in:
Aurélien Sibiril
2026-06-03 16:03:18 +02:00
parent 760f950a48
commit b4e6f73b78
13 changed files with 203 additions and 198 deletions

View File

@@ -43,6 +43,10 @@ import type { AddAccessSourceDialogCreateAPIKeyConnectorMutation } from "#/__gen
import type { AddAccessSourceDialogCreateClientCredentialsConnectorMutation } from "#/__generated__/core/AddAccessSourceDialogCreateClientCredentialsConnectorMutation.graphql"; import type { AddAccessSourceDialogCreateClientCredentialsConnectorMutation } from "#/__generated__/core/AddAccessSourceDialogCreateClientCredentialsConnectorMutation.graphql";
import { createAccessSourceMutation } from "./accessSourceMutations"; import { createAccessSourceMutation } from "./accessSourceMutations";
import {
isPostHogDeploymentSelected,
PostHogDeploymentField,
} from "./PostHogDeploymentField";
export const addAccessSourceDialogConnectorProviderInfoFragment = graphql` export const addAccessSourceDialogConnectorProviderInfoFragment = graphql`
fragment AddAccessSourceDialogConnectorProviderInfoFragment on ConnectorProviderInfo @relay(plural: true) { fragment AddAccessSourceDialogConnectorProviderInfoFragment on ConnectorProviderInfo @relay(plural: true) {
@@ -124,8 +128,6 @@ function mapAPIKeyExtraSettingToField(
break; break;
case "POSTHOG": case "POSTHOG":
if (settingKey === "region") return "posthogRegion"; if (settingKey === "region") return "posthogRegion";
break;
case "POSTHOG_SELF_HOSTED":
if (settingKey === "instanceUrl") return "posthogInstanceUrl"; if (settingKey === "instanceUrl") return "posthogInstanceUrl";
break; break;
} }
@@ -503,6 +505,43 @@ export function AddAccessSourceDialog({
); );
}; };
// PostHog renders a dedicated deployment selector (Cloud region or
// self-hosted URL); every other provider falls back to generic fields.
const renderAPIKeyExtraSettings = () => {
if (!activeProvider) {
return null;
}
if (activeProvider.provider === "POSTHOG") {
return (
<PostHogDeploymentField
values={extraSettingValues}
onChange={setExtraSettingValues}
/>
);
}
return activeProvider.extraSettings.map((setting) => {
const value = extraSettingValues[setting.key] ?? "";
return (
<Field
key={setting.key}
label={__(setting.label)}
value={value}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setExtraSettingValues(prev => ({ ...prev, [setting.key]: e.target.value }))}
required={setting.required}
/>
);
});
};
// PostHog's extra settings are individually optional (region OR instance
// URL), so the generic required-field check can't gate it.
const postHogAPIKeyValid
= activeProvider?.provider !== "POSTHOG"
|| isPostHogDeploymentSelected(extraSettingValues);
const apiKeyExtraSettingsValid = activeProvider const apiKeyExtraSettingsValid = activeProvider
? hasRequiredExtraSettings(activeProvider.extraSettings, extraSettingValues) ? hasRequiredExtraSettings(activeProvider.extraSettings, extraSettingValues)
: true; : true;
@@ -586,40 +625,7 @@ export function AddAccessSourceDialog({
required required
autoFocus autoFocus
/> />
{activeProvider?.extraSettings.map((setting) => { {renderAPIKeyExtraSettings()}
const value = extraSettingValues[setting.key] ?? "";
const setValue = (next: string) =>
setExtraSettingValues(prev => ({ ...prev, [setting.key]: next }));
// The "region" setting is a fixed US/EU choice; every other
// extra setting is a free-text field.
if (setting.key === "region") {
return (
<div key={setting.key} className="space-y-1.5">
<label className="text-sm font-medium">{__(setting.label)}</label>
<Select
value={value}
onValueChange={setValue}
placeholder={__("Select a region")}
>
<Option value="US">{__("United States (US)")}</Option>
<Option value="EU">{__("Europe (EU)")}</Option>
</Select>
</div>
);
}
return (
<Field
key={setting.key}
label={__(setting.label)}
value={value}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setValue(e.target.value)}
required={setting.required}
/>
);
})}
</DialogContent> </DialogContent>
<DialogFooter> <DialogFooter>
<Button <Button
@@ -628,6 +634,7 @@ export function AddAccessSourceDialog({
isConnectingAPIKey isConnectingAPIKey
|| !apiKeyValue.trim() || !apiKeyValue.trim()
|| !apiKeyExtraSettingsValid || !apiKeyExtraSettingsValid
|| !postHogAPIKeyValid
} }
> >
{isConnectingAPIKey ? __("Connecting...") : __("Connect")} {isConnectingAPIKey ? __("Connecting...") : __("Connect")}

View File

@@ -0,0 +1,79 @@
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import { useTranslate } from "@probo/i18n";
import { Field, Option, Select } from "@probo/ui";
// PostHog is a single provider spanning Cloud (region us/eu) and self-hosted
// (instance URL). The API-key form surfaces this as one deployment choice;
// the two settings are mutually exclusive, so picking one clears the other.
type PostHogDeploymentFieldProps = {
values: Record<string, string>;
onChange: (values: Record<string, string>) => void;
};
export function PostHogDeploymentField({
values,
onChange,
}: PostHogDeploymentFieldProps) {
const { __ } = useTranslate();
const region = values.region ?? "";
let deployment = "";
if (region === "US" || region === "EU") {
deployment = region;
} else if ("instanceUrl" in values) {
deployment = "SELF_HOSTED";
}
return (
<>
<div className="space-y-1.5">
<label className="text-sm font-medium">{__("Deployment")}</label>
<Select
value={deployment}
onValueChange={(val: string) =>
onChange(val === "SELF_HOSTED" ? { instanceUrl: "" } : { region: val })}
placeholder={__("Select a deployment")}
>
<Option value="US">{__("PostHog Cloud (US)")}</Option>
<Option value="EU">{__("PostHog Cloud (EU)")}</Option>
<Option value="SELF_HOSTED">{__("Self-hosted")}</Option>
</Select>
</div>
{deployment === "SELF_HOSTED" && (
<Field
label={__("Instance URL")}
value={values.instanceUrl ?? ""}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
onChange({ instanceUrl: e.target.value })}
required
/>
)}
</>
);
}
// isPostHogDeploymentSelected reports whether a valid PostHog deployment has
// been chosen: a Cloud region (us/eu) or a non-empty self-hosted instance URL.
export function isPostHogDeploymentSelected(
values: Record<string, string>,
): boolean {
return (
values.region === "US"
|| values.region === "EU"
|| !!values.instanceUrl?.trim()
);
}

View File

@@ -78,7 +78,6 @@ const thirdParties: Record<string, FC<ComponentProps<"svg">>> = {
OPENAI: OpenAI, OPENAI: OpenAI,
PAGERDUTY: PagerDuty, PAGERDUTY: PagerDuty,
POSTHOG: PostHog, POSTHOG: PostHog,
POSTHOG_SELF_HOSTED: PostHog,
RESEND: Resend, RESEND: Resend,
SENTRY: Sentry, SENTRY: Sentry,
SLACK: Slack, SLACK: Slack,

View File

@@ -34,7 +34,7 @@ func TestPostHogDriverListAccounts(t *testing.T) {
rec := newRecorder(t, "testdata/posthog", "POSTHOG_PERSONAL_API_KEY") rec := newRecorder(t, "testdata/posthog", "POSTHOG_PERSONAL_API_KEY")
client := newVCRClient(rec, bearerAuth(os.Getenv("POSTHOG_PERSONAL_API_KEY"))) client := newVCRClient(rec, bearerAuth(os.Getenv("POSTHOG_PERSONAL_API_KEY")))
records, err := NewPostHogDriver(client, "https://app.posthog.com").ListAccounts(context.Background()) records, err := NewPostHogDriver(client, "https://us.posthog.com").ListAccounts(context.Background())
require.NoError(t, err) require.NoError(t, err)
require.Len(t, records, 3) require.Len(t, records, 3)
@@ -165,7 +165,7 @@ func TestPostHogNameResolver(t *testing.T) {
client := &http.Client{Transport: &hostRewriter{target: srv.URL}} client := &http.Client{Transport: &hostRewriter{target: srv.URL}}
got, err := NewPostHogNameResolver(client, "https://app.posthog.com").ResolveInstanceName(context.Background()) got, err := NewPostHogNameResolver(client, "https://us.posthog.com").ResolveInstanceName(context.Background())
if tc.wantErr { if tc.wantErr {
require.Error(t, err) require.Error(t, err)
return return

View File

@@ -7,7 +7,7 @@ interactions:
proto_major: 1 proto_major: 1
proto_minor: 1 proto_minor: 1
content_length: 0 content_length: 0
host: app.posthog.com host: us.posthog.com
form: form:
limit: limit:
- "100" - "100"
@@ -16,7 +16,7 @@ interactions:
headers: headers:
Accept: Accept:
- application/json - application/json
url: https://app.posthog.com/api/organizations/@current/members/?limit=100&order=-joined_at url: https://us.posthog.com/api/organizations/@current/members/?limit=100&order=-joined_at
method: GET method: GET
response: response:
proto: HTTP/2.0 proto: HTTP/2.0

View File

@@ -46,7 +46,6 @@ func NewBuiltinRegistry() *Registry {
onePasswordRegistration(), onePasswordRegistration(),
openaiRegistration(), openaiRegistration(),
posthogRegistration(), posthogRegistration(),
posthogSelfHostedRegistration(),
pagerdutyRegistration(), pagerdutyRegistration(),
resendRegistration(), resendRegistration(),
sentryRegistration(), sentryRegistration(),

View File

@@ -24,13 +24,15 @@ import (
"go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/coredata"
) )
// posthogRegistration is PostHog Cloud (US + EU). OAuth is the preferred // posthogRegistration is PostHog — Cloud (US + EU) and self-hosted, under one
// path: oauth.posthog.com is PostHog's region-agnostic OAuth + API gateway, // provider. OAuth (CIMD public client) is the preferred path for Cloud: the
// so one app serves both regions and the driver reaches the customer's data // region-agnostic oauth.posthog.com gateway handles the handshake for both
// through it without a per-connection host. An API-key fallback is also // regions, after which the driver resolves the data region (us/eu) itself,
// supported, but personal API keys are region-pinned, so it requires the // since that gateway does not serve the data API. An API-key fallback covers
// customer to pick their region (us/eu). Self-hosted instances are a separate // both deployments: Cloud personal API keys are region-pinned (the customer
// provider (POSTHOG_SELF_HOSTED). // picks us/eu) and self-hosted connections carry an instance URL. Both store a
// single data-host BaseURL; cloud OAuth connections leave it empty for lazy
// region probing.
func posthogRegistration() *Registration { func posthogRegistration() *Registration {
return &Registration{ return &Registration{
Provider: coredata.ConnectorProviderPostHog, Provider: coredata.ConnectorProviderPostHog,
@@ -56,8 +58,13 @@ func posthogRegistration() *Registration {
// token surfaces on the first ListAccounts. // token surfaces on the first ListAccounts.
SupportsAPIKey: true, SupportsAPIKey: true,
// API-key connections are either PostHog Cloud (a region, us/eu) or
// self-hosted (an instance URL). The two are mutually exclusive, so
// neither is individually Required; apiKeyConnectorSettings enforces
// that exactly one is supplied.
ExtraSettings: []ExtraSetting{ ExtraSettings: []ExtraSetting{
{Key: "region", Label: "Region", Required: true}, {Key: "region", Label: "Region"},
{Key: "instanceUrl", Label: "Instance URL"},
}, },
NewDriver: func(_ context.Context, c *http.Client, conn *coredata.Connector, _ *log.Logger) (drivers.Driver, error) { NewDriver: func(_ context.Context, c *http.Client, conn *coredata.Connector, _ *log.Logger) (drivers.Driver, error) {

View File

@@ -1,71 +0,0 @@
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package provider
import (
"context"
"fmt"
"net/http"
"go.gearno.de/kit/log"
"go.probo.inc/probo/pkg/accessreview/drivers"
"go.probo.inc/probo/pkg/coredata"
)
// posthogSelfHostedRegistration is customer-hosted PostHog: API-key plus an
// operator-supplied instance URL (Metabase/Grafana style). It shares the
// PostHog driver and name resolver, pointed at the instance's BaseURL. OAuth
// is deliberately not offered here — a single static authorization URL cannot
// serve arbitrary per-customer instances, so self-hosted OAuth is a separate
// future effort. Cloud PostHog (POSTHOG) owns the OAuth path.
func posthogSelfHostedRegistration() *Registration {
return &Registration{
Provider: coredata.ConnectorProviderPostHogSelfHosted,
DisplayName: "PostHog (Self-Hosted)",
SupportsAPIKey: true,
ExtraSettings: []ExtraSetting{
{Key: "instanceUrl", Label: "Instance URL", Required: true},
},
NewDriver: func(_ context.Context, c *http.Client, conn *coredata.Connector, _ *log.Logger) (drivers.Driver, error) {
s, err := coredata.ConnectorSettings[coredata.PostHogConnectorSettings](conn)
if err != nil {
return nil, fmt.Errorf("cannot read posthog self-hosted connector settings: %w", err)
}
// Never fall back to the cloud gateway for a self-hosted
// connector — the instance URL is required at creation time.
if s.BaseURL == "" {
return nil, fmt.Errorf("cannot create posthog self-hosted driver: instance URL is required")
}
return drivers.NewPostHogDriver(c, s.BaseURL), nil
},
NewNameResolver: func(ctx context.Context, c *http.Client, conn *coredata.Connector, logger *log.Logger) drivers.NameResolver {
s, err := coredata.ConnectorSettings[coredata.PostHogConnectorSettings](conn)
if err != nil {
logger.ErrorCtx(ctx, "cannot read posthog self-hosted connector settings", log.Error(err))
return nil
}
if s.BaseURL == "" {
return nil
}
return drivers.NewPostHogNameResolver(c, s.BaseURL)
},
}
}

View File

@@ -26,41 +26,35 @@ const (
ConnectorProviderGoogleWorkspace ConnectorProvider = "GOOGLE_WORKSPACE" ConnectorProviderGoogleWorkspace ConnectorProvider = "GOOGLE_WORKSPACE"
ConnectorProviderLinear ConnectorProvider = "LINEAR" ConnectorProviderLinear ConnectorProvider = "LINEAR"
// _ ConnectorProvider = "FIGMA" — formerly Figma; removed (no driver, no OAuth config, no usage) // _ ConnectorProvider = "FIGMA" — formerly Figma; removed (no driver, no OAuth config, no usage)
ConnectorProviderOnePassword ConnectorProvider = "ONE_PASSWORD" ConnectorProviderOnePassword ConnectorProvider = "ONE_PASSWORD"
ConnectorProviderHubSpot ConnectorProvider = "HUBSPOT" ConnectorProviderHubSpot ConnectorProvider = "HUBSPOT"
ConnectorProviderDocuSign ConnectorProvider = "DOCUSIGN" ConnectorProviderDocuSign ConnectorProvider = "DOCUSIGN"
ConnectorProviderNotion ConnectorProvider = "NOTION" ConnectorProviderNotion ConnectorProvider = "NOTION"
ConnectorProviderBrex ConnectorProvider = "BREX" ConnectorProviderBrex ConnectorProvider = "BREX"
ConnectorProviderTally ConnectorProvider = "TALLY" ConnectorProviderTally ConnectorProvider = "TALLY"
ConnectorProviderCloudflare ConnectorProvider = "CLOUDFLARE" ConnectorProviderCloudflare ConnectorProvider = "CLOUDFLARE"
ConnectorProviderGrafana ConnectorProvider = "GRAFANA" ConnectorProviderGrafana ConnectorProvider = "GRAFANA"
ConnectorProviderOpenAI ConnectorProvider = "OPENAI" ConnectorProviderOpenAI ConnectorProvider = "OPENAI"
ConnectorProviderPostHog ConnectorProvider = "POSTHOG" ConnectorProviderPostHog ConnectorProvider = "POSTHOG"
// ConnectorProviderPostHogSelfHosted is a distinct provider for ConnectorProviderSentry ConnectorProvider = "SENTRY"
// customer-hosted PostHog instances: API-key + operator-supplied ConnectorProviderSupabase ConnectorProvider = "SUPABASE"
// instance URL. Cloud PostHog (POSTHOG) carries the OAuth path; a ConnectorProviderGitHub ConnectorProvider = "GITHUB"
// separate provider keeps the per-connection instance URL out of the ConnectorProviderIntercom ConnectorProvider = "INTERCOM"
// shared OAuth flow. ConnectorProviderResend ConnectorProvider = "RESEND"
ConnectorProviderPostHogSelfHosted ConnectorProvider = "POSTHOG_SELF_HOSTED" ConnectorProviderMicrosoft365 ConnectorProvider = "MICROSOFT_365"
ConnectorProviderSentry ConnectorProvider = "SENTRY" ConnectorProviderGitLab ConnectorProvider = "GITLAB"
ConnectorProviderSupabase ConnectorProvider = "SUPABASE" ConnectorProviderBitbucket ConnectorProvider = "BITBUCKET"
ConnectorProviderGitHub ConnectorProvider = "GITHUB" ConnectorProviderHeroku ConnectorProvider = "HEROKU"
ConnectorProviderIntercom ConnectorProvider = "INTERCOM" ConnectorProviderPagerDuty ConnectorProvider = "PAGERDUTY"
ConnectorProviderResend ConnectorProvider = "RESEND" ConnectorProviderAsana ConnectorProvider = "ASANA"
ConnectorProviderMicrosoft365 ConnectorProvider = "MICROSOFT_365" ConnectorProviderNetlify ConnectorProvider = "NETLIFY"
ConnectorProviderGitLab ConnectorProvider = "GITLAB" ConnectorProviderClickUp ConnectorProvider = "CLICKUP"
ConnectorProviderBitbucket ConnectorProvider = "BITBUCKET" ConnectorProviderVercel ConnectorProvider = "VERCEL"
ConnectorProviderHeroku ConnectorProvider = "HEROKU" ConnectorProviderMonday ConnectorProvider = "MONDAY"
ConnectorProviderPagerDuty ConnectorProvider = "PAGERDUTY" ConnectorProviderMetabase ConnectorProvider = "METABASE"
ConnectorProviderAsana ConnectorProvider = "ASANA" ConnectorProviderTailscale ConnectorProvider = "TAILSCALE"
ConnectorProviderNetlify ConnectorProvider = "NETLIFY" ConnectorProviderAnthropic ConnectorProvider = "ANTHROPIC"
ConnectorProviderClickUp ConnectorProvider = "CLICKUP" ConnectorProviderCursor ConnectorProvider = "CURSOR"
ConnectorProviderVercel ConnectorProvider = "VERCEL"
ConnectorProviderMonday ConnectorProvider = "MONDAY"
ConnectorProviderMetabase ConnectorProvider = "METABASE"
ConnectorProviderTailscale ConnectorProvider = "TAILSCALE"
ConnectorProviderAnthropic ConnectorProvider = "ANTHROPIC"
ConnectorProviderCursor ConnectorProvider = "CURSOR"
) )
var ( var (
@@ -84,7 +78,6 @@ func ConnectorProviders() []ConnectorProvider {
ConnectorProviderGrafana, ConnectorProviderGrafana,
ConnectorProviderOpenAI, ConnectorProviderOpenAI,
ConnectorProviderPostHog, ConnectorProviderPostHog,
ConnectorProviderPostHogSelfHosted,
ConnectorProviderSentry, ConnectorProviderSentry,
ConnectorProviderSupabase, ConnectorProviderSupabase,
ConnectorProviderGitHub, ConnectorProviderGitHub,
@@ -123,7 +116,6 @@ func (v ConnectorProvider) IsValid() bool {
ConnectorProviderGrafana, ConnectorProviderGrafana,
ConnectorProviderOpenAI, ConnectorProviderOpenAI,
ConnectorProviderPostHog, ConnectorProviderPostHog,
ConnectorProviderPostHogSelfHosted,
ConnectorProviderSentry, ConnectorProviderSentry,
ConnectorProviderSupabase, ConnectorProviderSupabase,
ConnectorProviderGitHub, ConnectorProviderGitHub,

View File

@@ -92,12 +92,13 @@ type (
InstanceURL string `json:"instance_url"` InstanceURL string `json:"instance_url"`
} }
// PostHogConnectorSettings carries the data-API base host for both the // PostHogConnectorSettings carries the data-API base host for the
// cloud (POSTHOG) and self-hosted (POSTHOG_SELF_HOSTED) providers. It // PostHog provider, which spans cloud and self-hosted deployments. For
// is the region-pinned host for API-key connections // API-key connections it is the region-pinned host
// (https://us.posthog.com / https://eu.posthog.com / a self-hosted // (https://us.posthog.com / https://eu.posthog.com) or a self-hosted
// instance URL). It is empty for cloud OAuth connections — the driver // instance URL. It is empty for cloud OAuth connections — the driver
// then defaults to the region-agnostic gateway https://oauth.posthog.com. // then discovers the region (us/eu) by probing, since the
// region-agnostic oauth.posthog.com gateway does not serve the data API.
PostHogConnectorSettings struct { PostHogConnectorSettings struct {
BaseURL string `json:"base_url"` BaseURL string `json:"base_url"`
} }

View File

@@ -1,15 +0,0 @@
-- Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
--
-- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted, provided that the above
-- copyright notice and this permission notice appear in all copies.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-- PERFORMANCE OF THIS SOFTWARE.
ALTER TYPE connector_provider ADD VALUE IF NOT EXISTS 'POSTHOG_SELF_HOSTED';

View File

@@ -95,27 +95,38 @@ func apiKeyConnectorSettings(input types.CreateAPIKeyConnectorInput) (json.RawMe
return json.Marshal(&coredata.MetabaseConnectorSettings{InstanceURL: *input.MetabaseInstanceURL}) return json.Marshal(&coredata.MetabaseConnectorSettings{InstanceURL: *input.MetabaseInstanceURL})
case coredata.ConnectorProviderPostHog: case coredata.ConnectorProviderPostHog:
if input.PosthogRegion == nil || *input.PosthogRegion == "" { region := ""
return nil, fmt.Errorf("cannot create posthog connector: posthogRegion is required") if input.PosthogRegion != nil {
region = *input.PosthogRegion
} }
baseURL, ok := drivers.PostHogRegionBaseURL(*input.PosthogRegion) instanceURL := ""
if !ok { if input.PosthogInstanceURL != nil {
return nil, fmt.Errorf("cannot create posthog connector: posthogRegion must be US or EU") instanceURL = *input.PosthogInstanceURL
} }
return json.Marshal(&coredata.PostHogConnectorSettings{BaseURL: baseURL}) // Cloud (region) and self-hosted (instance URL) are mutually
case coredata.ConnectorProviderPostHogSelfHosted: // exclusive; exactly one identifies the connection's data host.
if input.PosthogInstanceURL == nil || *input.PosthogInstanceURL == "" { switch {
return nil, fmt.Errorf("cannot create posthog self-hosted connector: posthogInstanceUrl is required") case region != "" && instanceURL != "":
} return nil, fmt.Errorf("cannot create posthog connector: set either posthogRegion or posthogInstanceUrl, not both")
case region != "":
baseURL, ok := drivers.PostHogRegionBaseURL(region)
if !ok {
return nil, fmt.Errorf("cannot create posthog connector: posthogRegion must be US or EU")
}
u, err := url.Parse(*input.PosthogInstanceURL) return json.Marshal(&coredata.PostHogConnectorSettings{BaseURL: baseURL})
if err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" { case instanceURL != "":
return nil, fmt.Errorf("cannot create posthog self-hosted connector: posthogInstanceUrl must be an http(s) URL") u, err := url.Parse(instanceURL)
} if err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" {
return nil, fmt.Errorf("cannot create posthog connector: posthogInstanceUrl must be an http(s) URL")
}
return json.Marshal(&coredata.PostHogConnectorSettings{BaseURL: *input.PosthogInstanceURL}) return json.Marshal(&coredata.PostHogConnectorSettings{BaseURL: instanceURL})
default:
return nil, fmt.Errorf("cannot create posthog connector: posthogRegion or posthogInstanceUrl is required")
}
} }
return nil, nil return nil, nil

View File

@@ -23,10 +23,6 @@ enum ConnectorProvider
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderCloudflare") @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderCloudflare")
OPENAI @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderOpenAI") OPENAI @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderOpenAI")
POSTHOG @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderPostHog") POSTHOG @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderPostHog")
POSTHOG_SELF_HOSTED
@goEnum(
value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderPostHogSelfHosted"
)
SENTRY @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderSentry") SENTRY @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderSentry")
SUPABASE SUPABASE
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderSupabase") @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderSupabase")