Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ module.exports = {
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "error",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-unused-vars": ["error", { varsIgnorePattern: "^_" }],
"@typescript-eslint/no-use-before-define": "error",
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/prefer-for-of": "error",
Expand Down
11 changes: 10 additions & 1 deletion src/feature/featureType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ const FEATURE_TYPES = {
platform: "platform",
};

type Entrypoint = "catalog" | "labs";

const ENTRYPOINTS: Entrypoint[] = ["catalog", "labs"];

type FeatureType = keyof typeof FEATURE_TYPES;

type PatientOptions = {
Expand All @@ -19,9 +23,12 @@ type PatientOptions = {
discount?: number;
};
type TreatmentPlanOptions = { patient?: PatientOptions; secretToken: string };
type PlatformOptions = TreatmentPlanOptions & { entrypoint?: Entrypoint };

type FeatureOptions<F extends FeatureType> = F extends "treatmentPlan" | "platform"
type FeatureOptions<F extends FeatureType> = F extends "treatmentPlan"
? TreatmentPlanOptions
: F extends "platform"
? PlatformOptions
: Record<any, never>;

interface Feature {
Expand All @@ -34,8 +41,10 @@ interface Feature {
export {
FeatureType,
FeatureOptions,
PlatformOptions,
TreatmentPlanOptions,
PatientOptions,
Feature,
FEATURE_TYPES,
ENTRYPOINTS,
};
116 changes: 92 additions & 24 deletions src/feature/featureUtil.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,34 +32,102 @@ describe("getFeatureUrl", () => {
});

describe("feature type", () => {
it("returns the proper url when the feature type is 'treatmentPlan'", async () => {
const url = await getFeatureURL(
"treatmentPlan",
mockFeatureOptions,
mockFullscriptOptions,
mockFrameId
);
describe("the feature type is 'treatmentPlan'", () => {
it("returns the proper url", async () => {
const url = await getFeatureURL(
"treatmentPlan",
mockFeatureOptions,
mockFullscriptOptions,
mockFrameId
);

expect(url).toEqual(
`https://us-snd.fullscript.io/api/embeddable/session/treatment_plans/new?data_token=${encodeURIComponent(
mockDataToken
)}&secret_token=secretToken&public_key=publicKey&frame_id=uuid&target_origin=http://localhost`
);
expect(url).toEqual(
`https://us-snd.fullscript.io/api/embeddable/session/treatment_plans/new?data_token=${encodeURIComponent(
mockDataToken
)}&secret_token=secretToken&public_key=publicKey&frame_id=uuid&target_origin=http://localhost`
);
});

it("doesn't add entrypoint to the url when entrypoint is given", async () => {
const url = await getFeatureURL(
"treatmentPlan",
// @ts-expect-error
{ ...mockFeatureOptions, entrypoint: "labs" },
mockFullscriptOptions,
mockFrameId
);

expect(url).toEqual(
`https://us-snd.fullscript.io/api/embeddable/session/treatment_plans/new?data_token=${encodeURIComponent(
mockDataToken
)}&secret_token=secretToken&public_key=publicKey&frame_id=uuid&target_origin=http://localhost`
);
});
});

it("returns the proper url when the feature type is 'platform'", async () => {
const url = await getFeatureURL(
"platform",
mockFeatureOptions,
mockFullscriptOptions,
mockFrameId
);
describe("the feature type is 'platform'", () => {
it("returns the proper url", async () => {
const url = await getFeatureURL(
"platform",
mockFeatureOptions,
mockFullscriptOptions,
mockFrameId
);

expect(url).toEqual(
`https://us-snd.fullscript.io/api/embeddable/session/embed/entry?data_token=${encodeURIComponent(
mockDataToken
)}&secret_token=secretToken&public_key=publicKey&frame_id=uuid&target_origin=http://localhost`
);
expect(url).toEqual(
`https://us-snd.fullscript.io/api/embeddable/session/embed/entry?data_token=${encodeURIComponent(
mockDataToken
)}&secret_token=secretToken&public_key=publicKey&frame_id=uuid&target_origin=http://localhost`
);
});

describe("entrypoint", () => {
it("adds labs entrypoint to the url when it is given", async () => {
const url = await getFeatureURL(
"platform",
{ ...mockFeatureOptions, entrypoint: "labs" },
mockFullscriptOptions,
mockFrameId
);

expect(url).toEqual(
`https://us-snd.fullscript.io/api/embeddable/session/embed/entry?data_token=${encodeURIComponent(
mockDataToken
)}&secret_token=secretToken&entrypoint=labs&public_key=publicKey&frame_id=uuid&target_origin=http://localhost`
);
});

it("adds catalog entrypoint to the url when it is given", async () => {
const url = await getFeatureURL(
"platform",
{ ...mockFeatureOptions, entrypoint: "catalog" },
mockFullscriptOptions,
mockFrameId
);

expect(url).toEqual(
`https://us-snd.fullscript.io/api/embeddable/session/embed/entry?data_token=${encodeURIComponent(
mockDataToken
)}&secret_token=secretToken&entrypoint=catalog&public_key=publicKey&frame_id=uuid&target_origin=http://localhost`
);
});

it("doesn't add entrypoint to the url when an invalid entrypoint is given", async () => {
const url = await getFeatureURL(
"platform",
// @ts-expect-error
{ ...mockFeatureOptions, entrypoint: "invalid" },
mockFullscriptOptions,
mockFrameId
);

expect(url).toEqual(
`https://us-snd.fullscript.io/api/embeddable/session/embed/entry?data_token=${encodeURIComponent(
mockDataToken
)}&secret_token=secretToken&public_key=publicKey&frame_id=uuid&target_origin=http://localhost`
);
});
});
});
});

Expand Down
18 changes: 16 additions & 2 deletions src/feature/featureUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,31 @@ import { validateFeatureType } from "../fullscriptJsValidator";
import { buildQueryString } from "../utils";

import { FEATURE_PATHS } from "./featurePath";
import { FeatureType, FeatureOptions } from "./featureType";
import { ENTRYPOINTS, FeatureType, FeatureOptions } from "./featureType";

const getValidFeatureOptions = (
featureType: FeatureType,
featureOptions: FeatureOptions<FeatureType>
) => {
if ("entrypoint" in featureOptions) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this if necessary to confirm the type to tsc?

Copy link
Collaborator Author

@pipopotamasu pipopotamasu Mar 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not for tsc.

We would like to remove entrypoint point option when it is given. That's why I put this if condition. Technically, we can merge this if with the following one but I wanted to make it separated for readability

if (featureType === "treatmentPlan" || !ENTRYPOINTS.includes(featureOptions.entrypoint)) {
const { entrypoint: _removed, ...validOptions } = featureOptions;
return validOptions;
}
}

return featureOptions;
};
const getFeatureURL = async <F extends FeatureType>(
featureType: F,
featureOptions: FeatureOptions<F>,
fullscriptOptions: FullscriptOptions,
frameId: string
): Promise<string> => {
const { publicKey, env, domain } = fullscriptOptions;

const queryString = await buildQueryString({
...featureOptions,
...getValidFeatureOptions(featureType, featureOptions),
fullscriptOptions,
publicKey,
frameId,
Expand Down