Skip to content

Commit 0bce50e

Browse files
committed
Adding support for baseWorkflowDomain, ID vs URL
1 parent 1b02d65 commit 0bce50e

File tree

2 files changed

+138
-7
lines changed

2 files changed

+138
-7
lines changed

packages/sdk/src/server/__tests__/server.test.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import fetchMock from "jest-fetch-mock";
55
import { ClientCredentials } from "simple-oauth2";
66

77
let client: ServerClient;
8+
let customDomainClient: ServerClient;
89
let oauthClientMock: ClientCredentials;
910

1011
beforeEach(() => {
@@ -30,6 +31,16 @@ beforeEach(() => {
3031
},
3132
oauthClientMock,
3233
);
34+
35+
customDomainClient = new ServerClient({
36+
publicKey: "test-public-key",
37+
secretKey: "test-secret-key",
38+
oauth: {
39+
clientId: "test-client-id",
40+
clientSecret: "test-client-secret",
41+
},
42+
baseWorkflowDomain: "example.com",
43+
});
3344
});
3445

3546
describe("ServerClient", () => {
@@ -730,4 +741,70 @@ describe("ServerClient", () => {
730741
})).rejects.toThrow("External user ID is required");
731742
});
732743
});
744+
745+
describe("ServerClient - buildWorkflowUrl", () => {
746+
describe("Default domain (m.pipedream.net)", () => {
747+
it("should return full URL if input is a full URL with protocol", () => {
748+
const input = "https://en123.m.pipedream.net";
749+
const expected = "https://en123.m.pipedream.net/";
750+
expect(client["buildWorkflowUrl"](input)).toBe(expected);
751+
});
752+
753+
it("should return full URL if input is a URL without protocol", () => {
754+
const input = "en123.m.pipedream.net";
755+
const expected = "https://en123.m.pipedream.net/";
756+
expect(client["buildWorkflowUrl"](input)).toBe(expected);
757+
});
758+
759+
it("should construct URL with 'm.pipedream.net' if input is an endpoint ID", () => {
760+
const input = "en123";
761+
const expected = "https://en123.m.pipedream.net";
762+
expect(client["buildWorkflowUrl"](input)).toBe(expected);
763+
});
764+
765+
it("should handle input with a path in full URL with protocol", () => {
766+
const input = "https://en123.m.pipedream.net/foo";
767+
const expected = "https://en123.m.pipedream.net/foo";
768+
expect(client["buildWorkflowUrl"](input)).toBe(expected);
769+
});
770+
771+
it("should handle input with a path when no protocol is provided", () => {
772+
const input = "en123.m.pipedream.net/foo";
773+
const expected = "https://en123.m.pipedream.net/foo";
774+
expect(client["buildWorkflowUrl"](input)).toBe(expected);
775+
});
776+
});
777+
778+
describe("Custom domain (example.com)", () => {
779+
it("should return full URL if input is a full URL with protocol", () => {
780+
const input = "https://en123.example.com";
781+
const expected = "https://en123.example.com/";
782+
expect(customDomainClient["buildWorkflowUrl"](input)).toBe(expected);
783+
});
784+
785+
it("should return full URL if input is a URL without protocol", () => {
786+
const input = "en123.example.com";
787+
const expected = "https://en123.example.com/";
788+
expect(customDomainClient["buildWorkflowUrl"](input)).toBe(expected);
789+
});
790+
791+
it("should construct URL with 'example.com' if input is an endpoint ID", () => {
792+
const input = "en123";
793+
const expected = "https://en123.example.com";
794+
expect(customDomainClient["buildWorkflowUrl"](input)).toBe(expected);
795+
});
796+
797+
it("should handle input with a path in full URL with protocol", () => {
798+
const input = "https://en123.example.com/foo";
799+
const expected = "https://en123.example.com/foo";
800+
expect(customDomainClient["buildWorkflowUrl"](input)).toBe(expected);
801+
});
802+
803+
it("should handle input with a path when no protocol is provided", () => {
804+
const input = "en123.example.com/foo";
805+
const expected = "https://en123.example.com/foo";
806+
expect(customDomainClient["buildWorkflowUrl"](input)).toBe(expected);
807+
});
808+
});
809+
});
733810
});

packages/sdk/src/server/index.ts

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ export type CreateServerClientOpts = {
5555
* The API host URL. Used by Pipedream employees. Defaults to "api.pipedream.com" if not provided.
5656
*/
5757
apiHost?: string;
58+
59+
/**
60+
* Base domain for workflows. Used for custom domains: https://pipedream.com/docs/workflows/domains
61+
*/
62+
baseWorkflowDomain?: string;
5863
};
5964

