@embeddable.com/sdk-core
Version:
Core Embeddable SDK module responsible for web-components bundling and publishing.
313 lines (292 loc) • 9.04 kB
text/typescript
import * as path from "node:path";
import { existsSync } from "node:fs";
import { RollupOptions } from "rollup";
import { z } from "zod";
import {
errorFormatter,
ComponentLibraryConfig,
} from "@embeddable.com/sdk-utils";
export type Region = "EU" | "US" | "legacy-US";
export type EmbeddableConfig = {
plugins: (() => {
pluginName: string;
build: (config: ResolvedEmbeddableConfig) => Promise<unknown>;
cleanup: (config: ResolvedEmbeddableConfig) => Promise<unknown>;
validate: (config: ResolvedEmbeddableConfig) => Promise<unknown>;
buildPackage: (config: ResolvedEmbeddableConfig) => Promise<unknown>;
})[];
pushModels?: boolean;
pushComponents?: boolean;
pushBaseUrl?: string;
audienceUrl?: string;
authDomain?: string;
authClientId?: string;
errorFallbackComponent?: string;
applicationEnvironment?: string;
rollbarAccessToken?: string;
previewBaseUrl?: string;
componentsSrc?: string;
modelsSrc?: string;
presetsSrc?: string;
customCanvasCss?: string;
viteConfig?: {
resolve?: {
alias?: Record<string, string>;
};
};
rollupOptions?: RollupOptions;
region?: Region;
componentLibraries?: string[] | ComponentLibraryConfig[];
customizationFile?: string;
lifecycleHooksFile?: string;
};
const PLUGIN_NAME = "sdk-react" as const;
export type PluginName = typeof PLUGIN_NAME;
export type ResolvedEmbeddableConfig = {
core: {
rootDir: string;
templatesDir: string;
configsDir: string;
};
client: {
rootDir: string;
srcDir: string;
modelsSrc: string;
presetsSrc: string;
buildDir: string;
tmpDir: string;
customCanvasCss: string;
webComponentRoot: string;
componentDir: string;
stencilBuild: string;
archiveFile: string;
errorFallbackComponent?: string;
bundleHash?: string;
customizationFile: string;
lifecycleHooksFile: string;
componentLibraries: string[] | ComponentLibraryConfig[];
viteConfig: {
resolve?: {
alias?: Record<string, string>;
};
};
rollupOptions: RollupOptions;
};
outputOptions: {
typesEntryPointFilename: string;
};
pushModels: boolean;
pushComponents: boolean;
pushBaseUrl: string;
audienceUrl: string;
previewBaseUrl: string;
authDomain: string;
authClientId: string;
applicationEnvironment: string;
rollbarAccessToken: string;
plugins: EmbeddableConfig["plugins"];
buildTime: [number, number];
dev?: {
watch: boolean;
logger: any;
sys: any;
};
region: Region;
[PLUGIN_NAME]: {
rootDir: string;
templatesDir: string;
outputOptions: {
fileName: string;
buildName: string;
componentsEntryPointFilename: string;
};
};
};
const REGION_CONFIGS = {
EU: {
pushBaseUrl: "https://api.eu.embeddable.com",
audienceUrl: "https://auth.eu.embeddable.com",
previewBaseUrl: "https://app.eu.embeddable.com",
authDomain: "auth.eu.embeddable.com",
authClientId: "6OGPwIQsVmtrBKhNrwAaXhz4ePb0kBGV",
},
US: {
pushBaseUrl: "https://api.us.embeddable.com",
audienceUrl: "https://auth.embeddable.com",
previewBaseUrl: "https://app.us.embeddable.com",
authDomain: "auth.embeddable.com",
authClientId: "dygrSUmI6HmgY5ymVbEAoLDEBxIOyr1V",
},
"legacy-US": {
pushBaseUrl: "https://api.embeddable.com",
audienceUrl: "https://auth.embeddable.com",
previewBaseUrl: "https://app.embeddable.com",
authDomain: "auth.embeddable.com",
authClientId: "dygrSUmI6HmgY5ymVbEAoLDEBxIOyr1V",
},
};
const ComponentLibraryConfigSchema = z.object({
name: z.string(),
include: z.array(z.string()).optional(),
exclude: z.array(z.string()).optional(),
});
export const embeddableConfigSchema = z
.object({
plugins: z.array(z.function()),
region: z
.union([z.literal("EU"), z.literal("US"), z.literal("legacy-US")])
.optional(),
pushModels: z.boolean().optional(),
pushComponents: z.boolean().optional(),
pushBaseUrl: z.string().optional(),
audienceUrl: z.string().optional(),
authDomain: z.string().optional(),
authClientId: z.string().optional(),
errorFallbackComponent: z.string().optional(),
applicationEnvironment: z.string().optional(),
rollbarAccessToken: z.string().optional(),
previewBaseUrl: z.string().optional(),
modelsSrc: z.string().optional(),
presetsSrc: z.string().optional(),
componentsSrc: z.string().optional(),
customCanvasCss: z.string().optional(),
customizationFile: z.string().optional(),
lifecycleHooksFile: z.string().optional(),
componentLibraries: z
.union([z.array(z.string()), z.array(ComponentLibraryConfigSchema)])
.optional(),
viteConfig: z
.object({
resolve: z
.object({
alias: z.record(z.string()),
})
.optional(),
})
.optional(),
rollupOptions: z.object({}).optional(),
})
.strict();
export default (config: EmbeddableConfig) => {
const safeParse = embeddableConfigSchema.safeParse(config);
const errors: string[] = [];
if (!safeParse.success) {
errorFormatter(safeParse.error.issues).forEach((error) => {
errors.push(`${error}`);
});
}
if (errors.length > 0) {
throw new Error(`Invalid Embeddable Configuration: ${errors.join("\n")}}`);
}
let {
plugins,
region = "legacy-US",
pushModels = true,
pushComponents = true,
pushBaseUrl,
audienceUrl,
authDomain,
authClientId,
errorFallbackComponent,
applicationEnvironment,
rollbarAccessToken,
previewBaseUrl,
modelsSrc = "src",
presetsSrc = "src",
componentsSrc = "src",
customCanvasCss = "src/custom-canvas.css",
viteConfig = {},
rollupOptions = {},
componentLibraries = [],
customizationFile = "embeddable.theme.ts",
lifecycleHooksFile = "lifecycle.config.ts",
} = config;
const regionConfig = REGION_CONFIGS[region];
const __dirname = import.meta.dirname;
const coreRoot = path.resolve(__dirname, "..");
const clientRoot = process.cwd();
if (!path.isAbsolute(componentsSrc)) {
componentsSrc = path.resolve(clientRoot, componentsSrc);
if (!existsSync(componentsSrc)) {
throw new Error(
`componentsSrc directory ${componentsSrc} does not exist`
);
}
}
if (modelsSrc && !path.isAbsolute(modelsSrc)) {
modelsSrc = path.resolve(clientRoot, modelsSrc);
if (!existsSync(modelsSrc)) {
throw new Error(`modelsSrc directory ${modelsSrc} does not exist`);
}
}
if (presetsSrc && !path.isAbsolute(presetsSrc)) {
presetsSrc = path.resolve(clientRoot, presetsSrc);
if (!existsSync(presetsSrc)) {
throw new Error(`presetsSrc directory ${presetsSrc} does not exist`);
}
}
return {
core: {
rootDir: coreRoot,
templatesDir: path.resolve(coreRoot, "templates"),
configsDir: path.resolve(coreRoot, "configs"),
},
client: {
rootDir: clientRoot,
srcDir: path.resolve(clientRoot, componentsSrc),
modelsSrc: modelsSrc ? path.resolve(clientRoot, modelsSrc) : undefined,
presetsSrc: presetsSrc ? path.resolve(clientRoot, presetsSrc) : undefined,
buildDir: path.resolve(clientRoot, ".embeddable-build"),
tmpDir: path.resolve(clientRoot, ".embeddable-tmp"),
customCanvasCss: path.resolve(clientRoot, customCanvasCss),
webComponentRoot: path.resolve(
clientRoot,
".embeddable-build",
"web-component"
),
componentDir: path.resolve(
clientRoot,
".embeddable-build",
"web-component",
"component"
),
stencilBuild: path.resolve(
clientRoot,
".embeddable-build",
"dist",
"embeddable-wrapper"
),
archiveFile: path.resolve(clientRoot, "embeddable-build.zip"),
errorFallbackComponent: errorFallbackComponent
? path.resolve(clientRoot, errorFallbackComponent)
: undefined,
bundleHash: undefined, // This will be set by the build process
viteConfig,
rollupOptions,
componentLibraries,
customizationFile: path.resolve(clientRoot, customizationFile),
lifecycleHooksFile: path.resolve(clientRoot, lifecycleHooksFile),
},
outputOptions: {
typesEntryPointFilename: "embeddable-types-entry-point.js",
},
buildTime: undefined, // This will be set by the build process
dev: {
watch: false,
logger: undefined,
sys: undefined,
},
region,
pushModels,
pushComponents,
pushBaseUrl: pushBaseUrl ?? regionConfig.pushBaseUrl,
audienceUrl: audienceUrl ?? regionConfig.audienceUrl,
previewBaseUrl: previewBaseUrl ?? regionConfig.previewBaseUrl,
authDomain: authDomain ?? regionConfig.authDomain,
authClientId: authClientId ?? regionConfig.authClientId,
applicationEnvironment: applicationEnvironment ?? "production",
rollbarAccessToken:
rollbarAccessToken ?? "5c6028038d844bf1835a0f4db5f55d9e",
plugins,
};
};