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:
@@ -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")}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ func NewBuiltinRegistry() *Registry {
|
|||||||
onePasswordRegistration(),
|
onePasswordRegistration(),
|
||||||
openaiRegistration(),
|
openaiRegistration(),
|
||||||
posthogRegistration(),
|
posthogRegistration(),
|
||||||
posthogSelfHostedRegistration(),
|
|
||||||
pagerdutyRegistration(),
|
pagerdutyRegistration(),
|
||||||
resendRegistration(),
|
resendRegistration(),
|
||||||
sentryRegistration(),
|
sentryRegistration(),
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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';
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
Reference in New Issue
Block a user