6065
/**
@@ -329,7 +334,8 @@ export class ServerClient {
329334
private environment: string;
330335
private oauthClient?: ClientCredentials;
331336
private oauthToken?: AccessToken;
332-
private readonly baseURL: string;
337+
private readonly baseAPIURL: string;
338+
private readonly baseWorkflowDomain: string;
333339

334340
/**
335341
* Constructs a new ServerClient instance.
@@ -345,15 +351,18 @@ export class ServerClient {
345351
this.secretKey = opts.secretKey;
346352
this.publicKey = opts.publicKey;
347353

348-
const { apiHost = "api.pipedream.com" } = opts;
349-
this.baseURL = `https://${apiHost}/v1`;
354+
const {
355+
apiHost = "api.pipedream.com", baseWorkflowDomain = "m.pipedream.net",
356+
} = opts;
357+
this.baseAPIURL = `https://${apiHost}/v1`;
358+
this.baseWorkflowDomain = baseWorkflowDomain;
350359

351360
if (oauthClient) {
352361
// Use the provided OAuth client (useful for testing)
353362
this.oauthClient = oauthClient;
354363
} else {
355364
// Configure the OAuth client normally
356-
this.configureOauthClient(opts, this.baseURL);
365+
this.configureOauthClient(opts, this.baseAPIURL);
357366
}
358367
}
359368

@@ -445,7 +454,7 @@ export class ServerClient {
445454
headers: customHeaders,
446455
body,
447456
method = "GET",
448-
baseURL = this.baseURL,
457+
baseURL = this.baseAPIURL,
449458
...fetchOpts
450459
} = opts;
451460

@@ -754,10 +763,53 @@ export class ServerClient {
754763
});
755764
}
756765

766+
/**
767+
* Builds a full workflow URL based on the input.
768+
*
769+
* @param input - Either a full URL (with or without protocol) or just an endpoint ID.
770+
*
771+
* @returns The fully constructed URL.
772+
*
773+
* @throws If the input is not a valid URL and not an ID, the function assumes it's an endpoint ID.
774+
*
775+
* @example
776+
* // Full URL input
777+
* this.buildWorkflowUrl("https://en123.m.pipedream.net");
778+
* // Returns: "https://en123.m.pipedream.net"
779+
*
780+
* @example
781+
* // Partial URL (without protocol)
782+
* this.buildWorkflowUrl("en123.m.pipedream.net");
783+
* // Returns: "https://en123.m.pipedream.net"
784+
*
785+
* @example
786+
* // ID only input
787+
* this.buildWorkflowUrl("en123");
788+
* // Returns: "https://en123.yourdomain.com" (where `yourdomain.com` is set in `baseWorkflowDomain`)
789+
*/
790+
private buildWorkflowUrl(input: string): string {
791+
let url: string;
792+
793+
const isUrl = input.includes(".") || input.startsWith("http");
794+
795+
if (isUrl) {
796+
// Try to parse the input as a URL
797+
const parsedUrl = new URL(input.startsWith("http")
798+
? input
799+
: `https://${input}`);
800+
url = parsedUrl.href;
801+
} else {
802+
// If the input is an ID, construct the full URL using the base domain
803+
url = `https://${input}.${this.baseWorkflowDomain}`;
804+
}
805+
806+
return url;
807+
}
808+
757809
/**
758810
* Invokes a workflow using the URL of its HTTP interface(s), by sending an
759811
*
760-
* @param url - The URL of the workflow's HTTP interface.
812+
* @param urlOrEndpoint - The URL of the workflow's HTTP interface, or the ID of the endpoint
761813
* @param opts - The options for the request.
762814
* @param opts.body - The body of the request. It must be a JSON-serializable
763815
* value (e.g. an object, null, a string, etc.).
@@ -787,12 +839,14 @@ export class ServerClient {
787839
* console.log(response);
788840
* ```
789841
*/
790-
public async invokeWorkflow(url: string, opts: RequestOptions = {}, authType: HTTPAuthType = HTTPAuthType.None): Promise<unknown> {
842+
public async invokeWorkflow(urlOrEndpoint: string, opts: RequestOptions = {}, authType: HTTPAuthType = HTTPAuthType.None): Promise<unknown> {
791843
const {
792844
body,
793845
headers = {},
794846
} = opts;
795847

848+
const url = this.buildWorkflowUrl(urlOrEndpoint);
849+
796850
let authHeader: string | undefined;
797851
switch (authType) {
798852
// It's expected that users will pass their own Authorization header in the static bearer case

0 commit comments

Comments
 (0)